|
240 | 240 | ip_address_type: "{{ 'public_ip_address' if server_public_ip | bool else 'private_ip_address' }}" |
241 | 241 |
|
242 | 242 | # Server and volume |
243 | | - - name: "AWS: Create or modify EC2 instance" |
244 | | - amazon.aws.ec2_instance: |
245 | | - access_key: "{{ lookup('ansible.builtin.env', 'AWS_ACCESS_KEY_ID') }}" |
246 | | - secret_key: "{{ lookup('ansible.builtin.env', 'AWS_SECRET_ACCESS_KEY') }}" |
247 | | - name: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
248 | | - state: present |
249 | | - instance_type: "{{ server_type }}" |
250 | | - image_id: "{{ server_image }}" |
251 | | - key_name: "{{ ssh_key_name }}" |
252 | | - region: "{{ server_location }}" |
253 | | - network_interfaces: |
254 | | - - subnet_id: "{{ server_network }}" |
255 | | - groups: "{{ ([] if not cloud_firewall | bool else [ec2_security_group_result.group_id]) }}" |
256 | | - assign_public_ip: "{{ server_public_ip | bool }}" |
257 | | - delete_on_termination: true |
258 | | - volumes: |
259 | | - - device_name: /dev/sda1 |
260 | | - ebs: |
261 | | - volume_type: "{{ system_volume_type | default('gp3', true) }}" |
262 | | - volume_size: "{{ system_volume_size | default(80) | int }}" |
263 | | - delete_on_termination: true |
264 | | - - device_name: /dev/sdb |
265 | | - ebs: |
266 | | - volume_type: "{{ volume_type | default('gp3', true) }}" |
267 | | - volume_size: "{{ volume_size | int }}" |
268 | | - delete_on_termination: true |
269 | | - loop: "{{ range(0, server_count | int) | list }}" |
270 | | - loop_control: |
271 | | - index_var: idx |
272 | | - label: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
273 | | - register: server_result |
274 | | - until: |
275 | | - - server_result.instances[0][ip_address_type] is defined |
276 | | - - server_result.instances[0][ip_address_type] | length > 0 |
277 | | - retries: 3 |
278 | | - delay: 10 |
| 243 | + - block: |
| 244 | + - name: "AWS: Gather information about EC2 instances" |
| 245 | + amazon.aws.ec2_instance_info: |
| 246 | + access_key: "{{ lookup('ansible.builtin.env', 'AWS_ACCESS_KEY_ID') }}" |
| 247 | + secret_key: "{{ lookup('ansible.builtin.env', 'AWS_SECRET_ACCESS_KEY') }}" |
| 248 | + region: "{{ server_location }}" |
| 249 | + filters: |
| 250 | + instance-type: "{{ server_type }}" |
| 251 | + instance-state-name: ["pending", "running", "shutting-down", "stopping", "stopped"] |
| 252 | + "tag:Name": "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
| 253 | + loop: "{{ range(0, server_count | int) | list }}" |
| 254 | + loop_control: |
| 255 | + index_var: idx |
| 256 | + label: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
| 257 | + register: ec2_instance_info |
| 258 | + |
| 259 | + - name: "AWS: Create EC2 instance" |
| 260 | + amazon.aws.ec2_instance: |
| 261 | + access_key: "{{ lookup('ansible.builtin.env', 'AWS_ACCESS_KEY_ID') }}" |
| 262 | + secret_key: "{{ lookup('ansible.builtin.env', 'AWS_SECRET_ACCESS_KEY') }}" |
| 263 | + name: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
| 264 | + state: running |
| 265 | + instance_type: "{{ server_type }}" |
| 266 | + image_id: "{{ server_image }}" |
| 267 | + key_name: "{{ ssh_key_name }}" |
| 268 | + region: "{{ server_location }}" |
| 269 | + network_interfaces: |
| 270 | + - subnet_id: "{{ server_network }}" |
| 271 | + groups: "{{ ([] if not cloud_firewall | bool else [ec2_security_group_result.group_id]) }}" |
| 272 | + assign_public_ip: "{{ server_public_ip | bool }}" |
| 273 | + delete_on_termination: true |
| 274 | + volumes: |
| 275 | + - device_name: /dev/sda1 |
| 276 | + ebs: |
| 277 | + volume_type: "{{ system_volume_type | default('gp3', true) }}" |
| 278 | + volume_size: "{{ system_volume_size | default(80) | int }}" |
| 279 | + delete_on_termination: true |
| 280 | + - device_name: /dev/sdb |
| 281 | + ebs: |
| 282 | + volume_type: "{{ volume_type | default('gp3', true) }}" |
| 283 | + volume_size: "{{ volume_size | int }}" |
| 284 | + delete_on_termination: true |
| 285 | + tags: |
| 286 | + Name: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
| 287 | + Cluster: "{{ patroni_cluster_name }}" |
| 288 | + loop: "{{ range(0, server_count | int) | list }}" |
| 289 | + loop_control: |
| 290 | + index_var: idx |
| 291 | + label: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
| 292 | + register: ec2_instance_result |
| 293 | + retries: 3 |
| 294 | + delay: 10 |
| 295 | + when: ec2_instance_info.results[idx].instances | length == 0 # only if instance does not exist |
279 | 296 | when: not server_spot | default(aws_ec2_spot_instance | default(false)) | bool |
280 | 297 |
|
281 | 298 | # Spot instance (if 'server_spot' is 'true') |
|
288 | 305 | filters: |
289 | 306 | instance-lifecycle: "spot" |
290 | 307 | instance-type: "{{ server_type }}" |
291 | | - image-id: "{{ server_image }}" |
292 | 308 | instance-state-name: ["pending", "running", "shutting-down", "stopping", "stopped"] |
293 | 309 | "tag:Name": "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
294 | 310 | loop: "{{ range(0, server_count | int) | list }}" |
|
327 | 343 | delete_on_termination: true |
328 | 344 | tags: |
329 | 345 | Name: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
| 346 | + Cluster: "{{ patroni_cluster_name }}" |
330 | 347 | loop: "{{ ec2_spot_instance_info.results }}" |
331 | 348 | loop_control: |
332 | 349 | index_var: idx |
|
353 | 370 | retries: 3 |
354 | 371 | delay: 10 |
355 | 372 | when: item.spot_request.spot_instance_request_id is defined |
356 | | - |
357 | | - # if spot instances are created now |
358 | | - - name: "Set variable: server_result" |
359 | | - ansible.builtin.set_fact: |
360 | | - server_result: "{{ ec2_spot_instance_result }}" |
361 | | - when: ec2_spot_instance_result.changed | default(false) |
362 | | - |
363 | | - # if spot instances have already been created |
364 | | - - name: "Set variable: server_result" |
365 | | - ansible.builtin.set_fact: |
366 | | - server_result: "{{ ec2_spot_instance_info }}" |
367 | | - when: not ec2_spot_instance_result.changed | default(false) |
368 | 373 | when: server_spot | default(aws_ec2_spot_instance | default(false)) | bool |
369 | 374 |
|
| 375 | + # Combine existing and newly created instances |
| 376 | + - name: "Set variable: server_result" |
| 377 | + ansible.builtin.set_fact: |
| 378 | + server_result: |
| 379 | + results: >- |
| 380 | + {{ |
| 381 | + ( |
| 382 | + (ec2_instance_info.results | default([])) |
| 383 | + + (ec2_instance_result.results | default([])) |
| 384 | + + (ec2_spot_instance_info.results | default([])) |
| 385 | + + (ec2_spot_instance_result.results | default([])) |
| 386 | + ) |
| 387 | + | selectattr('instances', 'defined') |
| 388 | + | selectattr('instances', '!=', []) |
| 389 | + | list |
| 390 | + }} |
| 391 | +
|
370 | 392 | # Classic Load Balancer (CLB) - previous generation |
371 | 393 | - name: "AWS: Create Classic Load Balancer (CLB)" |
372 | 394 | amazon.aws.elb_classic_lb: |
|
402 | 424 | loop_control: |
403 | 425 | label: "{{ patroni_cluster_name }}-{{ item }}" |
404 | 426 | register: aws_elb_classic_lb |
405 | | - when: cloud_load_balancer | bool and aws_load_balancer_type | lower == 'clb' and |
| 427 | + when: server_result.results | default([]) | length > 0 and |
| 428 | + cloud_load_balancer | bool and aws_load_balancer_type | lower == 'clb' and |
406 | 429 | (item == 'primary' or |
407 | 430 | (item == 'replica' and server_count | int > 1) or |
408 | 431 | (item in ['sync', 'async'] and server_count | int > 1 and synchronous_mode | bool)) |
409 | 432 |
|
410 | 433 | # Network Load Balancer (NLB) |
411 | | - - name: "AWS: Create NLB Target Group" |
| 434 | + - name: Build NLB targets |
| 435 | + ansible.builtin.set_fact: |
| 436 | + nlb_targets: "{{ (nlb_targets | default([])) + [{'Id': item, 'Port': target_port | int}] }}" |
| 437 | + loop: "{{ instance_ids | default([]) }}" |
| 438 | + vars: |
| 439 | + instance_ids: "{{ (server_result | default({'results': []})) | json_query('results[].instances[].instance_id') }}" |
| 440 | + target_port: "{{ pgbouncer_listen_port | default('6432') if pgbouncer_install | bool else postgresql_port | default('5432') }}" |
| 441 | + when: cloud_load_balancer | bool and aws_load_balancer_type | lower == 'nlb' |
| 442 | + |
| 443 | + - name: "AWS: Create or modify NLB Target Group" |
412 | 444 | community.aws.elb_target_group: |
413 | 445 | access_key: "{{ lookup('ansible.builtin.env', 'AWS_ACCESS_KEY_ID') }}" |
414 | 446 | secret_key: "{{ lookup('ansible.builtin.env', 'AWS_SECRET_ACCESS_KEY') }}" |
|
427 | 459 | healthy_threshold_count: 3 |
428 | 460 | successful_response_codes: "200" |
429 | 461 | target_type: instance |
430 | | - targets: >- |
431 | | - {{ |
432 | | - server_result.results |
433 | | - | map(attribute='instances') |
434 | | - | map('first') |
435 | | - | map(attribute='instance_id') |
436 | | - | map('community.general.dict_kv', 'Id') |
437 | | - | map('combine', {'Port': target_port | int}) |
438 | | - | list |
439 | | - }} |
| 462 | + targets: "{{ nlb_targets | default([]) }}" |
440 | 463 | modify_targets: true |
441 | 464 | wait: false |
442 | 465 | state: present |
|
514 | 537 | volume_size: "{{ volume_size }} GB" |
515 | 538 | public_ip: "{{ item.instances[0].public_ip_address | default('N/A', true) }}" |
516 | 539 | private_ip: "{{ item.instances[0].private_ip_address | default('N/A', true) }}" |
517 | | - loop: "{{ server_result.results }}" |
| 540 | + loop: "{{ server_result.results | default([]) }}" |
518 | 541 | loop_control: |
519 | 542 | index_var: idx |
520 | 543 | label: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
|
529 | 552 | port: 22 |
530 | 553 | delay: 5 |
531 | 554 | timeout: 300 |
532 | | - loop: "{{ server_result.results }}" |
| 555 | + loop: "{{ server_result.results | default([]) }}" |
533 | 556 | loop_control: |
534 | 557 | index_var: idx |
535 | 558 | label: "{{ server_name | lower }}{{ '%02d' % (idx + 1) }}" |
|
545 | 568 | {{ ip_addresses | default([]) + |
546 | 569 | [{ |
547 | 570 | 'public_ip': item.instances[0].public_ip_address | default(''), |
548 | | - 'private_ip': item.instances[0].private_ip_address | default('') |
| 571 | + 'private_ip': item.instances[0].private_ip_address | default(''), |
| 572 | + 'new_node': (cluster_scaling | default(false) | bool and item.instances[0].instance_id not in existing_instance_ids) |
549 | 573 | }] |
550 | 574 | }} |
| 575 | + vars: |
| 576 | + existing_instance_ids: >- |
| 577 | + {{ |
| 578 | + ( |
| 579 | + (ec2_instance_info.results | default([])) + |
| 580 | + (ec2_spot_instance_info.results | default([])) |
| 581 | + ) |
| 582 | + | selectattr('instances','defined') | map(attribute='instances') | list | flatten |
| 583 | + | selectattr('instance_id','defined') | map(attribute='instance_id') | list |
| 584 | + }} |
551 | 585 | loop: "{{ server_result.results | selectattr('instances', 'defined') }}" |
552 | 586 | loop_control: |
553 | 587 | label: >- |
|
0 commit comments