Skip to content

Commit

Permalink
feat: Add actor_nr as substitution variable
Browse files Browse the repository at this point in the history
This is a long time coming, since we are now using actors instead of
hardcoded teams. Old team_nr will stay working for now
  • Loading branch information
mromulus committed Nov 25, 2024
1 parent cc7e320 commit edf3445
Show file tree
Hide file tree
Showing 17 changed files with 67 additions and 33 deletions.
4 changes: 2 additions & 2 deletions app/calculation/hostname_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ class HostnameGenerator < Patterns::Calculation
def result
subject.virtual_machine = virtual_machine
hostname_sequence_suffix = '{{ seq }}' if virtual_machine.clustered?
hostname_team_suffix = '{{ team_nr_str }}' if virtual_machine.numbered_actor && (!nic || !nic.network&.numbered?)
hostname_team_suffix = '{{ actor_nr_str }}' if virtual_machine.numbered_actor && (!nic || !nic.network&.numbered?)

sequences = [
hostname_sequence_suffix,
hostname_team_suffix
].compact
hostname = "#{subject.hostname}#{sequences.join('-')}"
domain = nic&.network&.full_domain.to_s.gsub(/#+/, '{{ team_nr_str }}')
domain = nic&.network&.full_domain.to_s.gsub(/#+/, '{{ actor_nr_str }}')

Struct.new(:hostname, :domain, :fqdn).new(
hostname:,
Expand Down
6 changes: 4 additions & 2 deletions app/calculation/liquid_range_substitution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ def network_numbering_source(object)

def replacement_ranges
{
'seq' => sequential_range.map { |a| a.to_s.rjust(2, '0') },
'seq' => sequential_range.map { _1.to_s.rjust(2, '0') },
'team_nr' => numbering_range,
'team_nr_str' => numbering_range&.map { |a| a.to_s.rjust(2, '0') }
'team_nr_str' => numbering_range&.map { _1.to_s.rjust(2, '0') },
'actor_nr' => numbering_range,
'actor_nr_str' => numbering_range&.map { _1.to_s.rjust(2, '0') }
}
end

Expand Down
3 changes: 2 additions & 1 deletion app/calculation/string_substituter.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

class StringSubstituter < Patterns::Calculation
VALID_LIQUID_KEYS = %i(seq team_nr)
VALID_LIQUID_KEYS = %i(seq team_nr actor_nr)

private
def result
Expand All @@ -21,6 +21,7 @@ def substitution_keys
options.slice(*VALID_LIQUID_KEYS).symbolize_keys.tap do |keys|
keys[:seq] = keys[:seq].to_s.rjust(2, '0') if keys[:seq]
keys[:team_nr_str] = keys[:team_nr].to_s.rjust(2, '0') if keys[:team_nr]
keys[:actor_nr_str] = keys[:actor_nr].to_s.rjust(2, '0') if keys[:actor_nr]
end.stringify_keys
end
end
2 changes: 1 addition & 1 deletion app/forms/address_pool_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AddressPoolForm < Patterns::Form
if input == ''
public_send("#{field.to_s.sub('_address', '')}=", nil)
else
address = IPAddress::IPv4.new("#{StringSubstituter.result_for(input, { team_nr: 1 })}/#{resource.ip_network.prefix}") rescue nil
address = IPAddress::IPv4.new("#{StringSubstituter.result_for(input, { team_nr: 1, actor_nr: 1 })}/#{resource.ip_network.prefix}") rescue nil
if address && resource.ip_network.include?(address)
public_send("#{field.to_s.sub('_address', '')}=", address.u32 - resource.ip_network.network_u32 - 1)
else
Expand Down
6 changes: 3 additions & 3 deletions app/models/address_pool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def self.to_icon
end

def numbered?
network_address =~ /#|team_nr/
network_address =~ /#|team_nr|actor_nr/
end

def gateway_address_object
Expand All @@ -59,12 +59,12 @@ def ip_network(team = nil, base = network_address.dup)
return unless base

if last_octet_is_dynamic?
first_net = IPAddress(StringSubstituter.result_for(base, { team_nr: 1 })).network
first_net = IPAddress(StringSubstituter.result_for(base, { team_nr: 1, actor_nr: 1 })).network
IPAddress::IPv4.parse_u32(
first_net.to_i + ((team || 1) - 1) * first_net.size, first_net.prefix
)
else
templated = StringSubstituter.result_for(base, { team_nr: team || 1 })
templated = StringSubstituter.result_for(base, { team_nr: team || 1, actor_nr: team || 1 })
IPAddress(templated).network
end
end
Expand Down
5 changes: 3 additions & 2 deletions app/models/network.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def gateway_hosts
end

def numbered?
cloud_id =~ /#|team_nr/ || address_pools.any?(&:numbered?)
cloud_id =~ /#|team_nr|actor_nr/ || address_pools.any?(&:numbered?)
end

def slug_candidates
Expand All @@ -84,7 +84,8 @@ def ip_network(index, type)
return unless public_send(type)
raw_value = public_send(type).dup
templated = StringSubstituter.result_for(raw_value, {
team_nr: index || 1
team_nr: index || 1,
actor_nr: index || 1
})
IPAddress(templated).network
end
Expand Down
3 changes: 2 additions & 1 deletion app/presenters/address_preview_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def substitute(text)
text,
{
seq: sequential_number,
team_nr: team_number
team_nr: team_number,
actor_nr: team_number
}
)
end
Expand Down
5 changes: 4 additions & 1 deletion app/presenters/api/v3/instance_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def substitute(text)
text,
{
team_nr: team_number,
actor_nr: team_number,
seq: sequential_number
}
)
Expand All @@ -84,6 +85,8 @@ def team_numbers
{
team_nr: team_number,
team_nr_str: team_number.to_s.rjust(2, '0'),
actor_nr: team_number,
actor_nr_str: team_number.to_s.rjust(2, '0'),
}
end

Expand All @@ -105,7 +108,7 @@ def hostname_sequence_suffix
end

def hostname_team_suffix
't{{ team_nr_str }}' if vm.numbered_actor
't{{ actor_nr_str }}' if vm.numbered_actor
end

def inventory_name
Expand Down
4 changes: 3 additions & 1 deletion app/presenters/api/v3/network_instance_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class NetworkInstancePresenter < Struct.new(:network, :team_number)
def as_json
{
team_nr: team_number,
actor_nr: team_number,
cloud_id: substitute(network.cloud_id),
domains: [
substitute(network.full_domain)
Expand All @@ -29,7 +30,8 @@ def substitute(text)
StringSubstituter.result_for(
text,
{
team_nr: team_number
team_nr: team_number,
actor_nr: team_number
}
)
end
Expand Down
18 changes: 10 additions & 8 deletions app/views/docs/templating.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@ Main use case is using dynamic variables in `Network` or `VirtualMachine` fields

Currently, following variables can be used:

1. `team_nr` - the number of Blue team, as iterated over the environment maximum
1. `team_nr_str` - the number of Blue team, as iterated over the environment maximum, leftpadded with zeroes.
1. `actor_nr` - the number of Blue team, as iterated over the environment maximum
1. `actor_nr_str` - the number of Blue team, as iterated over the environment maximum, leftpadded with zeroes.
1. `team_nr` - legacy version of `actor_nr`
1. `team_nr_str` - legacy version of `actor_nr_str`
1. `seq` - sequential number, if a `VirtualMachine` is configured with a custom deploy count.

### Network

When `{{ team_nr }}` or `{{ team_nr_str }}` is added to compatible field (domain, cloud ID, network address), the network is switched to be in numbered mode. Any virtual machine attached to this network will be forced to deploy in "one per each actor entry" mode.
When `{{ actor_nr }}` or `{{ actor_nr_str }}` is added to compatible field (domain, cloud ID, network address), the network is switched to be in numbered mode. Any virtual machine attached to this network will be forced to deploy in "one per each actor entry" mode.

### Filters

Commonly used filter patterns, when current actor entries count equals _5_:

| Pattern | Description | Resulting values |
| ------------------------------------------ | ---------------------------------------------------------------------------------- | ---------------------------- |
| 10.{{ team_nr }}.1.0/24 | basic substitution | 10. **[1-5]** .1.0/24 |
| a:b:c:d:12{{ team_nr_str }}::/80 | leftpad equivalent, makes the substitution always be 2 characters, with 0 in front | a:b:c:d:12 **[01-05]** ::/80 |
| 100.64.{{ team_nr &vert; plus: 200 }}.0/24 | offset applied to addressing, allows for more efficient use of address space | 100.64. **[201-205]** .0/24 |
| Pattern | Description | Resulting values |
| ------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------- |
| 10.{{ actor_nr }}.1.0/24 | basic substitution | 10. **[1-5]** .1.0/24 |
| a:b:c:d:12{{ actor_nr_str }}::/80 | leftpad equivalent, makes the substitution always be 2 characters, with 0 in front | a:b:c:d:12 **[01-05]** ::/80 |
| 100.64.{{ actor_nr &vert; plus: 200 }}.0/24 | offset applied to addressing, allows for more efficient use of address space | 100.64. **[201-205]** .0/24 |
8 changes: 4 additions & 4 deletions app/views/virtual_machines/_address_preview.html.haml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
- cache([@virtual_machine.cache_key_with_version, 'address_preview']) do
= render TableComponent.new do |c|
- @virtual_machine.host_spec.deployable_instances(AddressPreviewPresenter).group_by(&:team_number).each do |team_nr, instances|
- @virtual_machine.host_spec.deployable_instances(AddressPreviewPresenter).group_by(&:team_number).each do |actor_nr, instances|
- c.with_table_row do
%td.text-center.font-lg.font-bold.py-2{colspan: 100, class: actor_color_classes(team_nr ? @virtual_machine.numbered_actor : @virtual_machine.actor)}
- if team_nr
%td.text-center.font-lg.font-bold.py-2{colspan: 100, class: actor_color_classes(actor_nr ? @virtual_machine.numbered_actor : @virtual_machine.actor)}
- if actor_nr
= @virtual_machine.numbered_actor.name
%strong= team_nr.to_s.rjust(2, "0")
%strong= actor_nr.to_s.rjust(2, "0")
- else
= @virtual_machine.actor.name

Expand Down
2 changes: 1 addition & 1 deletion spec/calculations/address_values_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
end

context 'and dynamic last octet' do
let(:address_pool) { build(:address_pool, network_address: '1.0.0.{{ team_nr }}/27', network:) }
let(:address_pool) { build(:address_pool, network_address: '1.0.0.{{ actor_nr }}/27', network:) }

it { is_expected.to be_nil }

Expand Down
18 changes: 18 additions & 0 deletions spec/calculations/liquid_range_substitution_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,24 @@
context 'vm' do
let(:source_object) { build(:virtual_machine) }

context 'with actor number node' do
let(:input_string) { '{{ actor_nr }}' }

it { is_expected.to eq 'actor_nr: N/A' }

context 'with numbered actor' do
let(:source_object) { build(:virtual_machine, actor: build(:actor, :numbered)) }

it { is_expected.to eq "actor_nr: 1 - #{source_object.actor.number}" }
end

context 'with numbering actor' do
let(:source_object) { build(:virtual_machine, numbered_by: build(:actor, :numbered)) }

it { is_expected.to eq "actor_nr: 1 - #{source_object.numbered_by.number}" }
end
end

context 'with team number node' do
let(:input_string) { '{{ team_nr }}' }

Expand Down
2 changes: 1 addition & 1 deletion spec/models/address_pool_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

context 'dynamic last octet' do
let(:network) { build(:network, actor: build(:actor, :numbered)) }
subject { build(:address_pool, network_address: '1.0.0.{{ team_nr }}/28', network:) }
subject { build(:address_pool, network_address: '1.0.0.{{ actor_nr }}/28', network:) }

it 'should generate correctly numbered network segments' do
expect(subject.ip_network(1).to_string).to eq '1.0.0.0/28'
Expand Down
4 changes: 2 additions & 2 deletions spec/models/address_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
end

context 'numbered net' do
let(:network_address) { '1.{{ team_nr }}.0.0/24' }
let(:network_address) { '1.{{ actor_nr }}.0.0/24' }

it 'should return first address by default' do
expect(subject.ip_object.to_s).to eq '1.1.0.1'
Expand Down Expand Up @@ -112,7 +112,7 @@
end

context 'numbered net' do
let(:network_address) { '1:a:{{ team_nr }}::/64' }
let(:network_address) { '1:a:{{ actor_nr }}::/64' }

it 'should return first address by default' do
expect(subject.ip_object.to_s).to eq '1:a:1::'
Expand Down
4 changes: 2 additions & 2 deletions spec/presenters/instance_presenter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
let(:virtual_machine) { create(:virtual_machine) }
let(:spec) { virtual_machine.host_spec }

let(:team_nr) { nil }
let(:actor_nr) { nil }
let(:seq_nr) { nil }
let(:opts) { nil }

subject { described_class.new(spec, team_nr, seq_nr, **opts) }
subject { described_class.new(spec, actor_nr, seq_nr, **opts) }

before {
Current.interfaces_cache ||= {}
Expand Down
6 changes: 5 additions & 1 deletion spec/requests/api_v3_network_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
actor: net.actor.abbreviation.downcase,
instances: [{
team_nr: nil,
actor_nr: nil,
cloud_id: '',
domains: [],
address_pools: [
Expand All @@ -40,7 +41,7 @@

context 'with numbered network' do
let!(:numbered_actor) { create(:actor, :numbered, exercise:) }
let!(:networks) { [create(:network, exercise:, actor: numbered_actor, cloud_id: 'hello{{ team_nr }}')] }
let!(:networks) { [create(:network, exercise:, actor: numbered_actor, cloud_id: 'hello{{ actor_nr }}')] }

it 'should list network with numbered instances' do
expect(response).to be_successful
Expand All @@ -53,6 +54,7 @@
actor: numbered_actor.abbreviation.downcase,
instances: [{
team_nr: 1,
actor_nr: 1,
cloud_id: 'hello1',
domains: [],
address_pools: [
Expand All @@ -62,6 +64,7 @@
config_map: nil
}, {
team_nr: 2,
actor_nr: 2,
cloud_id: 'hello2',
domains: [],
address_pools: [
Expand All @@ -71,6 +74,7 @@
config_map: nil
}, {
team_nr: 3,
actor_nr: 3,
cloud_id: 'hello3',
domains: [],
address_pools: [
Expand Down

0 comments on commit edf3445

Please sign in to comment.