diff --git a/README.md b/README.md index 0189548b5..548b196ca 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,12 @@ Image Builder (DIB). To configure the seed host OS: (kayobe-venv) $ kayobe seed host configure +If the seed host uses disks that have been in use in a previous installation, +it may be necessary to wipe partition and LVM data from those disks. To wipe +all disks that are not mounted during host configuration: + + (kayobe-venv) $ kayobe seed host configure --wipe-disks + It is possible to use prebuilt container images from an image registry such as Dockerhub. In some cases it may be necessary to build images locally either to apply local image customisation or to use a downstream version of Kolla. To @@ -159,6 +165,12 @@ provisioned with an OS image. To configure the overcloud hosts' OS: (kayobe-venv) $ kayobe overcloud host configure +If the controller hosts use disks that have been in use in a previous +installation, it may be necessary to wipe partition and LVM data from those +disks. To wipe all disks that are not mounted during host configuration: + + (kayobe-venv) $ kayobe overcloud host configure --wipe-disks + It is possible to use prebuilt container images from an image registry such as Dockerhub. In some cases it may be necessary to build images locally either to apply local image customisation or to use a downstream version of Kolla. To diff --git a/ansible/roles/wipe-disks/tasks/main.yml b/ansible/roles/wipe-disks/tasks/main.yml new file mode 100644 index 000000000..cad98fc7c --- /dev/null +++ b/ansible/roles/wipe-disks/tasks/main.yml @@ -0,0 +1,60 @@ +--- +# Warning! These tasks can result in lost data. Take care when developing and +# using them. + +# Initialisation tasks to be applied on first boot of a system to initalise +# disks. We search for block devices that are not currently mounted, then wipe +# any LVM or file system state from them. + +- name: Ensure LVM2 is installed + yum: + name: lvm2 + state: present + become: True + +- name: Check for unmounted block devices + shell: > + lsblk -i -o NAME,MOUNTPOINT | awk \ + '/^ *[|`]-/ && NF > 1 { mounts[master_dev] = mounts[master_dev] $2 " " } + /^sd/ && NF == 1 { master_dev = $1; mounts[master_dev] = "" } + END { for (dev in mounts) if (mounts[dev] == "") print dev }' + register: unmounted_devices + changed_when: False + +- name: Ensure that all unmounted block devices have LVM state removed + shell: | + set -e + if pvs /dev/{{ item }} >/dev/null 2>&1 + then + echo "Found PV on /dev/{{ item }}" + vg=$(pvs --noheadings -o vg_name /dev/{{ item }}) + if [[ -n $vg ]] && [[ $vg != " " ]] + then + echo "Found VG $vg on PV /dev/{{ item }}" + lvs --noheadings -o lv_name $vg | while read lv + do + if [[ -n $lv ]] && [[ $lv != " " ]] + then + echo "Found LV $lv on VG $vg. Removing" + lvremove -yf ${vg}/${lv} + fi + done + vgremove -f $vg + fi + pvremove -yff /dev/{{ item }} + fi + with_items: "{{ unmounted_devices.stdout_lines }}" + become: True + +- name: Ensure that all unmounted block devices have filesystems wiped + command: "wipefs -f /dev/{{ item }}" + with_items: "{{ unmounted_devices.stdout_lines }}" + become: True + # The command can fail in some cases which are valid, so ignore the + # result. + failed_when: False + +- name: Ensure that all unmounted block device headers are zeroed + command: "dd if=/dev/zero of=/dev/{{ item }} bs=1M count=100" + with_items: "{{ unmounted_devices.stdout_lines }}" + become: True diff --git a/ansible/wipe-disks.yml b/ansible/wipe-disks.yml new file mode 100644 index 000000000..415edb2aa --- /dev/null +++ b/ansible/wipe-disks.yml @@ -0,0 +1,12 @@ +--- +# Warning! This play can result in lost data. Take care when developing and +# using it. + +# Initialisation task to be applied on first boot of a system to initalise +# disks. We search for block devices that are not currently mounted, then wipe +# any LVM or file system state from them. + +- name: Ensure that all unmounted block devices are wiped + hosts: seed:controllers + roles: + - role: wipe-disks diff --git a/kayobe/cli/commands.py b/kayobe/cli/commands.py index dc1dfe063..e3a17667f 100644 --- a/kayobe/cli/commands.py +++ b/kayobe/cli/commands.py @@ -160,12 +160,24 @@ class SeedVMProvision(KollaAnsibleMixin, KayobeAnsibleMixin, Command): class SeedHostConfigure(KollaAnsibleMixin, KayobeAnsibleMixin, Command): """Configure the seed node host OS.""" + def get_parser(self, prog_name): + parser = super(SeedHostConfigure, self).get_parser(prog_name) + group = parser.add_argument_group("Host Configuration") + group.add_argument("--wipe-disks", action='store_true', + help="wipe partition and LVM data from all disks " + "that are not mounted. Warning: this can " + "result in the loss of data") + return parser + def take_action(self, parsed_args): self.app.LOG.debug("Configuring seed host OS") ansible_user = ansible.config_dump(parsed_args, host="seed", var_name="kayobe_ansible_user") playbooks = _build_playbook_list( - "ip-allocation", "ssh-known-host", "kayobe-ansible-user", + "ip-allocation", "ssh-known-host", "kayobe-ansible-user") + if parsed_args.wipe_disks: + playbooks += _build_playbook_list("disk-wipe") + playbooks += _build_playbook_list( "dev-tools", "disable-selinux", "network", "ntp", "lvm") ansible.run_playbooks(parsed_args, playbooks, limit="seed") kolla_ansible.run_seed(parsed_args, "bootstrap-servers", @@ -245,12 +257,24 @@ class OvercloudProvision(KayobeAnsibleMixin, Command): class OvercloudHostConfigure(KollaAnsibleMixin, KayobeAnsibleMixin, Command): """Configure the overcloud host OS.""" + def get_parser(self, prog_name): + parser = super(OvercloudHostConfigure, self).get_parser(prog_name) + group = parser.add_argument_group("Host Configuration") + group.add_argument("--wipe-disks", action='store_true', + help="wipe partition and LVM data from all disks " + "that are not mounted. Warning: this can " + "result in the loss of data") + return parser + def take_action(self, parsed_args): self.app.LOG.debug("Configuring overcloud host OS") ansible_user = ansible.config_dump(parsed_args, host="controllers[0]", var_name="kayobe_ansible_user") playbooks = _build_playbook_list( - "ip-allocation", "ssh-known-host", "kayobe-ansible-user", + "ip-allocation", "ssh-known-host", "kayobe-ansible-user") + if parsed_args.wipe_disks: + playbooks += _build_playbook_list("disk-wipe") + playbooks += _build_playbook_list( "dev-tools", "disable-selinux", "network", "ntp", "lvm") ansible.run_playbooks(parsed_args, playbooks, limit="controllers") kolla_ansible.run_overcloud(parsed_args, "bootstrap-servers",