From 22631ec76d34d782878a33d3def540e35164b718 Mon Sep 17 00:00:00 2001 From: Joseph Sawaya Date: Thu, 9 Sep 2021 15:14:29 -0400 Subject: [PATCH] mgr/rook: implement `orch device zap` in rook orchestrator This commit implements orch device zap by creating a pod on the target host that mounts the /dev directory and runs either overwrites the first few blocks of the device with zeros if it's a raw device or if it's not a raw device it will use `ceph-volume lvm zap`. Signed-off-by: Joseph Sawaya --- src/pybind/mgr/rook/module.py | 10 ++++ src/pybind/mgr/rook/rook_cluster.py | 81 +++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/pybind/mgr/rook/module.py b/src/pybind/mgr/rook/module.py index d1412a708374d..b08f6aa161dce 100644 --- a/src/pybind/mgr/rook/module.py +++ b/src/pybind/mgr/rook/module.py @@ -1,3 +1,5 @@ +from logging import error +import logging import threading import functools import os @@ -442,6 +444,14 @@ class RookOrchestrator(MgrModule, orchestrator.Orchestrator): else: raise orchestrator.OrchestratorError(f'Service type {service_type} not supported') + def zap_device(self, host: str, path: str) -> OrchResult[str]: + try: + self.rook_cluster.create_zap_job(host, path) + except Exception as e: + logging.error(e) + return OrchResult(None, Exception("Unable to zap device: " + str(e.with_traceback(None)))) + return OrchResult(f'{path} on {host} zapped') + @handle_orch_error def apply_mon(self, spec): # type: (ServiceSpec) -> str diff --git a/src/pybind/mgr/rook/rook_cluster.py b/src/pybind/mgr/rook/rook_cluster.py index 1a28093509386..8bc3561fbe19c 100644 --- a/src/pybind/mgr/rook/rook_cluster.py +++ b/src/pybind/mgr/rook/rook_cluster.py @@ -1127,6 +1127,87 @@ class RookCluster(object): ret.append(spec) return ret + def create_zap_job(self, host: str, path: str) -> None: + body = client.V1Job( + api_version="batch/v1", + metadata=client.V1ObjectMeta( + name="rook-ceph-device-zap", + namespace="rook-ceph" + ), + spec=client.V1JobSpec( + template=client.V1PodTemplateSpec( + spec=client.V1PodSpec( + containers=[ + client.V1Container( + name="device-zap", + image="rook/ceph:master", + command=["bash"], + args=["-c", f"ceph-volume raw list {path} && dd if=/dev/zero of=\"{path}\" bs=1M count=1 oflag=direct,dsync || ceph-volume lvm zap --destroy {path}"], + env=[ + client.V1EnvVar( + name="ROOK_CEPH_USERNAME", + value_from=client.V1EnvVarSource( + secret_key_ref=client.V1SecretKeySelector( + key="ceph-username", + name="rook-ceph-mon" + ) + ) + ), + client.V1EnvVar( + name="ROOK_CEPH_SECRET", + value_from=client.V1EnvVarSource( + secret_key_ref=client.V1SecretKeySelector( + key="ceph-secret", + name="rook-ceph-mon" + ) + ) + ) + ], + security_context=client.V1SecurityContext( + privileged=True + ), + volume_mounts=[ + client.V1VolumeMount( + mount_path="/etc/ceph", + name="ceph-conf-emptydir" + ), + client.V1VolumeMount( + mount_path="/etc/rook", + name="rook-config" + ), + client.V1VolumeMount( + mount_path="/dev", + name="devices" + ) + ] + ) + ], + volumes=[ + client.V1Volume( + name="ceph-conf-emptydir", + empty_dir=client.V1EmptyDirVolumeSource() + ), + client.V1Volume( + name="rook-config", + empty_dir=client.V1EmptyDirVolumeSource() + ), + client.V1Volume( + name="devices", + host_path=client.V1HostPathVolumeSource( + path="/dev" + ) + ), + ], + node_selector={ + "kubernetes.io/hostname": host + }, + restart_policy="Never" + ) + ) + ) + ) + self.batchV1_api.create_namespaced_job('rook-ceph', body) + def _patch(self, crd: Type, crd_name: str, cr_name: str, func: Callable[[CrdClassT, CrdClassT], CrdClassT]) -> str: current_json = self.rook_api_get( "{}/{}".format(crd_name, cr_name) -- 2.39.5