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 <name> <pool>"
+    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',
         ],
     },