Skip to content

Commit 87bfefc

Browse files
priteausjpb
andauthored
Support fixed IP addresses for nodes (#643)
* Support fixed IP addresses for control node The variable control_ip_address was documented but not implemented. Since we support multiple networks, change it to control_ip_addresses and implement it. Closes #642. * Update environments/skeleton/{{cookiecutter.environment}}/tofu/variables.tf * tf style tweaks * update production docs for control_ip_addresses * fix control IP address logic * add validation for control_ip_addresses * remove fixed IPs from production docs - not standard process * support ip_addresses fo all nodes * make stackhpc tofu format consistent --------- Co-authored-by: Steve Brasier <[email protected]> Co-authored-by: Steve Brasier <[email protected]>
1 parent 8820cdb commit 87bfefc

File tree

8 files changed

+108
-69
lines changed

8 files changed

+108
-69
lines changed

docs/production.md

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -134,23 +134,6 @@ and referenced from the `site` and `production` environments, e.g.:
134134
135135
- Consider whether having (read-only) access to Grafana without login is OK. If not, remove `grafana_auth_anonymous` in `environments/$ENV/inventory/group_vars/all/grafana.yml`
136136
137-
- Modify `environments/site/tofu/nodes.tf` to provide fixed IPs for at least
138-
the control node, and (if not using FIPs) the login node(s):
139-
140-
```
141-
resource "openstack_networking_port_v2" "control" {
142-
...
143-
fixed_ip {
144-
subnet_id = data.openstack_networking_subnet_v2.cluster_subnet.id
145-
ip_address = var.control_ip_address
146-
}
147-
}
148-
```
149-
150-
Note the variable `control_ip_address` is new.
151-
152-
Using fixed IPs will require either using admin credentials or policy changes.
153-
154137
- If floating IPs are required for login nodes, modify the OpenTofu configurations
155138
appropriately.
156139

environments/.stackhpc/tofu/main.tf

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,23 +69,23 @@ module "cluster" {
6969
control_node_flavor = var.control_node_flavor
7070

7171
login = {
72-
login: {
73-
nodes: ["login-0"]
74-
flavor: var.other_node_flavor
72+
login = {
73+
nodes = ["login-0"]
74+
flavor = var.other_node_flavor
7575
}
7676
}
7777
compute = {
78-
standard: { # NB: can't call this default!
79-
nodes: ["compute-0", "compute-1"]
80-
flavor: var.other_node_flavor
81-
compute_init_enable: ["compute", "chrony", "etc_hosts", "nfs", "basic_users", "eessi", "tuned", "cacerts"]
82-
ignore_image_changes: true
78+
standard = { # NB: can't call this default!
79+
nodes = ["compute-0", "compute-1"]
80+
flavor = var.other_node_flavor
81+
compute_init_enable = ["compute", "chrony", "etc_hosts", "nfs", "basic_users", "eessi", "tuned", "cacerts"]
82+
ignore_image_changes = true
8383
}
8484
# Normally-empty partition for testing:
85-
extra: {
86-
nodes: []
87-
#nodes: ["extra-0", "extra-1"]
88-
flavor: var.other_node_flavor
85+
extra = {
86+
nodes = []
87+
#nodes = ["extra-0", "extra-1"]
88+
flavor = var.other_node_flavor
8989
}
9090
}
9191

environments/skeleton/{{cookiecutter.environment}}/tofu/compute.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ module "compute" {
3030
ignore_image_changes = lookup(each.value, "ignore_image_changes", null)
3131
match_ironic_node = lookup(each.value, "match_ironic_node", null)
3232
availability_zone = lookup(each.value, "availability_zone", null)
33+
ip_addresses = lookup(each.value, "ip_addresses", null)
3334

3435
# computed
3536
# not using openstack_compute_instance_v2.control.access_ip_v4 to avoid
@@ -55,6 +56,7 @@ module "compute" {
5556
"extra_volumes",
5657
"match_ironic_node",
5758
"availability_zone",
59+
"ip_addresses",
5860
"gateway_ip",
5961
"nodename_template",
6062
]

environments/skeleton/{{cookiecutter.environment}}/tofu/control.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ resource "openstack_networking_port_v2" "control" {
2424
admin_state_up = "true"
2525

2626
fixed_ip {
27-
subnet_id = data.openstack_networking_subnet_v2.cluster_subnet[each.key].id
27+
subnet_id = data.openstack_networking_subnet_v2.cluster_subnet[each.key].id
28+
ip_address = lookup(var.control_ip_addresses, each.key, null)
2829
}
2930

3031
no_security_groups = lookup(each.value, "no_security_groups", false)

environments/skeleton/{{cookiecutter.environment}}/tofu/login.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ module "login" {
3030
fip_network = lookup(each.value, "fip_network", null)
3131
match_ironic_node = lookup(each.value, "match_ironic_node", null)
3232
availability_zone = lookup(each.value, "availability_zone", null)
33+
ip_addresses = lookup(each.value, "ip_addresses", null)
3334

3435
# can't be set for login
3536
compute_init_enable = []
@@ -59,6 +60,7 @@ module "login" {
5960
"fip_network",
6061
"match_ironic_node",
6162
"availability_zone",
63+
"ip_addresses",
6264
"gateway_ip",
6365
"nodename_template",
6466
]

environments/skeleton/{{cookiecutter.environment}}/tofu/node_group/nodes.tf

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,26 @@ resource "openstack_compute_volume_attach_v2" "compute" {
4747
resource "openstack_networking_port_v2" "compute" {
4848

4949
for_each = {for item in setproduct(var.nodes, var.networks):
50-
"${item[0]}-${item[1].network}" => item[1]
50+
"${item[0]}-${item[1].network}" => {
51+
node_idx = index(var.nodes, item[0])
52+
net = item[1]
53+
}
5154
}
5255

5356
name = "${var.cluster_name}-${each.key}"
54-
network_id = data.openstack_networking_network_v2.network[each.value.network].id
57+
network_id = data.openstack_networking_network_v2.network[each.value.net.network].id
5558
admin_state_up = "true"
5659

5760
fixed_ip {
58-
subnet_id = data.openstack_networking_subnet_v2.subnet[each.value.network].id
61+
subnet_id = data.openstack_networking_subnet_v2.subnet[each.value.net.network].id
62+
ip_address = try(var.ip_addresses[each.value.net.network][each.value.node_idx], null)
5963
}
6064

61-
no_security_groups = lookup(each.value, "no_security_groups", false)
62-
security_group_ids = lookup(each.value, "no_security_groups", false) ? [] : var.security_group_ids
65+
no_security_groups = lookup(each.value.net, "no_security_groups", false)
66+
security_group_ids = lookup(each.value.net, "no_security_groups", false) ? [] : var.security_group_ids
6367

6468
binding {
65-
vnic_type = lookup(var.vnic_types, each.value.network, "normal")
69+
vnic_type = lookup(var.vnic_types, each.value.net.network, "normal")
6670
}
6771
}
6872

environments/skeleton/{{cookiecutter.environment}}/tofu/node_group/variables.tf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,27 @@ variable "fip_network" {
119119
nullable = false
120120
}
121121

122+
variable "ip_addresses" {
123+
type = map(list(string))
124+
description = <<-EOT
125+
Mapping of list of fixed IP addresses for nodes, keyed by network name,
126+
in same order as nodes parameter. For any networks not specified here
127+
the cloud will select addresses.
128+
129+
NB: Changing IP addresses after deployment may hit terraform provider bugs.
130+
EOT
131+
default = {}
132+
nullable = false
133+
validation {
134+
condition = length(setsubtract(keys(var.ip_addresses), var.networks[*].network)) == 0
135+
error_message = "Keys in ip_addresses for nodegroup \"${var.group_name}\" must match network names in var.cluster_networks"
136+
}
137+
validation {
138+
condition = alltrue([for v in values(var.ip_addresses): length(v) == length(var.nodes)])
139+
error_message = "Values in ip_addresses for nodegroup \"${var.group_name}\" must be a list of the same length as var.nodes"
140+
}
141+
}
142+
122143
variable "match_ironic_node" {
123144
type = bool
124145
description = "Whether to launch instances on the Ironic node of the same name as each cluster node"

environments/skeleton/{{cookiecutter.environment}}/tofu/variables.tf

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,45 +24,67 @@ variable "key_pair" {
2424
description = "Name of an existing keypair in OpenStack"
2525
}
2626

27+
variable "control_ip_addresses" {
28+
type = map(string)
29+
description = <<-EOT
30+
Mapping of fixed IP addresses for control node, keyed by network name.
31+
For any networks not specified here the cloud will select an address.
32+
33+
NB: Changing IP addresses after deployment may hit terraform provider bugs.
34+
EOT
35+
default = {}
36+
validation {
37+
# check all keys are network names in cluster_networks
38+
condition = length(setsubtract(keys(var.control_ip_addresses), var.cluster_networks[*].network)) == 0
39+
error_message = "Keys in var.control_ip_addresses must match network names in var.cluster_networks"
40+
}
41+
}
42+
2743
variable "control_node_flavor" {
2844
type = string
2945
description = "Flavor name for control node"
3046
}
3147

3248
variable "login" {
33-
type = any
34-
description = <<-EOF
35-
Mapping defining homogenous groups of login nodes. Multiple groups may
36-
be useful for e.g. separating nodes for ssh and Open Ondemand usage, or
37-
to define login nodes with different capabilities such as high-memory.
49+
default = {}
50+
description = <<-EOF
51+
Mapping defining homogenous groups of login nodes. Multiple groups may
52+
be useful for e.g. separating nodes for ssh and Open Ondemand usage, or
53+
to define login nodes with different capabilities such as high-memory.
54+
55+
Keys are names of groups.
56+
Values are a mapping as follows:
3857
39-
Keys are names of groups.
40-
Values are a mapping as follows:
58+
Required:
59+
nodes: List of node names
60+
flavor: String flavor name
61+
Optional:
62+
image_id: Overrides variable cluster_image_id
63+
extra_networks: List of mappings in same format as cluster_networks
64+
vnic_types: Overrides variable vnic_types
65+
volume_backed_instances: Overrides variable volume_backed_instances
66+
root_volume_size: Overrides variable root_volume_size
67+
extra_volumes: Mapping defining additional volumes to create and attach
68+
Keys are unique volume name.
69+
Values are a mapping with:
70+
size: Size of volume in GB
71+
**NB**: The order in /dev is not guaranteed to match the mapping
72+
fip_addresses: List of addresses of floating IPs to associate with
73+
nodes, in the same order as nodes parameter. The
74+
floating IPs must already be allocated to the project.
75+
fip_network: Name of network containing ports to attach FIPs to. Only
76+
required if multiple networks are defined.
77+
ip_addresses: Mapping of list of fixed IP addresses for nodes, keyed
78+
by network name, in same order as nodes parameter.
79+
For any networks not specified here the cloud will
80+
select addresses.
81+
match_ironic_node: Set true to launch instances on the Ironic node of the same name as each cluster node
82+
availability_zone: Name of availability zone - ignored unless match_ironic_node is true (default: "nova")
83+
gateway_ip: Address to add default route via
84+
nodename_template: Overrides variable cluster_nodename_template
85+
EOF
4186

42-
Required:
43-
nodes: List of node names
44-
flavor: String flavor name
45-
Optional:
46-
image_id: Overrides variable cluster_image_id
47-
extra_networks: List of mappings in same format as cluster_networks
48-
vnic_types: Overrides variable vnic_types
49-
volume_backed_instances: Overrides variable volume_backed_instances
50-
root_volume_size: Overrides variable root_volume_size
51-
extra_volumes: Mapping defining additional volumes to create and attach
52-
Keys are unique volume name.
53-
Values are a mapping with:
54-
size: Size of volume in GB
55-
**NB**: The order in /dev is not guaranteed to match the mapping
56-
fip_addresses: List of addresses of floating IPs to associate with nodes,
57-
in the same order as nodes parameter. The floating IPs
58-
must already be allocated to the project.
59-
fip_network: Name of network containing ports to attach FIPs to. Only
60-
required if multiple networks are defined.
61-
match_ironic_node: Set true to launch instances on the Ironic node of the same name as each cluster node
62-
availability_zone: Name of availability zone - ignored unless match_ironic_node is true (default: "nova")
63-
gateway_ip: Address to add default route via
64-
nodename_template: Overrides variable cluster_nodename_template
65-
EOF
87+
type = any
6688
}
6789

6890
variable "cluster_image_id" {
@@ -71,7 +93,7 @@ variable "cluster_image_id" {
7193
}
7294

7395
variable "compute" {
74-
96+
default = {}
7597
description = <<-EOF
7698
Mapping defining homogenous groups of compute nodes. Groups are used
7799
in Slurm partition definitions.
@@ -95,12 +117,16 @@ variable "compute" {
95117
Values are a mapping with:
96118
size: Size of volume in GB
97119
**NB**: The order in /dev is not guaranteed to match the mapping
120+
ip_addresses: Mapping of list of fixed IP addresses for nodes, keyed
121+
by network name, in same order as nodes parameter.
122+
For any networks not specified here the cloud will
123+
select addresses.
98124
match_ironic_node: Set true to launch instances on the Ironic node of the same name as each cluster node
99125
availability_zone: Name of availability zone - ignored unless match_ironic_node is true (default: "nova")
100126
gateway_ip: Address to add default route via
101127
nodename_template: Overrides variable cluster_nodename_template
102128
EOF
103-
default = {}
129+
104130
type = any # can't do any better; TF type constraints can't cope with heterogeneous inner mappings
105131
}
106132

0 commit comments

Comments
 (0)