You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

602 lines
21 KiB

  1. data "openstack_images_image_v2" "vm_image" {
  2. name = var.image
  3. }
  4. data "openstack_images_image_v2" "gfs_image" {
  5. name = var.image_gfs == "" ? var.image : var.image_gfs
  6. }
  7. resource "openstack_compute_keypair_v2" "k8s" {
  8. name = "kubernetes-${var.cluster_name}"
  9. public_key = chomp(file(var.public_key_path))
  10. }
  11. resource "openstack_networking_secgroup_v2" "k8s_master" {
  12. name = "${var.cluster_name}-k8s-master"
  13. description = "${var.cluster_name} - Kubernetes Master"
  14. delete_default_rules = true
  15. }
  16. resource "openstack_networking_secgroup_rule_v2" "k8s_master" {
  17. count = length(var.master_allowed_remote_ips)
  18. direction = "ingress"
  19. ethertype = "IPv4"
  20. protocol = "tcp"
  21. port_range_min = "6443"
  22. port_range_max = "6443"
  23. remote_ip_prefix = var.master_allowed_remote_ips[count.index]
  24. security_group_id = openstack_networking_secgroup_v2.k8s_master.id
  25. }
  26. resource "openstack_networking_secgroup_v2" "bastion" {
  27. name = "${var.cluster_name}-bastion"
  28. count = var.number_of_bastions != "" ? 1 : 0
  29. description = "${var.cluster_name} - Bastion Server"
  30. delete_default_rules = true
  31. }
  32. resource "openstack_networking_secgroup_rule_v2" "bastion" {
  33. count = var.number_of_bastions != "" ? length(var.bastion_allowed_remote_ips) : 0
  34. direction = "ingress"
  35. ethertype = "IPv4"
  36. protocol = "tcp"
  37. port_range_min = "22"
  38. port_range_max = "22"
  39. remote_ip_prefix = var.bastion_allowed_remote_ips[count.index]
  40. security_group_id = openstack_networking_secgroup_v2.bastion[0].id
  41. }
  42. resource "openstack_networking_secgroup_v2" "k8s" {
  43. name = "${var.cluster_name}-k8s"
  44. description = "${var.cluster_name} - Kubernetes"
  45. delete_default_rules = true
  46. }
  47. resource "openstack_networking_secgroup_rule_v2" "k8s" {
  48. direction = "ingress"
  49. ethertype = "IPv4"
  50. remote_group_id = openstack_networking_secgroup_v2.k8s.id
  51. security_group_id = openstack_networking_secgroup_v2.k8s.id
  52. }
  53. resource "openstack_networking_secgroup_rule_v2" "k8s_allowed_remote_ips" {
  54. count = length(var.k8s_allowed_remote_ips)
  55. direction = "ingress"
  56. ethertype = "IPv4"
  57. protocol = "tcp"
  58. port_range_min = "22"
  59. port_range_max = "22"
  60. remote_ip_prefix = var.k8s_allowed_remote_ips[count.index]
  61. security_group_id = openstack_networking_secgroup_v2.k8s.id
  62. }
  63. resource "openstack_networking_secgroup_rule_v2" "egress" {
  64. count = length(var.k8s_allowed_egress_ips)
  65. direction = "egress"
  66. ethertype = "IPv4"
  67. remote_ip_prefix = var.k8s_allowed_egress_ips[count.index]
  68. security_group_id = openstack_networking_secgroup_v2.k8s.id
  69. }
  70. resource "openstack_networking_secgroup_v2" "worker" {
  71. name = "${var.cluster_name}-k8s-worker"
  72. description = "${var.cluster_name} - Kubernetes worker nodes"
  73. delete_default_rules = true
  74. }
  75. resource "openstack_networking_secgroup_rule_v2" "worker" {
  76. count = length(var.worker_allowed_ports)
  77. direction = "ingress"
  78. ethertype = "IPv4"
  79. protocol = lookup(var.worker_allowed_ports[count.index], "protocol", "tcp")
  80. port_range_min = lookup(var.worker_allowed_ports[count.index], "port_range_min")
  81. port_range_max = lookup(var.worker_allowed_ports[count.index], "port_range_max")
  82. remote_ip_prefix = lookup(var.worker_allowed_ports[count.index], "remote_ip_prefix", "0.0.0.0/0")
  83. security_group_id = openstack_networking_secgroup_v2.worker.id
  84. }
  85. resource "openstack_compute_servergroup_v2" "k8s_master" {
  86. count = "%{if var.use_server_groups}1%{else}0%{endif}"
  87. name = "k8s-master-srvgrp"
  88. policies = ["anti-affinity"]
  89. }
  90. resource "openstack_compute_servergroup_v2" "k8s_node" {
  91. count = "%{if var.use_server_groups}1%{else}0%{endif}"
  92. name = "k8s-node-srvgrp"
  93. policies = ["anti-affinity"]
  94. }
  95. resource "openstack_compute_servergroup_v2" "k8s_etcd" {
  96. count = "%{if var.use_server_groups}1%{else}0%{endif}"
  97. name = "k8s-etcd-srvgrp"
  98. policies = ["anti-affinity"]
  99. }
  100. resource "openstack_compute_instance_v2" "bastion" {
  101. name = "${var.cluster_name}-bastion-${count.index + 1}"
  102. count = var.number_of_bastions
  103. image_name = var.image
  104. flavor_id = var.flavor_bastion
  105. key_pair = openstack_compute_keypair_v2.k8s.name
  106. dynamic "block_device" {
  107. for_each = var.bastion_root_volume_size_in_gb > 0 ? [var.image] : []
  108. content {
  109. uuid = data.openstack_images_image_v2.vm_image.id
  110. source_type = "image"
  111. volume_size = var.bastion_root_volume_size_in_gb
  112. boot_index = 0
  113. destination_type = "volume"
  114. delete_on_termination = true
  115. }
  116. }
  117. network {
  118. name = var.network_name
  119. }
  120. security_groups = [openstack_networking_secgroup_v2.k8s.name,
  121. element(openstack_networking_secgroup_v2.bastion.*.name, count.index),
  122. ]
  123. metadata = {
  124. ssh_user = var.ssh_user
  125. kubespray_groups = "bastion"
  126. depends_on = var.network_id
  127. use_access_ip = var.use_access_ip
  128. }
  129. provisioner "local-exec" {
  130. command = "sed s/USER/${var.ssh_user}/ ../../contrib/terraform/openstack/ansible_bastion_template.txt | sed s/BASTION_ADDRESS/${var.bastion_fips[0]}/ > group_vars/no-floating.yml"
  131. }
  132. }
  133. resource "openstack_compute_instance_v2" "k8s_master" {
  134. name = "${var.cluster_name}-k8s-master-${count.index + 1}"
  135. count = var.number_of_k8s_masters
  136. availability_zone = element(var.az_list, count.index)
  137. image_name = var.image
  138. flavor_id = var.flavor_k8s_master
  139. key_pair = openstack_compute_keypair_v2.k8s.name
  140. dynamic "block_device" {
  141. for_each = var.master_root_volume_size_in_gb > 0 ? [var.image] : []
  142. content {
  143. uuid = data.openstack_images_image_v2.vm_image.id
  144. source_type = "image"
  145. volume_size = var.master_root_volume_size_in_gb
  146. boot_index = 0
  147. destination_type = "volume"
  148. delete_on_termination = true
  149. }
  150. }
  151. network {
  152. name = var.network_name
  153. }
  154. security_groups = [openstack_networking_secgroup_v2.k8s_master.name,
  155. openstack_networking_secgroup_v2.k8s.name,
  156. ]
  157. dynamic "scheduler_hints" {
  158. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_master[0]] : []
  159. content {
  160. group = openstack_compute_servergroup_v2.k8s_master[0].id
  161. }
  162. }
  163. metadata = {
  164. ssh_user = var.ssh_user
  165. kubespray_groups = "etcd,kube-master,${var.supplementary_master_groups},k8s-cluster,vault"
  166. depends_on = var.network_id
  167. use_access_ip = var.use_access_ip
  168. }
  169. provisioner "local-exec" {
  170. command = "sed s/USER/${var.ssh_user}/ ../../contrib/terraform/openstack/ansible_bastion_template.txt | sed s/BASTION_ADDRESS/${element(concat(var.bastion_fips, var.k8s_master_fips), 0)}/ > group_vars/no-floating.yml"
  171. }
  172. }
  173. resource "openstack_compute_instance_v2" "k8s_master_no_etcd" {
  174. name = "${var.cluster_name}-k8s-master-ne-${count.index + 1}"
  175. count = var.number_of_k8s_masters_no_etcd
  176. availability_zone = element(var.az_list, count.index)
  177. image_name = var.image
  178. flavor_id = var.flavor_k8s_master
  179. key_pair = openstack_compute_keypair_v2.k8s.name
  180. dynamic "block_device" {
  181. for_each = var.master_root_volume_size_in_gb > 0 ? [var.image] : []
  182. content {
  183. uuid = data.openstack_images_image_v2.vm_image.id
  184. source_type = "image"
  185. volume_size = var.master_root_volume_size_in_gb
  186. boot_index = 0
  187. destination_type = "volume"
  188. delete_on_termination = true
  189. }
  190. }
  191. network {
  192. name = var.network_name
  193. }
  194. security_groups = [openstack_networking_secgroup_v2.k8s_master.name,
  195. openstack_networking_secgroup_v2.k8s.name,
  196. ]
  197. dynamic "scheduler_hints" {
  198. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_master[0]] : []
  199. content {
  200. group = openstack_compute_servergroup_v2.k8s_master[0].id
  201. }
  202. }
  203. metadata = {
  204. ssh_user = var.ssh_user
  205. kubespray_groups = "kube-master,${var.supplementary_master_groups},k8s-cluster,vault"
  206. depends_on = var.network_id
  207. use_access_ip = var.use_access_ip
  208. }
  209. provisioner "local-exec" {
  210. command = "sed s/USER/${var.ssh_user}/ ../../contrib/terraform/openstack/ansible_bastion_template.txt | sed s/BASTION_ADDRESS/${element(concat(var.bastion_fips, var.k8s_master_fips), 0)}/ > group_vars/no-floating.yml"
  211. }
  212. }
  213. resource "openstack_compute_instance_v2" "etcd" {
  214. name = "${var.cluster_name}-etcd-${count.index + 1}"
  215. count = var.number_of_etcd
  216. availability_zone = element(var.az_list, count.index)
  217. image_name = var.image
  218. flavor_id = var.flavor_etcd
  219. key_pair = openstack_compute_keypair_v2.k8s.name
  220. dynamic "block_device" {
  221. for_each = var.etcd_root_volume_size_in_gb > 0 ? [var.image] : []
  222. content {
  223. uuid = data.openstack_images_image_v2.vm_image.id
  224. source_type = "image"
  225. volume_size = var.etcd_root_volume_size_in_gb
  226. boot_index = 0
  227. destination_type = "volume"
  228. delete_on_termination = true
  229. }
  230. }
  231. network {
  232. name = var.network_name
  233. }
  234. security_groups = [openstack_networking_secgroup_v2.k8s.name]
  235. dynamic "scheduler_hints" {
  236. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_etcd[0]] : []
  237. content {
  238. group = openstack_compute_servergroup_v2.k8s_etcd[0].id
  239. }
  240. }
  241. metadata = {
  242. ssh_user = var.ssh_user
  243. kubespray_groups = "etcd,vault,no-floating"
  244. depends_on = var.network_id
  245. use_access_ip = var.use_access_ip
  246. }
  247. }
  248. resource "openstack_compute_instance_v2" "k8s_master_no_floating_ip" {
  249. name = "${var.cluster_name}-k8s-master-nf-${count.index + 1}"
  250. count = var.number_of_k8s_masters_no_floating_ip
  251. availability_zone = element(var.az_list, count.index)
  252. image_name = var.image
  253. flavor_id = var.flavor_k8s_master
  254. key_pair = openstack_compute_keypair_v2.k8s.name
  255. dynamic "block_device" {
  256. for_each = var.master_root_volume_size_in_gb > 0 ? [var.image] : []
  257. content {
  258. uuid = data.openstack_images_image_v2.vm_image.id
  259. source_type = "image"
  260. volume_size = var.master_root_volume_size_in_gb
  261. boot_index = 0
  262. destination_type = "volume"
  263. delete_on_termination = true
  264. }
  265. }
  266. network {
  267. name = var.network_name
  268. }
  269. security_groups = [openstack_networking_secgroup_v2.k8s_master.name,
  270. openstack_networking_secgroup_v2.k8s.name,
  271. ]
  272. dynamic "scheduler_hints" {
  273. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_master[0]] : []
  274. content {
  275. group = openstack_compute_servergroup_v2.k8s_master[0].id
  276. }
  277. }
  278. metadata = {
  279. ssh_user = var.ssh_user
  280. kubespray_groups = "etcd,kube-master,${var.supplementary_master_groups},k8s-cluster,vault,no-floating"
  281. depends_on = var.network_id
  282. use_access_ip = var.use_access_ip
  283. }
  284. }
  285. resource "openstack_compute_instance_v2" "k8s_master_no_floating_ip_no_etcd" {
  286. name = "${var.cluster_name}-k8s-master-ne-nf-${count.index + 1}"
  287. count = var.number_of_k8s_masters_no_floating_ip_no_etcd
  288. availability_zone = element(var.az_list, count.index)
  289. image_name = var.image
  290. flavor_id = var.flavor_k8s_master
  291. key_pair = openstack_compute_keypair_v2.k8s.name
  292. dynamic "block_device" {
  293. for_each = var.master_root_volume_size_in_gb > 0 ? [var.image] : []
  294. content {
  295. uuid = data.openstack_images_image_v2.vm_image.id
  296. source_type = "image"
  297. volume_size = var.master_root_volume_size_in_gb
  298. boot_index = 0
  299. destination_type = "volume"
  300. delete_on_termination = true
  301. }
  302. }
  303. network {
  304. name = var.network_name
  305. }
  306. security_groups = [openstack_networking_secgroup_v2.k8s_master.name,
  307. openstack_networking_secgroup_v2.k8s.name,
  308. ]
  309. dynamic "scheduler_hints" {
  310. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_master[0]] : []
  311. content {
  312. group = openstack_compute_servergroup_v2.k8s_master[0].id
  313. }
  314. }
  315. metadata = {
  316. ssh_user = var.ssh_user
  317. kubespray_groups = "kube-master,${var.supplementary_master_groups},k8s-cluster,vault,no-floating"
  318. depends_on = var.network_id
  319. use_access_ip = var.use_access_ip
  320. }
  321. }
  322. resource "openstack_compute_instance_v2" "k8s_node" {
  323. name = "${var.cluster_name}-k8s-node-${count.index + 1}"
  324. count = var.number_of_k8s_nodes
  325. availability_zone = element(var.az_list_node, count.index)
  326. image_name = var.image
  327. flavor_id = var.flavor_k8s_node
  328. key_pair = openstack_compute_keypair_v2.k8s.name
  329. dynamic "block_device" {
  330. for_each = var.node_root_volume_size_in_gb > 0 ? [var.image] : []
  331. content {
  332. uuid = data.openstack_images_image_v2.vm_image.id
  333. source_type = "image"
  334. volume_size = var.node_root_volume_size_in_gb
  335. boot_index = 0
  336. destination_type = "volume"
  337. delete_on_termination = true
  338. }
  339. }
  340. network {
  341. name = var.network_name
  342. }
  343. security_groups = [openstack_networking_secgroup_v2.k8s.name,
  344. openstack_networking_secgroup_v2.worker.name,
  345. ]
  346. dynamic "scheduler_hints" {
  347. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_node[0]] : []
  348. content {
  349. group = openstack_compute_servergroup_v2.k8s_node[0].id
  350. }
  351. }
  352. metadata = {
  353. ssh_user = var.ssh_user
  354. kubespray_groups = "kube-node,k8s-cluster,${var.supplementary_node_groups}"
  355. depends_on = var.network_id
  356. use_access_ip = var.use_access_ip
  357. }
  358. provisioner "local-exec" {
  359. command = "sed s/USER/${var.ssh_user}/ ../../contrib/terraform/openstack/ansible_bastion_template.txt | sed s/BASTION_ADDRESS/${element(concat(var.bastion_fips, var.k8s_node_fips), 0)}/ > group_vars/no-floating.yml"
  360. }
  361. }
  362. resource "openstack_compute_instance_v2" "k8s_node_no_floating_ip" {
  363. name = "${var.cluster_name}-k8s-node-nf-${count.index + 1}"
  364. count = var.number_of_k8s_nodes_no_floating_ip
  365. availability_zone = element(var.az_list_node, count.index)
  366. image_name = var.image
  367. flavor_id = var.flavor_k8s_node
  368. key_pair = openstack_compute_keypair_v2.k8s.name
  369. dynamic "block_device" {
  370. for_each = var.node_root_volume_size_in_gb > 0 ? [var.image] : []
  371. content {
  372. uuid = data.openstack_images_image_v2.vm_image.id
  373. source_type = "image"
  374. volume_size = var.node_root_volume_size_in_gb
  375. boot_index = 0
  376. destination_type = "volume"
  377. delete_on_termination = true
  378. }
  379. }
  380. network {
  381. name = var.network_name
  382. }
  383. security_groups = [openstack_networking_secgroup_v2.k8s.name,
  384. openstack_networking_secgroup_v2.worker.name,
  385. ]
  386. dynamic "scheduler_hints" {
  387. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_node[0]] : []
  388. content {
  389. group = openstack_compute_servergroup_v2.k8s_node[0].id
  390. }
  391. }
  392. metadata = {
  393. ssh_user = var.ssh_user
  394. kubespray_groups = "kube-node,k8s-cluster,no-floating,${var.supplementary_node_groups}"
  395. depends_on = var.network_id
  396. use_access_ip = var.use_access_ip
  397. }
  398. }
  399. resource "openstack_compute_instance_v2" "k8s_nodes" {
  400. for_each = var.number_of_k8s_nodes == 0 && var.number_of_k8s_nodes_no_floating_ip == 0 ? var.k8s_nodes : {}
  401. name = "${var.cluster_name}-k8s-node-${each.key}"
  402. availability_zone = each.value.az
  403. image_name = var.image
  404. flavor_id = each.value.flavor
  405. key_pair = openstack_compute_keypair_v2.k8s.name
  406. dynamic "block_device" {
  407. for_each = var.node_root_volume_size_in_gb > 0 ? [var.image] : []
  408. content {
  409. uuid = data.openstack_images_image_v2.vm_image.id
  410. source_type = "image"
  411. volume_size = var.node_root_volume_size_in_gb
  412. boot_index = 0
  413. destination_type = "volume"
  414. delete_on_termination = true
  415. }
  416. }
  417. network {
  418. name = var.network_name
  419. }
  420. security_groups = [openstack_networking_secgroup_v2.k8s.name,
  421. openstack_networking_secgroup_v2.worker.name,
  422. ]
  423. dynamic "scheduler_hints" {
  424. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_node[0]] : []
  425. content {
  426. group = openstack_compute_servergroup_v2.k8s_node[0].id
  427. }
  428. }
  429. metadata = {
  430. ssh_user = var.ssh_user
  431. kubespray_groups = "kube-node,k8s-cluster,%{if each.value.floating_ip == false}no-floating,%{endif}${var.supplementary_node_groups}"
  432. depends_on = var.network_id
  433. use_access_ip = var.use_access_ip
  434. }
  435. provisioner "local-exec" {
  436. command = "%{if each.value.floating_ip}sed s/USER/${var.ssh_user}/ ../../contrib/terraform/openstack/ansible_bastion_template.txt | sed s/BASTION_ADDRESS/${element(concat(var.bastion_fips, [for key, value in var.k8s_nodes_fips : value.address]), 0)}/ > group_vars/no-floating.yml%{else}true%{endif}"
  437. }
  438. }
  439. resource "openstack_compute_instance_v2" "glusterfs_node_no_floating_ip" {
  440. name = "${var.cluster_name}-gfs-node-nf-${count.index + 1}"
  441. count = var.number_of_gfs_nodes_no_floating_ip
  442. availability_zone = element(var.az_list, count.index)
  443. image_name = var.image_gfs
  444. flavor_id = var.flavor_gfs_node
  445. key_pair = openstack_compute_keypair_v2.k8s.name
  446. dynamic "block_device" {
  447. for_each = var.gfs_root_volume_size_in_gb > 0 ? [var.image] : []
  448. content {
  449. uuid = data.openstack_images_image_v2.vm_image.id
  450. source_type = "image"
  451. volume_size = var.gfs_root_volume_size_in_gb
  452. boot_index = 0
  453. destination_type = "volume"
  454. delete_on_termination = true
  455. }
  456. }
  457. network {
  458. name = var.network_name
  459. }
  460. security_groups = [openstack_networking_secgroup_v2.k8s.name]
  461. dynamic "scheduler_hints" {
  462. for_each = var.use_server_groups ? [openstack_compute_servergroup_v2.k8s_node[0]] : []
  463. content {
  464. group = openstack_compute_servergroup_v2.k8s_node[0].id
  465. }
  466. }
  467. metadata = {
  468. ssh_user = var.ssh_user_gfs
  469. kubespray_groups = "gfs-cluster,network-storage,no-floating"
  470. depends_on = var.network_id
  471. use_access_ip = var.use_access_ip
  472. }
  473. }
  474. resource "openstack_compute_floatingip_associate_v2" "bastion" {
  475. count = var.number_of_bastions
  476. floating_ip = var.bastion_fips[count.index]
  477. instance_id = element(openstack_compute_instance_v2.bastion.*.id, count.index)
  478. wait_until_associated = var.wait_for_floatingip
  479. }
  480. resource "openstack_compute_floatingip_associate_v2" "k8s_master" {
  481. count = var.number_of_k8s_masters
  482. instance_id = element(openstack_compute_instance_v2.k8s_master.*.id, count.index)
  483. floating_ip = var.k8s_master_fips[count.index]
  484. wait_until_associated = var.wait_for_floatingip
  485. }
  486. resource "openstack_compute_floatingip_associate_v2" "k8s_master_no_etcd" {
  487. count = var.master_root_volume_size_in_gb == 0 ? var.number_of_k8s_masters_no_etcd : 0
  488. instance_id = element(openstack_compute_instance_v2.k8s_master_no_etcd.*.id, count.index)
  489. floating_ip = var.k8s_master_no_etcd_fips[count.index]
  490. }
  491. resource "openstack_compute_floatingip_associate_v2" "k8s_node" {
  492. count = var.node_root_volume_size_in_gb == 0 ? var.number_of_k8s_nodes : 0
  493. floating_ip = var.k8s_node_fips[count.index]
  494. instance_id = element(openstack_compute_instance_v2.k8s_node[*].id, count.index)
  495. wait_until_associated = var.wait_for_floatingip
  496. }
  497. resource "openstack_compute_floatingip_associate_v2" "k8s_nodes" {
  498. for_each = var.number_of_k8s_nodes == 0 && var.number_of_k8s_nodes_no_floating_ip == 0 ? { for key, value in var.k8s_nodes : key => value if value.floating_ip } : {}
  499. floating_ip = var.k8s_nodes_fips[each.key].address
  500. instance_id = openstack_compute_instance_v2.k8s_nodes[each.key].id
  501. wait_until_associated = var.wait_for_floatingip
  502. }
  503. resource "openstack_blockstorage_volume_v2" "glusterfs_volume" {
  504. name = "${var.cluster_name}-glusterfs_volume-${count.index + 1}"
  505. count = var.gfs_root_volume_size_in_gb == 0 ? var.number_of_gfs_nodes_no_floating_ip : 0
  506. description = "Non-ephemeral volume for GlusterFS"
  507. size = var.gfs_volume_size_in_gb
  508. }
  509. resource "openstack_compute_volume_attach_v2" "glusterfs_volume" {
  510. count = var.gfs_root_volume_size_in_gb == 0 ? var.number_of_gfs_nodes_no_floating_ip : 0
  511. instance_id = element(openstack_compute_instance_v2.glusterfs_node_no_floating_ip.*.id, count.index)
  512. volume_id = element(openstack_blockstorage_volume_v2.glusterfs_volume.*.id, count.index)
  513. }