diff --git a/ansible/roles/libvirt-vm/defaults/main.yml b/ansible/roles/libvirt-vm/defaults/main.yml index e7a1e196a..054a1c21f 100644 --- a/ansible/roles/libvirt-vm/defaults/main.yml +++ b/ansible/roles/libvirt-vm/defaults/main.yml @@ -1,4 +1,7 @@ --- +# State of the VM. May be 'present' or 'absent'. +libvirt_vm_state: present + # Name of the VM. libvirt_vm_name: diff --git a/ansible/roles/libvirt-vm/files/destroy_virt_volume.sh b/ansible/roles/libvirt-vm/files/destroy_virt_volume.sh new file mode 100644 index 000000000..3863ae3b4 --- /dev/null +++ b/ansible/roles/libvirt-vm/files/destroy_virt_volume.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# Copyright (c) 2017 StackHPC Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# Ensure that a libvirt volume does not exists. +# On success, output a JSON object with a 'changed' item. + +if [[ $# -ne 2 ]]; then + echo "Usage: $0 " + exit 1 +fi + +NAME=$1 +POOL=$2 + +# Check whether a volume with this name exists. +output=$(virsh vol-info --pool $POOL --vol $NAME 2>&1) +result=$? +if [[ $result -ne 0 ]]; then + if echo "$output" | grep 'Storage volume not found' >/dev/null 2>&1; then + echo '{"changed": false}' + exit 0 + else + echo "Unexpected error while getting volume info" + echo "$output" + exit $result + fi +fi + +# Delete the volume. +output=$(virsh vol-delete --pool $POOL --vol $NAME 2>&1) +result=$? +if [[ $result -ne 0 ]]; then + echo "Failed to delete volume" + echo "$output" + exit $result +fi + +echo '{"changed": true}' +exit 0 diff --git a/ansible/roles/libvirt-vm/files/virt_volume.sh b/ansible/roles/libvirt-vm/files/virt_volume.sh index c1aae0924..006babcf8 100644 --- a/ansible/roles/libvirt-vm/files/virt_volume.sh +++ b/ansible/roles/libvirt-vm/files/virt_volume.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Copyright (c) 2017 StackHPC Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -12,8 +14,6 @@ # License for the specific language governing permissions and limitations # under the License. -#!/bin/bash - # Ensure that a libvirt volume exists, optionally uploading an image. # On success, output a JSON object with a 'changed' item. diff --git a/ansible/roles/libvirt-vm/tasks/destroy-vm.yml b/ansible/roles/libvirt-vm/tasks/destroy-vm.yml new file mode 100644 index 000000000..eda76f19b --- /dev/null +++ b/ansible/roles/libvirt-vm/tasks/destroy-vm.yml @@ -0,0 +1,20 @@ +--- +# The destroyed state does not seem to be idempotent, so check whether the VM +# exists before destroying it. +- name: Check the VM's status + virt: + name: "{{ libvirt_vm_name }}" + command: list_vms + register: result + +- block: + - name: Ensure the VM is absent + virt: + name: "{{ libvirt_vm_name }}" + state: destroyed + + - name: Ensure the VM is undefined + virt: + name: "{{ libvirt_vm_name }}" + command: undefine + when: libvirt_vm_name in result.list_vms diff --git a/ansible/roles/libvirt-vm/tasks/destroy-volumes.yml b/ansible/roles/libvirt-vm/tasks/destroy-volumes.yml new file mode 100644 index 000000000..e24ee3c38 --- /dev/null +++ b/ansible/roles/libvirt-vm/tasks/destroy-volumes.yml @@ -0,0 +1,11 @@ +--- +- name: Ensure the VM volumes do not exist + script: > + destroy_virt_volume.sh + {{ item.name }} + {{ item.pool }} + with_items: "{{ libvirt_vm_volumes }}" + register: volume_result + changed_when: + - "{{ volume_result | success }}" + - "{{ (volume_result.stdout | from_json).changed | default(True) }}" diff --git a/ansible/roles/libvirt-vm/tasks/main.yml b/ansible/roles/libvirt-vm/tasks/main.yml index c25c34040..6808418ff 100644 --- a/ansible/roles/libvirt-vm/tasks/main.yml +++ b/ansible/roles/libvirt-vm/tasks/main.yml @@ -1,3 +1,10 @@ --- -- include: volumes.yml -- include: vm.yml +- block: + - include: volumes.yml + - include: vm.yml + when: libvirt_vm_state == 'present' + +- block: + - include: destroy-volumes.yml + - include: destroy-vm.yml + when: libvirt_vm_state == 'absent' diff --git a/ansible/seed-vm-deprovision.yml b/ansible/seed-vm-deprovision.yml new file mode 100644 index 000000000..3f09f5f0f --- /dev/null +++ b/ansible/seed-vm-deprovision.yml @@ -0,0 +1,15 @@ +--- +- name: Ensure that the seed VM is deprovisioned + hosts: seed-hypervisor + vars: + seed_host: "{{ groups['seed'][0] }}" + seed_hostvars: "{{ hostvars[seed_host] }}" + roles: + - role: libvirt-vm + seed_vm_configdrive_volume: + name: "{{ seed_hostvars.seed_vm_name }}-configdrive" + pool: "{{ seed_hostvars.seed_vm_pool }}" + libvirt_vm_name: "{{ seed_hostvars.seed_vm_name }}" + libvirt_vm_volumes: "{{ seed_hostvars.seed_vm_volumes + [seed_vm_configdrive_volume] }}" + libvirt_vm_state: "absent" + become: True diff --git a/ansible/seed-vm.yml b/ansible/seed-vm-provision.yml similarity index 100% rename from ansible/seed-vm.yml rename to ansible/seed-vm-provision.yml diff --git a/doc/source/administration.rst b/doc/source/administration.rst index 611461966..7c5211876 100644 --- a/doc/source/administration.rst +++ b/doc/source/administration.rst @@ -69,6 +69,17 @@ To deprovision the overcloud:: (kayobe-venv) $ kayobe overcloud deprovision +Deprovisioning The Seed VM +========================== + +.. note:: + + This step will destroy the seed VM and its data volumes. + +To deprovision the seed VM:: + + (kayobe-venv) $ kayobe seed vm deprovision + Running Kayobe Playbooks on Demand ================================== diff --git a/kayobe/cli/commands.py b/kayobe/cli/commands.py index 7f356bb62..385fdbfd2 100644 --- a/kayobe/cli/commands.py +++ b/kayobe/cli/commands.py @@ -241,12 +241,25 @@ class SeedVMProvision(KollaAnsibleMixin, KayobeAnsibleMixin, VaultMixin, self.app.LOG.debug("Provisioning seed VM") self.run_kayobe_playbook(parsed_args, "ansible/ip-allocation.yml", limit="seed") - self.run_kayobe_playbook(parsed_args, "ansible/seed-vm.yml") + self.run_kayobe_playbook(parsed_args, "ansible/seed-vm-provision.yml") # Now populate the Kolla Ansible inventory. self.run_kayobe_playbook(parsed_args, "ansible/kolla-ansible.yml", tags="config") +class SeedVMDeprovision(KollaAnsibleMixin, KayobeAnsibleMixin, VaultMixin, + Command): + """Deprovision the seed VM. + + This will destroy the seed VM and all associated volumes. + """ + + def take_action(self, parsed_args): + self.app.LOG.debug("Deprovisioning seed VM") + self.run_kayobe_playbook(parsed_args, + "ansible/seed-vm-deprovision.yml") + + class SeedHostConfigure(KollaAnsibleMixin, KayobeAnsibleMixin, VaultMixin, Command): """Configure the seed node host OS.""" diff --git a/setup.py b/setup.py index 313f686ba..8ebfaaea5 100644 --- a/setup.py +++ b/setup.py @@ -74,6 +74,7 @@ setup( 'seed_host_configure = kayobe.cli.commands:SeedHostConfigure', 'seed_hypervisor_host_configure = kayobe.cli.commands:SeedHypervisorHostConfigure', 'seed_service_deploy = kayobe.cli.commands:SeedServiceDeploy', + 'seed_vm_deprovision = kayobe.cli.commands:SeedVMDeprovision', 'seed_vm_provision = kayobe.cli.commands:SeedVMProvision', ], },