Skip to content

Commit 0d3329d

Browse files
ops(iac): Support preexisting controller host in openstack docker module (#19)
1 parent 2465742 commit 0d3329d

File tree

6 files changed

+118
-15
lines changed

6 files changed

+118
-15
lines changed

deployment/terraform/modules/cogstack-docker-services/ansible.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ resource "ansible_playbook" "playbook" {
1010
replayable = false
1111
lifecycle {
1212
replace_triggered_by = [terraform_data.hash_of_all_config_files]
13+
ignore_changes = [extra_vars]
1314
}
1415

1516
extra_vars = {

deployment/terraform/modules/openstack-cogstack-infra/compute.tf

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,41 @@ resource "openstack_compute_instance_v2" "cogstack_ops_compute" {
3737
]
3838
}
3939

40+
lifecycle {
41+
precondition {
42+
condition = (length([for x in var.host_instances : x if x.is_controller == true]) == 1) || var.preexisting_controller_host != null
43+
error_message = <<-EOT
44+
Invalid variable input.
45+
Must have exactly one controller host defined in host_instances if preexisting_controller_host is not provided.
46+
Either pass a host with is_controller = true in host_instances, or provide details of an existing host using preexisting_controller_host.
47+
48+
Valid module input to create a controller:
49+
host_instances = [
50+
{ name = "example-test", is_controller = true },
51+
]
52+
53+
54+
Valid module input with details of an existing controller:
55+
host_instances = [
56+
{ name = "example-test" },
57+
]
58+
preexisting_controller_host = {
59+
ip_address = "10.1.1.1"
60+
name = "existing-controller-host"
61+
unique_name = "WFXGH-existing-controller-host"
62+
}
63+
64+
Invalid module input:
65+
{
66+
host_instances = [
67+
{ name = "example-test" },
68+
]
69+
}
70+
71+
EOT
72+
}
73+
}
74+
4075
}
4176

4277
# TODO: Read content from files and put into cloud-init config

deployment/terraform/modules/openstack-cogstack-infra/networking.tf

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22

33
locals {
4-
devops_controller_cidr = "${local.controller_host_instance.access_ip_v4}/32"
4+
devops_controller_cidr = "${local.controller_host_instance.ip_address}/32"
55

66
cogstack_apps_ingress_rules = [
77
{ port = 22, cidr = var.allowed_ingress_ips_cidr, description = "SSH" },
@@ -15,6 +15,8 @@ locals {
1515
]
1616
cogstack_apps_ingress_rules_map = { for rule in local.cogstack_apps_ingress_rules : "${rule.port}-${rule.description}" => rule }
1717
cogstack_apps_devops_controller_rules_map = { for rule in local.cogstack_apps_devops_controller_rules : "${rule.port}-${rule.description}" => rule }
18+
19+
user_provided_security_rules_map = { for rule in var.allowed_security_group_rules : "${rule.port}-${rule.description}" => rule }
1820
}
1921

2022
resource "openstack_networking_secgroup_v2" "cogstack_apps_security_group" {
@@ -44,3 +46,15 @@ resource "openstack_networking_secgroup_rule_v2" "cogstack_apps_devops_controlle
4446
description = each.value.description
4547
security_group_id = openstack_networking_secgroup_v2.cogstack_apps_security_group.id
4648
}
49+
50+
resource "openstack_networking_secgroup_rule_v2" "user_provided_security_rules_map" {
51+
for_each = local.user_provided_security_rules_map
52+
direction = "ingress"
53+
ethertype = "IPv4"
54+
protocol = "tcp"
55+
port_range_min = each.value.port
56+
port_range_max = each.value.port
57+
remote_ip_prefix = each.value.cidr
58+
description = each.value.description
59+
security_group_id = openstack_networking_secgroup_v2.cogstack_apps_security_group.id
60+
}

deployment/terraform/modules/openstack-cogstack-infra/outputs.tf

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ output "created_hosts" {
99
}
1010

1111
output "created_controller_host" {
12-
value = {
13-
name = (local.controller_host.name)
14-
ip_address = local.controller_host_instance.access_ip_v4
15-
unique_name = local.controller_host_instance.name
16-
17-
}
18-
12+
value = local.controller_host_instance
1913
description = "Created Controller Host: A map of { hostname: { data } }"
2014
}
2115

@@ -27,10 +21,15 @@ output "compute_keypair" {
2721
description = "Absolute path to a public and private SSH key pair that is granted login on created VMs"
2822
}
2923

24+
output "created_security_group" {
25+
value = openstack_networking_secgroup_v2.cogstack_apps_security_group
26+
description = "Security group associated to the created hosts"
27+
}
28+
3029
output "portainer_instance" {
3130
sensitive = true
3231
value = {
33-
endpoint = "https://${local.controller_host_instance.access_ip_v4}:9443"
32+
endpoint = "https://${local.controller_host_instance.ip_address}:9443"
3433
username = "admin"
3534
password = local.portainer_admin_password
3635
}

deployment/terraform/modules/openstack-cogstack-infra/shared-locals.tf

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,20 @@ locals {
55

66

77
locals {
8-
controller_host = one([for host in var.host_instances : host if host.is_controller])
9-
controller_host_instance = openstack_compute_instance_v2.cogstack_ops_compute[local.controller_host.name]
8+
# Desired controller host
9+
controller_host = var.preexisting_controller_host != null ? var.preexisting_controller_host : one([for host in var.host_instances : host if host.is_controller])
10+
11+
# Created controller host instance
12+
created_controller_host = var.preexisting_controller_host != null ? null : openstack_compute_instance_v2.cogstack_ops_compute[local.controller_host.name]
13+
14+
# Final controller host instance (either created or preexisting)
15+
controller_host_instance = {
16+
name = local.controller_host.name
17+
ip_address = var.preexisting_controller_host != null ? var.preexisting_controller_host.ip_address : local.created_controller_host.access_ip_v4
18+
unique_name = var.preexisting_controller_host != null && var.preexisting_controller_host.unique_name != null ? var.preexisting_controller_host.unique_name : local.created_controller_host.name
19+
}
20+
21+
1022
}
1123

1224
resource "random_id" "server" {
@@ -20,9 +32,19 @@ resource "random_id" "server" {
2032
}
2133

2234
resource "random_password" "portainer_password" {
23-
count = var.portainer_secrets.admin_password != null ? 0 : 1
35+
count = (var.portainer_secrets.admin_password == null) && (var.preexisting_controller_host == null) ? 1 : 0
2436
length = 16
2537
}
2638
locals {
27-
portainer_admin_password = var.portainer_secrets.admin_password != null ? var.portainer_secrets.admin_password : random_password.portainer_password[0].result
39+
40+
# Nested ternary for portainer password:
41+
# admin_password preexisting_host Result
42+
# notnull any provided password
43+
# null not null "unknown"
44+
# null null generated password
45+
portainer_admin_password = (
46+
var.portainer_secrets.admin_password != null ? var.portainer_secrets.admin_password :
47+
var.preexisting_controller_host != null ? "unknown" :
48+
random_password.portainer_password[0].result
49+
)
2850
}

deployment/terraform/modules/openstack-cogstack-infra/variables.tf

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,44 @@ EOT
4646
}
4747

4848
validation {
49-
condition = length([for x in var.host_instances : x if x.is_controller == true]) == 1
50-
error_message = "Must have exactly one controller host"
49+
condition = length([for x in var.host_instances : x if x.is_controller == true]) <= 1
50+
error_message = "Must have at most 1 controller host"
5151
}
5252

5353
}
5454

55+
variable "preexisting_controller_host" {
56+
type = object({
57+
name = string,
58+
ip_address = string,
59+
unique_name = optional(string)
60+
})
61+
default = null
62+
description = <<EOT
63+
Optionally provide details of an existing host to use as the controller host for Portainer
64+
65+
name = Human readable hostname for this host,
66+
ip_address = IP Address of the existing controller host,
67+
unique_name = optional(string)
68+
EOT
69+
}
70+
71+
variable "allowed_security_group_rules" {
72+
type = list(object({
73+
port = number
74+
cidr = string
75+
description = string
76+
}))
77+
default = [ ]
78+
description = <<EOT
79+
Optionally provide additional security group rules to allow ingress to the created hosts
80+
81+
port = Port number to allow ingress to
82+
cidr = CIDR block to allow ingress from
83+
description = Description for the rule
84+
EOT
85+
}
86+
5587
variable "ssh_key_pair" {
5688
type = object({
5789
public_key_file = string

0 commit comments

Comments
 (0)