chore: move to vexxhost.ceph
diff --git a/.github/workflows/csi.yml b/.github/workflows/csi.yml
new file mode 100644
index 0000000..a0e43c6
--- /dev/null
+++ b/.github/workflows/csi.yml
@@ -0,0 +1,73 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# 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.
+
+name: csi
+
+on:
+  pull_request:
+    paths:
+      - .github/workflows/csi.yml
+      - molecule/csi/**
+      - playbooks/csi.yml
+      - playbooks/kubernetes.yml
+      - roles/ceph_csi_rbd/**
+      - roles/csi/**
+      - galaxy.yml
+  push:
+    branches:
+      - main
+    paths:
+      - .github/workflows/csi.yml
+      - molecule/csi/**
+      - playbooks/csi.yml
+      - playbooks/kubernetes.yml
+      - roles/ceph_csi_rbd/**
+      - roles/csi/**
+      - galaxy.yml
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        driver:
+          - rbd
+    steps:
+      - name: Checkout project
+        uses: actions/checkout@v3
+
+      - name: Install Poetry
+        run: pipx install poetry
+
+      - name: Setup Python
+        uses: actions/setup-python@v4
+        with:
+          cache: poetry
+
+      - name: Install dependencies
+        run: poetry install --no-interaction --with dev
+
+      # NOTE(mnaser): LVM commands take a long time if there are any existing
+      #               loop devices created by "snapd", so we uninstall it.
+      - name: Uninstall "snapd"
+        run: sudo apt-get purge -y snapd
+
+      - name: Turn off swap
+        run: sudo swapoff -a
+
+      - name: Run Molecule
+        run: poetry run molecule test -s csi
+        env:
+          MOLECULE_CSI_DRIVER: ${{ matrix.driver }}
diff --git a/galaxy.yml b/galaxy.yml
index 618fb6b..62a71eb 100644
--- a/galaxy.yml
+++ b/galaxy.yml
@@ -16,6 +16,7 @@
   kubernetes.core: 2.3.2
   openstack.cloud: 1.7.0
   community.mysql: 3.6.0
+  vexxhost.ceph: 2.0.1
   vexxhost.kubernetes: 1.4.0
 tags:
   - application
diff --git a/roles/ceph_mgr/meta/main.yml b/molecule/csi/cleanup.yml
similarity index 65%
rename from roles/ceph_mgr/meta/main.yml
rename to molecule/csi/cleanup.yml
index cec72d8..45d16dc 100644
--- a/roles/ceph_mgr/meta/main.yml
+++ b/molecule/csi/cleanup.yml
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
+# Copyright (c) 2023 VEXXHOST, Inc.
 #
 # 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
@@ -12,16 +12,4 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-galaxy_info:
-  author: VEXXHOST, Inc.
-  description: Ansible role for Ceph manager
-  license: Apache-2.0
-  min_ansible_version: 5.5.0
-  standalone: false
-  platforms:
-    - name: Ubuntu
-      versions:
-        - focal
-
-dependencies:
-  - role: defaults
+- ansible.builtin.import_playbook: vexxhost.ceph.destroy_fake_devices
diff --git a/roles/ceph_mgr/meta/main.yml b/molecule/csi/converge.yml
similarity index 65%
copy from roles/ceph_mgr/meta/main.yml
copy to molecule/csi/converge.yml
index cec72d8..d97e10c 100644
--- a/roles/ceph_mgr/meta/main.yml
+++ b/molecule/csi/converge.yml
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
+# Copyright (c) 2023 VEXXHOST, Inc.
 #
 # 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
@@ -12,16 +12,6 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-galaxy_info:
-  author: VEXXHOST, Inc.
-  description: Ansible role for Ceph manager
-  license: Apache-2.0
-  min_ansible_version: 5.5.0
-  standalone: false
-  platforms:
-    - name: Ubuntu
-      versions:
-        - focal
-
-dependencies:
-  - role: defaults
+- ansible.builtin.import_playbook: vexxhost.ceph.site
+- ansible.builtin.import_playbook: vexxhost.atmosphere.kubernetes
+- ansible.builtin.import_playbook: vexxhost.atmosphere.csi
diff --git a/molecule/csi/molecule.yml b/molecule/csi/molecule.yml
new file mode 100644
index 0000000..a1cdf53
--- /dev/null
+++ b/molecule/csi/molecule.yml
@@ -0,0 +1,76 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# 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.
+
+dependency:
+  name: galaxy
+driver:
+  name: docker
+platforms:
+  - name: instance
+    image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2004}-ansible:latest
+    command: ${MOLECULE_DOCKER_COMMAND:-""}
+    privileged: true
+    cgroupns_mode: host
+    pre_build_image: true
+    etc_hosts:
+      k8s: 172.17.0.100
+    environment:
+      container: docker
+    security_opts:
+      - apparmor=unconfined
+    volumes:
+      - /dev:/dev
+      - /lib/modules:/lib/modules:ro
+      - /sys/fs/cgroup:/sys/fs/cgroup:rw
+      - /usr/src:/usr/src:ro
+    groups:
+      - controllers
+      - cephs
+provisioner:
+  name: ansible
+  config_options:
+    connection:
+      pipelining: true
+    tags:
+      skip: sysctl,ethtool
+  inventory:
+    group_vars:
+      all:
+        ceph_fsid: ${MOLECULE_CEPH_FSID:-"1dff0e0f-3c44-48da-81cd-4f3c6e8722b2"}
+        ceph_conf_overrides:
+          - section: global
+            option: osd crush chooseleaf type
+            value: 0
+          - section: mon
+            option: auth allow insecure global id reclaim
+            value: false
+        cilium_helm_values:
+          operator:
+            replicas: 1
+        csi_driver: ${MOLECULE_CSI_DRIVER:-"rbd"}
+        ceph_csi_rbd_helm_values:
+          provisioner:
+            replicaCount: 1
+      controllers:
+        kubernetes_keepalived_interface: "{{ ansible_default_ipv4.interface }}"
+        kubernetes_keepalived_vip: 172.17.0.100
+        kubernetes_keepalived_vrid: 42
+        kubernetes_hostname: k8s
+      cephs:
+        ceph_osd_devices:
+          - "/dev/ceph-{{ inventory_hostname_short }}-osd0/data"
+          - "/dev/ceph-{{ inventory_hostname_short }}-osd1/data"
+          - "/dev/ceph-{{ inventory_hostname_short }}-osd2/data"
+verifier:
+  name: ansible
diff --git a/molecule/csi/prepare.yml b/molecule/csi/prepare.yml
new file mode 100644
index 0000000..dac0bc4
--- /dev/null
+++ b/molecule/csi/prepare.yml
@@ -0,0 +1,47 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# 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.
+
+- name: Prepare
+  hosts: all
+  become: true
+  pre_tasks:
+    - name: Wait for systemd to complete initialization
+      ansible.builtin.command: systemctl is-system-running
+      register: systemctl_status
+      until: >
+        'running' in systemctl_status.stdout or
+        'degraded' in systemctl_status.stdout
+      retries: 30
+      delay: 5
+      changed_when: false
+      failed_when: systemctl_status.rc > 1
+  tasks:
+    - name: Refresh cache
+      ansible.builtin.package:
+        update_cache: true
+
+    # NOTE(mnaser): The base image installs Ansible using `pip` which breaks
+    #               the system Python, we uninstall all Python packages.
+    - name: Fix Python installation
+      block:
+        - name: Get all Python packages
+          ansible.builtin.command: pip freeze
+          register: pip_freeze
+
+        - name: Uninstall all Python packages
+          ansible.builtin.pip:
+            name: "{{ pip_freeze.stdout_lines }}"
+            state: absent
+
+- ansible.builtin.import_playbook: vexxhost.ceph.create_fake_devices
diff --git a/molecule/csi/verify.yml b/molecule/csi/verify.yml
new file mode 100644
index 0000000..0add366
--- /dev/null
+++ b/molecule/csi/verify.yml
@@ -0,0 +1,84 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# 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.
+
+- name: Verify
+  hosts: controllers
+  become: true
+  tasks:
+    - name: Create a persistent volume
+      kubernetes.core.k8s:
+        state: present
+        definition:
+          apiVersion: v1
+          kind: PersistentVolumeClaim
+          metadata:
+            name: test-pvc
+            namespace: default
+          spec:
+            accessModes:
+              - ReadWriteOnce
+            resources:
+              requests:
+                storage: 5Gi
+            storageClassName: general
+
+    - name: Create a pod
+      kubernetes.core.k8s:
+        state: present
+        definition:
+          apiVersion: v1
+          kind: Pod
+          metadata:
+            name: test-pvc-pod
+            namespace: default
+          spec:
+            volumes:
+              - name: test-pvc
+                persistentVolumeClaim:
+                  claimName: test-pvc
+            containers:
+              - name: test-pvc-pod-container
+                image: nginx
+                volumeMounts:
+                  - name: test-pvc
+                    mountPath: /usr/share/nginx/html
+        wait: true
+        wait_timeout: 120
+        wait_condition:
+          type: Ready
+          status: "True"
+
+    - name: Delete the pod
+      kubernetes.core.k8s:
+        state: absent
+        definition:
+          apiVersion: v1
+          kind: Pod
+          metadata:
+            name: test-pvc-pod
+            namespace: default
+
+    - name: Delete the persistent volume
+      kubernetes.core.k8s:
+        state: absent
+        definition:
+          apiVersion: v1
+          kind: PersistentVolume
+          metadata:
+            name: test-pv
+        wait: true
+        wait_timeout: 120
+        wait_condition:
+          type: Available
+          status: "True"
diff --git a/playbooks/ceph.yml b/playbooks/ceph.yml
deleted file mode 100644
index 6fb2c9c..0000000
--- a/playbooks/ceph.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-- name: Setup Ceph repository
-  hosts: controllers:cephs
-  become: true
-  roles:
-    - role: ceph_repository
-      when: atmosphere_ceph_enabled | default(true)
-
-- name: Deploy Ceph monitors & managers
-  hosts: controllers
-  become: true
-  roles:
-    - role: ceph_mon
-      when: atmosphere_ceph_enabled | default(true)
-    - role: ceph_mgr
-      when: atmosphere_ceph_enabled | default(true)
-
-- name: Deploy Ceph OSDs
-  hosts: cephs
-  become: true
-  roles:
-    - role: ceph_osd
-      when: atmosphere_ceph_enabled | default(true)
diff --git a/playbooks/kubernetes.yml b/playbooks/kubernetes.yml
index 056dd2e..47f9a7f 100644
--- a/playbooks/kubernetes.yml
+++ b/playbooks/kubernetes.yml
@@ -17,6 +17,8 @@
   roles:
     - role: defaults
     - role: sysctl
+      tags:
+        - sysctl
     - role: ethtool
       tags:
         - ethtool
diff --git a/playbooks/site.yml b/playbooks/site.yml
index c8fca05..8b7255b 100644
--- a/playbooks/site.yml
+++ b/playbooks/site.yml
@@ -12,7 +12,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-- import_playbook: vexxhost.atmosphere.ceph
+- import_playbook: vexxhost.ceph.site
 - import_playbook: vexxhost.atmosphere.kubernetes
 - import_playbook: vexxhost.atmosphere.csi
 - import_playbook: vexxhost.atmosphere.openstack
diff --git a/plugins/module_utils/ca_common.py b/plugins/module_utils/ca_common.py
deleted file mode 100644
index 5336582..0000000
--- a/plugins/module_utils/ca_common.py
+++ /dev/null
@@ -1,126 +0,0 @@
-import datetime
-import os
-
-
-def generate_ceph_cmd(
-    sub_cmd,
-    args,
-    user_key=None,
-    cluster="ceph",
-    user="client.admin",
-    container_image=None,
-    interactive=False,
-):
-    """
-    Generate 'ceph' command line to execute
-    """
-
-    if not user_key:
-        user_key = "/etc/ceph/{}.{}.keyring".format(cluster, user)
-
-    cmd = pre_generate_ceph_cmd(
-        container_image=container_image, interactive=interactive
-    )
-
-    base_cmd = ["-n", user, "-k", user_key, "--cluster", cluster]
-    base_cmd.extend(sub_cmd)
-    cmd.extend(base_cmd + args)
-
-    return cmd
-
-
-def container_exec(binary, container_image, interactive=False):
-    """
-    Build the docker CLI to run a command inside a container
-    """
-
-    container_binary = os.getenv("CEPH_CONTAINER_BINARY")
-    command_exec = [container_binary, "run"]
-
-    if interactive:
-        command_exec.extend(["--interactive"])
-
-    command_exec.extend(
-        [
-            "--rm",
-            "--net=host",
-            "-v",
-            "/etc/ceph:/etc/ceph:z",
-            "-v",
-            "/var/lib/ceph/:/var/lib/ceph/:z",
-            "-v",
-            "/var/log/ceph/:/var/log/ceph/:z",
-            "--entrypoint=" + binary,
-            container_image,
-        ]
-    )
-    return command_exec
-
-
-def is_containerized():
-    """
-    Check if we are running on a containerized cluster
-    """
-
-    if "CEPH_CONTAINER_IMAGE" in os.environ:
-        container_image = os.getenv("CEPH_CONTAINER_IMAGE")
-    else:
-        container_image = None
-
-    return container_image
-
-
-def pre_generate_ceph_cmd(container_image=None, interactive=False):
-    """
-    Generate ceph prefix comaand
-    """
-    if container_image:
-        cmd = container_exec("ceph", container_image, interactive=interactive)
-    else:
-        cmd = ["ceph"]
-
-    return cmd
-
-
-def exec_command(module, cmd, stdin=None):
-    """
-    Execute command(s)
-    """
-
-    binary_data = False
-    if stdin:
-        binary_data = True
-    rc, out, err = module.run_command(cmd, data=stdin, binary_data=binary_data)
-
-    return rc, cmd, out, err
-
-
-def exit_module(
-    module, out, rc, cmd, err, startd, changed=False, diff=dict(before="", after="")
-):
-    endd = datetime.datetime.now()
-    delta = endd - startd
-
-    result = dict(
-        cmd=cmd,
-        start=str(startd),
-        end=str(endd),
-        delta=str(delta),
-        rc=rc,
-        stdout=out.rstrip("\r\n"),
-        stderr=err.rstrip("\r\n"),
-        changed=changed,
-        diff=diff,
-    )
-    module.exit_json(**result)
-
-
-def fatal(message, module):
-    """
-    Report a fatal error and exit
-    """
-
-    if module:
-        module.fail_json(msg=message, rc=1)
-    else:
-        raise (Exception(message))
diff --git a/plugins/modules/ceph_config.py b/plugins/modules/ceph_config.py
deleted file mode 100644
index 968ba8e..0000000
--- a/plugins/modules/ceph_config.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/python3
-
-from ansible.module_utils.basic import AnsibleModule
-
-
-def run_module():
-    module_args = dict(
-        who=dict(type="str", required=True),
-        name=dict(type="str", required=True),
-        value=dict(type="str", required=True),
-    )
-
-    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
-
-    who = module.params["who"]
-    name = module.params["name"]
-    value = module.params["value"]
-
-    changed = False
-
-    _, out, _ = module.run_command(["ceph", "config", "get", who, name], check_rc=True)
-
-    if out.strip() != value:
-        changed = True
-
-    if not module.check_mode:
-        _, _, _ = module.run_command(
-            ["ceph", "config", "set", who, name, value], check_rc=True
-        )
-
-    module.exit_json(changed=changed)
-
-
-def main():
-    run_module()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/plugins/modules/ceph_key.py b/plugins/modules/ceph_key.py
deleted file mode 100644
index 33cb13f..0000000
--- a/plugins/modules/ceph_key.py
+++ /dev/null
@@ -1,816 +0,0 @@
-#!/usr/bin/python3
-
-# Copyright 2018, Red Hat, Inc.
-#
-# 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.
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-import base64
-import datetime
-import json
-import os
-import socket
-import struct
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.vexxhost.atmosphere.plugins.module_utils.ca_common import (
-    container_exec,
-    fatal,
-    generate_ceph_cmd,
-    is_containerized,
-)
-
-ANSIBLE_METADATA = {
-    "metadata_version": "1.1",
-    "status": ["preview"],
-    "supported_by": "community",
-}
-
-DOCUMENTATION = """
----
-module: ceph_key
-
-author: Sebastien Han <seb@redhat.com>
-
-short_description: Manage Cephx key(s)
-
-version_added: "2.6"
-
-description:
-    - Manage CephX creation, deletion and updates.
-    It can also list and get information about keyring(s).
-options:
-    cluster:
-        description:
-            - The ceph cluster name.
-        required: false
-        default: ceph
-    name:
-        description:
-            - name of the CephX key
-        required: true
-    user:
-        description:
-            - entity used to perform operation.
-            It corresponds to the -n option (--name)
-        required: false
-    user_key:
-        description:
-            - the path to the keyring corresponding to the
-            user being used.
-            It corresponds to the -k option (--keyring)
-    state:
-        description:
-            - If 'present' is used, the module creates a keyring
-            with the associated capabilities.
-            If 'present' is used and a secret is provided the module
-            will always add the key. Which means it will update
-            the keyring if the secret changes, the same goes for
-            the capabilities.
-            If 'absent' is used, the module will simply delete the keyring.
-            If 'list' is used, the module will list all the keys and will
-            return a json output.
-            If 'info' is used, the module will return in a json format the
-            description of a given keyring.
-            If 'generate_secret' is used, the module will simply output a cephx keyring.
-        required: false
-        choices: ['present', 'update', 'absent', 'list', 'info', 'fetch_initial_keys', 'generate_secret']
-        default: present
-    caps:
-        description:
-            - CephX key capabilities
-        default: None
-        required: false
-    secret:
-        description:
-            - keyring's secret value
-        required: false
-        default: None
-    import_key:
-        description:
-            - Wether or not to import the created keyring into Ceph.
-            This can be useful for someone that only wants to generate keyrings
-            but not add them into Ceph.
-        required: false
-        default: True
-    dest:
-        description:
-            - Destination to write the keyring, can a file or a directory
-        required: false
-        default: /etc/ceph/
-    fetch_initial_keys:
-        description:
-            - Fetch client.admin and bootstrap key.
-            This is only needed for Nautilus and above.
-            Writes down to the filesystem the initial keys generated by the monitor.  # noqa: E501
-            This command can ONLY run from a monitor node.
-        required: false
-        default: false
-    output_format:
-        description:
-            - The key output format when retrieving the information of an
-            entity.
-        required: false
-        default: json
-"""
-
-EXAMPLES = """
-
-keys_to_create:
-  - { name: client.key, key: "AQAin8tUUK84ExAA/QgBtI7gEMWdmnvKBzlXdQ==", caps: { mon: "allow rwx", mds: "allow *" } , mode: "0600" }  # noqa: E501
-  - { name: client.cle, caps: { mon: "allow r", osd: "allow *" } , mode: "0600" }  # noqa: E501
-
-caps:
-  mon: "allow rwx"
-  mds: "allow *"
-
-- name: create ceph admin key
-  ceph_key:
-    name: client.admin
-    state: present
-    secret: AQAin8tU2DsKFBAAFIAzVTzkL3+gtAjjpQiomw==
-    caps:
-      mon: allow *
-      osd: allow *
-      mgr: allow *
-      mds: allow
-    mode: 0400
-    import_key: False
-
-- name: create monitor initial keyring
-  ceph_key:
-    name: mon.
-    state: present
-    secret: AQAin8tUMICVFBAALRHNrV0Z4MXupRw4v9JQ6Q==
-    caps:
-      mon: allow *
-    dest: "/var/lib/ceph/tmp/"
-    import_key: False
-
-- name: create cephx key
-  ceph_key:
-    name: "{{ keys_to_create }}"
-    user: client.bootstrap-rgw
-    user_key: /var/lib/ceph/bootstrap-rgw/ceph.keyring
-    state: present
-    caps: "{{ caps }}"
-
-- name: create cephx key but don't import it in Ceph
-  ceph_key:
-    name: "{{ keys_to_create }}"
-    state: present
-    caps: "{{ caps }}"
-    import_key: False
-
-- name: delete cephx key
-  ceph_key:
-    name: "my_key"
-    state: absent
-
-- name: info cephx key
-  ceph_key:
-    name: "my_key""
-    state: info
-
-- name: info cephx admin key (plain)
-  ceph_key:
-    name: client.admin
-    output_format: plain
-    state: info
-  register: client_admin_key
-
-- name: list cephx keys
-  ceph_key:
-    state: list
-
-- name: fetch cephx keys
-  ceph_key:
-    state: fetch_initial_keys
-"""
-
-RETURN = """#  """
-
-
-CEPH_INITIAL_KEYS = [
-    "client.admin",
-    "client.bootstrap-mds",
-    "client.bootstrap-mgr",  # noqa: E501
-    "client.bootstrap-osd",
-    "client.bootstrap-rbd",
-    "client.bootstrap-rbd-mirror",
-    "client.bootstrap-rgw",
-]  # noqa: E501
-
-
-def str_to_bool(val):
-    try:
-        val = val.lower()
-    except AttributeError:
-        val = str(val).lower()
-    if val == "true":
-        return True
-    elif val == "false":
-        return False
-    else:
-        raise ValueError("Invalid input value: %s" % val)
-
-
-def generate_secret():
-    """
-    Generate a CephX secret
-    """
-
-    key = os.urandom(16)
-    header = struct.pack("<hiih", 1, int(time.time()), 0, len(key))
-    secret = base64.b64encode(header + key)
-
-    return secret
-
-
-def generate_caps(_type, caps):
-    """
-    Generate CephX capabilities list
-    """
-
-    caps_cli = []
-
-    for k, v in caps.items():
-        # makes sure someone didn't pass an empty var,
-        # we don't want to add an empty cap
-        if len(k) == 0:
-            continue
-        if _type == "ceph-authtool":
-            caps_cli.extend(["--cap"])
-        caps_cli.extend([k, v])
-
-    return caps_cli
-
-
-def generate_ceph_authtool_cmd(
-    cluster, name, secret, caps, dest, container_image=None
-):  # noqa: E501
-    """
-    Generate 'ceph-authtool' command line to execute
-    """
-
-    if container_image:
-        binary = "ceph-authtool"
-        cmd = container_exec(binary, container_image)
-    else:
-        binary = ["ceph-authtool"]
-        cmd = binary
-
-    base_cmd = [
-        "--create-keyring",
-        dest,
-        "--name",
-        name,
-        "--add-key",
-        secret,
-    ]
-
-    cmd.extend(base_cmd)
-    cmd.extend(generate_caps("ceph-authtool", caps))
-
-    return cmd
-
-
-def create_key(
-    module,
-    result,
-    cluster,
-    user,
-    user_key,
-    name,
-    secret,
-    caps,
-    import_key,
-    dest,
-    container_image=None,
-):  # noqa: E501
-    """
-    Create a CephX key
-    """
-
-    cmd_list = []
-    if not secret:
-        secret = generate_secret()
-
-    if user == "client.admin":
-        args = ["import", "-i", dest]
-    else:
-        args = ["get-or-create", name]
-        args.extend(generate_caps(None, caps))
-        args.extend(["-o", dest])
-
-    cmd_list.append(
-        generate_ceph_authtool_cmd(cluster, name, secret, caps, dest, container_image)
-    )
-
-    if import_key or user != "client.admin":
-        cmd_list.append(
-            generate_ceph_cmd(
-                sub_cmd=["auth"],
-                args=args,
-                cluster=cluster,
-                user=user,
-                user_key=user_key,
-                container_image=container_image,
-            )
-        )
-
-    return cmd_list
-
-
-def delete_key(cluster, user, user_key, name, container_image=None):
-    """
-    Delete a CephX key
-    """
-
-    cmd_list = []
-
-    args = [
-        "del",
-        name,
-    ]
-
-    cmd_list.append(
-        generate_ceph_cmd(
-            sub_cmd=["auth"],
-            args=args,
-            cluster=cluster,
-            user=user,
-            user_key=user_key,
-            container_image=container_image,
-        )
-    )
-
-    return cmd_list
-
-
-def get_key(cluster, user, user_key, name, dest, container_image=None):
-    """
-    Get a CephX key (write on the filesystem)
-    """
-
-    cmd_list = []
-
-    args = [
-        "get",
-        name,
-        "-o",
-        dest,
-    ]
-
-    cmd_list.append(
-        generate_ceph_cmd(
-            sub_cmd=["auth"],
-            args=args,
-            cluster=cluster,
-            user=user,
-            user_key=user_key,
-            container_image=container_image,
-        )
-    )
-
-    return cmd_list
-
-
-def info_key(
-    cluster, name, user, user_key, output_format, container_image=None
-):  # noqa: E501
-    """
-    Get information about a CephX key
-    """
-
-    cmd_list = []
-
-    args = [
-        "get",
-        name,
-        "-f",
-        output_format,
-    ]
-
-    cmd_list.append(
-        generate_ceph_cmd(
-            sub_cmd=["auth"],
-            args=args,
-            cluster=cluster,
-            user=user,
-            user_key=user_key,
-            container_image=container_image,
-        )
-    )
-
-    return cmd_list
-
-
-def list_keys(cluster, user, user_key, container_image=None):
-    """
-    List all CephX keys
-    """
-
-    cmd_list = []
-
-    args = [
-        "ls",
-        "-f",
-        "json",
-    ]
-
-    cmd_list.append(
-        generate_ceph_cmd(
-            sub_cmd=["auth"],
-            args=args,
-            cluster=cluster,
-            user=user,
-            user_key=user_key,
-            container_image=container_image,
-        )
-    )
-
-    return cmd_list
-
-
-def exec_commands(module, cmd_list):
-    """
-    Execute command(s)
-    """
-
-    for cmd in cmd_list:
-        rc, out, err = module.run_command(cmd)
-        if rc != 0:
-            return rc, cmd, out, err
-
-    return rc, cmd, out, err
-
-
-def lookup_ceph_initial_entities(module, out):
-    """
-    Lookup Ceph initial keys entries in the auth map
-    """
-
-    # convert out to json, ansible returns a string...
-    try:
-        out_dict = json.loads(out)
-    except ValueError as e:
-        fatal(
-            "Could not decode 'ceph auth list' json output: {}".format(e), module
-        )  # noqa: E501
-
-    entities = []
-    if "auth_dump" in out_dict:
-        for key in out_dict["auth_dump"]:
-            for k, v in key.items():
-                if k == "entity":
-                    if v in CEPH_INITIAL_KEYS:
-                        entities.append(v)
-    else:
-        fatal("'auth_dump' key not present in json output:", module)  # noqa: E501
-
-    if len(entities) != len(CEPH_INITIAL_KEYS) and not str_to_bool(
-        os.environ.get("CEPH_ROLLING_UPDATE", False)
-    ):  # noqa: E501
-        # must be missing in auth_dump, as if it were in CEPH_INITIAL_KEYS
-        # it'd be in entities from the above test. Report what's missing.
-        missing = []
-        for e in CEPH_INITIAL_KEYS:
-            if e not in entities:
-                missing.append(e)
-        fatal(
-            "initial keyring does not contain keys: " + " ".join(missing), module
-        )  # noqa: E501
-    return entities
-
-
-def build_key_path(cluster, entity):
-    """
-    Build key path depending on the key type
-    """
-
-    if "admin" in entity:
-        path = "/etc/ceph"
-        keyring_filename = cluster + "." + entity + ".keyring"
-        key_path = os.path.join(path, keyring_filename)
-    elif "bootstrap" in entity:
-        path = "/var/lib/ceph"
-        # bootstrap keys show up as 'client.boostrap-osd'
-        # however the directory is called '/var/lib/ceph/bootstrap-osd'
-        # so we need to substring 'client.'
-        entity_split = entity.split(".")[1]
-        keyring_filename = cluster + ".keyring"
-        key_path = os.path.join(path, entity_split, keyring_filename)
-    else:
-        return None
-
-    return key_path
-
-
-def run_module():
-    module_args = dict(
-        cluster=dict(type="str", required=False, default="ceph"),
-        name=dict(type="str", required=False),
-        state=dict(
-            type="str",
-            required=False,
-            default="present",
-            choices=[
-                "present",
-                "update",
-                "absent",  # noqa: E501
-                "list",
-                "info",
-                "fetch_initial_keys",
-                "generate_secret",
-            ],
-        ),  # noqa: E501
-        caps=dict(type="dict", required=False, default=None),
-        secret=dict(type="str", required=False, default=None, no_log=True),
-        import_key=dict(type="bool", required=False, default=True),
-        dest=dict(type="str", required=False, default="/etc/ceph/"),
-        user=dict(type="str", required=False, default="client.admin"),
-        user_key=dict(type="str", required=False, default=None),
-        output_format=dict(
-            type="str",
-            required=False,
-            default="json",
-            choices=["json", "plain", "xml", "yaml"],
-        ),  # noqa: E501
-    )
-
-    module = AnsibleModule(
-        argument_spec=module_args,
-        supports_check_mode=True,
-        add_file_common_args=True,
-    )
-
-    file_args = module.load_file_common_arguments(module.params)
-
-    # Gather module parameters in variables
-    state = module.params["state"]
-    name = module.params.get("name")
-    cluster = module.params.get("cluster")
-    caps = module.params.get("caps")
-    secret = module.params.get("secret")
-    import_key = module.params.get("import_key")
-    dest = module.params.get("dest")
-    user = module.params.get("user")
-    user_key = module.params.get("user_key")
-    output_format = module.params.get("output_format")
-
-    changed = False
-
-    result = dict(
-        changed=changed,
-        stdout="",
-        stderr="",
-        rc=0,
-        start="",
-        end="",
-        delta="",
-    )
-
-    if module.check_mode and state != "info":
-        module.exit_json(**result)
-
-    startd = datetime.datetime.now()
-
-    # will return either the image name or None
-    container_image = is_containerized()
-
-    # Test if the key exists, if it does we skip its creation
-    # We only want to run this check when a key needs to be added
-    # There is no guarantee that any cluster is running and we don't need one
-    _secret = secret
-    _caps = caps
-    key_exist = 1
-
-    if not user_key:
-        user_key_filename = "{}.{}.keyring".format(cluster, user)
-        user_key_dir = "/etc/ceph"
-        user_key_path = os.path.join(user_key_dir, user_key_filename)
-    else:
-        user_key_path = user_key
-
-    if state in ["present", "update"]:
-        # if dest is not a directory, the user wants to change the file's name
-        # (e,g: /etc/ceph/ceph.mgr.ceph-mon2.keyring)
-        if not os.path.isdir(dest):
-            file_path = dest
-        else:
-            if "bootstrap" in dest:
-                # Build a different path for bootstrap keys as there are stored
-                # as /var/lib/ceph/bootstrap-rbd/ceph.keyring
-                keyring_filename = cluster + ".keyring"
-            else:
-                keyring_filename = cluster + "." + name + ".keyring"
-            file_path = os.path.join(dest, keyring_filename)
-
-        file_args["path"] = file_path
-
-        if import_key:
-            _info_key = []
-            rc, cmd, out, err = exec_commands(
-                module,
-                info_key(
-                    cluster, name, user, user_key_path, output_format, container_image
-                ),
-            )  # noqa: E501
-            key_exist = rc
-            if not caps and key_exist != 0:
-                fatal(
-                    "Capabilities must be provided when state is 'present'", module
-                )  # noqa: E501
-            if key_exist != 0 and secret is None and caps is None:
-                fatal(
-                    "Keyring doesn't exist, you must provide 'secret' and 'caps'",
-                    module,
-                )  # noqa: E501
-            if key_exist == 0:
-                _info_key = json.loads(out)
-                if not secret:
-                    secret = _info_key[0]["key"]
-                _secret = _info_key[0]["key"]
-                if not caps:
-                    caps = _info_key[0]["caps"]
-                _caps = _info_key[0]["caps"]
-                if secret == _secret and caps == _caps:
-                    if not os.path.isfile(file_path):
-                        rc, cmd, out, err = exec_commands(
-                            module,
-                            get_key(
-                                cluster,
-                                user,
-                                user_key_path,
-                                name,
-                                file_path,
-                                container_image,
-                            ),
-                        )  # noqa: E501
-                        result["rc"] = rc
-                        if rc != 0:
-                            result[
-                                "stdout"
-                            ] = "Couldn't fetch the key {0} at {1}.".format(
-                                name, file_path
-                            )  # noqa: E501
-                            module.exit_json(**result)
-                        result["stdout"] = "fetched the key {0} at {1}.".format(
-                            name, file_path
-                        )  # noqa: E501
-
-                    result[
-                        "stdout"
-                    ] = "{0} already exists and doesn't need to be updated.".format(
-                        name
-                    )  # noqa: E501
-                    result["rc"] = 0
-                    module.set_fs_attributes_if_different(file_args, False)
-                    module.exit_json(**result)
-        else:
-            if os.path.isfile(file_path) and not secret or not caps:
-                result[
-                    "stdout"
-                ] = "{0} already exists in {1} you must provide secret *and* caps when import_key is {2}".format(
-                    name, dest, import_key
-                )  # noqa: E501
-                result["rc"] = 0
-                module.exit_json(**result)
-        if (
-            key_exist == 0 and (secret != _secret or caps != _caps)
-        ) or key_exist != 0:  # noqa: E501
-            rc, cmd, out, err = exec_commands(
-                module,
-                create_key(
-                    module,
-                    result,
-                    cluster,
-                    user,
-                    user_key_path,
-                    name,
-                    secret,
-                    caps,
-                    import_key,
-                    file_path,
-                    container_image,
-                ),
-            )  # noqa: E501
-            if rc != 0:
-                result["stdout"] = "Couldn't create or update {0}".format(name)
-                result["stderr"] = err
-                module.exit_json(**result)
-            module.set_fs_attributes_if_different(file_args, False)
-            changed = True
-
-    elif state == "absent":
-        if key_exist == 0:
-            rc, cmd, out, err = exec_commands(
-                module, delete_key(cluster, user, user_key_path, name, container_image)
-            )  # noqa: E501
-            if rc == 0:
-                changed = True
-        else:
-            rc = 0
-
-    elif state == "info":
-        rc, cmd, out, err = exec_commands(
-            module,
-            info_key(
-                cluster, name, user, user_key_path, output_format, container_image
-            ),
-        )  # noqa: E501
-
-    elif state == "list":
-        rc, cmd, out, err = exec_commands(
-            module, list_keys(cluster, user, user_key_path, container_image)
-        )
-
-    elif state == "fetch_initial_keys":
-        hostname = socket.gethostname().split(".", 1)[0]
-        user = "mon."
-        keyring_filename = cluster + "-" + hostname + "/keyring"
-        user_key_path = os.path.join("/var/lib/ceph/mon/", keyring_filename)
-        rc, cmd, out, err = exec_commands(
-            module, list_keys(cluster, user, user_key_path, container_image)
-        )
-        if rc != 0:
-            result["stdout"] = "failed to retrieve ceph keys"
-            result["sdterr"] = err
-            result["rc"] = 0
-            module.exit_json(**result)
-
-        entities = lookup_ceph_initial_entities(module, out)
-
-        output_format = "plain"
-        for entity in entities:
-            key_path = build_key_path(cluster, entity)
-            if key_path is None:
-                fatal("Failed to build key path, no entity yet?", module)
-            elif os.path.isfile(key_path):
-                # if the key is already on the filesystem
-                # there is no need to fetch it again
-                continue
-
-            extra_args = [
-                "-o",
-                key_path,
-            ]
-
-            info_cmd = info_key(
-                cluster, entity, user, user_key_path, output_format, container_image
-            )
-            # we use info_cmd[0] because info_cmd is an array made of an array
-            info_cmd[0].extend(extra_args)
-            rc, cmd, out, err = exec_commands(module, info_cmd)  # noqa: E501
-
-            file_args = module.load_file_common_arguments(module.params)
-            file_args["path"] = key_path
-            module.set_fs_attributes_if_different(file_args, False)
-    elif state == "generate_secret":
-        out = generate_secret().decode()
-        cmd = ""
-        rc = 0
-        err = ""
-        changed = True
-
-    endd = datetime.datetime.now()
-    delta = endd - startd
-
-    result = dict(
-        cmd=cmd,
-        start=str(startd),
-        end=str(endd),
-        delta=str(delta),
-        rc=rc,
-        stdout=out.rstrip("\r\n"),
-        stderr=err.rstrip("\r\n"),
-        changed=changed,
-    )
-
-    if rc != 0:
-        module.fail_json(msg="non-zero return code", **result)
-
-    module.exit_json(**result)
-
-
-def main():
-    run_module()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/plugins/modules/ceph_pool.py b/plugins/modules/ceph_pool.py
deleted file mode 100644
index e749725..0000000
--- a/plugins/modules/ceph_pool.py
+++ /dev/null
@@ -1,751 +0,0 @@
-#!/usr/bin/python3
-
-# Copyright 2020, Red Hat, Inc.
-#
-# 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.
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-import datetime
-import json
-import os
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.vexxhost.atmosphere.plugins.module_utils.ca_common import (
-    exec_command,
-    exit_module,
-    generate_ceph_cmd,
-    is_containerized,
-    pre_generate_ceph_cmd,
-)
-
-ANSIBLE_METADATA = {
-    "metadata_version": "1.1",
-    "status": ["preview"],
-    "supported_by": "community",
-}
-
-DOCUMENTATION = """
----
-module: ceph_pool
-
-author: Guillaume Abrioux <gabrioux@redhat.com>
-
-short_description: Manage Ceph Pools
-
-version_added: "2.8"
-
-description:
-    - Manage Ceph pool(s) creation, deletion and updates.
-options:
-    cluster:
-        description:
-            - The ceph cluster name.
-        required: false
-        default: ceph
-    name:
-        description:
-            - name of the Ceph pool
-        required: true
-    state:
-        description:
-            If 'present' is used, the module creates a pool if it doesn't exist
-            or update it if it already exists.
-            If 'absent' is used, the module will simply delete the pool.
-            If 'list' is used, the module will return all details about the
-            existing pools. (json formatted).
-        required: false
-        choices: ['present', 'absent', 'list']
-        default: present
-    size:
-        description:
-            - set the replica size of the pool.
-        required: false
-        default: 3
-    min_size:
-        description:
-            - set the min_size parameter of the pool.
-        required: false
-        default: default to `osd_pool_default_min_size` (ceph)
-    pg_num:
-        description:
-            - set the pg_num of the pool.
-        required: false
-        default: default to `osd_pool_default_pg_num` (ceph)
-    pgp_num:
-        description:
-            - set the pgp_num of the pool.
-        required: false
-        default: default to `osd_pool_default_pgp_num` (ceph)
-    pg_autoscale_mode:
-        description:
-            - set the pg autoscaler on the pool.
-        required: false
-        default: 'on'
-    target_size_ratio:
-        description:
-            - set the target_size_ratio on the pool
-        required: false
-        default: None
-    pool_type:
-        description:
-            - set the pool type, either 'replicated' or 'erasure'
-        required: false
-        default: 'replicated'
-    erasure_profile:
-        description:
-            - When pool_type = 'erasure', set the erasure profile of the pool
-        required: false
-        default: 'default'
-    rule_name:
-        description:
-            - Set the crush rule name assigned to the pool
-        required: false
-        default: 'replicated_rule' when pool_type is 'erasure' else None
-    expected_num_objects:
-        description:
-            -   Set the expected_num_objects parameter of the pool.
-        required: false
-        default: '0'
-    application:
-        description:
-            - Set the pool application on the pool.
-        required: false
-        default: None
-"""
-
-EXAMPLES = """
-
-pools:
-  - { name: foo, size: 3, application: rbd, pool_type: 'replicated',
-      pg_autoscale_mode: 'on' }
-
-- hosts: all
-  become: true
-  tasks:
-    - name: create a pool
-      ceph_pool:
-        name: "{{ item.name }}"
-        state: present
-        size: "{{ item.size }}"
-        application: "{{ item.application }}"
-        pool_type: "{{ item.pool_type }}"
-        pg_autoscale_mode: "{{ item.pg_autoscale_mode }}"
-      with_items: "{{ pools }}"
-"""
-
-RETURN = """#  """
-
-
-def check_pool_exist(
-    cluster, name, user, user_key, output_format="json", container_image=None
-):
-    """
-    Check if a given pool exists
-    """
-
-    args = ["stats", name, "-f", output_format]
-
-    cmd = generate_ceph_cmd(
-        sub_cmd=["osd", "pool"],
-        args=args,
-        cluster=cluster,
-        user=user,
-        user_key=user_key,
-        container_image=container_image,
-    )
-
-    return cmd
-
-
-def generate_get_config_cmd(param, cluster, user, user_key, container_image=None):
-    _cmd = pre_generate_ceph_cmd(container_image=container_image)
-    args = [
-        "-n",
-        user,
-        "-k",
-        user_key,
-        "--cluster",
-        cluster,
-        "config",
-        "get",
-        "mon.*",
-        param,
-    ]
-    cmd = _cmd + args
-    return cmd
-
-
-def get_application_pool(
-    cluster, name, user, user_key, output_format="json", container_image=None
-):
-    """
-    Get application type enabled on a given pool
-    """
-
-    args = ["application", "get", name, "-f", output_format]
-
-    cmd = generate_ceph_cmd(
-        sub_cmd=["osd", "pool"],
-        args=args,
-        cluster=cluster,
-        user=user,
-        user_key=user_key,
-        container_image=container_image,
-    )
-
-    return cmd
-
-
-def enable_application_pool(
-    cluster, name, application, user, user_key, container_image=None
-):
-    """
-    Enable application on a given pool
-    """
-
-    args = ["application", "enable", name, application]
-
-    cmd = generate_ceph_cmd(
-        sub_cmd=["osd", "pool"],
-        args=args,
-        cluster=cluster,
-        user=user,
-        user_key=user_key,
-        container_image=container_image,
-    )
-
-    return cmd
-
-
-def disable_application_pool(
-    cluster, name, application, user, user_key, container_image=None
-):
-    """
-    Disable application on a given pool
-    """
-
-    args = ["application", "disable", name, application, "--yes-i-really-mean-it"]
-
-    cmd = generate_ceph_cmd(
-        sub_cmd=["osd", "pool"],
-        args=args,
-        cluster=cluster,
-        user=user,
-        user_key=user_key,
-        container_image=container_image,
-    )
-
-    return cmd
-
-
-def get_pool_details(
-    module, cluster, name, user, user_key, output_format="json", container_image=None
-):
-    """
-    Get details about a given pool
-    """
-
-    args = ["ls", "detail", "-f", output_format]
-
-    cmd = generate_ceph_cmd(
-        sub_cmd=["osd", "pool"],
-        args=args,
-        cluster=cluster,
-        user=user,
-        user_key=user_key,
-        container_image=container_image,
-    )
-
-    rc, cmd, out, err = exec_command(module, cmd)
-
-    if rc == 0:
-        out = [p for p in json.loads(out.strip()) if p["pool_name"] == name][0]
-
-    _rc, _cmd, application_pool, _err = exec_command(
-        module,
-        get_application_pool(
-            cluster,  # noqa: E501
-            name,  # noqa: E501
-            user,  # noqa: E501
-            user_key,  # noqa: E501
-            container_image=container_image,
-        ),
-    )  # noqa: E501
-
-    # This is a trick because "target_size_ratio" isn't present at the same
-    # level in the dict
-    # ie:
-    # {
-    # 'pg_num': 8,
-    # 'pgp_num': 8,
-    # 'pg_autoscale_mode': 'on',
-    #     'options': {
-    #          'target_size_ratio': 0.1
-    #     }
-    # }
-    # If 'target_size_ratio' is present in 'options', we set it, this way we
-    # end up with a dict containing all needed keys at the same level.
-    if "target_size_ratio" in out["options"].keys():
-        out["target_size_ratio"] = out["options"]["target_size_ratio"]
-    else:
-        out["target_size_ratio"] = None
-
-    application = list(json.loads(application_pool.strip()).keys())
-
-    if len(application) == 0:
-        out["application"] = ""
-    else:
-        out["application"] = application[0]
-
-    return rc, cmd, out, err
-
-
-def compare_pool_config(user_pool_config, running_pool_details):
-    """
-    Compare user input config pool details with current running pool details
-    """
-
-    delta = {}
-    filter_keys = [
-        "pg_num",
-        "pg_placement_num",
-        "size",
-        "pg_autoscale_mode",
-        "target_size_ratio",
-    ]
-    for key in filter_keys:
-        if (
-            str(running_pool_details[key]) != user_pool_config[key]["value"]
-            and user_pool_config[key]["value"]  # noqa: E501
-        ):
-            delta[key] = user_pool_config[key]
-
-    if (
-        running_pool_details["application"] != user_pool_config["application"]["value"]
-        and user_pool_config["application"]["value"]
-    ):
-        delta["application"] = {}
-        delta["application"]["new_application"] = user_pool_config["application"][
-            "value"
-        ]  # noqa: E501
-        # to be improved (for update_pools()...)
-        delta["application"]["value"] = delta["application"]["new_application"]
-        delta["application"]["old_application"] = running_pool_details[
-            "application"
-        ]  # noqa: E501
-
-    return delta
-
-
-def list_pools(
-    cluster, user, user_key, details, output_format="json", container_image=None
-):
-    """
-    List existing pools
-    """
-
-    args = ["ls"]
-
-    if details:
-        args.append("detail")
-
-    args.extend(["-f", output_format])
-
-    cmd = generate_ceph_cmd(
-        sub_cmd=["osd", "pool"],
-        args=args,
-        cluster=cluster,
-        user=user,
-        user_key=user_key,
-        container_image=container_image,
-    )
-
-    return cmd
-
-
-def create_pool(cluster, name, user, user_key, user_pool_config, container_image=None):
-    """
-    Create a new pool
-    """
-
-    args = [
-        "create",
-        user_pool_config["pool_name"]["value"],
-        user_pool_config["type"]["value"],
-    ]
-
-    if user_pool_config["pg_autoscale_mode"]["value"] != "on":
-        args.extend(
-            [
-                "--pg_num",
-                user_pool_config["pg_num"]["value"],
-                "--pgp_num",
-                user_pool_config["pgp_num"]["value"]
-                or user_pool_config["pg_num"]["value"],
-            ]
-        )
-    elif user_pool_config["target_size_ratio"]["value"]:
-        args.extend(
-            ["--target_size_ratio", user_pool_config["target_size_ratio"]["value"]]
-        )
-
-    if user_pool_config["type"]["value"] == "replicated":
-        args.extend(
-            [
-                user_pool_config["crush_rule"]["value"],
-                "--expected_num_objects",
-                user_pool_config["expected_num_objects"]["value"],
-                "--autoscale-mode",
-                user_pool_config["pg_autoscale_mode"]["value"],
-            ]
-        )
-
-    if (
-        user_pool_config["size"]["value"]
-        and user_pool_config["type"]["value"] == "replicated"
-    ):
-        args.extend(["--size", user_pool_config["size"]["value"]])
-
-    elif user_pool_config["type"]["value"] == "erasure":
-        args.extend([user_pool_config["erasure_profile"]["value"]])
-
-        if user_pool_config["crush_rule"]["value"]:
-            args.extend([user_pool_config["crush_rule"]["value"]])
-
-        args.extend(
-            [
-                "--expected_num_objects",
-                user_pool_config["expected_num_objects"]["value"],
-                "--autoscale-mode",
-                user_pool_config["pg_autoscale_mode"]["value"],
-            ]
-        )
-
-    cmd = generate_ceph_cmd(
-        sub_cmd=["osd", "pool"],
-        args=args,
-        cluster=cluster,
-        user=user,
-        user_key=user_key,
-        container_image=container_image,
-    )
-
-    return cmd
-
-
-def remove_pool(cluster, name, user, user_key, container_image=None):
-    """
-    Remove a pool
-    """
-
-    args = ["rm", name, name, "--yes-i-really-really-mean-it"]
-
-    cmd = generate_ceph_cmd(
-        sub_cmd=["osd", "pool"],
-        args=args,
-        cluster=cluster,
-        user=user,
-        user_key=user_key,
-        container_image=container_image,
-    )
-
-    return cmd
-
-
-def update_pool(module, cluster, name, user, user_key, delta, container_image=None):
-    """
-    Update an existing pool
-    """
-
-    report = ""
-
-    for key in delta.keys():
-        if key != "application":
-            args = ["set", name, delta[key]["cli_set_opt"], delta[key]["value"]]
-
-            cmd = generate_ceph_cmd(
-                sub_cmd=["osd", "pool"],
-                args=args,
-                cluster=cluster,
-                user=user,
-                user_key=user_key,
-                container_image=container_image,
-            )
-
-            rc, cmd, out, err = exec_command(module, cmd)
-            if rc != 0:
-                return rc, cmd, out, err
-
-        else:
-            rc, cmd, out, err = exec_command(
-                module,
-                disable_application_pool(
-                    cluster,
-                    name,
-                    delta["application"]["old_application"],
-                    user,
-                    user_key,
-                    container_image=container_image,
-                ),
-            )  # noqa: E501
-            if rc != 0:
-                return rc, cmd, out, err
-
-            rc, cmd, out, err = exec_command(
-                module,
-                enable_application_pool(
-                    cluster,
-                    name,
-                    delta["application"]["new_application"],
-                    user,
-                    user_key,
-                    container_image=container_image,
-                ),
-            )  # noqa: E501
-            if rc != 0:
-                return rc, cmd, out, err
-
-        report = (
-            report
-            + "\n"
-            + "{} has been updated: {} is now {}".format(name, key, delta[key]["value"])
-        )  # noqa: E501
-
-    out = report
-    return rc, cmd, out, err
-
-
-def run_module():
-    module_args = dict(
-        cluster=dict(type="str", required=False, default="ceph"),
-        name=dict(type="str", required=True),
-        state=dict(
-            type="str",
-            required=False,
-            default="present",
-            choices=["present", "absent", "list"],
-        ),
-        details=dict(type="bool", required=False, default=False),
-        size=dict(type="str", required=False),
-        min_size=dict(type="str", required=False),
-        pg_num=dict(type="str", required=False),
-        pgp_num=dict(type="str", required=False),
-        pg_autoscale_mode=dict(type="str", required=False, default="on"),
-        target_size_ratio=dict(type="str", required=False, default=None),
-        pool_type=dict(
-            type="str",
-            required=False,
-            default="replicated",
-            choices=["replicated", "erasure", "1", "3"],
-        ),
-        erasure_profile=dict(type="str", required=False, default="default"),
-        rule_name=dict(type="str", required=False, default=None),
-        expected_num_objects=dict(type="str", required=False, default="0"),
-        application=dict(type="str", required=False, default=None),
-    )
-
-    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
-
-    # Gather module parameters in variables
-    cluster = module.params.get("cluster")
-    name = module.params.get("name")
-    state = module.params.get("state")
-    details = module.params.get("details")
-    size = module.params.get("size")
-    min_size = module.params.get("min_size")
-    pg_num = module.params.get("pg_num")
-    pgp_num = module.params.get("pgp_num")
-    pg_autoscale_mode = module.params.get("pg_autoscale_mode")
-    target_size_ratio = module.params.get("target_size_ratio")
-    application = module.params.get("application")
-
-    if module.params.get("pg_autoscale_mode").lower() in ["true", "on", "yes"]:
-        pg_autoscale_mode = "on"
-    elif module.params.get("pg_autoscale_mode").lower() in ["false", "off", "no"]:
-        pg_autoscale_mode = "off"
-    else:
-        pg_autoscale_mode = "warn"
-
-    if module.params.get("pool_type") == "1":
-        pool_type = "replicated"
-    elif module.params.get("pool_type") == "3":
-        pool_type = "erasure"
-    else:
-        pool_type = module.params.get("pool_type")
-
-    if not module.params.get("rule_name"):
-        rule_name = "replicated_rule" if pool_type == "replicated" else None
-    else:
-        rule_name = module.params.get("rule_name")
-
-    erasure_profile = module.params.get("erasure_profile")
-    expected_num_objects = module.params.get("expected_num_objects")
-    user_pool_config = {
-        "pool_name": {"value": name},
-        "pg_num": {"value": pg_num, "cli_set_opt": "pg_num"},
-        "pgp_num": {"value": pgp_num, "cli_set_opt": "pgp_num"},
-        "pg_autoscale_mode": {
-            "value": pg_autoscale_mode,
-            "cli_set_opt": "pg_autoscale_mode",
-        },
-        "target_size_ratio": {
-            "value": target_size_ratio,
-            "cli_set_opt": "target_size_ratio",
-        },
-        "application": {"value": application},
-        "type": {"value": pool_type},
-        "erasure_profile": {"value": erasure_profile},
-        "crush_rule": {"value": rule_name, "cli_set_opt": "crush_rule"},
-        "expected_num_objects": {"value": expected_num_objects},
-        "size": {"value": size, "cli_set_opt": "size"},
-        "min_size": {"value": min_size},
-    }
-
-    if module.check_mode:
-        module.exit_json(
-            changed=False,
-            stdout="",
-            stderr="",
-            rc=0,
-            start="",
-            end="",
-            delta="",
-        )
-
-    startd = datetime.datetime.now()
-    changed = False
-
-    # will return either the image name or None
-    container_image = is_containerized()
-
-    user = "client.admin"
-    keyring_filename = cluster + "." + user + ".keyring"
-    user_key = os.path.join("/etc/ceph/", keyring_filename)
-
-    if state == "present":
-        rc, cmd, out, err = exec_command(
-            module,
-            check_pool_exist(
-                cluster, name, user, user_key, container_image=container_image
-            ),
-        )  # noqa: E501
-        if rc == 0:
-            running_pool_details = get_pool_details(
-                module, cluster, name, user, user_key, container_image=container_image
-            )  # noqa: E501
-            user_pool_config["pg_placement_num"] = {
-                "value": str(running_pool_details[2]["pg_placement_num"]),
-                "cli_set_opt": "pgp_num",
-            }  # noqa: E501
-            delta = compare_pool_config(user_pool_config, running_pool_details[2])
-            if len(delta) > 0:
-                keys = list(delta.keys())
-                details = running_pool_details[2]
-                if details["erasure_code_profile"] and "size" in keys:
-                    del delta["size"]
-                if details["pg_autoscale_mode"] == "on":
-                    delta.pop("pg_num", None)
-                    delta.pop("pgp_num", None)
-
-                if len(delta) == 0:
-                    out = "Skipping pool {}.\nUpdating either 'size' on an erasure-coded pool or 'pg_num'/'pgp_num' on a pg autoscaled pool is incompatible".format(  # noqa: E501
-                        name
-                    )
-                else:
-                    rc, cmd, out, err = update_pool(
-                        module,
-                        cluster,
-                        name,
-                        user,
-                        user_key,
-                        delta,
-                        container_image=container_image,
-                    )  # noqa: E501
-                    if rc == 0:
-                        changed = True
-            else:
-                out = "Pool {} already exists and there is nothing to update.".format(
-                    name
-                )  # noqa: E501
-        else:
-            rc, cmd, out, err = exec_command(
-                module,
-                create_pool(
-                    cluster,
-                    name,
-                    user,
-                    user_key,
-                    user_pool_config=user_pool_config,  # noqa: E501
-                    container_image=container_image,
-                ),
-            )  # noqa: E501
-            if user_pool_config["application"]["value"]:
-                rc, _, _, _ = exec_command(
-                    module,
-                    enable_application_pool(
-                        cluster,
-                        name,
-                        user_pool_config["application"]["value"],  # noqa: E501
-                        user,
-                        user_key,
-                        container_image=container_image,
-                    ),
-                )  # noqa: E501
-            if user_pool_config["min_size"]["value"]:
-                # not implemented yet
-                pass
-            changed = True
-
-    elif state == "list":
-        rc, cmd, out, err = exec_command(
-            module,
-            list_pools(
-                cluster, name, user, user_key, details, container_image=container_image
-            ),
-        )  # noqa: E501
-        if rc != 0:
-            out = "Couldn't list pool(s) present on the cluster"
-
-    elif state == "absent":
-        rc, cmd, out, err = exec_command(
-            module,
-            check_pool_exist(
-                cluster, name, user, user_key, container_image=container_image
-            ),
-        )  # noqa: E501
-        if rc == 0:
-            rc, cmd, out, err = exec_command(
-                module,
-                remove_pool(
-                    cluster, name, user, user_key, container_image=container_image
-                ),
-            )  # noqa: E501
-            changed = True
-        else:
-            rc = 0
-            out = "Skipped, since pool {} doesn't exist".format(name)
-
-    exit_module(
-        module=module, out=out, rc=rc, cmd=cmd, err=err, startd=startd, changed=changed
-    )
-
-
-def main():
-    run_module()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/roles/ceph_csi_rbd/defaults/main.yml b/roles/ceph_csi_rbd/defaults/main.yml
index 708d3a1..c64ad8f 100644
--- a/roles/ceph_csi_rbd/defaults/main.yml
+++ b/roles/ceph_csi_rbd/defaults/main.yml
@@ -12,7 +12,6 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-ceph_csi_rbd_ceph_fsid: "{{ ceph_mon_fsid }}"
 ceph_csi_rbd_mons_group: controllers
 ceph_csi_rbd_id: kube
 ceph_csi_rbd_user: "client.{{ ceph_csi_rbd_id }}"
diff --git a/roles/ceph_csi_rbd/tasks/main.yml b/roles/ceph_csi_rbd/tasks/main.yml
index f992364..6db53e0 100644
--- a/roles/ceph_csi_rbd/tasks/main.yml
+++ b/roles/ceph_csi_rbd/tasks/main.yml
@@ -22,12 +22,13 @@
 - name: Generate fact with list of Ceph monitors
   run_once: true
   ansible.builtin.set_fact:
+    ceph_csi_rbd_ceph_fsid: "{{ _ceph_mon_dump.stdout | from_json | community.general.json_query('fsid') }}"
     ceph_monitors: "{{ _ceph_mon_dump.stdout | from_json | community.general.json_query('mons[*].addr') | map('regex_replace', '(.*):(.*)', '\\1') }}"
 
 - name: Create Ceph pool
   delegate_to: "{{ groups[ceph_csi_rbd_mons_group][0] }}"
   run_once: true
-  vexxhost.atmosphere.ceph_pool:
+  vexxhost.ceph.pool:
     name: "{{ ceph_csi_rbd_pool }}"
     rule_name: "{{ ceph_csi_rbd_rule_name | default(omit) }}"
     application: rbd
@@ -36,7 +37,7 @@
 - name: Create user {{ ceph_csi_rbd_user }}
   delegate_to: "{{ groups[ceph_csi_rbd_mons_group][0] }}"
   run_once: true
-  vexxhost.atmosphere.ceph_key:
+  vexxhost.ceph.key:
     name: "{{ ceph_csi_rbd_user }}"
     caps:
       mon: profile rbd
@@ -46,7 +47,7 @@
 - name: Retrieve keyring for {{ ceph_csi_rbd_user }}
   delegate_to: "{{ groups[ceph_csi_rbd_mons_group][0] }}"
   run_once: true
-  vexxhost.atmosphere.ceph_key:
+  vexxhost.ceph.key:
     name: "{{ ceph_csi_rbd_user }}"
     state: info
     output_format: json
diff --git a/roles/ceph_mgr/README.md b/roles/ceph_mgr/README.md
deleted file mode 100644
index ccc483a..0000000
--- a/roles/ceph_mgr/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# `ceph_mgr`
diff --git a/roles/ceph_mgr/tasks/main.yml b/roles/ceph_mgr/tasks/main.yml
deleted file mode 100644
index 9ee70ee..0000000
--- a/roles/ceph_mgr/tasks/main.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-- name: Install packages
-  ansible.builtin.apt:
-    name: ["ceph-mgr"]
-    install_recommends: false
-
-- name: Create manager folder
-  ansible.builtin.file:
-    path: "/var/lib/ceph/mgr/ceph-{{ inventory_hostname_short }}"
-    state: directory
-    owner: ceph
-    group: ceph
-    mode: "0700"
-
-- name: Create Ceph manager keyring
-  vexxhost.atmosphere.ceph_key:
-    name: "mgr.{{ inventory_hostname_short }}"
-    dest: "/var/lib/ceph/mgr/ceph-{{ inventory_hostname_short }}/keyring"
-    caps:
-      mon: allow profile mgr
-      osd: allow *
-      mds: allow *
-    owner: ceph
-    group: ceph
-
-- name: Ensure permissions are fixed
-  ansible.builtin.file:
-    path: "/var/lib/ceph/mon/ceph-{{ inventory_hostname_short }}"
-    owner: ceph
-    group: ceph
-    recurse: true
-
-- name: Enable and start service
-  ansible.builtin.service:
-    name: "ceph-mgr@{{ inventory_hostname_short }}"
-    state: started
-    enabled: true
diff --git a/roles/ceph_mon/README.md b/roles/ceph_mon/README.md
deleted file mode 100644
index d742bc2..0000000
--- a/roles/ceph_mon/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# `ceph_mon`
diff --git a/roles/ceph_mon/defaults/main.yml b/roles/ceph_mon/defaults/main.yml
deleted file mode 100644
index 86c1717..0000000
--- a/roles/ceph_mon/defaults/main.yml
+++ /dev/null
@@ -1,25 +0,0 @@
----
-# .. vim: foldmarker=[[[,]]]:foldmethod=marker
-
-# .. Copyright (C) 2022 VEXXHOST, Inc.
-# .. SPDX-License-Identifier: Apache-2.0
-
-# Default variables
-# =================
-
-# .. contents:: Sections
-#    :local:
-
-
-# .. envvar:: ceph_mon_group [[[
-#
-# Name of Ansible group that contains all Ceph monitors
-ceph_mon_group: controllers
-
-                                                                   # ]]]
-# .. envvar:: ceph_mon_cluster_network [[[
-#
-# Cluster (replication) network used by Ceph
-ceph_mon_cluster_network: "{{ ceph_mon_public_network }}"
-
-                                                                   # ]]]
diff --git a/roles/ceph_mon/meta/main.yml b/roles/ceph_mon/meta/main.yml
deleted file mode 100644
index d59c2bc..0000000
--- a/roles/ceph_mon/meta/main.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-galaxy_info:
-  author: VEXXHOST, Inc.
-  description: Ansible role for Ceph monitor
-  license: Apache-2.0
-  min_ansible_version: 5.5.0
-  standalone: false
-  platforms:
-    - name: Ubuntu
-      versions:
-        - focal
-
-dependencies:
-  - role: defaults
diff --git a/roles/ceph_mon/tasks/bootstrap-ceph.yml b/roles/ceph_mon/tasks/bootstrap-ceph.yml
deleted file mode 100644
index dc19f62..0000000
--- a/roles/ceph_mon/tasks/bootstrap-ceph.yml
+++ /dev/null
@@ -1,111 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-# TODO(mnaser): Move to using vexxhost.atmosphere.ceph_key
-- name: Create monitor keyring
-  ansible.builtin.command:
-    ceph-authtool --gen-key --create-keyring
-                  --name mon.
-                  --cap mon 'allow *'
-                  /tmp/ceph.mon.keyring
-  args:
-    creates: /tmp/ceph.mon.keyring
-  when:
-    - inventory_hostname == groups[ceph_mon_group][0]
-
-# TODO(mnaser): Move to using vexxhost.atmosphere.ceph_key
-- name: Create admin keyring
-  ansible.builtin.command:
-    ceph-authtool --gen-key --create-keyring
-                  --name client.admin
-                  --cap mon 'allow *'
-                  --cap osd 'allow *'
-                  --cap mds 'allow *'
-                  --cap mgr 'allow *'
-                  /etc/ceph/ceph.client.admin.keyring
-  args:
-    creates: /etc/ceph/ceph.client.admin.keyring
-  when:
-    - inventory_hostname == groups[ceph_mon_group][0]
-
-# TODO(mnaser): Move to using vexxhost.atmosphere.ceph_key
-- name: Create bootstrap-osd keyring
-  ansible.builtin.command:
-    ceph-authtool --gen-key --create-keyring
-                  --name client.bootstrap-osd
-                  --cap mon 'profile bootstrap-osd'
-                  --cap mgr 'allow r'
-                  /var/lib/ceph/bootstrap-osd/ceph.keyring
-  args:
-    creates: /var/lib/ceph/bootstrap-osd/ceph.keyring
-  when:
-    - inventory_hostname == groups[ceph_mon_group][0]
-
-# TODO(mnaser): Move to using vexxhost.atmosphere.ceph_key
-- name: Add admin keyring to monitor
-  changed_when: true
-  ansible.builtin.command:
-    ceph-authtool --import-keyring /etc/ceph/ceph.client.admin.keyring
-                  /tmp/ceph.mon.keyring
-  when:
-    - inventory_hostname == groups[ceph_mon_group][0]
-
-# TODO(mnaser): Move to using vexxhost.atmosphere.ceph_key
-- name: Add bootstrap-osd keyring to monitor
-  changed_when: true
-  ansible.builtin.command:
-    ceph-authtool --import-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring
-                  /tmp/ceph.mon.keyring
-  when:
-    - inventory_hostname == groups[ceph_mon_group][0]
-
-- name: Create monmap
-  ansible.builtin.command:
-    monmaptool --create
-               --fsid {{ ceph_mon_fsid }}
-               --add {{ inventory_hostname_short }} {{ ceph_mon_ip_address }}
-               /tmp/monmap
-  args:
-    creates: /tmp/monmap
-  when:
-    - inventory_hostname == groups[ceph_mon_group][0]
-
-- name: Create monitor folder
-  ansible.builtin.file:
-    path: "/var/lib/ceph/mon/ceph-{{ inventory_hostname_short }}"
-    state: directory
-    owner: ceph
-    group: ceph
-    mode: "0700"
-  when:
-    - inventory_hostname == groups[ceph_mon_group][0]
-
-- name: Configure mon initial members
-  community.general.ini_file:
-    path: /etc/ceph/ceph.conf
-    section: global
-    option: mon initial members
-    value: "{{ inventory_hostname_short }}"
-    owner: ceph
-    group: ceph
-    mode: "0640"
-
-- name: Start monitor
-  ansible.builtin.include_tasks: start-monitor.yml
-  when:
-    - inventory_hostname == groups[ceph_mon_group][0]
-
-- name: Set bootstrap node
-  ansible.builtin.set_fact:
-    _ceph_mon_bootstrap_node: "{{ groups[ceph_mon_group][0] }}"
diff --git a/roles/ceph_mon/tasks/main.yml b/roles/ceph_mon/tasks/main.yml
deleted file mode 100644
index 5ce89e2..0000000
--- a/roles/ceph_mon/tasks/main.yml
+++ /dev/null
@@ -1,92 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-- name: Install packages
-  ansible.builtin.apt:
-    name: ["ceph-mon"]
-    install_recommends: false
-
-- name: Set ceph monitor ip address
-  ansible.builtin.set_fact:
-    ceph_mon_ip_address: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr(ceph_mon_public_network) | first }}"
-
-- name: Generate basic configuration file
-  community.general.ini_file:
-    path: /etc/ceph/ceph.conf
-    section: global
-    option: "{{ item.option }}"
-    value: "{{ item.value }}"
-    owner: ceph
-    group: ceph
-    mode: "0640"
-  loop:
-    - option: fsid
-      value: "{{ ceph_mon_fsid }}"
-    - option: mon host
-      value: "{{ groups[ceph_mon_group] | map('extract', hostvars, ['ceph_mon_ip_address']) | join(',') }}"
-    - option: public network
-      value: "{{ ceph_mon_public_network }}"
-    - option: cluster network
-      value: "{{ ceph_mon_cluster_network }}"
-
-- name: Check if any node is bootstrapped
-  ansible.builtin.stat:
-    path: "/var/lib/ceph/mon/ceph-{{ hostvars[item]['inventory_hostname_short'] }}/store.db"
-  register: _ceph_mon_stat
-  loop: "{{ groups[ceph_mon_group] }}"
-  delegate_to: "{{ item }}"
-
-- name: Select pre-existing bootstrap node if exists
-  ansible.builtin.set_fact:
-    _ceph_mon_bootstrap_node: "{{ _ceph_mon_stat.results | selectattr('stat.exists', 'equalto', true) | map(attribute='item') | first }}"
-  when:
-    - _ceph_mon_stat.results | selectattr('stat.exists', 'equalto', true) | length > 0
-
-- name: Bootstrap cluster
-  ansible.builtin.include_tasks: bootstrap-ceph.yml
-  when:
-    - _ceph_mon_stat.results | selectattr('stat.exists', 'equalto', true) | length == 0
-
-- name: Grab admin keyring
-  delegate_to: "{{ _ceph_mon_bootstrap_node }}"
-  ansible.builtin.slurp:
-    src: /etc/ceph/ceph.client.admin.keyring
-  register: _ceph_mon_admin_keyring
-  when: inventory_hostname != _ceph_mon_bootstrap_node
-
-- name: Upload client.admin keyring
-  ansible.builtin.copy:
-    content: "{{ _ceph_mon_admin_keyring['content'] | b64decode }}"
-    dest: /etc/ceph/ceph.client.admin.keyring
-    mode: "0600"
-  when: inventory_hostname != _ceph_mon_bootstrap_node
-
-- name: Get monitor keyring
-  ansible.builtin.command: ceph auth get mon. -o /tmp/ceph.mon.keyring
-  changed_when: false
-  when: inventory_hostname != _ceph_mon_bootstrap_node
-
-- name: Get monmap keyring
-  ansible.builtin.command: ceph mon getmap -o /tmp/monmap
-  changed_when: false
-  when: inventory_hostname != _ceph_mon_bootstrap_node
-
-- name: Start monitor
-  ansible.builtin.include_tasks: start-monitor.yml
-  when: inventory_hostname != _ceph_mon_bootstrap_node
-
-- name: Enable "msgr2"
-  ansible.builtin.command: ceph mon enable-msgr2
-  changed_when: false
-  when: inventory_hostname == _ceph_mon_bootstrap_node
diff --git a/roles/ceph_mon/tasks/start-monitor.yml b/roles/ceph_mon/tasks/start-monitor.yml
deleted file mode 100644
index 308d44b..0000000
--- a/roles/ceph_mon/tasks/start-monitor.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-- name: Create monitor filesystem
-  ansible.builtin.shell: |
-    ceph-mon --mkfs -i {{ inventory_hostname_short }} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring
-  args:
-    creates: "/var/lib/ceph/mon/ceph-{{ inventory_hostname_short }}/store.db"
-
-- name: Ensure permissions are fixed
-  ansible.builtin.file:
-    path: "/var/lib/ceph/mon/ceph-{{ inventory_hostname_short }}"
-    owner: ceph
-    group: ceph
-    recurse: true
-
-# NOTE(mnaser): https://bugs.launchpad.net/ubuntu/+source/ceph/+bug/1917414/comments/30
-- name: Workaround for aarch64 systems
-  community.general.ini_file:
-    path: /lib/systemd/system/ceph-mon@.service
-    section: Service
-    option: MemoryDenyWriteExecute
-    value: false
-    owner: ceph
-    group: ceph
-    mode: "0644"
-  register: _ceph_aarch64_fix
-  when: ansible_architecture == 'aarch64'
-
-- name: Enable and start service
-  ansible.builtin.service:
-    name: "ceph-mon@{{ inventory_hostname_short }}"
-    state: started
-    enabled: true
-    daemon_reload: "{{ _ceph_aarch64_fix.changed }}"
diff --git a/roles/ceph_osd/README.md b/roles/ceph_osd/README.md
deleted file mode 100644
index e725e9e..0000000
--- a/roles/ceph_osd/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# `ceph_osd`
diff --git a/roles/ceph_osd/defaults/main.yml b/roles/ceph_osd/defaults/main.yml
deleted file mode 100644
index 9671346..0000000
--- a/roles/ceph_osd/defaults/main.yml
+++ /dev/null
@@ -1,19 +0,0 @@
----
-# .. vim: foldmarker=[[[,]]]:foldmethod=marker
-
-# .. Copyright (C) 2022 VEXXHOST, Inc.
-# .. SPDX-License-Identifier: Apache-2.0
-
-# Default variables
-# =================
-
-# .. contents:: Sections
-#    :local:
-
-
-# .. envvar:: ceph_osd_mons_group [[[
-#
-# Name of Ansible group that contains all Ceph monitors
-ceph_osd_mons_group: controllers
-
-                                                                   # ]]]
diff --git a/roles/ceph_osd/meta/main.yml b/roles/ceph_osd/meta/main.yml
deleted file mode 100644
index bd74938..0000000
--- a/roles/ceph_osd/meta/main.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-galaxy_info:
-  author: VEXXHOST, Inc.
-  description: Ansible role for Ceph OSD
-  license: Apache-2.0
-  min_ansible_version: 5.5.0
-  standalone: false
-  platforms:
-    - name: Ubuntu
-      versions:
-        - focal
-
-dependencies:
-  - role: defaults
diff --git a/roles/ceph_osd/tasks/main.yml b/roles/ceph_osd/tasks/main.yml
deleted file mode 100644
index 989424d..0000000
--- a/roles/ceph_osd/tasks/main.yml
+++ /dev/null
@@ -1,104 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-- name: Install packages
-  ansible.builtin.apt:
-    name: ["udev", "ceph-osd"]
-    install_recommends: false
-
-- name: Grab ceph fsid from monitors
-  delegate_to: "{{ groups[ceph_osd_mons_group][0] }}"
-  register: _ceph_fsid
-  changed_when: false
-  ansible.builtin.command: ceph fsid
-
-- name: Collect "ceph mon dump" output from a monitor
-  delegate_to: "{{ groups[ceph_osd_mons_group][0] }}"
-  run_once: true
-  ansible.builtin.command: ceph mon dump -f json
-  changed_when: false
-  register: _ceph_mon_dump
-
-- name: Generate fact with list of Ceph monitors
-  run_once: true
-  ansible.builtin.set_fact:
-    ceph_monitors: "{{ _ceph_mon_dump.stdout | from_json | community.general.json_query('mons[*].addr') | map('regex_replace', '(.*):(.*)', '\\1') }}"
-
-- name: Generate basic configuration file
-  community.general.ini_file:
-    path: /etc/ceph/ceph.conf
-    section: global
-    option: "{{ item.option }}"
-    value: "{{ item.value }}"
-    owner: ceph
-    group: ceph
-    mode: "0640"
-  loop:
-    - option: fsid
-      value: "{{ _ceph_fsid.stdout | trim }}"
-    - option: mon host
-      value: "{{ ceph_monitors | join(',') }}"
-
-- name: Grab bootstrap-osd from monitors
-  delegate_to: "{{ groups[ceph_osd_mons_group][0] }}"
-  register: _ceph_bootstrap_osd_keyring
-  changed_when: false
-  ansible.builtin.command: ceph auth get client.bootstrap-osd
-
-- name: Install bootstrap-osd keyring
-  ansible.builtin.copy:
-    content: "{{ _ceph_bootstrap_osd_keyring.stdout }}\n"
-    dest: /var/lib/ceph/bootstrap-osd/ceph.keyring
-    owner: ceph
-    group: ceph
-    mode: "0640"
-
-- name: Workaround to allow usage of loop devices
-  ansible.builtin.replace:
-    path: /usr/lib/python3/dist-packages/ceph_volume/util/disk.py
-    regexp: "'mpath']"
-    replace: "'mpath', 'loop']"
-    owner: ceph
-    group: ceph
-    mode: "0640"
-  when: molecule | default(false)
-
-# NOTE(mnaser): https://bugs.launchpad.net/ubuntu/+source/ceph/+bug/1917414/comments/30
-- name: Workaround for aarch64 systems
-  community.general.ini_file:
-    path: /lib/systemd/system/ceph-osd@.service
-    section: Service
-    option: MemoryDenyWriteExecute
-    value: false
-    owner: ceph
-    group: ceph
-    mode: "0644"
-  register: _ceph_aarch64_fix
-  when: ansible_architecture == 'aarch64'
-
-- name: Reload systemd
-  ansible.builtin.service:
-    daemon_reload: "{{ _ceph_aarch64_fix.changed }}"
-
-- name: Get which devices don't contain osds
-  register: _ceph_osd_check
-  failed_when: false
-  changed_when: false
-  ansible.builtin.command: /usr/sbin/ceph-volume lvm list {{ item }}
-  loop: "{{ ceph_osd_devices }}"
-
-- name: Create osds for volumes which are not setup
-  changed_when: true
-  ansible.builtin.command: /usr/sbin/ceph-volume lvm create --data {{ item }}
-  loop: "{{ _ceph_osd_check.results | selectattr('rc', 'equalto', 1) | map(attribute='item') }}"
diff --git a/roles/ceph_provisioners/tasks/main.yml b/roles/ceph_provisioners/tasks/main.yml
index 057b75a..775ab28 100644
--- a/roles/ceph_provisioners/tasks/main.yml
+++ b/roles/ceph_provisioners/tasks/main.yml
@@ -77,7 +77,7 @@
 
 - name: Retrieve client.admin keyring
   delegate_to: "{{ groups[ceph_provisioners_ceph_mon_group][0] }}"
-  vexxhost.atmosphere.ceph_key:
+  vexxhost.ceph.key:
     name: client.admin
     state: info
     output_format: json
diff --git a/roles/ceph_repository/README.md b/roles/ceph_repository/README.md
deleted file mode 100644
index 6e54014..0000000
--- a/roles/ceph_repository/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# `ceph_repository`
diff --git a/roles/ceph_repository/defaults/main.yml b/roles/ceph_repository/defaults/main.yml
deleted file mode 100644
index 63c9290..0000000
--- a/roles/ceph_repository/defaults/main.yml
+++ /dev/null
@@ -1,31 +0,0 @@
----
-# .. vim: foldmarker=[[[,]]]:foldmethod=marker
-
-# .. Copyright (C) 2022 VEXXHOST, Inc.
-# .. SPDX-License-Identifier: Apache-2.0
-
-# Default variables
-# =================
-
-# .. contents:: Sections
-#    :local:
-
-
-# .. envvar:: ceph_repository_apt_key [[[
-#
-# Ceph APT repository GPG key
-ceph_repository_apt_key: "https://download.ceph.com/keys/release.asc"
-
-                                                                   # ]]]
-# .. envvar:: ceph_repository_url [[[
-#
-# Ceph APT repository URL
-ceph_repository_url: https://download.ceph.com/debian-pacific/
-
-                                                                   # ]]]
-# .. envvar:: ceph_repository_version [[[
-#
-# Ceph version to pin package manager to
-ceph_repository_version: 16.2.9
-
-                                                                   # ]]]
diff --git a/roles/ceph_repository/meta/main.yml b/roles/ceph_repository/meta/main.yml
deleted file mode 100644
index 2e86618..0000000
--- a/roles/ceph_repository/meta/main.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-galaxy_info:
-  author: VEXXHOST, Inc.
-  description: Ansible role for Ceph repository
-  license: Apache-2.0
-  min_ansible_version: 5.5.0
-  standalone: false
-  platforms:
-    - name: Ubuntu
-      versions:
-        - focal
-
-dependencies:
-  - role: defaults
diff --git a/roles/ceph_repository/tasks/main.yml b/roles/ceph_repository/tasks/main.yml
deleted file mode 100644
index e3d184e..0000000
--- a/roles/ceph_repository/tasks/main.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# 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.
-
-- name: Install packages
-  ansible.builtin.apt:
-    name: ["gnupg"]
-    install_recommends: false
-
-- name: Add apt key
-  ansible.builtin.apt_key:
-    url: "{{ ceph_repository_apt_key }}"
-    state: present
-
-- name: Configure version pinning
-  ansible.builtin.template:
-    src: apt-preferences.j2
-    dest: /etc/apt/preferences.d/ceph
-    mode: "0644"
-
-- name: Add apt repository
-  ansible.builtin.apt_repository:
-    repo: "deb {{ ceph_repository_url }} {{ ansible_distribution_release }} main"
-    state: present
diff --git a/roles/ceph_repository/templates/apt-preferences.j2 b/roles/ceph_repository/templates/apt-preferences.j2
deleted file mode 100644
index c197476..0000000
--- a/roles/ceph_repository/templates/apt-preferences.j2
+++ /dev/null
@@ -1,11 +0,0 @@
-Package: ceph-mon
-Pin: version {{ ceph_repository_version }}-*
-Pin-Priority: 1000
-
-Package: ceph-mgr
-Pin: version {{ ceph_repository_version }}-*
-Pin-Priority: 1000
-
-Package: ceph-osd
-Pin: version {{ ceph_repository_version }}-*
-Pin-Priority: 1000
diff --git a/roles/rook_ceph_cluster/tasks/main.yml b/roles/rook_ceph_cluster/tasks/main.yml
index a2ba898..0c8232a 100644
--- a/roles/rook_ceph_cluster/tasks/main.yml
+++ b/roles/rook_ceph_cluster/tasks/main.yml
@@ -22,7 +22,7 @@
 - name: Retrieve keyring for client.admin
   run_once: true
   delegate_to: "{{ groups[rook_ceph_cluster_mon_group][0] }}"
-  vexxhost.atmosphere.ceph_key:
+  vexxhost.ceph.key:
     name: client.admin
     state: info
     output_format: json
@@ -31,7 +31,7 @@
 - name: Retrieve keyring for monitors
   run_once: true
   delegate_to: "{{ groups[rook_ceph_cluster_mon_group][0] }}"
-  vexxhost.atmosphere.ceph_key:
+  vexxhost.ceph.key:
     name: mon.
     state: info
     output_format: json