Skip to content

Commit

Permalink
Add Neutron floating IP support for Issue rhtconsulting#195
Browse files Browse the repository at this point in the history
Also addressed the following issues encountered while testing this PR:
* It is possible for an instance to not have a floating IP for whatever reason (such as manually deallocating or releasing the IP), in this case SSH will not work to the instance so it will not be included in the host group to attempt subscription manager unregister, but will still be deleted
* It is possible that an instance will have a volume created but not attached. In this case as a precautionary measure I am excluding these unattached volumes from the deletion in case this was intentionally detached to preserve data. We can further discuss if this should be a parameter to override instead or if we need to change this behavior.
* Excluded instances in ERROR state as they will most likely not delete. We can discuss if this should be parameterized instead.
* Changed default ansible_ssh_user to cloud-user in line with our images
* Add check for and set_fact if Neutron is in use which is used by several tasks
* Add count for ips and volumes to display since these may not always be the same as instance count
* Enhance displayed warning/note message to include new counts
* Add check for valid item when attempting to delete objects
  • Loading branch information
vvaldez committed Jun 28, 2016
1 parent 5fd360e commit 4c70d0d
Showing 1 changed file with 118 additions and 11 deletions.
129 changes: 118 additions & 11 deletions rhc-ose-ansible/playbooks/openstack/terminate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- hosts: localhost
gather_facts: false
vars:
ansible_ssh_user: root
ansible_ssh_user: cloud-user
max_instances: 6
min_env_id_length: 8
really_really_sure: false
Expand Down Expand Up @@ -44,14 +44,19 @@
failed_when: nova_result.rc != 0

- name: "Determine number of matching instances"
shell: nova list | grep -E "{{ env_id }}" | awk '{print $2}' | sed ':a;N;$!ba;s/\n/, /g'
shell: nova list | grep -v "ERROR" | grep -E "{{ env_id }}" | awk '{print $2}' | sed ':a;N;$!ba;s/\n/, /g'
register: instances_to_delete

- debug:
var:
instances_to_delete
when: dry_run

- name: "Set instance count fact"
set_fact:
instance_count: "{{ instances_to_delete.stdout.split(', ')|length }}"

- name: "Fix count if list is empty"
- name: "Fix instance count if list is empty"
# Python counts an empty list as length 1, so fixing it if so
set_fact:
instance_count: 0
Expand All @@ -73,21 +78,86 @@
- not really_really_sure

- name: "Determine instance names to delete"
shell: nova list | grep -E "{{ env_id }}" | awk '{print $4}' | sed ':a;N;$!ba;s/\n/, /g'
shell: nova list | grep -v "ERROR" | grep -E "{{ env_id }}" | awk '{print $4}' | sed ':a;N;$!ba;s/\n/, /g'
register: names_to_delete

- debug:
var:
names_to_delete
when: dry_run

- name: "Query Neutron services"
command: neutron agent-list
register: neutron
ignore_errors: true

- name: "Check for Neutron services - (a failure assumes Legacy Networking (Nova Network)"
set_fact:
neutron_in_use: true
when: neutron.rc == 0

# There is a possibility of an instance not having a floating IP thus the extra sed to delete an empty field
- name: "Determine list of public IPs"
shell: nova list | grep -E "{{ env_id }}" | awk '{print $13}' | sed ':a;N;$!ba;s/\n/, /g'
shell: nova list | grep -v "ERROR" | grep -E "{{ env_id }}" | awk '{print $13}' | sed '/|/d' | sed ':a;N;$!ba;s/\n/, /g'
register: ips_to_delete

- name: "Set IP count fact"
set_fact:
ip_count: "{{ ips_to_delete.stdout.split(', ')|length }}"

- name: "Fix IP count if list is empty"
# Python counts an empty list as length 1, so fixing it if so
set_fact:
ip_count: 0
when:
- ips_to_delete.stdout.split(', ').0|trim == ''


- debug:
var:
ips_to_delete
when: dry_run

- name: "Determine list of Neutron Port IDs to delete"
shell: for floatingip in $(echo {{ ips_to_delete.stdout }} | sed -n 1'p' | tr ',' ' ' | while read ip; do echo ${ip}; done); do neutron floatingip-list | awk "/${floatingip}/"'{print $2}'; done | sed ':a;N;$!ba;s/\n/, /g'
register: floatingips_to_delete
when: neutron_in_use is defined

- debug:
var:
floatingips_to_delete
when: dry_run

# It is possible for a volume to exist but not be attached possibly intentionally to save data, so adding an extra grep to ensure only in-use volumes are deleted. This is because the volume names are set the ID of the instance which is difficult to determine when it is attached or not by looking for an attached ID.
- name: "Determine list of volumes"
shell: for instance in $(echo {{ instances_to_delete.stdout }} | sed -n 1'p' | tr ',' ' ' | while read id; do echo ${id}; done); do nova volume-list | awk "/${instance}/"'{print $2}'; done | sed ':a;N;$!ba;s/\n/, /g'
shell: for instance in $(echo {{ instances_to_delete.stdout }} | sed -n 1'p' | tr ',' ' ' | while read id; do echo ${id}; done); do nova volume-list | grep "in-use" | awk "/${instance}/"'{print $2}'; done | sed ':a;N;$!ba;s/\n/, /g'
register: volumes_to_delete

- debug:
var:
volumes_to_delete
when: dry_run

- name: "Set Volume count fact"
set_fact:
volume_count: "{{ volumes_to_delete.stdout.split(', ')|length }}"

- name: "Fix Volume count if list is empty"
# Python counts an empty list as length 1, so fixing it if so
set_fact:
volume_count: 0
when:
- volumes_to_delete.stdout.split(', ').0|trim == ''

- name: "Determine images used in instances"
shell: for instance in $(echo {{ instances_to_delete.stdout }} | sed -n 1'p' | tr ',' ' ' | while read id; do echo ${id}; done); do nova show ${instance} | awk "/image/"'{print $4}'; done | sed ':a;N;$!ba;s/\n/, /g'
register: images_to_delete

- debug:
var:
images_to_delete
when: dry_run

- name: "Initialize image fact to first image found"
set_fact:
image: "{{ images_to_delete.stdout.split(', ').0 }}"
Expand All @@ -98,6 +168,12 @@
when: "'{{ item }}' != image"
with_items: images_to_delete.stdout.split(', ')

- name: "Set Neutron Port ID fact"
set_fact:
floatingips_to_delete:
stdout: "Neutron not in use"
when: neutron_in_use is undefined

- name: "Warn if images are not unique"
pause:
prompt: "{{ newline }}
Expand All @@ -114,14 +190,20 @@ Press ENTER to continue or CTRL+c to cancel"
ansible_ssh_user: "{{ ansible_ssh_user }}"
groups: instance_ips
with_items: "ips_to_delete.stdout.split(', ')"
when:
- item is defined
- item is not none
- item|trim != ''

- name: "Pause for confirmation on normal run."
pause:
prompt: "{{ newline }}
WARNING! About to delete the following {{ instance_count|int }} instances and attached volumes{{':'}}{{ newline }}{{ newline }}
WARNING! About to delete the following objects matching the environment ID '{{ env_id}}'{{':'}}{{ newline }}
{{ instance_count|int }} instances, {{ ip_count|int }} IPs and {{ volume_count|int }} attached volumes{{':'}}{{ newline }}{{ newline }}
[Instance IDs]{{':'}} '{{ instances_to_delete.stdout }}'{{ newline }}{{ newline }}
[Instance Names]{{':'}} '{{ names_to_delete.stdout }}'{{ newline }}{{ newline }}
[Instance IPs]{{':'}} '{{ ips_to_delete.stdout }}'{{ newline }}{{ newline }}
[Floating IP IDs]{{':'}} '{{ floatingips_to_delete.stdout }}'{{ newline }}{{ newline }}
[Attached Volumes]{{':'}} '{{ volumes_to_delete.stdout }}'{{ newline }}{{ newline }}
[Unique Images]{{':'}} '{{ images_to_delete.stdout.split(', ') | unique | join(', ') }}'{{ newline }}{{ newline }}
Press ENTER to delete these or CTRL+c to cancel"
Expand All @@ -130,10 +212,12 @@ Press ENTER to delete these or CTRL+c to cancel"
- name: "Pause for confirmation on dry run."
pause:
prompt: "{{ newline }}
NOTE{{':'}} A normal run would delete the following {{ instance_count|int }} instances and attached volumes{{':'}}{{ newline }}{{ newline }}
NOTE{{':'}} A normal run would delete the following objects matching the environment ID '{{ env_id}}'{{':'}}{{ newline}}
{{ instance_count|int }} instances, {{ ip_count|int }} IPs and {{ volume_count|int }} attached volumes{{':'}}{{ newline }}{{ newline }}
[Instance IDs]{{':'}} '{{ instances_to_delete.stdout }}'{{ newline }}{{ newline }}
[Instance Names]{{':'}} '{{ names_to_delete.stdout }}'{{ newline }}{{ newline }}
[Instance IPs]{{':'}} '{{ ips_to_delete.stdout }}'{{ newline }}{{ newline }}
[Floating IP IDs]{{':'}} '{{ floatingips_to_delete.stdout }}'{{ newline }}{{ newline }}
[Attached Volumes]{{':'}} '{{ volumes_to_delete.stdout }}'{{ newline }}{{ newline }}
[Unique Images]{{':'}} '{{ images_to_delete.stdout.split(', ') | unique | join(', ') }}'{{ newline }}{{ newline }}
Press ENTER to view tasks that will be skipped or CTRL+c to cancel"
Expand Down Expand Up @@ -165,7 +249,11 @@ Press ENTER to view tasks that will be skipped or CTRL+c to cancel"
command: "nova delete {{ item }}"
ignore_errors: yes
with_items: "instances_to_delete.stdout.split(', ')"
when: not dry_run
when:
- not dry_run
- item is defined
- item is not none
- item|trim != ''

- name: "Wait for instance delete and volume detach"
shell: nova volume-list | awk "/{{ item }}/"'{ print $4 }'
Expand All @@ -174,10 +262,29 @@ Press ENTER to view tasks that will be skipped or CTRL+c to cancel"
retries: 5
delay: 10
with_items: "volumes_to_delete.stdout.split(', ')"
when: not dry_run
when:
- not dry_run
- item is defined
- item is not none
- item|trim != ''

- name: "Delete volume"
command: "nova volume-delete {{ item }}"
ignore_errors: yes
with_items: "volumes_to_delete.stdout.split(', ')"
when: not dry_run
when:
- not dry_run
- item is defined
- item is not none
- item|trim != ''

- name: "Release Neutron Floating IP"
command: "neutron floatingip-delete {{ item }}"
ignore_errors: yes
with_items: "floatingips_to_delete.stdout.split(', ')"
when:
- not dry_run
- neutron_in_use is defined
- item is defined
- item is not none
- item|trim != ''

0 comments on commit 4c70d0d

Please sign in to comment.