diff --git a/ansible.cfg b/ansible.cfg index 257a642..7f30524 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -1,7 +1,5 @@ [defaults] log_path = $HOME/ansible/ansible.log -library = ./library -module_utils = ./module_utils roles_path = ./ forks = 20 diff --git a/cephadm-clients.yml b/cephadm-clients.yml index 3385695..e655881 100644 --- a/cephadm-clients.yml +++ b/cephadm-clients.yml @@ -32,31 +32,31 @@ - run_once: true delegate_to: localhost block: - - name: import_role ceph_defaults - import_role: + - name: Import_role ceph_defaults + ansible.builtin.import_role: name: ceph_defaults - - name: fail if the fsid parameter is missing - fail: + - name: Fail if the fsid parameter is missing + ansible.builtin.fail: msg: > You must supply an 'fsid' parameter for the corresponding ceph cluster when: fsid is undefined - - name: fail if admin group doesn't exist or is empty - fail: + - name: Fail if admin group doesn't exist or is empty + ansible.builtin.fail: msg: | You must define a group [admin] in your inventory which provides the keyring that you want to distribute when: "'admin' not in groups or groups['admin'] | length < 1" - - name: fail if client_group is NOT in the inventory - fail: + - name: Fail if client_group is NOT in the inventory + ansible.builtin.fail: msg: > Variable client_group '{{ client_group }}' is not defined in the inventory when: client_group not in groups - - name: fail if keyring variable is missing - fail: + - name: Fail if keyring variable is missing + ansible.builtin.fail: msg: | You must supply a 'keyring' variable that defines the path to the key that you want to distribute to your client machines @@ -69,38 +69,38 @@ gather_facts: false tasks: - - name: check fsid is present on {{ inventory_hostname }} - stat: + - name: Check fsid is present on {{ inventory_hostname }} + ansible.builtin.stat: path: /var/lib/ceph/{{ fsid }} register: fsid_stat - - name: fail if fsid is not present - fail: + - name: Fail if fsid is not present + ansible.builtin.fail: msg: > The given fsid ({{ fsid }}), is not present in /var/lib/ceph on {{ inventory_hostname }} when: - not fsid_stat.stat.exists | bool - not fsid_stat.stat.isdir | bool - - name: check keyring status on {{ inventory_hostname }} - stat: + - name: Check keyring status on {{ inventory_hostname }} + ansible.builtin.stat: path: "{{ keyring }}" register: keyring_stat - - name: fail if keyring not found on {{ inventory_hostname }} - fail: + - name: Fail if keyring not found on {{ inventory_hostname }} + ansible.builtin.fail: msg: > The keyring path provided '{{ keyring }}' can not be found on {{ inventory_hostname }} when: not keyring_stat.stat.exists | bool - - name: check conf is OK to use - stat: + - name: Check conf is OK to use + ansible.builtin.stat: path: "{{ conf }}" register: conf_stat when: conf is defined - - name: fail if conf supplied is not on {{ inventory_hostname }} - fail: + - name: Fail if conf supplied is not on {{ inventory_hostname }} + ansible.builtin.fail: msg: | The conf file '{{ conf }}' can not be found on {{ inventory_hostname }} when: @@ -115,26 +115,26 @@ gather_facts: false tasks: - - name: import_role ceph_defaults - import_role: + - name: Import_role ceph_defaults + ansible.builtin.import_role: name: ceph_defaults - - name: slurp the keyring - slurp: + - name: Slurp the keyring + ansible.builtin.slurp: src: "{{ keyring }}" register: client_keyring no_log: true - - name: slurp the conf if it's supplied - slurp: + - name: Slurp the conf if it's supplied + ansible.builtin.slurp: src: "{{ conf }}" register: ceph_config when: - conf is defined - conf | length > 0 - - name: create minimal conf as a default - command: cephadm shell -- ceph config generate-minimal-conf + - name: Create minimal conf as a default + ansible.builtin.command: cephadm shell -- ceph config generate-minimal-conf register: minimal_ceph_config when: conf is undefined @@ -145,26 +145,26 @@ gather_facts: true tasks: - - name: import_role ceph_defaults - import_role: + - name: Import_role ceph_defaults + ansible.builtin.import_role: name: ceph_defaults - - name: install ceph-common on rhel - command: dnf install --allowerasing --assumeyes ceph-common + - name: Install ceph-common on rhel + ansible.builtin.command: dnf install --allowerasing --assumeyes ceph-common changed_when: false register: result until: result is succeeded when: ansible_facts['os_family'] == 'RedHat' - - name: install ceph client prerequisites if needed - package: + - name: Install ceph client prerequisites if needed + ansible.builtin.package: name: "{{ ceph_client_pkgs }}" state: present register: result until: result is succeeded - - name: copy configuration and keyring files to the clients - copy: + - name: Copy configuration and keyring files to the clients + ansible.builtin.copy: content: "{{ item.content }}" dest: "{{ item.dest }}" owner: ceph diff --git a/cephadm-distribute-ssh-key.yml b/cephadm-distribute-ssh-key.yml index e5881ac..cde2b0d 100644 --- a/cephadm-distribute-ssh-key.yml +++ b/cephadm-distribute-ssh-key.yml @@ -27,25 +27,25 @@ become: true gather_facts: false tasks: - - name: fail if admin_node is not defined - fail: + - name: Fail if admin_node is not defined + ansible.builtin.fail: msg: "You must set the variable admin_node" run_once: true delegate_to: localhost when: admin_node is undefined - - name: get ssh public key from a file on the Ansible controller host + - name: Get ssh public key from a file on the Ansible controller host when: cephadm_pubkey_path is defined block: - - name: get details about {{ cephadm_pubkey_path }} - stat: + - name: Get details about {{ cephadm_pubkey_path }} + ansible.builtin.stat: path: "{{ cephadm_pubkey_path }}" register: cephadm_pubkey_path_stat delegate_to: localhost run_once: true - - name: fail if {{ cephadm_pubkey_path }} doesn't exist - fail: + - name: Fail if {{ cephadm_pubkey_path }} doesn't exist + ansible.builtin.fail: msg: "{{ cephadm_pubkey_path }} doesn't exist or is invalid." run_once: true delegate_to: localhost @@ -53,21 +53,21 @@ - not cephadm_pubkey_path_stat.stat.exists | bool or not cephadm_pubkey_path_stat.stat.isfile | bool - - name: get the cephadm ssh pub key - command: "cephadm shell {{ '--fsid ' + fsid if fsid is defined else '' }} ceph cephadm get-pub-key" + - name: Get the cephadm ssh pub key + ansible.builtin.command: "cephadm shell {{ '--fsid ' + fsid if fsid is defined else '' }} ceph cephadm get-pub-key" changed_when: false run_once: true register: cephadm_get_pub_key delegate_to: "{{ admin_node }}" when: cephadm_pubkey_path is undefined - - name: allow ssh public key for {{ cephadm_ssh_user | default('root') }} account - authorized_key: + - name: Allow ssh public key for {{ cephadm_ssh_user | default('root') }} account + ansible.posix.authorized_key: user: "{{ cephadm_ssh_user | default('root') }}" key: "{{ lookup('file', cephadm_pubkey_path) if cephadm_pubkey_path is defined else cephadm_get_pub_key.stdout }}" - - name: set cephadm ssh user to {{ cephadm_ssh_user }} - command: "cephadm shell {{ '--fsid ' + fsid if fsid is defined else '' }} ceph cephadm set-user {{ cephadm_ssh_user | default('root') }}" + - name: Set cephadm ssh user to {{ cephadm_ssh_user }} + ansible.builtin.command: "cephadm shell {{ '--fsid ' + fsid if fsid is defined else '' }} ceph cephadm set-user {{ cephadm_ssh_user | default('root') }}" changed_when: false run_once: true delegate_to: "{{ admin_node }}" \ No newline at end of file diff --git a/cephadm-preflight.yml b/cephadm-preflight.yml index 617f740..1f256c1 100644 --- a/cephadm-preflight.yml +++ b/cephadm-preflight.yml @@ -18,7 +18,7 @@ # ansible-playbook -i cephadm-preflight.yml --extra-vars "ceph_origin=rhcs" # -- name: variables validations +- name: Variables validations ansible.builtin.import_playbook: validate/preflight.yml - hosts: all @@ -41,37 +41,37 @@ - ceph-radosgw - rbd-mirror tasks: - - name: import_role ceph_defaults - import_role: + - name: Import_role ceph_defaults + ansible.builtin.import_role: name: ceph_defaults - - name: redhat family of OS related tasks + - name: Redhat family of OS related tasks when: ansible_facts['os_family'] == 'RedHat' block: - - name: rhcs related tasks + - name: Rhcs related tasks when: ceph_origin == 'rhcs' block: - - name: enable red hat ceph storage tools repository - rhsm_repository: + - name: Enable red hat ceph storage tools repository + community.general.rhsm_repository: name: "rhceph-{{ ceph_rhcs_version }}-tools-for-rhel-{{ ansible_facts['distribution_major_version'] }}-{{ ansible_facts['architecture'] }}-rpms" - - name: disable older rhceph repositories if any on RHEL{{ansible_facts['distribution_major_version']}} + - name: Disable older rhceph repositories if any on RHEL{{ansible_facts['distribution_major_version']}} when: ansible_facts['distribution_major_version'] == '8' - rhsm_repository: + community.general.rhsm_repository: name: "{{ repos_4_to_disable + repos_5_to_disable }}" state: absent - - name: disable older rhceph repositories if any on RHEL{{ansible_facts['distribution_major_version']}} + - name: Disable older rhceph repositories if any on RHEL{{ansible_facts['distribution_major_version']}} when: ansible_facts['distribution_major_version'] == '9' - rhsm_repository: + community.general.rhsm_repository: name: "{{ repos_5_to_disable + repos_6_to_disable }}" state: absent - - name: enable ceph package repositories + - name: Enable ceph package repositories when: ceph_origin in ['community', 'ibm'] block: - - name: set_fact _ceph_repo - set_fact: + - name: Set_fact _ceph_repo + ansible.builtin.set_fact: _ceph_repo: name: ceph_stable description: "{{ 'Ceph Stable repo' if ceph_origin == 'community' else 'IBM Ceph repo' }}" @@ -79,15 +79,15 @@ baseurl: "{{ ceph_community_repo_baseurl if ceph_origin == 'community' else ceph_ibm_repo_baseurl }}" paths: "{{ [ 'noarch', '$basearch' ] if ceph_origin == 'community' else [ '$basearch' ] }}" - - name: configure ceph repository key - rpm_key: + - name: Configure ceph repository key + ansible.builtin.rpm_key: key: "{{ _ceph_repo.rpm_key }}" state: present register: result until: result is succeeded - - name: configure ceph stable repository - yum_repository: + - name: Configure ceph stable repository + ansible.builtin.yum_repository: name: "ceph_stable_{{ item }}" description: "{{ _ceph_repo.description }} - {{ item }}" gpgcheck: true @@ -100,11 +100,11 @@ until: result is succeeded loop: "{{ _ceph_repo.paths }}" - - name: enable repo from shaman - dev + - name: Enable repo from shaman - dev when: ceph_origin == 'shaman' block: - - name: fetch ceph development repository - uri: + - name: Fetch ceph development repository + ansible.builtin.uri: url: "https://shaman.ceph.com/api/repos/ceph/\ {{ ceph_dev_branch }}/\ @@ -114,8 +114,8 @@ return_content: true register: ceph_dev_yum_repo - - name: configure ceph development repository - copy: + - name: Configure ceph development repository + ansible.builtin.copy: content: "{{ ceph_dev_yum_repo.content }}" dest: /etc/yum.repos.d/ceph-dev.repo owner: root @@ -123,8 +123,8 @@ mode: '0644' backup: true - - name: remove ceph_stable repositories - yum_repository: + - name: Remove ceph_stable repositories + ansible.builtin.yum_repository: name: '{{ item }}' file: ceph_stable state: absent @@ -132,13 +132,13 @@ - ceph_stable - ceph_stable_noarch - - name: enable custom repo + - name: Enable custom repo when: ceph_origin == 'custom' block: - - name: set_fact ceph_custom_repositories - set_fact: + - name: Set_fact ceph_custom_repositories + ansible.builtin.set_fact: ceph_custom_repositories: - - name: ceph_custom + - name: Ceph_custom description: Ceph custom repo gpgcheck: "{{ 'yes' if custom_repo_gpgkey is defined else 'no' }}" state: "{{ custom_repo_state | default('present') }}" @@ -149,8 +149,8 @@ priority: '2' when: ceph_custom_repositories is undefined - - name: setup custom repositories - yum_repository: + - name: Setup custom repositories + ansible.builtin.yum_repository: name: "{{ item.name }}" description: "{{ item.description }}" state: "{{ item.state | default(omit) }}" @@ -164,43 +164,43 @@ until: result is succeeded loop: "{{ ceph_custom_repositories }}" - - name: install epel-release + - name: Install epel-release when: ansible_facts['distribution'] != 'RedHat' block: - - name: enable required CentOS repository for epel - command: dnf config-manager --set-enabled "{{ 'powertools' if ansible_facts['distribution_major_version'] == '8' else 'crb' }}" + - name: Enable required CentOS repository for epel + ansible.builtin.command: dnf config-manager --set-enabled "{{ 'powertools' if ansible_facts['distribution_major_version'] == '8' else 'crb' }}" changed_when: false - - name: install package - package: + - name: Install package + ansible.builtin.package: name: epel-release state: present register: result until: result is succeeded - - name: remove remaining local services ceph packages - dnf: + - name: Remove remaining local services ceph packages + ansible.builtin.dnf: name: "{{ packages_to_uninstall }}" state: absent autoremove: false - - name: install ceph-common on rhel - package: + - name: Install ceph-common on rhel + ansible.builtin.package: name: ceph-common state: "{{ (upgrade_ceph_packages | bool) | ternary('latest', 'present') }}" register: result until: result is succeeded - - name: install prerequisites packages on servers - package: + - name: Install prerequisites packages on servers + ansible.builtin.package: name: "{{ ceph_pkgs + infra_pkgs }}" state: "{{ (upgrade_ceph_packages | bool) | ternary('latest', 'present') }}" register: result until: result is succeeded when: group_names != [client_group] - - name: install prerequisites packages on clients - package: + - name: Install prerequisites packages on clients + ansible.builtin.package: name: "{{ ceph_client_pkgs }}" state: "{{ (upgrade_ceph_packages | bool) | ternary('latest', 'present') }}" register: result @@ -208,8 +208,8 @@ when: group_names == [client_group] - - name: ensure chronyd is running - service: + - name: Ensure chronyd is running + ansible.builtin.service: name: chronyd state: started enabled: true @@ -217,76 +217,76 @@ - name: Ubuntu related tasks when: ansible_facts['distribution'] == 'Ubuntu' block: - - name: enable repo from download.ceph.com + - name: Enable repo from download.ceph.com block: - - name: prevent ceph certificate error - apt: + - name: Prevent ceph certificate error + ansible.builtin.apt: name: ca-certificates state: latest update_cache: true register: result until: result is succeeded - - name: configure ceph community repository stable key - apt_key: + - name: Configure ceph community repository stable key + ansible.builtin.apt_key: url: "{{ ceph_stable_key }}" state: present - - name: configure Ceph community repository + - name: Configure Ceph community repository when: ceph_origin == 'community' - apt_repository: + ansible.builtin.apt_repository: repo: "deb https://download.ceph.com/debian-{{ ceph_release }}/ {{ ansible_facts['distribution_release'] }} main" state: present filename: ceph update_cache: false - - name: configure Ceph testing repository + - name: Configure Ceph testing repository when: ceph_origin == 'testing' - apt_repository: + ansible.builtin.apt_repository: repo: "deb https://download.ceph.com/debian-testing/ {{ ansible_facts['distribution_release'] }} main" state: present filename: ceph update_cache: false - - name: configure Ceph custom repositories + - name: Configure Ceph custom repositories when: ceph_origin == 'custom' - apt_repository: + ansible.builtin.apt_repository: repo: "deb {{ item.baseurl }}/ {{ ansible_facts['distribution_release'] }} {{ item.components }}" state: "{{ item.state | default(omit) }}" filename: ceph_custom update_cache: false loop: "{{ ceph_custom_repositories }}" - - name: install prerequisites packages - apt: + - name: Install prerequisites packages + ansible.builtin.apt: name: "{{ ['python3','chrony'] + ceph_pkgs }}" state: "{{ (upgrade_ceph_packages | bool) | ternary('latest', 'present') }}" update_cache: true register: result until: result is succeeded - - name: ensure chronyd is running - service: + - name: Ensure chronyd is running + ansible.builtin.service: name: chronyd state: started enabled: true - - name: install container engine + - name: Install container engine block: - - name: install podman + - name: Install podman when: ansible_facts['distribution_version'] is version('20.10', '>=') - apt: + ansible.builtin.apt: name: podman state: present update_cache: true register: result until: result is succeeded - - name: install docker + - name: Install docker when: ansible_facts['distribution_version'] is version('20.10', '<') block: - - name: uninstall old version packages - apt: + - name: Uninstall old version packages + ansible.builtin.apt: name: "{{ item }}" state: absent loop: @@ -296,20 +296,20 @@ - containerd - runc - - name: configure docker repository key - apt_key: + - name: Configure docker repository key + ansible.builtin.apt_key: url: "https://download.docker.com/linux/ubuntu/gpg" state: present - - name: setup docker repository - apt_repository: + - name: Setup docker repository + ansible.builtin.apt_repository: repo: "deb https://download.docker.com/linux/ubuntu {{ ansible_facts['distribution_release'] }} stable" state: present filename: docker update_cache: false - - name: install docker - apt: + - name: Install docker + ansible.builtin.apt: name: "{{ item }}" state: present update_cache: true @@ -320,6 +320,6 @@ - docker-ce-cli - containerd.io -- name: set insecure container registry in /etc/containers/registries.conf +- name: Set insecure container registry in /etc/containers/registries.conf ansible.builtin.import_playbook: cephadm-set-container-insecure-registries.yml when: set_insecure_registries | default(false) | bool diff --git a/cephadm-purge-cluster.yml b/cephadm-purge-cluster.yml index de3c411..2469fa9 100644 --- a/cephadm-purge-cluster.yml +++ b/cephadm-purge-cluster.yml @@ -12,7 +12,7 @@ # ansible-playbook -i cephadm-purge-cluster.yml -e fsid= -e infra_pkgs_purge= -- name: check local prerequisites are in place +- name: Check local prerequisites are in place hosts: all gather_facts: false become: true @@ -22,70 +22,70 @@ - run_once: true delegate_to: localhost block: - - name: fail if fsid was not provided - fail: + - name: Fail if fsid was not provided + ansible.builtin.fail: msg: | You must provide the cluster fsid to be purged. e.g. ansible-playbook -i cephadm-purge-cluster.yml -e fsid= when: fsid is undefined - - name: fail if admin group doesn't exist or is empty - fail: + - name: Fail if admin group doesn't exist or is empty + ansible.builtin.fail: msg: | You must define a group [admin] in your inventory and add a node where admin keyring is present at /etc/ceph/ceph.client.admin.keyring when: "'admin' not in groups or groups['admin'] | length < 1" -- name: check keyring is present on the admin host +- name: Check keyring is present on the admin host hosts: admin[0] gather_facts: false any_errors_fatal: true tasks: - - name: check /etc/ceph/ceph.client.admin.keyring - stat: + - name: Check /etc/ceph/ceph.client.admin.keyring + ansible.builtin.stat: path: /etc/ceph/ceph.client.admin.keyring register: admin_keyring_stat - - name: fail if /etc/ceph/ceph.client.admin.keyring is not present - fail: + - name: Fail if /etc/ceph/ceph.client.admin.keyring is not present + ansible.builtin.fail: msg: > You must have /etc/ceph/ceph.client.admin.keyring present on {{ inventory_hostname }} when: not admin_keyring_stat.stat.exists | bool -- name: check cluster hosts have cephadm and the required fsid {{ fsid }} +- name: Check cluster hosts have cephadm and the required fsid {{ fsid }} hosts: all,!{{ client_group }} gather_facts: false become: true any_errors_fatal: true tasks: - - name: import_role ceph_defaults - import_role: + - name: Import_role ceph_defaults + ansible.builtin.import_role: name: ceph_defaults - - name: check cephadm binary is available - command: which cephadm + - name: Check cephadm binary is available + ansible.builtin.command: which cephadm register: cephadm_exists changed_when: false failed_when: false - - name: fail if cephadm is not available - fail: + - name: Fail if cephadm is not available + ansible.builtin.fail: msg: | The cephadm binary is missing on {{ inventory_hostname }}. To purge the cluster you must have cephadm installed on ALL ceph hosts. Install manually or use the preflight playbook. when: - cephadm_exists.rc - - name: check fsid directory given is valid across the cluster - stat: + - name: Check fsid directory given is valid across the cluster + ansible.builtin.stat: path: /var/lib/ceph/{{ fsid }} register: fsid_exists - - name: fail if the fsid directory is missing - fail: + - name: Fail if the fsid directory is missing + ansible.builtin.fail: msg: | The fsid directory '/var/lib/ceph/{{ fsid }}' can not be found on {{ inventory_hostname }} Is the fsid correct? @@ -93,13 +93,13 @@ - not fsid_exists.stat.exists | bool -- name: confirm whether user really wants to purge the cluster +- name: Confirm whether user really wants to purge the cluster hosts: all gather_facts: false become: false vars_prompt: - - name: ireallymeanit + - name: Ireallymeanit prompt: | Are you sure you want to purge the cluster with fsid={{ fsid }} ? @@ -107,10 +107,10 @@ private: no tasks: - - name: exit playbook, if user did not mean to purge cluster + - name: Exit playbook, if user did not mean to purge cluster run_once: true delegate_to: localhost - fail: + ansible.builtin.fail: msg: | Exiting cephadm-purge-cluster playbook, cluster was NOT purged. To purge the cluster, either say 'yes' at the prompt or use `-e ireallymeanit=yes` @@ -118,13 +118,13 @@ when: ireallymeanit != 'yes' -- name: disable cephadm operations +- name: Disable cephadm operations hosts: "admin[0]" become: true gather_facts: false tasks: - - name: disable cephadm - command: "cephadm shell --fsid {{ fsid }} -- ceph mgr module disable cephadm" + - name: Disable cephadm + ansible.builtin.command: "cephadm shell --fsid {{ fsid }} -- ceph mgr module disable cephadm" changed_when: false @@ -134,35 +134,35 @@ gather_facts: false any_errors_fatal: true tasks: - - name: import_role ceph_defaults - import_role: + - name: Import_role ceph_defaults + ansible.builtin.import_role: name: ceph_defaults - - name: purge ceph daemons - command: "cephadm rm-cluster --force --zap-osds --fsid {{ fsid }}" + - name: Purge ceph daemons + ansible.builtin.command: "cephadm rm-cluster --force --zap-osds --fsid {{ fsid }}" changed_when: false -- name: remove ceph packages +- name: Remove ceph packages hosts: all become: true gather_facts: false any_errors_fatal: true tasks: - - name: import_role ceph_defaults - import_role: + - name: Import_role ceph_defaults + ansible.builtin.import_role: name: ceph_defaults - - name: remove ceph packages on ceph nodes - package: + - name: Remove ceph packages on ceph nodes + ansible.builtin.package: name: "{{ ceph_pkgs | union(infra_pkgs | intersect(infra_pkgs_purge | default([]))) }}" state: absent register: result until: result is succeeded when: group_names != [client_group] - - name: remove ceph packages on client nodes - package: + - name: Remove ceph packages on client nodes + ansible.builtin.package: name: ceph-common state: absent register: result diff --git a/cephadm-set-container-insecure-registries.yml b/cephadm-set-container-insecure-registries.yml index 1d8b22b..5bd26ca 100644 --- a/cephadm-set-container-insecure-registries.yml +++ b/cephadm-set-container-insecure-registries.yml @@ -11,20 +11,20 @@ # # ansible-playbook -i hosts cephadm-set-container-insecure-registries.yml -e insecure_registry=localhost:5000 -- name: variables validations +- name: Variables validations ansible.builtin.import_playbook: validate/insecure-registries.yml - hosts: all become: true gather_facts: false tasks: - - name: fail if insecure_registry is undefined - fail: + - name: Fail if insecure_registry is undefined + ansible.builtin.fail: msg: "'insecure_registry' is undefined" when: insecure_registry is undefined - - name: add registry as insecure registry in registries.conf - blockinfile: + - name: Add registry as insecure registry in registries.conf + ansible.builtin.blockinfile: path: "{{ registries_conf_path | default('/etc/containers/registries.conf') }}" state: present marker: "# {mark} cephadm-ansible managed : {{ insecure_registry }}" diff --git a/library/__init__.py b/library/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/library/ceph_config.py b/library/ceph_config.py deleted file mode 100644 index d7a52b7..0000000 --- a/library/ceph_config.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright Red Hat -# SPDX-License-Identifier: Apache-2.0 -# Author: Guillaume Abrioux - -from __future__ import absolute_import, division, print_function -from typing import Any, Dict, List, Tuple, Union -__metaclass__ = type - -from ansible.module_utils.basic import AnsibleModule # type: ignore -try: - from ansible.module_utils.ceph_common import exit_module, build_base_cmd_shell, fatal # type: ignore -except ImportError: - from module_utils.ceph_common import exit_module, build_base_cmd_shell, fatal # type: ignore - -import datetime -import json - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community' -} - -DOCUMENTATION = ''' ---- -module: ceph_config -short_description: set ceph config -version_added: "2.10" -description: - - Set Ceph config options. -options: - fsid: - description: - - the fsid of the Ceph cluster to interact with. - required: false - image: - description: - - The Ceph container image to use. - required: false - action: - description: - - whether to get or set the parameter specified in 'option' - required: false - default: 'set' - who: - description: - - which daemon the configuration should be set to - required: true - option: - description: - - name of the parameter to be set - required: true - value: - description: - - value of the parameter - required: true if action is 'set' - -author: - - Guillaume Abrioux -''' - -EXAMPLES = ''' -- name: set osd_memory_target for osd.0 - ceph_config: - action: set - who: osd.0 - option: osd_memory_target - value: 5368709120 - -- name: set osd_memory_target for host ceph-osd-02 - ceph_config: - action: set - who: osd/host:ceph-osd-02 - option: osd_memory_target - value: 5368709120 - -- name: get osd_pool_default_size value - ceph_config: - action: get - who: global - option: osd_pool_default_size - value: 1 -''' - -RETURN = '''# ''' - - -def set_option(module: "AnsibleModule", - who: str, - option: str, - value: str) -> Tuple[int, List[str], str, str]: - cmd = build_base_cmd_shell(module) - cmd.extend(['ceph', 'config', 'set', who, option, value]) - - rc, out, err = module.run_command(cmd) - - return rc, cmd, out.strip(), err - - -def get_config_dump(module: "AnsibleModule") -> Tuple[int, List[str], str, str]: - cmd = build_base_cmd_shell(module) - cmd.extend(['ceph', 'config', 'dump', '--format', 'json']) - rc, out, err = module.run_command(cmd) - if rc: - fatal(message=f"Can't get current configuration via `ceph config dump`.Error:\n{err}", module=module) - out = out.strip() - return rc, cmd, out, err - - -def get_current_value(who: str, option: str, config_dump: List[Dict[str, Any]]) -> Union[str, None]: - for config in config_dump: - if config['section'] == who and config['name'] == option: - return config['value'] - return None - - -def main() -> None: - module = AnsibleModule( - argument_spec=dict( - who=dict(type='str', required=True), - action=dict(type='str', required=False, choices=['get', 'set'], default='set'), - option=dict(type='str', required=True), - value=dict(type='str', required=False), - fsid=dict(type='str', required=False), - image=dict(type='str', required=False) - ), - supports_check_mode=True, - required_if=[['action', 'set', ['value']]] - ) - - # Gather module parameters in variables - who = module.params.get('who') - option = module.params.get('option') - value = module.params.get('value') - action = module.params.get('action') - - if module.check_mode: - module.exit_json( - changed=False, - stdout='', - cmd=[], - stderr='', - rc=0, - start='', - end='', - delta='', - ) - - startd = datetime.datetime.now() - changed = False - - rc, cmd, out, err = get_config_dump(module) - config_dump = json.loads(out) - current_value = get_current_value(who, option, config_dump) - - if action == 'set': - if value.lower() == current_value: - out = 'who={} option={} value={} already set. Skipping.'.format(who, option, value) - else: - rc, cmd, out, err = set_option(module, who, option, value) - changed = True - else: - if current_value is None: - out = '' - err = 'No value found for who={} option={}'.format(who, option) - else: - out = current_value - - exit_module(module=module, out=out, rc=rc, - cmd=cmd, err=err, startd=startd, - changed=changed) - - -if __name__ == '__main__': - main() diff --git a/library/ceph_orch_apply.py b/library/ceph_orch_apply.py deleted file mode 100644 index 2b40be6..0000000 --- a/library/ceph_orch_apply.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright Red Hat -# SPDX-License-Identifier: Apache-2.0 -# Author: Guillaume Abrioux -# -# 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 -from typing import List, Tuple, Dict -__metaclass__ = type - -import datetime -import yaml - -from ansible.module_utils.basic import AnsibleModule # type: ignore -try: - from ansible.module_utils.ceph_common import exit_module, build_base_cmd_orch # type: ignore -except ImportError: - from module_utils.ceph_common import exit_module, build_base_cmd_orch - - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community' -} - -DOCUMENTATION = ''' ---- -module: ceph_orch_apply -short_description: apply service spec -version_added: "2.9" -description: - - apply a service spec -options: - fsid: - description: - - the fsid of the Ceph cluster to interact with. - required: false - image: - description: - - The Ceph container image to use. - required: false - spec: - description: - - The service spec to apply - required: true -author: - - Guillaume Abrioux -''' - -EXAMPLES = ''' -- name: apply osd spec - ceph_orch_apply: - spec: | - service_type: osd - service_id: osd - placement: - label: osds - spec: - data_devices: - all: true -''' - - -def parse_spec(spec: str) -> Dict: - """ parse spec string to yaml """ - yaml_spec = yaml.safe_load(spec) - return yaml_spec - - -def retrieve_current_spec(module: AnsibleModule, expected_spec: Dict) -> Dict: - """ retrieve current config of the service """ - service: str = expected_spec["service_type"] - cmd = build_base_cmd_orch(module) - cmd.extend(['ls', service, '--format=yaml']) - out = module.run_command(cmd) - if isinstance(out, str): - # if there is no existing service, cephadm returns the string 'No services reported' - return {} - else: - return yaml.safe_load(out[1]) - - -def apply_spec(module: "AnsibleModule", - data: str) -> Tuple[int, List[str], str, str]: - cmd = build_base_cmd_orch(module) - cmd.extend(['apply', '-i', '-']) - rc, out, err = module.run_command(cmd, data=data) - - if rc: - raise RuntimeError(err) - - return rc, cmd, out, err - - -def change_required(current: Dict, expected: Dict) -> bool: - """ checks if the current config differs from what is expected """ - if not current: - return True - - for key, value in expected.items(): - if key in current: - if current[key] != value: - return True - continue - else: - return True - return False - - -def run_module() -> None: - - module_args = dict( - spec=dict(type='str', required=True), - fsid=dict(type='str', required=False), - docker=dict(type=bool, - required=False, - default=False), - image=dict(type='str', required=False) - ) - - module = AnsibleModule( - argument_spec=module_args, - supports_check_mode=True - ) - - startd = datetime.datetime.now() - spec = module.params.get('spec') - - if module.check_mode: - exit_module( - module=module, - out='', - rc=0, - cmd=[], - err='', - startd=startd, - changed=False - ) - - # Idempotency check - expected = parse_spec(module.params.get('spec')) - current_spec = retrieve_current_spec(module, expected) - - if change_required(current_spec, expected): - rc, cmd, out, err = apply_spec(module, spec) - changed = True - else: - rc = 0 - cmd = [] - out = '' - err = '' - changed = False - - exit_module( - module=module, - out=out, - rc=rc, - cmd=cmd, - err=err, - startd=startd, - changed=changed - ) - - -def main() -> None: - run_module() - - -if __name__ == '__main__': - main() diff --git a/library/ceph_orch_daemon.py b/library/ceph_orch_daemon.py deleted file mode 100644 index 303d193..0000000 --- a/library/ceph_orch_daemon.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright Red Hat -# SPDX-License-Identifier: Apache-2.0 -# Author: Guillaume Abrioux - -from __future__ import absolute_import, division, print_function -from typing import List, Tuple -__metaclass__ = type - -from ansible.module_utils.basic import AnsibleModule # type: ignore -try: - from ansible.module_utils.ceph_common import retry, exit_module, build_base_cmd_orch, fatal # type: ignore -except ImportError: - from module_utils.ceph_common import retry, exit_module, build_base_cmd_orch, fatal # type: ignore - -import datetime -import json - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community' -} - -DOCUMENTATION = ''' ---- -module: ceph_orch_daemon -short_description: stop/start daemon -version_added: "2.9" -description: - - Start, stop or restart ceph daemon -options: - fsid: - description: - - the fsid of the Ceph cluster to interact with. - required: false - image: - description: - - The Ceph container image to use. - required: false - state: - description: - - The desired state of the service specified in 'name'. - If 'started', it ensures the service is started. - If 'stopped', it ensures the service is stopped. - If 'restarted', it will restart the service. - required: True - daemon_id: - description: - - The id of the service. - required: true - daemon_type: - description: - - The type of the service. - required: true - -author: - - Guillaume Abrioux -''' - -EXAMPLES = ''' -- name: start osd.0 - ceph_orch_daemon: - state: started - daemon_id: 0 - daemon_type: osd - -- name: stop mon.ceph-node0 - ceph_orch_daemon: - state: stopped - daemon_id: ceph-node0 - daemon_type: mon -''' - -RETURN = '''# ''' - - -def get_current_state(module: "AnsibleModule", - daemon_type: str, - daemon_id: str) -> Tuple[int, List[str], str, str]: - cmd = build_base_cmd_orch(module) - cmd.extend(['ps', '--daemon_type', - daemon_type, '--daemon_id', - daemon_id, '--format', 'json', - '--refresh']) - rc, out, err = module.run_command(cmd) - - return rc, cmd, out, err - - -def update_daemon_status(module: "AnsibleModule", - action: str, - daemon_name: str) -> Tuple[int, List[str], str, str]: - cmd = build_base_cmd_orch(module) - cmd.extend(['daemon', action, daemon_name]) - rc, out, err = module.run_command(cmd) - - return rc, cmd, out, err - - -@retry(RuntimeError) -def validate_updated_status(module: "AnsibleModule", - action: str, - daemon_type: str, - daemon_id: str) -> None: - rc, cmd, out, err = get_current_state(module, daemon_type, daemon_id) - expected_state = 1 if action == 'start' else 0 - if not json.loads(out)[0]['status'] == expected_state: - raise RuntimeError("Status for {}.{} isn't reported as expected.".format(daemon_type, daemon_id)) - - -def main() -> None: - module = AnsibleModule( - argument_spec=dict( - state=dict(type='str', - required=True, - choices=['started', 'stopped', 'restarted']), - daemon_id=dict(type='str', required=True), - daemon_type=dict(type='str', required=True), - docker=dict(type=bool, - required=False, - default=False), - fsid=dict(type='str', required=False), - image=dict(type='str', required=False) - ), - supports_check_mode=True, - ) - - # Gather module parameters in variables - state = module.params.get('state') - daemon_id = module.params.get('daemon_id') - daemon_type = module.params.get('daemon_type') - daemon_name = "{}.{}".format(daemon_type, daemon_id) - - if module.check_mode: - module.exit_json( - changed=False, - stdout='', - cmd=[], - stderr='', - rc=0, - start='', - end='', - delta='', - ) - - startd = datetime.datetime.now() - changed = False - - rc, cmd, out, err = get_current_state(module, daemon_type, daemon_id) - - if rc or not json.loads(out): - if not err: - err = 'osd id {} not found'.format(daemon_id) - fatal("Can't get current status of {}: {}".format(daemon_name, err), module) - - is_running = json.loads(out)[0]['status'] == 1 - - current_state = 'started' if is_running else 'stopped' - action = 'start' if state == 'started' else 'stop' - if state == current_state: - out = "{} is already {}, skipping.".format(daemon_name, state) - else: - rc, cmd, out, err = update_daemon_status(module, action, daemon_name) - validate_updated_status(module, action, daemon_type, daemon_id) - changed = True - - if state == 'restarted': - action = 'restart' - changed = True - rc, cmd, out, err = update_daemon_status(module, action, daemon_name) - - if rc: - fatal("Can't {} {}: {}".format(action, daemon_name, err)) - - exit_module(module=module, out=out, rc=rc, - cmd=cmd, err=err, startd=startd, - changed=changed) - - -if __name__ == '__main__': - main() diff --git a/library/ceph_orch_host.py b/library/ceph_orch_host.py deleted file mode 100644 index d7b58cb..0000000 --- a/library/ceph_orch_host.py +++ /dev/null @@ -1,248 +0,0 @@ -# Copyright Red Hat -# SPDX-License-Identifier: Apache-2.0 -# Author: Guillaume Abrioux -# -# 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 -from typing import Optional, List, Tuple -__metaclass__ = type - -from ansible.module_utils.basic import AnsibleModule # type: ignore -try: - from ansible.module_utils.ceph_common import exit_module, build_base_cmd_orch # type: ignore -except ImportError: - from module_utils.ceph_common import exit_module, build_base_cmd_orch -import datetime -import json - - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community' -} - -DOCUMENTATION = ''' ---- -module: ceph_orch_host -short_description: add/remove hosts -version_added: "2.9" -description: - - Add or remove hosts from ceph orchestration. -options: - fsid: - description: - - the fsid of the Ceph cluster to interact with. - required: false - name: - description: - - name of the host - required: true - image: - description: - - The Ceph container image to use. - required: false - address: - description: - - address of the host - required: true when state is present - set_admin_label: - description: - - enforce '_admin' label on the host specified - in 'name' - required: false - default: false - labels: - description: - - list of labels to apply on the host - required: false - default: [] - state: - description: - - if set to 'present', it will ensure the name specified - in 'name' will be present. - - if set to 'absent', it will remove the host specified in - 'name'. - - if set to 'drain', it will schedule to remove all daemons - from the host specified in 'name'. - required: false - default: present -author: - - Guillaume Abrioux -''' - -EXAMPLES = ''' -- name: add a host - ceph_orch_host: - name: my-node-01 - address: 10.10.10.101 - -- name: add a host - ceph_orch_host: - name: my-node-02 - labels: - - mon - - mgr - - grp013 - address: 10.10.10.102 - -- name: remove a host - ceph_orch_host: - name: my-node-01 - state: absent -''' - - -def get_current_state(module: "AnsibleModule") -> Tuple[int, List[str], str, str]: - cmd = build_base_cmd_orch(module) - cmd.extend(['host', 'ls', '--format', 'json']) - rc, out, err = module.run_command(cmd) - - if rc: - raise RuntimeError(err) - - return rc, cmd, out, err - - -def update_label(module: "AnsibleModule", - action: str, - host: str, - label: str = '') -> Tuple[int, List[str], str, str]: - cmd = build_base_cmd_orch(module) - cmd.extend(['host', 'label', action, - host, label]) - rc, out, err = module.run_command(cmd) - - if rc: - raise RuntimeError(err) - - return rc, cmd, out, err - - -def update_host(module: "AnsibleModule", - action: str, - name: str, - address: str = '', - labels: Optional[List[str]] = None) -> Tuple[int, List[str], str, str]: - cmd = build_base_cmd_orch(module) - cmd.extend(['host', action, name]) - if action == 'add' and address: - cmd.append(address) - if labels: - cmd.extend(["--labels", ",".join(labels)]) - rc, out, err = module.run_command(cmd) - - if rc: - raise RuntimeError(err) - - return rc, cmd, out, err - - -def main() -> None: - module = AnsibleModule( - argument_spec=dict( - name=dict(type='str', required=True), - address=dict(type='str', required=False), - set_admin_label=dict(type=bool, required=False, default=False), - labels=dict(type='list', required=False, default=[]), - state=dict(type='str', - required=False, - choices=['present', 'absent', 'drain'], - default='present'), - docker=dict(type=bool, - required=False, - default=False), - fsid=dict(type='str', required=False), - image=dict(type='str', required=False) - ), - supports_check_mode=True - ) - - name = module.params.get('name') - address = module.params.get('address') - set_admin_label = module.params.get('set_admin_label') - labels = module.params.get('labels') - state = module.params.get('state') - if state == 'absent': - state = 'rm' - - startd = datetime.datetime.now() - changed = False - - cmd = ['cephadm'] - - if module.check_mode: - exit_module( - module=module, - out='', - rc=0, - cmd=[], - err='', - startd=startd, - changed=False - ) - - rc, cmd, out, err = get_current_state(module) - current_state = json.loads(out) - current_names = [name['hostname'] for name in current_state] - - if state == 'present': - if set_admin_label and '_admin' not in labels: - labels.append('_admin') - if name in current_names: - current_state_host = [host for host in current_state if host['hostname'] == name][0] - differences = set(labels) ^ set(current_state_host['labels']) - if differences: - _out = [] - for diff in differences: - if diff in current_state_host['labels']: - action = 'rm' - else: - action = 'add' - rc, cmd, out, err = update_label(module, action, current_state_host['hostname'], diff) - _out.append(diff) - - exit_module(rc=rc, - startd=startd, - module=module, - cmd=cmd, - out=f"Label(s) updated: {','.join(_out)}", - err=err, - changed=True) - out = '{} is already present, skipping.'.format(name) - else: - rc, cmd, out, err = update_host(module, 'add', name, address, labels) - if not rc: - changed = True - - if state in ['rm', 'drain']: - if name not in current_names: - out = '{} is not present, skipping.'.format(name) - else: - rc, cmd, out, err = update_host(module, state, name) - changed = True - - exit_module( - module=module, - out=out, - rc=rc, - cmd=cmd, - err=err, - startd=startd, - changed=changed - ) - - -if __name__ == '__main__': - main() diff --git a/library/cephadm_bootstrap.py b/library/cephadm_bootstrap.py deleted file mode 100644 index 9b4b2d0..0000000 --- a/library/cephadm_bootstrap.py +++ /dev/null @@ -1,371 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright Red Hat -# SPDX-License-Identifier: Apache-2.0 -# -# 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 - -from ansible.module_utils.basic import AnsibleModule # type: ignore -try: - from ansible.module_utils.ceph_common import exit_module # type: ignore -except ImportError: - from module_utils.ceph_common import exit_module -import datetime -import os - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community' -} - -DOCUMENTATION = ''' ---- -module: cephadm_bootstrap -short_description: Bootstrap a Ceph cluster via cephadm -version_added: "2.8" -description: - - Bootstrap a Ceph cluster via cephadm -options: - mon_ip: - description: - - Ceph monitor IP address. - required: true - image: - description: - - Ceph container image. - required: false - docker: - description: - - Use docker instead of podman. - required: false - fsid: - description: - - Ceph FSID. - required: false - pull: - description: - - Pull the Ceph container image. - required: false - default: true - dashboard: - description: - - Deploy the Ceph dashboard. - required: false - default: true - dashboard_user: - description: - - Ceph dashboard user. - required: false - dashboard_password: - description: - - Ceph dashboard password. - required: false - monitoring: - description: - - Deploy the monitoring stack. - required: false - default: true - firewalld: - description: - - Manage firewall rules with firewalld. - required: false - default: true - allow_overwrite: - description: - - allow overwrite of existing –output-* config/keyring/ssh files. - required: false - default: false - registry_url: - description: - - URL for custom registry. - required: false - registry_username: - description: - - Username for custom registry. - required: false - registry_password: - description: - - Password for custom registry. - required: false - registry_json: - description: - - JSON file with custom registry login info (URL, - username, password). - required: false - ssh_user: - description: - - SSH user used for cephadm ssh to the hosts. - required: false - ssh_config: - description: - - SSH config file path for cephadm ssh client. - required: false - allow_fqdn_hostname: - description: - - Allow hostname that is fully-qualified. - required: false - default: false - cluster_network: - description: - - subnet to use for cluster replication, recovery and heartbeats. - required: false -author: - - Dimitri Savineau - - Teoman ONAY -''' - -EXAMPLES = ''' -- name: bootstrap a cluster via cephadm (with default values) - cephadm_bootstrap: - mon_ip: 192.168.42.1 - -- name: bootstrap a cluster via cephadm (with custom values) - cephadm_bootstrap: - mon_ip: 192.168.42.1 - fsid: 3c9ba63a-c7df-4476-a1e7-317dfc711f82 - image: quay.ceph.io/ceph/daemon-base:latest-main-devel - dashboard: false - monitoring: false - firewalld: false - -- name: bootstrap a cluster via cephadm with custom image via env var - cephadm_bootstrap: - mon_ip: 192.168.42.1 - environment: - CEPHADM_IMAGE: quay.ceph.io/ceph/daemon-base:latest-main-devel -''' - -RETURN = '''# ''' - - -def run_module() -> None: - - backward_compat = dict( - dashboard=dict(type='bool', required=False, remove_in_version='4.0.0'), - firewalld=dict(type='bool', required=False, remove_in_version='4.0.0'), - monitoring=dict(type='bool', - required=False, - remove_in_version='4.0.0'), - pull=dict(type='bool', required=False, remove_in_version='4.0.0'), - dashboard_password=dict(type='str', - required=False, - no_log=True), - dashboard_user=dict(type='str', required=False), - ) - - cephadm_params = dict( - docker=dict(type='bool', required=False, default=False), - image=dict(type='str', required=False), - ) - - cephadm_bootstrap_downstream_only = dict( - call_home_config=dict(type='str', required=False), - call_home_icn=dict(type='str', required=False), - ceph_call_home_contact_email=dict(type='str', required=False), - ceph_call_home_contact_first_name=dict(type='str', required=False), - ceph_call_home_contact_last_name=dict(type='str', required=False), - ceph_call_home_contact_phone=dict(type='str', required=False), - ceph_call_home_country_code=dict(type='str', required=False), - deploy_cephadm_agent=dict(type='bool', required=False), - enable_ibm_call_home=dict(type='bool', required=False), - enable_storage_insights=dict(type='bool', required=False), - storage_insights_config=dict(type='str', required=False), - storage_insights_tenant_id=dict(type='str', required=False), - ) - - cephadm_bootstrap_params = dict( - allow_fqdn_hostname=dict(type='bool', required=False, default=False), - allow_mismatched_release=dict(type='bool', required=False), - allow_overwrite=dict(type='bool', required=False, default=False), - apply_spec=dict(type='str', required=False), - cluster_network=dict(type='str', required=False), - config=dict(type='str', required=False), - dashboard_crt=dict(type='str', required=False), - dashboard_key=dict(type='str', required=False), - dashboard_password_noupdate=dict(type='bool', required=False), - fsid=dict(type='str', required=False), - initial_dashboard_password=dict(type='str', - required=False, - no_log=True), - initial_dashboard_user=dict(type='str', required=False), - log_to_file=dict(type='bool', required=False), - mgr_id=dict(type='str', required=False), - mon_addrv=dict(type='str', required=False), - mon_id=dict(type='str', required=False), - mon_ip=dict(type='str', required=False), - no_cleanup_on_failure=dict(type='bool', required=False), - no_minimize_config=dict(type='bool', required=False), - orphan_initial_daemons=dict(type='bool', required=False), - output_config=dict(type='str', required=False), - output_dir=dict(type='str', required=False), - output_keyring=dict(type='str', required=False), - output_pub_ssh_key=dict(type='str', required=False), - registry_json=dict(type='str', required=False), - registry_password=dict(type='str', required=False, no_log=True), - registry_url=dict(type='str', required=False), - registry_username=dict(type='str', required=False), - shared_ceph_folder=dict(type='str', required=False), - single_host_defaults=dict(type='bool', required=False), - skip_admin_label=dict(type='bool', required=False), - skip_dashboard=dict(type='bool', required=False, default=False), - skip_firewalld=dict(type='bool', required=False, default=False), - skip_monitoring_stack=dict(type='bool', required=False, default=False), - skip_mon_network=dict(type='bool', required=False), - skip_ping_check=dict(type='bool', required=False), - skip_prepare_host=dict(type='bool', required=False), - skip_pull=dict(type='bool', required=False), - skip_ssh=dict(type='bool', required=False), - ssh_config=dict(type='str', required=False), - ssh_private_key=dict(type='str', required=False), - ssh_public_key=dict(type='str', required=False), - ssh_signed_cert=dict(type='str', required=False), - ssh_user=dict(type='str', required=False), - ssl_dashboard_port=dict(type='str', required=False), - with_centralized_logging=dict(type='bool', required=False), - **cephadm_bootstrap_downstream_only, - ) - - module = AnsibleModule( - argument_spec={**cephadm_params, - **cephadm_bootstrap_params, - **backward_compat}, - supports_check_mode=True, - mutually_exclusive=[ - ('registry_json', 'registry_url'), - ('registry_json', 'registry_username'), - ('registry_json', 'registry_password'), - ('mon_addrv', 'mon_ip'), - ], - required_together=[ - ('registry_url', 'registry_username', 'registry_password'), - ('initial_dashboard_user', 'initial_dashboard_password'), - ], - required_one_of=[('mon_ip', 'mon_addrv'), - ], - ) - - fsid = module.params.get('fsid') - allow_overwrite = module.params.get('allow_overwrite') - - startd = datetime.datetime.now() - - cmd: list[str] = [] - data_dir = '/var/lib/ceph' - ceph_conf = 'ceph.conf' - ceph_keyring = 'ceph.client.admin.keyring' - ceph_pubkey = 'ceph.pub' - - def extend_append(command: str, params: dict) -> list: - cmd: list[str] = [] - cmd.append(command) - for k in params: - if module.params.get(k): - if params[k]['type'] == 'bool': - cmd.append('--' + k.replace('_', '-')) - else: - cmd.extend(['--' + k.replace('_', '-'), - module.params.get(k)]) - return cmd - - if fsid: - if os.path.exists(os.path.join(data_dir, fsid)): - out = f'A cluster with fsid {fsid} is already deployed.' - exit_module( - rc=0, - startd=startd, - module=module, - cmd=cmd, - out=out, - changed=False - ) - - for f in [ceph_conf, - ceph_keyring, - ceph_pubkey]: - if not allow_overwrite: - path: str = os.path.join(data_dir, f) - if os.path.exists(path): - out = f'{path} already exists, skipping.' - exit_module( - rc=0, - startd=startd, - module=module, - cmd=cmd, - out=out, - changed=False - ) - - # Build cephadm with parameters - cmd = extend_append('cephadm', cephadm_params) - # Extends with boostrap parameters - cmd.extend(extend_append('bootstrap', cephadm_bootstrap_params)) - - # keep backward compatibility - for k in backward_compat: - result = module.params.get(k) - if result is not None: - if k == 'pull' and not result: - if '--skip-pull' not in cmd: - cmd.append('--skip-pull') - elif k == 'monitoring' and not result: - if '--skip-monitoring-stack' not in cmd: - cmd.append('--skip-monitoring-stack') - elif k == 'firewalld' and not result: - if '--skip-firewalld' not in cmd: - cmd.append('--skip-firewalld') - elif k == 'dashboard': - if result: - if 'dashboard-user' not in cmd: - cmd.extend(['--dashboard-user', - module.params.get('dashboard_user'), - '--dashboard-password', - module.params.get('dashboard_password'), - ]) - else: - if '--skip-dashboard' not in cmd: - cmd.append('--skip-dashboard') - - if module.check_mode: - exit_module( - module=module, - out='', - rc=0, - cmd=cmd, - err='', - startd=startd, - changed=False - ) - else: - rc, out, err = module.run_command(cmd) - exit_module( - module=module, - out=out, - rc=rc, - cmd=cmd, - err=err, - startd=startd, - changed=True - ) - - -def main() -> None: - run_module() - - -if __name__ == '__main__': - main() diff --git a/library/cephadm_registry_login.py b/library/cephadm_registry_login.py deleted file mode 100644 index 2f8be0f..0000000 --- a/library/cephadm_registry_login.py +++ /dev/null @@ -1,219 +0,0 @@ -# Copyright Red Hat -# SPDX-License-Identifier: Apache-2.0 -# Author: Guillaume Abrioux -# -# 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 - -from ansible.module_utils.basic import AnsibleModule # type: ignore -from typing import List, Tuple -try: - from ansible.module_utils.ceph_common import exit_module, build_base_cmd, fatal # type: ignore -except ImportError: - from module_utils.ceph_common import exit_module, build_base_cmd, fatal -import datetime - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community' -} - -DOCUMENTATION = ''' ---- -module: cephadm_registry_login -short_description: Log in to container registry -version_added: "2.9" -description: - - Call cephadm registry-login command for logging in to container registry -options: - state: - description: - - log in or log out from the registry. - default: login - required: false - docker: - description: - - Use docker instead of podman. - required: false - registry_url: - description: - - The url of the registry - required: true - registry_username: - description: - - The username to log in - required: true when state is 'login' - registry_password: - description: - - The corresponding password to log in. - required: true when state is 'login' - registry_json: - description: - - The path to a json file. This file must be present on remote hosts - prior to running this task. - *not supported yet*. -author: - - Guillaume Abrioux -''' - -EXAMPLES = ''' -- name: log in to quay.io registry - cephadm_registry_login: - registry_url: quay.io - registry_username: my_login - registry_password: my_password - -- name: log out from quay.io registry - cephadm_registry_login: - state: logout - registry_url: quay.io -''' - -RETURN = '''# ''' - - -def build_base_container_cmd(module: "AnsibleModule", action: str = 'login') -> List[str]: - docker = module.params.get('docker') - container_binary = 'podman' - - if docker: - container_binary = 'docker' - - cmd = [container_binary, action] - - return cmd - - -def is_logged(module: "AnsibleModule") -> bool: - registry_url = module.params.get('registry_url') - registry_username = module.params.get('registry_username') - cmd = build_base_container_cmd(module) - - cmd.extend(['--get-login', registry_url]) - - rc, out, err = module.run_command(cmd) - - if not rc and out.strip() == registry_username: - return True - - return False - - -def do_login_or_logout(module: "AnsibleModule", action: str = 'login') -> Tuple[int, List[str], str, str]: - registry_url = module.params.get('registry_url') - registry_username = module.params.get('registry_username') - registry_password = module.params.get('registry_password') - - cmd = build_base_container_cmd(module, action) - if action == 'login': - cmd.extend(['--username', registry_username, '--password-stdin', registry_url]) - else: - cmd.extend([registry_url]) - - rc, out, err = module.run_command(cmd, data=registry_password) - - return rc, cmd, out, err - - -def main() -> None: - module = AnsibleModule( - argument_spec=dict( - state=dict(type='str', required=False, default='login', choices=['login', 'logout']), - docker=dict(type=bool, - required=False, - default=False), - registry_url=dict(type='str', required=True), - registry_username=dict(type='str', required=False), - registry_password=dict(type='str', required=False, no_log=True), - registry_json=dict(type='str', required=False) - ), - supports_check_mode=True, - mutually_exclusive=[ - ('registry_json', 'registry_url'), - ('registry_json', 'registry_username'), - ('registry_json', 'registry_password'), - ], - # Note: the following might be needed when registry_json will be implemented - # required_together=[ - # ('registry_url', 'registry_username', 'registry_password') - # ], - required_if=[ - ['state', 'login', ['registry_username', 'registry_password']], - ['state', 'logout', ['registry_url']] - ] - ) - startd = datetime.datetime.now() - changed = False - cmd = build_base_cmd(module) - cmd.append('registry-login') - - state = module.params.get('state') - registry_url = module.params.get('registry_url') - registry_username = module.params.get('registry_username') - registry_json = module.params.get('registry_json') - - if module.check_mode: - exit_module( - module=module, - out='', - rc=0, - cmd=[], - err='', - startd=startd, - changed=False - ) - if registry_json: - fatal('This feature is not supported yet.', module) - current_status = is_logged(module) - action = None - skip_msg = { - 'login': f'Already logged in to {registry_url} with {registry_username}.', - 'logout': f'Already logged out from {registry_url}.' - } - action_msg = { - 'login': f'Couldn\'t log in to {registry_url} with {registry_username}.', - 'logout': f'Couldn\'t log out from {registry_url}.' - } - - if state == 'login' and not current_status or state == 'logout' and current_status: - action = state - else: - out = skip_msg[state] - rc = 0 - err = '' - cmd = [] - - if action: - rc, cmd, out, err = do_login_or_logout(module, action) - if rc: - msg = f'{action_msg[state]}\nCmd: {cmd}\nErr: {err}' - fatal(msg, module) - else: - changed = True - - exit_module( - module=module, - out=out, - rc=rc, - cmd=cmd, - err=err, - startd=startd, - changed=changed - ) - - -if __name__ == '__main__': - main() diff --git a/module_utils/__init__.py b/module_utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/module_utils/ceph_common.py b/module_utils/ceph_common.py deleted file mode 100644 index cc19df4..0000000 --- a/module_utils/ceph_common.py +++ /dev/null @@ -1,92 +0,0 @@ -import datetime -import time -from typing import TYPE_CHECKING, Any, List, Dict, Callable, Type, TypeVar - -if TYPE_CHECKING: - from ansible.module_utils.basic import AnsibleModule # type: ignore - -ExceptionType = TypeVar('ExceptionType', bound=BaseException) - - -def retry(exceptions: Type[ExceptionType], retries: int = 20, delay: int = 1) -> Callable: - def decorator(f: Callable) -> Callable: - def _retry(*args: Any, **kwargs: Any) -> Callable: - _tries = retries - while _tries > 1: - try: - print("{}".format(_tries)) - return f(*args, **kwargs) - except exceptions: - time.sleep(delay) - _tries -= 1 - print("{} has failed after {} tries".format(f, retries)) - return f(*args, **kwargs) - return _retry - return decorator - - -def build_base_cmd(module: "AnsibleModule") -> List[str]: - cmd = ['cephadm'] - docker = module.params.get('docker') - image = module.params.get('image') - - if docker: - cmd.append('--docker') - if image: - cmd.extend(['--image', image]) - - return cmd - - -def build_base_cmd_shell(module: "AnsibleModule") -> List[str]: - cmd = build_base_cmd(module) - fsid = module.params.get('fsid') - - cmd.append('shell') - - if fsid: - cmd.extend(['--fsid', fsid]) - - return cmd - - -def build_base_cmd_orch(module: "AnsibleModule") -> List[str]: - cmd = build_base_cmd_shell(module) - cmd.extend(['ceph', 'orch']) - - return cmd - - -def exit_module(module: "AnsibleModule", - rc: int, cmd: List[str], - startd: datetime.datetime, - out: str = '', - err: str = '', - changed: bool = False, - diff: Dict[str, str] = dict(before="", after="")) -> None: - 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: str, module: "AnsibleModule") -> None: - ''' - Report a fatal error and exit - ''' - - if module: - module.fail_json(msg=message, rc=1) - else: - raise Exception(message) diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..403e37e --- /dev/null +++ b/requirements.yml @@ -0,0 +1,2 @@ +collections: + - ceph.automation \ No newline at end of file diff --git a/rocksdb-resharding.yml b/rocksdb-resharding.yml index f489f5d..9aac3c7 100644 --- a/rocksdb-resharding.yml +++ b/rocksdb-resharding.yml @@ -22,100 +22,100 @@ # rocksdb_sharding_parameters : the rocksdb sharding parameter to set. Default is 'm(3) p(3,0-12) O(3,0-13) L P'. # docker : bool to be set in order to use docker engine instead. Default is False. -- name: rocksdb-resharding +- name: Rocksdb-resharding hosts: all become: true gather_facts: false tasks: - - name: check prerequisites + - name: Check prerequisites run_once: true delegate_to: localhost block: - - name: fail if osd_id is not defined - fail: + - name: Fail if osd_id is not defined + ansible.builtin.fail: msg: "you must provide 'osd_id' variable" when: osd_id is undefined - - name: fail if admin_node is not defined - fail: + - name: Fail if admin_node is not defined + ansible.builtin.fail: msg: "you must pass 'admin_node' variable" when: admin_node is not defined - - name: fail if osd_id isn't an id - fail: + - name: Fail if osd_id isn't an id + ansible.builtin.fail: msg: "osd_id must be an id" when: not osd_id is regex('^\d+$') - - name: set_fact cephadm_cmd - set_fact: + - name: Set_fact cephadm_cmd + ansible.builtin.set_fact: cephadm_cmd: "cephadm {{ '--docker' if docker | default(False) | bool else '' }} shell ceph" - - name: test connectivity to admin node - ping: + - name: Test connectivity to admin node + ansible.builtin.ping: delegate_to: "{{ admin_node }}" run_once: true - - name: get details about the osd daemon + - name: Get details about the osd daemon delegate_to: "{{ admin_node }}" block: - - name: get cluster fsid - command: "{{ cephadm_cmd }} fsid" + - name: Get cluster fsid + ansible.builtin.command: "{{ cephadm_cmd }} fsid" register: fsid changed_when: false when: fsid is not defined - - name: set_fact fsid - set_fact: + - name: Set_fact fsid + ansible.builtin.set_fact: fsid: "{{ fsid.stdout }}" when: fsid.stdout is defined - - name: get container image currently used by osd container - command: "{{ cephadm_cmd }} orch ps --daemon_type osd --daemon_id {{ osd_id }} --format json" + - name: Get container image currently used by osd container + ansible.builtin.command: "{{ cephadm_cmd }} orch ps --daemon_type osd --daemon_id {{ osd_id }} --format json" changed_when: false register: ceph_orch_ps retries: 120 delay: 1 until: (ceph_orch_ps.stdout | from_json)[0]['status_desc'] == 'running' - - name: set_fact container_image, container_host - set_fact: + - name: Set_fact container_image, container_host + ansible.builtin.set_fact: container_image: "{{ (ceph_orch_ps.stdout | from_json)[0]['container_image_name'] }}" container_host: "{{ (ceph_orch_ps.stdout | from_json)[0]['hostname'] }}" - - name: stop the osd - ceph_orch_daemon: + - name: Stop the osd + ceph.automation.ceph_orch_daemon: fsid: "{{ fsid }}" state: stopped daemon_id: "{{ osd_id }}" daemon_type: osd - - name: set_fact ceph_cmd - set_fact: + - name: Set_fact ceph_cmd + ansible.builtin.set_fact: ceph_bluestore_tool_cmd: "{{ container_binary | default('podman') }} run --rm --privileged --entrypoint=ceph-bluestore-tool -v /var/run/ceph/{{ fsid }}:/var/run/ceph:z -v /var/log/ceph/{{ fsid }}:/var/log/ceph:z -v /var/lib/ceph/{{ fsid }}/crash:/var/lib/ceph/crash:z -v /var/lib/ceph/{{ fsid }}/osd.{{ osd_id }}:/var/lib/ceph/osd/ceph-{{ osd_id }}:z -v /var/lib/ceph/{{ fsid }}/osd.{{ osd_id }}/config:/etc/ceph/ceph.conf:z -v /dev:/dev -v /run/udev:/run/udev -v /sys:/sys -v /var/lib/ceph/{{ fsid }}/selinux:/sys/fs/selinux:ro -v /run/lvm:/run/lvm -v /run/lock/lvm:/run/lock/lvm {{ container_image }} --path /var/lib/ceph/osd/ceph-{{ osd_id }}" - - name: resharding operations + - name: Resharding operations delegate_to: "{{ container_host }}" run_once: true block: - - name: check fs consistency with fsck before resharding + - name: Check fs consistency with fsck before resharding command: "{{ ceph_bluestore_tool_cmd }} fsck" changed_when: false - - name: show current sharding + - name: Show current sharding command: "{{ ceph_bluestore_tool_cmd }} show-sharding" changed_when: false - - name: reshard + - name: Reshard command: "{{ ceph_bluestore_tool_cmd }} --sharding=\"{{ rocksdb_sharding_parameters | default('m(3) p(3,0-12) O(3,0-13) L P') }}\" reshard" changed_when: false - - name: check fs consistency with fsck after resharding + - name: Check fs consistency with fsck after resharding command: "{{ ceph_bluestore_tool_cmd }} fsck" changed_when: false - - name: restart the osd - ceph_orch_daemon: + - name: Restart the osd + ceph.automation.ceph_orch_daemon: fsid: "{{ fsid }}" state: started daemon_id: "{{ osd_id }}" diff --git a/tests/functional/deploy-cluster.yml b/tests/functional/deploy-cluster.yml index 49d1ccd..8c5b05b 100644 --- a/tests/functional/deploy-cluster.yml +++ b/tests/functional/deploy-cluster.yml @@ -1,11 +1,11 @@ --- -- name: load variables +- name: Load variables hosts: all become: false tasks: - include_vars: deploy-cluster-vars.yml -- name: gather facts and prepare system for cephadm +- name: Gather facts and prepare system for cephadm hosts: - mons - mgrs @@ -13,11 +13,11 @@ become: true gather_facts: false tasks: - - import_role: + - ansible.builtin.import_role: name: ceph_defaults - - name: gather and delegate facts - setup: + - name: Gather and delegate facts + ansible.builtin.setup: gather_subset: - 'all' - '!facter' @@ -28,8 +28,8 @@ run_once: true when: delegate_facts_host | bool - - name: container registry authentication - cephadm_registry_login: + - name: Container registry authentication + ceph.automation.cephadm_registry_login: registry_url: "{{ ceph_container_registry }}" registry_username: "{{ ceph_container_registry_username }}" registry_password: "{{ ceph_container_registry_password }}" @@ -39,16 +39,16 @@ NO_PROXY: "{{ ceph_container_no_proxy }}" when: ceph_container_registry_auth | default(False) | bool -- name: bootstrap the cluster +- name: Bootstrap the cluster hosts: "{{ groups.get('mons')[0] }}" become: true gather_facts: false tasks: - - import_role: + - ansible.builtin.import_role: name: ceph_defaults - - name: bootstrap initial cluster - cephadm_bootstrap: + - name: Bootstrap initial cluster + ceph.automation.cephadm_bootstrap: mon_ip: "{{ monitor_address }}" fsid: "{{ fsid if fsid is defined else omit }}" pull: false @@ -58,7 +58,7 @@ vars: admin_node: "{{ groups.get('admin')[0] }}" -- name: add the other nodes +- name: Add the other nodes hosts: - mons - mgrs @@ -66,15 +66,15 @@ become: true gather_facts: false tasks: - - import_role: + - ansible.builtin.import_role: name: ceph_defaults - - name: run cephadm prepare-host - command: cephadm prepare-host + - name: Run cephadm prepare-host + ansible.builtin.command: cephadm prepare-host changed_when: false - - name: add hosts - ceph_orch_host: + - name: Add hosts + ceph.automation.ceph_orch_host: name: "{{ ansible_facts['hostname'] }}" address: "{{ ansible_facts['default_ipv4']['address'] if inventory_hostname != 'ceph-node00' else omit }}" set_admin_label: "{{ True if inventory_hostname in groups.get('admin', []) else omit }}" @@ -82,35 +82,35 @@ delegate_to: "{{ groups['mons'][0] }}" -- name: adjust service placement +- name: Adjust service placement hosts: "{{ groups.get('mons')[0] }}" become: true gather_facts: false tasks: - - import_role: + - ansible.builtin.import_role: name: ceph_defaults - - name: update the placement of monitor hosts - ceph_orch_apply: + - name: Update the placement of monitor hosts + ceph.automation.ceph_orch_apply: spec: | service_type: mon service_id: mon placement: label: mons - - name: waiting for the monitor to join the quorum... - command: cephadm shell ceph quorum_status --format json + - name: Waiting for the monitor to join the quorum... + ansible.builtin.command: cephadm shell ceph quorum_status --format json register: ceph_health_raw changed_when: false until: (ceph_health_raw.stdout | from_json)["quorum_names"] | length == groups.get('mons', []) | length retries: "{{ health_mon_check_retries }}" delay: "{{ health_mon_check_delay }}" - - name: update the placement of manager hosts - command: cephadm shell ceph orch apply mgr --placement=label:mgrs + - name: Update the placement of manager hosts + ansible.builtin.command: cephadm shell ceph orch apply mgr --placement=label:mgrs - - name: update the placement of osd hosts - ceph_orch_apply: + - name: Update the placement of osd hosts + ceph.automation.ceph_orch_apply: spec: | service_type: osd service_id: osd @@ -120,16 +120,16 @@ data_devices: all: true - - name: update the placement of crash hosts - ceph_orch_apply: + - name: Update the placement of crash hosts + ceph.automation.ceph_orch_apply: spec: | service_type: crash service_id: crash placement: host_pattern: '*' - - name: enable the monitoring - command: "ceph {{ item }}" + - name: Enable the monitoring + ansible.builtin.command: "ceph {{ item }}" changed_when: false loop: - "mgr module enable prometheus" @@ -138,18 +138,18 @@ - "orch apply prometheus --placement=label:monitoring" - "orch apply node-exporter --placement=*" -- name: remove ceph-node5 +- name: Remove ceph-node5 hosts: "{{ groups.get('mons')[0] }}" become: true gather_facts: false tasks: - - name: drain ceph-node5 - ceph_orch_host: + - name: Drain ceph-node5 + ceph.automation.ceph_orch_host: state: drain name: ceph-node5 - - name: remove ceph-node5 - ceph_orch_host: + - name: Remove ceph-node5 + ceph.automation.ceph_orch_host: state: absent name: ceph-node5 retries: 20 @@ -157,23 +157,23 @@ until: result is succeeded register: result -- name: adjust service placement +- name: Adjust service placement hosts: "{{ groups.get('mons')[0] }}" become: true gather_facts: false tasks: - - import_role: + - ansible.builtin.import_role: name: ceph_defaults - - name: print bootstrap details - debug: + - name: Print bootstrap details + ansible.builtin.debug: msg: "{{ bootstrap_details }}" # TODO(guits): address the following tasks: - # - name: show ceph orchestrator services - # command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch ls --refresh" + # - name: Show ceph orchestrator services + # ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch ls --refresh" # changed_when: false - # - name: show ceph orchestrator daemons - # command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch ps --refresh" + # - name: Show ceph orchestrator daemons + # ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch ps --refresh" # changed_when: false \ No newline at end of file diff --git a/tests/library/common.py b/tests/library/common.py deleted file mode 100644 index eaa0bd6..0000000 --- a/tests/library/common.py +++ /dev/null @@ -1,29 +0,0 @@ -from ansible.module_utils import basic -from ansible.module_utils._text import to_bytes -import json - - -def set_module_args(args): - if '_ansible_remote_tmp' not in args: - args['_ansible_remote_tmp'] = '/tmp' - if '_ansible_keep_remote_files' not in args: - args['_ansible_keep_remote_files'] = False - - args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) - basic._ANSIBLE_ARGS = to_bytes(args) - - -class AnsibleExitJson(Exception): - pass - - -class AnsibleFailJson(Exception): - pass - - -def exit_json(*args, **kwargs): - raise AnsibleExitJson(kwargs) - - -def fail_json(*args, **kwargs): - raise AnsibleFailJson(kwargs) diff --git a/tests/library/test_ceph_orch_host.py b/tests/library/test_ceph_orch_host.py deleted file mode 100644 index 269f335..0000000 --- a/tests/library/test_ceph_orch_host.py +++ /dev/null @@ -1,206 +0,0 @@ -from mock.mock import patch -import pytest -import common -import ceph_orch_host - - -class TestCephOrchHost(object): - - @patch('ceph_orch_host.get_current_state') - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_state_absent_host_exists(self, m_run_command, m_exit_json, m_get_current_state): - common.set_module_args({ - 'state': 'absent', - 'name': 'ceph-node5' - }) - m_exit_json.side_effect = common.exit_json - stdout = "Removed host 'ceph-node5'" - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - m_get_current_state_stdout = '[{"addr": "10.10.10.11", "hostname": "ceph-node5", "labels": [], "status": ""}]' - m_get_current_state.return_value = rc, ["cephadm", - "shell", - "ceph", - "orch", - "host", - "ls", - "--format", - "json"], m_get_current_state_stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - ceph_orch_host.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ["cephadm", "shell", "ceph", "orch", "host", "rm", "ceph-node5"] - assert result['stdout'] == stdout - assert result['rc'] == 0 - - @patch('ceph_orch_host.get_current_state') - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_state_absent_host_doesnt_exist(self, m_run_command, m_exit_json, m_get_current_state): - common.set_module_args({ - 'state': 'absent', - 'name': 'ceph-node1' - }) - m_exit_json.side_effect = common.exit_json - - stdout = "" - stderr = "Error EINVAL: host ceph-node1 does not exist" - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - m_get_current_state_stdout = '[{"addr": "10.10.10.11", "hostname": "ceph-node5", "labels": [], "status": ""}]' - m_get_current_state.return_value = rc, ["cephadm", - "shell", - "ceph", - "orch", - "host", - "ls", - "--format", - "json"], m_get_current_state_stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - ceph_orch_host.main() - - result = result.value.args[0] - assert not result['changed'] - assert result['stdout'] == 'ceph-node1 is not present, skipping.' - assert result['rc'] == 0 - - @patch('ceph_orch_host.get_current_state') - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_state_drain(self, m_run_command, m_exit_json, m_get_current_state): - common.set_module_args({ - 'state': 'drain', - 'name': 'ceph-node5' - }) - m_exit_json.side_effect = common.exit_json - stdout = """ -Scheduled to remove the following daemons from host 'ceph-node5' -type id --------------------- --------------- -crash ceph-node5 -osd 3 -osd 5 -osd 7""" - m_get_current_state_stdout = '[{"addr": "10.10.10.11", "hostname": "ceph-node5", "labels": [], "status": ""}]' - stderr = '' - rc = 0 - cmd = ["cephadm", "shell", "ceph", "orch", "host", "drain", "ceph-node5"] - m_run_command.return_value = rc, stdout, stderr - m_get_current_state.return_value = rc, ["cephadm", - "shell", - "ceph", - "orch", - "host", - "ls", - "--format", - "json"], m_get_current_state_stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - ceph_orch_host.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == cmd - assert result['stdout'] == stdout - assert result['rc'] == 0 - - @patch('ceph_orch_host.get_current_state') - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_state_present_no_label_diff(self, m_run_command, m_exit_json, m_get_current_state): - common.set_module_args({ - 'state': 'present', - 'name': 'ceph-node5' - }) - m_exit_json.side_effect = common.exit_json - stdout = "ceph-node5 is already present, skipping." - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - m_get_current_state_stdout = '[{"addr": "10.10.10.11", "hostname": "ceph-node5", "labels": [], "status": ""}]' - m_get_current_state.return_value = rc, ["cephadm", - "shell", - "ceph", - "orch", - "host", - "ls", - "--format", - "json"], m_get_current_state_stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - ceph_orch_host.main() - - result = result.value.args[0] - assert not result['changed'] - assert result['stdout'] == stdout - assert result['rc'] == 0 - - @patch('ceph_orch_host.get_current_state') - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_state_present_label_diff(self, m_run_command, m_exit_json, m_get_current_state): - common.set_module_args({ - 'state': 'present', - 'name': 'ceph-node5', - 'labels': ["label1", "label2"] - }) - m_exit_json.side_effect = common.exit_json - stdout = "Label(s) updated:" - stderr = '' - rc = 0 - m_run_command.side_effect = [(rc, "Added label label1 to host ceph-node5", stderr), - (rc, "Added label label2 to host ceph-node5", stderr)] - m_get_current_state_stdout = '[{"addr": "10.10.10.11", "hostname": "ceph-node5", "labels": [], "status": ""}]' - m_get_current_state.return_value = rc, ["cephadm", - "shell", - "ceph", - "orch", - "host", - "ls", - "--format", - "json"], m_get_current_state_stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - ceph_orch_host.main() - - result = result.value.args[0] - assert result['changed'] - assert stdout in result['stdout'] - assert 'label1' in result['stdout'] - assert 'label2' in result['stdout'] - assert result['rc'] == 0 - - @patch('ceph_orch_host.get_current_state') - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_state_present_label_diff_error(self, m_run_command, m_exit_json, m_get_current_state): - common.set_module_args({ - 'state': 'present', - 'name': 'ceph-node5', - 'labels': ["label1", "label2"] - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = 'fake error' - rc = 0 - m_run_command.return_value = 1, stdout, stderr - m_get_current_state_stdout = '[{"addr": "10.10.10.11", "hostname": "ceph-node5", "labels": [], "status": ""}]' - m_get_current_state.return_value = rc, ["cephadm", - "shell", - "ceph", - "orch", - "host", - "ls", - "--format", - "json"], m_get_current_state_stdout, stderr - - with pytest.raises(RuntimeError) as result: - ceph_orch_host.main() - assert result == 'fake error' diff --git a/tests/library/test_cephadm_bootstrap.py b/tests/library/test_cephadm_bootstrap.py deleted file mode 100644 index 1a78c59..0000000 --- a/tests/library/test_cephadm_bootstrap.py +++ /dev/null @@ -1,304 +0,0 @@ -from mock.mock import patch -import pytest -import common -import cephadm_bootstrap - -fake_fsid = '0f1e0605-db0b-485c-b366-bd8abaa83f3b' -fake_image = 'quay.ceph.io/ceph/daemon-base:latest-main-devel' -fake_ip = '192.168.42.1' -fake_registry = 'quay.ceph.io' -fake_registry_user = 'foo' -fake_registry_pass = 'bar' -fake_registry_json = 'registry.json' - - -class TestCephadmBootstrapModule(object): - - @patch('ansible.module_utils.basic.AnsibleModule.fail_json') - def test_without_parameters(self, m_fail_json): - common.set_module_args({}) - m_fail_json.side_effect = common.fail_json - - with pytest.raises(common.AnsibleFailJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['msg'] == 'one of the following is required: mon_ip, mon_addrv' - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - def test_with_check_mode(self, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - '_ansible_check_mode': True - }) - m_exit_json.side_effect = common.exit_json - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert not result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip] - assert result['rc'] == 0 - assert not result['stdout'] - assert not result['stderr'] - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_with_failure(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = 'ERROR: cephadm should be run as root' - rc = 1 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip] - assert result['rc'] == 1 - assert result['stderr'] == 'ERROR: cephadm should be run as root' - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_with_default_values(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip - }) - m_exit_json.side_effect = common.exit_json - stdout = 'Bootstrap complete.' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip] - assert result['rc'] == 0 - assert result['stdout'] == 'Bootstrap complete.' - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_with_docker(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'docker': True - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', '--docker', 'bootstrap', '--mon-ip', fake_ip] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_with_custom_image(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'image': fake_image - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', '--image', fake_image, 'bootstrap', '--mon-ip', fake_ip] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_with_custom_fsid(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'fsid': fake_fsid - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--fsid', fake_fsid, '--mon-ip', fake_ip] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_without_pull(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'pull': False - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip, '--skip-pull'] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_with_dashboard_user_password(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'dashboard': True, - 'dashboard_user': 'foo', - 'dashboard_password': 'bar' - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip, '--dashboard-user', 'foo', '--dashboard-password', 'bar'] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_without_dashboard(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'dashboard': False - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip, '--skip-dashboard'] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_without_monitoring(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'monitoring': False - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip, '--skip-monitoring-stack'] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_without_firewalld(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'firewalld': False - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip, '--skip-firewalld'] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_with_registry_credentials(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'registry_url': fake_registry, - 'registry_username': fake_registry_user, - 'registry_password': fake_registry_pass - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip, - '--registry-password', fake_registry_pass, - '--registry-url', fake_registry, - '--registry-username', fake_registry_user] - assert result['rc'] == 0 - - @patch('ansible.module_utils.basic.AnsibleModule.exit_json') - @patch('ansible.module_utils.basic.AnsibleModule.run_command') - def test_with_registry_json_file(self, m_run_command, m_exit_json): - common.set_module_args({ - 'mon_ip': fake_ip, - 'registry_json': fake_registry_json - }) - m_exit_json.side_effect = common.exit_json - stdout = '' - stderr = '' - rc = 0 - m_run_command.return_value = rc, stdout, stderr - - with pytest.raises(common.AnsibleExitJson) as result: - cephadm_bootstrap.main() - - result = result.value.args[0] - assert result['changed'] - assert result['cmd'] == ['cephadm', 'bootstrap', '--mon-ip', fake_ip, - '--registry-json', fake_registry_json] - assert result['rc'] == 0 diff --git a/tests/module_utils/test_ceph_common.py b/tests/module_utils/test_ceph_common.py deleted file mode 100644 index 0e2d223..0000000 --- a/tests/module_utils/test_ceph_common.py +++ /dev/null @@ -1,39 +0,0 @@ -import ceph_common -import pytest -from mock.mock import MagicMock - - -class TestCephCommon(object): - def setup_method(self): - self.fake_module = MagicMock() - self.fake_params = {'foo': 'bar'} - self.fake_module.params = self.fake_params - - def test_build_base_cmd_orch_with_fsid_arg(self): - expected_cmd = ['cephadm', 'shell', '--fsid', '123', 'ceph', 'orch'] - self.fake_module.params = {'fsid': '123'} - cmd = ceph_common.build_base_cmd_orch(self.fake_module) - assert cmd == expected_cmd - - def test_build_base_cmd_orch_with_image_arg(self): - expected_cmd = ['cephadm', '--image', 'quay.io/ceph-ci/ceph:main', 'shell', 'ceph', 'orch'] - self.fake_module.params = {'image': 'quay.io/ceph-ci/ceph:main'} - cmd = ceph_common.build_base_cmd_orch(self.fake_module) - assert cmd == expected_cmd - - def test_build_base_cmd_orch_with_docker_arg(self): - expected_cmd = ['cephadm', '--docker', 'shell', 'ceph', 'orch'] - self.fake_module.params = {'docker': True} - cmd = ceph_common.build_base_cmd_orch(self.fake_module) - assert cmd == expected_cmd - - def test_build_base_cmd_orch_no_arg(self): - expected_cmd = ['cephadm', 'shell', 'ceph', 'orch'] - cmd = ceph_common.build_base_cmd_orch(self.fake_module) - assert cmd == expected_cmd - - def test_fatal(self): - ceph_common.fatal("error", self.fake_module) - self.fake_module.fail_json.assert_called_with(msg='error', rc=1) - with pytest.raises(Exception): - ceph_common.fatal("error", False) diff --git a/tox.ini b/tox.ini index ee42f76..4c8f41f 100644 --- a/tox.ini +++ b/tox.ini @@ -50,11 +50,14 @@ setenv= ANSIBLE_GATHERING = implicit # only available for ansible >= 2.5 ANSIBLE_STDOUT_CALLBACK = yaml + ANSIBLE_COLLECTIONS_PATH = {envdir}/ansible_collections + deps= -r{toxinidir}/tests/requirements.txt changedir= {toxinidir}/tests/functional commands= + ansible-galaxy collection install -r {toxinidir}/requirements.yml -v -p {envdir}/ansible_collections bash {toxinidir}/tests/scripts/vagrant_up.sh --no-provision {posargs:--provider=virtualbox} bash {toxinidir}/tests/scripts/generate_ssh_config.sh {changedir} diff --git a/validate/insecure-registries.yml b/validate/insecure-registries.yml index 10a0fd5..cc6c4d2 100644 --- a/validate/insecure-registries.yml +++ b/validate/insecure-registries.yml @@ -3,16 +3,16 @@ # SPDX-License-Identifier: Apache-2.0 # Author: Guillaume Abrioux -- name: insecure_registries +- name: Insecure_registries hosts: all become: false gather_facts: false tasks: - - name: fail if insecure_registry is undefined + - name: Fail if insecure_registry is undefined run_once: true delegate_to: localhost - fail: + ansible.builtin.fail: msg: "'insecure_registry' is undefined, it must be set when 'set_insecure_registries' is 'true'." when: - set_insecure_registries | default(false) | bool - - insecure_registry is undefined \ No newline at end of file + - insecure_registry is undefined diff --git a/validate/preflight.yml b/validate/preflight.yml index ac66fdb..e0d171e 100644 --- a/validate/preflight.yml +++ b/validate/preflight.yml @@ -6,7 +6,7 @@ - ansible.builtin.import_playbook: insecure-registries.yml when: set_insecure_registries | default(false) | bool -- name: preflight +- name: Preflight hosts: all become: false gather_facts: false @@ -14,20 +14,20 @@ - run_once: true delegate_to: localhost block: - - name: import_role ceph_defaults - import_role: + - name: Import_role ceph_defaults + ansible.builtin.import_role: name: ceph_defaults - - name: fail when ceph_origin is custom with no repository defined - fail: + - name: Fail when ceph_origin is custom with no repository defined + ansible.builtin.fail: msg: "You must define 'ceph_custom_repositories' or 'custom_repo_url' when ceph_origin is 'custom'" when: - ceph_origin == 'custom' - (custom_repo_url is undefined or custom_repo_url == '') - ceph_custom_repositories is undefined - - name: fail if baseurl is not defined for ceph_custom_repositories - fail: + - name: Fail if baseurl is not defined for ceph_custom_repositories + ansible.builtin.fail: msg: "One repository is missing a required parameter: name, description, baseurl." loop: "{{ ceph_custom_repositories }}" when: