deep_scrub_choked
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
Infrastructure playbooks
|
||||
========================
|
||||
|
||||
This directory contains a variety of playbooks that can be used independently of the Ceph roles we have.
|
||||
They aim to perform infrastructure related tasks that would help use managing a Ceph cluster or performing certain operational tasks.
|
||||
|
||||
To use them, run `ansible-playbook infrastructure-playbooks/<playbook>`.
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
# This playbook is used to add a new MON to
|
||||
# an existing cluster. It can run from any machine. Even if the fetch
|
||||
# directory is not present it will be created.
|
||||
#
|
||||
# Ensure that all monitors are present in the mons
|
||||
# group in your inventory so that the ceph configuration file
|
||||
# is created correctly for the new OSD(s).
|
||||
- name: Pre-requisites operations for adding new monitor(s)
|
||||
hosts: mons
|
||||
gather_facts: false
|
||||
vars:
|
||||
delegate_facts_host: true
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: Import raw_install_python tasks
|
||||
ansible.builtin.import_tasks: "{{ playbook_dir }}/../raw_install_python.yml"
|
||||
|
||||
- name: Gather facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'all'
|
||||
- '!facter'
|
||||
- '!ohai'
|
||||
when: not delegate_facts_host | bool or inventory_hostname in groups.get(client_group_name, [])
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Gather and delegate facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'all'
|
||||
- '!facter'
|
||||
- '!ohai'
|
||||
delegate_to: "{{ item }}"
|
||||
delegate_facts: true
|
||||
with_items: "{{ groups[mon_group_name] }}"
|
||||
run_once: true
|
||||
when: delegate_facts_host | bool
|
||||
tasks:
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
- name: Import ceph-validate role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-validate
|
||||
|
||||
- name: Import ceph-infra role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-infra
|
||||
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-common
|
||||
when: not containerized_deployment | bool
|
||||
|
||||
- name: Import ceph-container-engine role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Deploy Ceph monitors
|
||||
hosts: mons
|
||||
gather_facts: false
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-config role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-config
|
||||
|
||||
- name: Import ceph-mon role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-mon
|
||||
|
||||
- name: Import ceph-crash role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-crash
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Import ceph-exporter role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-exporter
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Update config file on OSD nodes
|
||||
hosts: osds
|
||||
gather_facts: true
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-config role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-config
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
# Copyright Red Hat
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# This playbook can help in order to backup some Ceph files and restore them later.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ansible-playbook -i <inventory> backup-and-restore-ceph-files.yml -e backup_dir=<backup directory path> -e mode=<backup|restore> -e target_node=<inventory_name>
|
||||
#
|
||||
# Required run-time variables
|
||||
# ------------------
|
||||
# backup_dir : a path where files will be read|write.
|
||||
# mode : tell the playbook either to backup or restore files.
|
||||
# target_node : the name of the node being processed, it must match the name set in the inventory.
|
||||
#
|
||||
# Examples
|
||||
# --------
|
||||
# ansible-playbook -i hosts, backup-and-restore-ceph-files.yml -e backup_dir=/usr/share/ceph-ansible/backup-ceph-files -e mode=backup -e target_node=mon01
|
||||
# ansible-playbook -i hosts, backup-and-restore-ceph-files.yml -e backup_dir=/usr/share/ceph-ansible/backup-ceph-files -e mode=restore -e target_node=mon01
|
||||
|
||||
- name: Backup and restore Ceph files
|
||||
hosts: localhost
|
||||
become: true
|
||||
gather_facts: true
|
||||
tasks:
|
||||
- name: Exit playbook, if user did not set the source node
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
"You must pass the node name: -e target_node=<inventory_name>.
|
||||
The name must match what is set in your inventory."
|
||||
when:
|
||||
- target_node is not defined
|
||||
or target_node not in groups.get('all', [])
|
||||
|
||||
- name: Exit playbook, if user did not set the backup directory
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
"you must pass the backup directory path: -e backup_dir=<backup directory path>"
|
||||
when: backup_dir is not defined
|
||||
|
||||
- name: Exit playbook, if user did not set the playbook mode (backup|restore)
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
"you must pass the mode: -e mode=<backup|restore>"
|
||||
when:
|
||||
- mode is not defined
|
||||
or mode not in ['backup', 'restore']
|
||||
|
||||
- name: Gather facts on source node
|
||||
ansible.builtin.setup:
|
||||
delegate_to: "{{ target_node }}"
|
||||
delegate_facts: true
|
||||
|
||||
- name: Backup mode
|
||||
when: mode == 'backup'
|
||||
block:
|
||||
- name: Create a temp directory
|
||||
ansible.builtin.tempfile:
|
||||
state: directory
|
||||
suffix: ansible-archive-ceph
|
||||
register: tmp_dir
|
||||
delegate_to: "{{ target_node }}"
|
||||
|
||||
- name: Archive files
|
||||
community.general.archive:
|
||||
path: "{{ item }}"
|
||||
dest: "{{ tmp_dir.path }}/backup{{ item | replace('/', '-') }}.tar"
|
||||
format: tar
|
||||
mode: "0644"
|
||||
delegate_to: "{{ target_node }}"
|
||||
loop:
|
||||
- /etc/ceph
|
||||
- /var/lib/ceph
|
||||
|
||||
- name: Create backup directory
|
||||
become: false
|
||||
ansible.builtin.file:
|
||||
path: "{{ backup_dir }}/{{ hostvars[target_node]['ansible_facts']['hostname'] }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Backup files
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ tmp_dir.path }}/backup{{ item | replace('/', '-') }}.tar"
|
||||
dest: "{{ backup_dir }}/{{ hostvars[target_node]['ansible_facts']['hostname'] }}/backup{{ item | replace('/', '-') }}.tar"
|
||||
flat: true
|
||||
loop:
|
||||
- /etc/ceph
|
||||
- /var/lib/ceph
|
||||
delegate_to: "{{ target_node }}"
|
||||
|
||||
- name: Remove temp directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ tmp_dir.path }}"
|
||||
state: absent
|
||||
delegate_to: "{{ target_node }}"
|
||||
|
||||
- name: Restore mode
|
||||
when: mode == 'restore'
|
||||
block:
|
||||
- name: Unarchive files
|
||||
ansible.builtin.unarchive:
|
||||
src: "{{ backup_dir }}/{{ hostvars[target_node]['ansible_facts']['hostname'] }}/backup{{ item | replace('/', '-') }}.tar"
|
||||
dest: "{{ item | dirname }}"
|
||||
loop:
|
||||
- /etc/ceph
|
||||
- /var/lib/ceph
|
||||
delegate_to: "{{ target_node }}"
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
# This playbook is used to manage CephX Keys
|
||||
# You will find examples below on how the module can be used on daily operations
|
||||
#
|
||||
# It currently runs on localhost
|
||||
|
||||
- name: CephX key management examples
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
cluster: ceph
|
||||
container_exec_cmd: "docker exec ceph-nano"
|
||||
keys_to_info:
|
||||
- client.admin
|
||||
- mds.0
|
||||
keys_to_delete:
|
||||
- client.leseb
|
||||
- client.leseb1
|
||||
- client.pythonnnn
|
||||
keys_to_create:
|
||||
- { name: client.pythonnnn, caps: { mon: "allow rwx", mds: "allow *" }, mode: "0600" }
|
||||
- { name: client.existpassss, caps: { mon: "allow r", osd: "allow *" }, mode: "0600" }
|
||||
- { name: client.path, caps: { mon: "allow r", osd: "allow *" }, mode: "0600" }
|
||||
|
||||
tasks:
|
||||
- name: Create ceph key(s) module
|
||||
ceph_key:
|
||||
name: "{{ item.name }}"
|
||||
caps: "{{ item.caps }}"
|
||||
cluster: "{{ cluster }}"
|
||||
secret: "{{ item.key | default('') }}"
|
||||
containerized: "{{ container_exec_cmd | default(False) }}"
|
||||
with_items: "{{ keys_to_create }}"
|
||||
|
||||
- name: Update ceph key(s)
|
||||
ceph_key:
|
||||
name: "{{ item.name }}"
|
||||
state: update
|
||||
caps: "{{ item.caps }}"
|
||||
cluster: "{{ cluster }}"
|
||||
containerized: "{{ container_exec_cmd | default(False) }}"
|
||||
with_items: "{{ keys_to_create }}"
|
||||
|
||||
- name: Delete ceph key(s)
|
||||
ceph_key:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
cluster: "{{ cluster }}"
|
||||
containerized: "{{ container_exec_cmd | default(False) }}"
|
||||
with_items: "{{ keys_to_delete }}"
|
||||
|
||||
- name: Info ceph key(s)
|
||||
ceph_key_info:
|
||||
name: "{{ item }}"
|
||||
state: info
|
||||
cluster: "{{ cluster }}"
|
||||
containerized: "{{ container_exec_cmd }}"
|
||||
register: key_info
|
||||
ignore_errors: true
|
||||
with_items: "{{ keys_to_info }}"
|
||||
|
||||
- name: List ceph key(s)
|
||||
ceph_key_info:
|
||||
state: list
|
||||
cluster: "{{ cluster }}"
|
||||
containerized: "{{ container_exec_cmd | default(False) }}"
|
||||
register: list_keys
|
||||
ignore_errors: true
|
||||
|
||||
- name: Fetch_initial_keys # noqa: ignore-errors
|
||||
ceph_key:
|
||||
state: fetch_initial_keys
|
||||
cluster: "{{ cluster }}"
|
||||
ignore_errors: true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,383 @@
|
||||
---
|
||||
- name: Gather facts and prepare system for cephadm
|
||||
hosts:
|
||||
- "{{ mon_group_name|default('mons') }}"
|
||||
- "{{ osd_group_name|default('osds') }}"
|
||||
- "{{ mds_group_name|default('mdss') }}"
|
||||
- "{{ rgw_group_name|default('rgws') }}"
|
||||
- "{{ mgr_group_name|default('mgrs') }}"
|
||||
- "{{ rbdmirror_group_name|default('rbdmirrors') }}"
|
||||
- "{{ nfs_group_name|default('nfss') }}"
|
||||
- "{{ monitoring_group_name|default('monitoring') }}"
|
||||
become: true
|
||||
gather_facts: false
|
||||
vars:
|
||||
delegate_facts_host: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Validate if monitor group doesn't exist or empty
|
||||
ansible.builtin.fail:
|
||||
msg: "you must add a [mons] group and add at least one node."
|
||||
run_once: true
|
||||
when: groups[mon_group_name] is undefined or groups[mon_group_name] | length == 0
|
||||
|
||||
- name: Validate if manager group doesn't exist or empty
|
||||
ansible.builtin.fail:
|
||||
msg: "you must add a [mgrs] group and add at least one node."
|
||||
run_once: true
|
||||
when: groups[mgr_group_name] is undefined or groups[mgr_group_name] | length == 0
|
||||
|
||||
- name: Validate dashboard configuration
|
||||
when: dashboard_enabled | bool
|
||||
run_once: true
|
||||
block:
|
||||
- name: Fail if [monitoring] group doesn't exist or empty
|
||||
ansible.builtin.fail:
|
||||
msg: "you must add a [monitoring] group and add at least one node."
|
||||
when: groups[monitoring_group_name] is undefined or groups[monitoring_group_name] | length == 0
|
||||
|
||||
- name: Fail when dashboard_admin_password is not set
|
||||
ansible.builtin.fail:
|
||||
msg: "you must set dashboard_admin_password."
|
||||
when: dashboard_admin_password is undefined
|
||||
|
||||
- name: Validate container registry credentials
|
||||
ansible.builtin.fail:
|
||||
msg: 'ceph_docker_registry_username and/or ceph_docker_registry_password variables need to be set'
|
||||
when:
|
||||
- ceph_docker_registry_auth | bool
|
||||
- (ceph_docker_registry_username is not defined or ceph_docker_registry_password is not defined) or
|
||||
(ceph_docker_registry_username | length == 0 or ceph_docker_registry_password | length == 0)
|
||||
|
||||
- name: Gather facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'all'
|
||||
- '!facter'
|
||||
- '!ohai'
|
||||
when: not delegate_facts_host | bool
|
||||
|
||||
- name: Gather and delegate facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'all'
|
||||
- '!facter'
|
||||
- '!ohai'
|
||||
delegate_to: "{{ item }}"
|
||||
delegate_facts: true
|
||||
with_items: "{{ groups['all'] }}"
|
||||
run_once: true
|
||||
when: delegate_facts_host | bool
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary.yml
|
||||
|
||||
- name: Check if it is atomic host
|
||||
ansible.builtin.stat:
|
||||
path: /run/ostree-booted
|
||||
register: stat_ostree
|
||||
|
||||
- name: Set_fact is_atomic
|
||||
ansible.builtin.set_fact:
|
||||
is_atomic: "{{ stat_ostree.stat.exists }}"
|
||||
|
||||
- name: Import ceph-container-engine role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
tasks_from: registry.yml
|
||||
when: ceph_docker_registry_auth | bool
|
||||
|
||||
- name: Configure repository for installing cephadm
|
||||
vars:
|
||||
ceph_origin: repository
|
||||
ceph_repository: community
|
||||
block:
|
||||
- name: Validate repository variables
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-validate
|
||||
tasks_from: check_repository.yml
|
||||
|
||||
- name: Configure repository
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-common
|
||||
tasks_from: "configure_repository.yml"
|
||||
|
||||
- name: Install cephadm requirements
|
||||
ansible.builtin.package:
|
||||
name: ['python3', 'lvm2']
|
||||
register: result
|
||||
until: result is succeeded
|
||||
|
||||
- name: Install cephadm
|
||||
ansible.builtin.package:
|
||||
name: cephadm
|
||||
register: result
|
||||
until: result is succeeded
|
||||
|
||||
- name: Set_fact cephadm_cmd
|
||||
ansible.builtin.set_fact:
|
||||
cephadm_cmd: "cephadm {{ '--docker' if container_binary == 'docker' else '' }}"
|
||||
|
||||
- name: Bootstrap the cluster
|
||||
hosts: "{{ mon_group_name|default('mons') }}[0]"
|
||||
become: true
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: set_monitor_address.yml
|
||||
|
||||
- name: Create /etc/ceph directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/ceph
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Bootstrap the new cluster
|
||||
cephadm_bootstrap:
|
||||
mon_ip: "{{ _monitor_addresses[inventory_hostname] }}"
|
||||
image: "{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}"
|
||||
docker: "{{ true if container_binary == 'docker' else false }}"
|
||||
pull: false
|
||||
dashboard: "{{ dashboard_enabled }}"
|
||||
dashboard_user: "{{ dashboard_admin_user if dashboard_enabled | bool else omit }}"
|
||||
dashboard_password: "{{ dashboard_admin_password if dashboard_enabled | bool else omit }}"
|
||||
monitoring: false
|
||||
firewalld: "{{ configure_firewall }}"
|
||||
ssh_user: "{{ cephadm_ssh_user | default('root') }}"
|
||||
ssh_config: "{{ cephadm_ssh_config | default(omit) }}"
|
||||
|
||||
- name: Set default container image in ceph configuration
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} config set global container_image {{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Set container image base in ceph configuration
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} config set mgr mgr/cephadm/container_image_base {{ ceph_docker_registry }}/{{ ceph_docker_image }}"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Set dashboard container image in ceph mgr configuration
|
||||
when: dashboard_enabled | bool
|
||||
block:
|
||||
- name: Set alertmanager container image in ceph configuration
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} config set mgr mgr/cephadm/container_image_alertmanager {{ alertmanager_container_image }}"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Set grafana container image in ceph configuration
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} config set mgr mgr/cephadm/container_image_grafana {{ grafana_container_image }}"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Set node-exporter container image in ceph configuration
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} config set mgr mgr/cephadm/container_image_node_exporter {{ node_exporter_container_image }}"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Set prometheus container image in ceph configuration
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} config set mgr mgr/cephadm/container_image_prometheus {{ prometheus_container_image }}"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Add the other nodes
|
||||
hosts:
|
||||
- "{{ mon_group_name|default('mons') }}"
|
||||
- "{{ osd_group_name|default('osds') }}"
|
||||
- "{{ mds_group_name|default('mdss') }}"
|
||||
- "{{ rgw_group_name|default('rgws') }}"
|
||||
- "{{ mgr_group_name|default('mgrs') }}"
|
||||
- "{{ rbdmirror_group_name|default('rbdmirrors') }}"
|
||||
- "{{ nfs_group_name|default('nfss') }}"
|
||||
- "{{ monitoring_group_name|default('monitoring') }}"
|
||||
become: true
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Get the cephadm ssh pub key
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} cephadm get-pub-key"
|
||||
changed_when: false
|
||||
run_once: true
|
||||
register: cephadm_pubpkey
|
||||
delegate_to: '{{ groups[mon_group_name][0] }}'
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Allow cephadm key
|
||||
ansible.posix.authorized_key:
|
||||
user: "{{ cephadm_ssh_user | default('root') }}"
|
||||
key: '{{ cephadm_pubpkey.stdout }}'
|
||||
|
||||
- name: Run cephadm prepare-host
|
||||
ansible.builtin.command: cephadm prepare-host
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Manage nodes with cephadm - ipv4
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch host add {{ ansible_facts['hostname'] }} {{ ansible_facts['all_ipv4_addresses'] | ips_in_ranges(public_network.split(',')) | first }} {{ group_names | join(' ') }} {{ '_admin' if mon_group_name | default('mons') in group_names else '' }}"
|
||||
changed_when: false
|
||||
delegate_to: '{{ groups[mon_group_name][0] }}'
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
when: ip_version == 'ipv4'
|
||||
|
||||
- name: Manage nodes with cephadm - ipv6
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch host add {{ ansible_facts['hostname'] }} {{ ansible_facts['all_ipv6_addresses'] | ips_in_ranges(public_network.split(',')) | last | ansible.utils.ipwrap }} {{ group_names | join(' ') }} {{ '_admin' if mon_group_name | default('mons') in group_names else '' }}"
|
||||
changed_when: false
|
||||
delegate_to: '{{ groups[mon_group_name][0] }}'
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
when: ip_version == 'ipv6'
|
||||
|
||||
- name: Add ceph label for core component
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch host label add {{ ansible_facts['hostname'] }} ceph"
|
||||
changed_when: false
|
||||
delegate_to: '{{ groups[mon_group_name][0] }}'
|
||||
when: inventory_hostname in groups.get(mon_group_name, []) or
|
||||
inventory_hostname in groups.get(osd_group_name, []) or
|
||||
inventory_hostname in groups.get(mds_group_name, []) or
|
||||
inventory_hostname in groups.get(rgw_group_name, []) or
|
||||
inventory_hostname in groups.get(mgr_group_name, []) or
|
||||
inventory_hostname in groups.get(rbdmirror_group_name, [])
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Adjust service placement
|
||||
hosts: "{{ mon_group_name|default('mons') }}[0]"
|
||||
become: true
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Update the placement of monitor hosts
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch apply mon --placement='label:{{ mon_group_name }}'"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Waiting for the monitor to join the quorum...
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} quorum_status --format json"
|
||||
changed_when: false
|
||||
register: ceph_health_raw
|
||||
until: (ceph_health_raw.stdout | from_json)["quorum_names"] | length == groups.get(mon_group_name, []) | length
|
||||
retries: "{{ health_mon_check_retries }}"
|
||||
delay: "{{ health_mon_check_delay }}"
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Update the placement of manager hosts
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch apply mgr --placement='label:{{ mgr_group_name }}'"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Update the placement of crash hosts
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch apply crash --placement='label:ceph'"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Update the placement of ceph-exporter hosts
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch apply ceph-exporter --placement='label:ceph'"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Adjust monitoring service placement
|
||||
hosts: "{{ monitoring_group_name|default('monitoring') }}"
|
||||
become: true
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Import ceph-defaults
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: With dashboard enabled
|
||||
when: dashboard_enabled | bool
|
||||
delegate_to: '{{ groups[mon_group_name][0] }}'
|
||||
run_once: true
|
||||
block:
|
||||
- name: Enable the prometheus module
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} mgr module enable prometheus"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Update the placement of alertmanager hosts
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch apply alertmanager --placement='label:{{ monitoring_group_name }}'"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Update the placement of grafana hosts
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch apply grafana --placement='label:{{ monitoring_group_name }}'"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Update the placement of prometheus hosts
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch apply prometheus --placement='label:{{ monitoring_group_name }}'"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Update the placement of node-exporter hosts
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch apply node-exporter --placement='*'"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Print information
|
||||
hosts: "{{ mon_group_name|default('mons') }}[0]"
|
||||
become: true
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Import ceph-defaults
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Show ceph orchestrator services
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch ls --refresh"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Show ceph orchestrator daemons
|
||||
ansible.builtin.command: "{{ cephadm_cmd }} shell -- ceph --cluster {{ cluster }} orch ps --refresh"
|
||||
changed_when: false
|
||||
environment:
|
||||
CEPHADM_IMAGE: '{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}'
|
||||
|
||||
- name: Inform users about cephadm
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
This Ceph cluster is now ready to receive more configuration like
|
||||
adding OSD, MDS daemons, create pools or keyring.
|
||||
You can do this by using the cephadm CLI and you don't need to use
|
||||
ceph-ansible playbooks anymore.
|
||||
@@ -0,0 +1,236 @@
|
||||
---
|
||||
# This playbook is intended to be used as part of the el7 to el8 OS upgrade.
|
||||
# It modifies the systemd unit files so containers are launched with podman
|
||||
# instead of docker after the OS reboot once it is upgraded.
|
||||
# It is *not* intended to restart services since we don't want to multiple services
|
||||
# restarts.
|
||||
|
||||
- name: Pre-requisite and facts gathering
|
||||
hosts:
|
||||
- mons
|
||||
- osds
|
||||
- mdss
|
||||
- rgws
|
||||
- nfss
|
||||
- rbdmirrors
|
||||
- clients
|
||||
- mgrs
|
||||
- monitoring
|
||||
|
||||
gather_facts: false
|
||||
become: true
|
||||
any_errors_fatal: true
|
||||
|
||||
vars:
|
||||
delegate_facts_host: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Import raw_install_python tasks
|
||||
ansible.builtin.import_tasks: "{{ playbook_dir }}/../raw_install_python.yml"
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
# pre-tasks for following import -
|
||||
- name: Gather facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'all'
|
||||
- '!facter'
|
||||
- '!ohai'
|
||||
when: not delegate_facts_host | bool or inventory_hostname in groups.get(client_group_name, [])
|
||||
|
||||
- name: Gather and delegate facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'all'
|
||||
- '!facter'
|
||||
- '!ohai'
|
||||
delegate_to: "{{ item }}"
|
||||
delegate_facts: true
|
||||
with_items: "{{ groups['all'] | difference(groups.get(client_group_name | default('clients'), [])) }}"
|
||||
run_once: true
|
||||
when: delegate_facts_host | bool
|
||||
|
||||
- name: Migrate to podman
|
||||
hosts:
|
||||
- "{{ mon_group_name | default('mons') }}"
|
||||
- "{{ osd_group_name | default('osds') }}"
|
||||
- "{{ mds_group_name | default('mdss') }}"
|
||||
- "{{ rgw_group_name | default('rgws') }}"
|
||||
- "{{ nfs_group_name | default('nfss') }}"
|
||||
- "{{ mgr_group_name | default('mgrs') }}"
|
||||
- "{{ rbdmirror_group_name | default('rbdmirrors') }}"
|
||||
- "{{ monitoring_group_name | default('monitoring') }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tasks:
|
||||
- name: Set_fact docker2podman and container_binary
|
||||
ansible.builtin.set_fact:
|
||||
docker2podman: true
|
||||
container_binary: podman
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Install podman
|
||||
ansible.builtin.package:
|
||||
name: podman
|
||||
state: present
|
||||
register: result
|
||||
until: result is succeeded
|
||||
tags: with_pkg
|
||||
when: not is_atomic | bool
|
||||
|
||||
- name: Check podman presence # noqa command-instead-of-shell
|
||||
ansible.builtin.shell: command -v podman
|
||||
register: podman_presence
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Pulling images from docker daemon
|
||||
when: podman_presence.rc == 0
|
||||
block:
|
||||
- name: Pulling Ceph container image from docker daemon
|
||||
ansible.builtin.command: "{{ timeout_command }} {{ container_binary }} pull docker-daemon:{{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}"
|
||||
changed_when: false
|
||||
register: pull_image
|
||||
until: pull_image.rc == 0
|
||||
retries: "{{ docker_pull_retry }}"
|
||||
delay: 10
|
||||
when: inventory_hostname in groups.get(mon_group_name, []) or
|
||||
inventory_hostname in groups.get(osd_group_name, []) or
|
||||
inventory_hostname in groups.get(mds_group_name, []) or
|
||||
inventory_hostname in groups.get(rgw_group_name, []) or
|
||||
inventory_hostname in groups.get(mgr_group_name, []) or
|
||||
inventory_hostname in groups.get(rbdmirror_group_name, []) or
|
||||
inventory_hostname in groups.get(nfs_group_name, [])
|
||||
|
||||
- name: Pulling alertmanager/grafana/prometheus images from docker daemon
|
||||
ansible.builtin.command: "{{ timeout_command }} {{ container_binary }} pull docker-daemon:{{ item }}"
|
||||
changed_when: false
|
||||
register: pull_image
|
||||
until: pull_image.rc == 0
|
||||
retries: "{{ docker_pull_retry }}"
|
||||
delay: 10
|
||||
loop:
|
||||
- "{{ alertmanager_container_image }}"
|
||||
- "{{ grafana_container_image }}"
|
||||
- "{{ prometheus_container_image }}"
|
||||
when:
|
||||
- dashboard_enabled | bool
|
||||
- inventory_hostname in groups.get(monitoring_group_name, [])
|
||||
|
||||
- name: Pulling node_exporter image from docker daemon
|
||||
ansible.builtin.command: "{{ timeout_command }} {{ container_binary }} pull docker-daemon:{{ node_exporter_container_image }}"
|
||||
changed_when: false
|
||||
register: pull_image
|
||||
until: pull_image.rc == 0
|
||||
retries: "{{ docker_pull_retry }}"
|
||||
delay: 10
|
||||
when: dashboard_enabled | bool
|
||||
|
||||
- name: Import ceph-mon role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-mon
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(mon_group_name, [])
|
||||
|
||||
- name: Import ceph-mds role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-mds
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(mds_group_name, [])
|
||||
|
||||
- name: Import ceph-mgr role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-mgr
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(mgr_group_name, [])
|
||||
|
||||
- name: Import ceph-nfs role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-nfs
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(nfs_group_name, [])
|
||||
|
||||
- name: Import ceph-osd role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-osd
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(osd_group_name, [])
|
||||
|
||||
- name: Import ceph-rbd-mirror role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-rbd-mirror
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(rbdmirror_group_name, [])
|
||||
|
||||
- name: Import ceph-rgw role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-rgw
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(rgw_group_name, [])
|
||||
|
||||
- name: Import ceph-crash role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-crash
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(mon_group_name, []) or
|
||||
inventory_hostname in groups.get(osd_group_name, []) or
|
||||
inventory_hostname in groups.get(mds_group_name, []) or
|
||||
inventory_hostname in groups.get(rgw_group_name, []) or
|
||||
inventory_hostname in groups.get(mgr_group_name, []) or
|
||||
inventory_hostname in groups.get(rbdmirror_group_name, [])
|
||||
|
||||
- name: Import ceph-exporter role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-exporter
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(mon_group_name, []) or
|
||||
inventory_hostname in groups.get(osd_group_name, []) or
|
||||
inventory_hostname in groups.get(mds_group_name, []) or
|
||||
inventory_hostname in groups.get(rgw_group_name, []) or
|
||||
inventory_hostname in groups.get(mgr_group_name, []) or
|
||||
inventory_hostname in groups.get(rbdmirror_group_name, [])
|
||||
|
||||
- name: Dashboard configuration
|
||||
when: dashboard_enabled | bool
|
||||
block:
|
||||
- name: Import ceph-node-exporter role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-node-exporter
|
||||
tasks_from: systemd.yml
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: grafana.yml
|
||||
when: inventory_hostname in groups.get(monitoring_group_name, [])
|
||||
|
||||
- name: Import ceph-grafana role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-grafana
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(monitoring_group_name, [])
|
||||
|
||||
- name: Import ceph-prometheus role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-prometheus
|
||||
tasks_from: systemd.yml
|
||||
when: inventory_hostname in groups.get(monitoring_group_name, [])
|
||||
|
||||
- name: Reload systemd daemon
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
- name: Gather ceph logs
|
||||
hosts:
|
||||
- mons
|
||||
- osds
|
||||
- mdss
|
||||
- rgws
|
||||
- nfss
|
||||
- rbdmirrors
|
||||
- clients
|
||||
- mgrs
|
||||
|
||||
gather_facts: false
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Create a temp directory
|
||||
ansible.builtin.tempfile:
|
||||
state: directory
|
||||
prefix: ceph_ansible
|
||||
run_once: true
|
||||
register: localtempfile
|
||||
become: false
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Set_fact lookup_ceph_config - lookup keys, conf and logs
|
||||
ansible.builtin.find:
|
||||
paths:
|
||||
- /etc/ceph
|
||||
- /var/log/ceph
|
||||
register: ceph_collect
|
||||
|
||||
- name: Collect ceph logs, config and keys on the machine running ansible
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ item.path }}"
|
||||
dest: "{{ localtempfile.path }}"
|
||||
fail_on_missing: false
|
||||
flat: false
|
||||
with_items: "{{ ceph_collect.files }}"
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
- name: Creates logical volumes for the bucket index or fs journals on a single device.
|
||||
become: true
|
||||
hosts: osds
|
||||
|
||||
vars:
|
||||
logfile: |
|
||||
Suggested cut and paste under "lvm_volumes:" in "group_vars/osds.yml"
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
{% for lv in nvme_device_lvs %}
|
||||
- data: {{ lv.lv_name }}
|
||||
data_vg: {{ nvme_vg_name }}
|
||||
journal: {{ lv.journal_name }}
|
||||
journal_vg: {{ nvme_vg_name }}
|
||||
{% endfor %}
|
||||
{% for hdd in hdd_devices %}
|
||||
- data: {{ hdd_lv_prefix }}-{{ hdd.split('/')[-1] }}
|
||||
data_vg: {{ hdd_vg_prefix }}-{{ hdd.split('/')[-1] }}
|
||||
journal: {{ hdd_journal_prefix }}-{{ hdd.split('/')[-1] }}
|
||||
journal_vg: {{ nvme_vg_name }}
|
||||
{% endfor %}
|
||||
|
||||
tasks:
|
||||
|
||||
- name: Include vars of lv_vars.yaml
|
||||
ansible.builtin.include_vars:
|
||||
file: lv_vars.yaml # noqa missing-import
|
||||
failed_when: false
|
||||
|
||||
# ensure nvme_device is set
|
||||
- name: Fail if nvme_device is not defined
|
||||
ansible.builtin.fail:
|
||||
msg: "nvme_device has not been set by the user"
|
||||
when: nvme_device is undefined or nvme_device == 'dummy'
|
||||
|
||||
# need to check if lvm2 is installed
|
||||
- name: Install lvm2
|
||||
ansible.builtin.package:
|
||||
name: lvm2
|
||||
state: present
|
||||
register: result
|
||||
until: result is succeeded
|
||||
|
||||
# Make entire nvme device a VG
|
||||
- name: Add nvme device as lvm pv
|
||||
community.general.lvg:
|
||||
force: true
|
||||
pvs: "{{ nvme_device }}"
|
||||
pesize: 4
|
||||
state: present
|
||||
vg: "{{ nvme_vg_name }}"
|
||||
|
||||
- name: Create lvs for fs journals for the bucket index on the nvme device
|
||||
community.general.lvol:
|
||||
lv: "{{ item.journal_name }}"
|
||||
vg: "{{ nvme_vg_name }}"
|
||||
size: "{{ journal_size }}"
|
||||
pvs: "{{ nvme_device }}"
|
||||
with_items: "{{ nvme_device_lvs }}"
|
||||
|
||||
- name: Create lvs for fs journals for hdd devices
|
||||
community.general.lvol:
|
||||
lv: "{{ hdd_journal_prefix }}-{{ item.split('/')[-1] }}"
|
||||
vg: "{{ nvme_vg_name }}"
|
||||
size: "{{ journal_size }}"
|
||||
with_items: "{{ hdd_devices }}"
|
||||
|
||||
- name: Create the lv for data portion of the bucket index on the nvme device
|
||||
community.general.lvol:
|
||||
lv: "{{ item.lv_name }}"
|
||||
vg: "{{ nvme_vg_name }}"
|
||||
size: "{{ item.size }}"
|
||||
pvs: "{{ nvme_device }}"
|
||||
with_items: "{{ nvme_device_lvs }}"
|
||||
|
||||
# Make sure all hdd devices have a unique volume group
|
||||
- name: Create vgs for all hdd devices
|
||||
community.general.lvg:
|
||||
force: true
|
||||
pvs: "{{ item }}"
|
||||
pesize: 4
|
||||
state: present
|
||||
vg: "{{ hdd_vg_prefix }}-{{ item.split('/')[-1] }}"
|
||||
with_items: "{{ hdd_devices }}"
|
||||
|
||||
- name: Create lvs for the data portion on hdd devices
|
||||
community.general.lvol:
|
||||
lv: "{{ hdd_lv_prefix }}-{{ item.split('/')[-1] }}"
|
||||
vg: "{{ hdd_vg_prefix }}-{{ item.split('/')[-1] }}"
|
||||
size: "{{ hdd_lv_size }}"
|
||||
pvs: "{{ item }}"
|
||||
with_items: "{{ hdd_devices }}"
|
||||
|
||||
- name: Write output for osds.yml
|
||||
become: false
|
||||
ansible.builtin.copy:
|
||||
content: "{{ logfile }}"
|
||||
dest: "{{ logfile_path }}"
|
||||
mode: preserve
|
||||
delegate_to: localhost
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
- name: Tear down existing osd filesystems then logical volumes, volume groups, and physical volumes
|
||||
become: true
|
||||
hosts: osds
|
||||
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to tear down the logical volumes?
|
||||
default: 'no'
|
||||
private: false
|
||||
|
||||
tasks:
|
||||
- name: Exit playbook, if user did not mean to tear down logical volumes
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
"Exiting lv-teardown playbook, logical volumes were NOT torn down.
|
||||
To tear down the logical volumes, either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
when: ireallymeanit != 'yes'
|
||||
|
||||
- name: Include vars of lv_vars.yaml
|
||||
ansible.builtin.include_vars:
|
||||
file: lv_vars.yaml # noqa missing-import
|
||||
failed_when: false
|
||||
|
||||
# need to check if lvm2 is installed
|
||||
- name: Install lvm2
|
||||
ansible.builtin.package:
|
||||
name: lvm2
|
||||
state: present
|
||||
register: result
|
||||
until: result is succeeded
|
||||
|
||||
# BEGIN TEARDOWN
|
||||
- name: Find any existing osd filesystems
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail;
|
||||
grep /var/lib/ceph/osd /proc/mounts | awk '{print $2}'
|
||||
register: old_osd_filesystems
|
||||
changed_when: false
|
||||
|
||||
- name: Tear down any existing osd filesystem
|
||||
ansible.posix.mount:
|
||||
path: "{{ item }}"
|
||||
state: unmounted
|
||||
with_items: "{{ old_osd_filesystems.stdout_lines }}"
|
||||
|
||||
- name: Kill all lvm commands that may have been hung
|
||||
ansible.builtin.command: "killall -q lvcreate pvcreate vgcreate lvconvert || echo -n"
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
## Logcal Vols
|
||||
- name: Tear down existing lv for bucket index
|
||||
community.general.lvol:
|
||||
lv: "{{ item.lv_name }}"
|
||||
vg: "{{ nvme_vg_name }}"
|
||||
state: absent
|
||||
force: true
|
||||
with_items: "{{ nvme_device_lvs }}"
|
||||
|
||||
- name: Tear down any existing hdd data lvs
|
||||
community.general.lvol:
|
||||
lv: "{{ hdd_lv_prefix }}-{{ item.split('/')[-1] }}"
|
||||
vg: "{{ hdd_vg_prefix }}-{{ item.split('/')[-1] }}"
|
||||
state: absent
|
||||
force: true
|
||||
with_items: "{{ hdd_devices }}"
|
||||
|
||||
- name: Tear down any existing lv of journal for bucket index
|
||||
community.general.lvol:
|
||||
lv: "{{ item.journal_name }}"
|
||||
vg: "{{ nvme_vg_name }}"
|
||||
state: absent
|
||||
force: true
|
||||
with_items: "{{ nvme_device_lvs }}"
|
||||
|
||||
- name: Tear down any existing lvs of hdd journals
|
||||
community.general.lvol:
|
||||
lv: "{{ hdd_journal_prefix }}-{{ item.split('/')[-1] }}"
|
||||
vg: "{{ nvme_vg_name }}"
|
||||
state: absent
|
||||
force: true
|
||||
with_items: "{{ hdd_devices }}"
|
||||
|
||||
## Volume Groups
|
||||
- name: Remove vg on nvme device
|
||||
community.general.lvg:
|
||||
vg: "{{ nvme_vg_name }}"
|
||||
state: absent
|
||||
force: true
|
||||
|
||||
- name: Remove vg for each hdd device
|
||||
community.general.lvg:
|
||||
vg: "{{ hdd_vg_prefix }}-{{ item.split('/')[-1] }}"
|
||||
state: absent
|
||||
force: true
|
||||
with_items: "{{ hdd_devices }}"
|
||||
|
||||
## Physical Vols
|
||||
- name: Tear down pv for nvme device
|
||||
ansible.builtin.command: "pvremove --force --yes {{ nvme_device }}"
|
||||
changed_when: false
|
||||
|
||||
- name: Tear down pv for each hdd device
|
||||
ansible.builtin.command: "pvremove --force --yes {{ item }}"
|
||||
changed_when: false
|
||||
with_items: "{{ hdd_devices }}"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
purge-cluster.yml
|
||||
@@ -0,0 +1,222 @@
|
||||
---
|
||||
# This playbook purges the Ceph MGR Dashboard and Monitoring
|
||||
# (alertmanager/prometheus/grafana/node-exporter) stack.
|
||||
# It removes: packages, configuration files and ALL THE DATA
|
||||
#
|
||||
# Use it like this:
|
||||
# ansible-playbook purge-dashboard.yml
|
||||
# Prompts for confirmation to purge, defaults to no and
|
||||
# doesn't purge anything. yes purges the dashboard and
|
||||
# monitoring stack.
|
||||
#
|
||||
# ansible-playbook -e ireallymeanit=yes|no purge-dashboard.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
|
||||
- name: Confirm whether user really meant to purge the dashboard
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to purge the dashboard?
|
||||
default: 'no'
|
||||
private: false
|
||||
tasks:
|
||||
- name: Exit playbook, if user did not mean to purge dashboard
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
"Exiting purge-dashboard playbook, dashboard was NOT purged.
|
||||
To purge the dashboard, either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
when: ireallymeanit != 'yes'
|
||||
|
||||
- name: Import_role ceph-defaults
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Gather facts on all hosts
|
||||
hosts:
|
||||
- "{{ mon_group_name|default('mons') }}"
|
||||
- "{{ osd_group_name|default('osds') }}"
|
||||
- "{{ mds_group_name|default('mdss') }}"
|
||||
- "{{ rgw_group_name|default('rgws') }}"
|
||||
- "{{ rbdmirror_group_name|default('rbdmirrors') }}"
|
||||
- "{{ nfs_group_name|default('nfss') }}"
|
||||
- "{{ client_group_name|default('clients') }}"
|
||||
- "{{ mgr_group_name|default('mgrs') }}"
|
||||
- "{{ monitoring_group_name | default('monitoring') }}"
|
||||
become: true
|
||||
tasks:
|
||||
- name: Gather facts on all Ceph hosts for following reference
|
||||
ansible.builtin.debug:
|
||||
msg: "gather facts on all Ceph hosts for following reference"
|
||||
|
||||
- name: Purge node exporter
|
||||
hosts:
|
||||
- "{{ mon_group_name|default('mons') }}"
|
||||
- "{{ osd_group_name|default('osds') }}"
|
||||
- "{{ mds_group_name|default('mdss') }}"
|
||||
- "{{ rgw_group_name|default('rgws') }}"
|
||||
- "{{ rbdmirror_group_name|default('rbdmirrors') }}"
|
||||
- "{{ nfs_group_name|default('nfss') }}"
|
||||
- "{{ client_group_name|default('clients') }}"
|
||||
- "{{ mgr_group_name|default('mgrs') }}"
|
||||
- "{{ monitoring_group_name | default('monitoring') }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
- name: Disable node_exporter service
|
||||
ansible.builtin.service:
|
||||
name: node_exporter
|
||||
state: stopped
|
||||
enabled: false
|
||||
failed_when: false
|
||||
|
||||
- name: Remove node_exporter service files
|
||||
ansible.builtin.file:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /etc/systemd/system/node_exporter.service
|
||||
- /run/node_exporter.service-cid
|
||||
|
||||
- name: Remove node-exporter image
|
||||
ansible.builtin.command: "{{ container_binary }} rmi {{ node_exporter_container_image }}"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Purge ceph monitoring
|
||||
hosts: "{{ monitoring_group_name | default('monitoring') }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
- name: Stop services
|
||||
ansible.builtin.service:
|
||||
name: "{{ item }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
failed_when: false
|
||||
loop:
|
||||
- alertmanager
|
||||
- prometheus
|
||||
- grafana-server
|
||||
|
||||
- name: Remove systemd service files
|
||||
ansible.builtin.file:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /etc/systemd/system/alertmanager.service
|
||||
- /etc/systemd/system/prometheus.service
|
||||
- /etc/systemd/system/grafana-server.service
|
||||
- /run/alertmanager.service-cid
|
||||
- /run/prometheus.service-cid
|
||||
- /run/grafana-server.service-cid
|
||||
|
||||
- name: Remove ceph dashboard container images
|
||||
ansible.builtin.command: "{{ container_binary }} rmi {{ item }}"
|
||||
loop:
|
||||
- "{{ alertmanager_container_image }}"
|
||||
- "{{ prometheus_container_image }}"
|
||||
- "{{ grafana_container_image }}"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Remove ceph-grafana-dashboards package on RedHat or SUSE
|
||||
ansible.builtin.package:
|
||||
name: ceph-grafana-dashboards
|
||||
state: absent
|
||||
when:
|
||||
- not containerized_deployment | bool
|
||||
- ansible_facts['os_family'] in ['RedHat', 'Suse']
|
||||
|
||||
- name: Remove data
|
||||
ansible.builtin.file:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- "{{ alertmanager_conf_dir }}"
|
||||
- "{{ prometheus_conf_dir }}"
|
||||
- /etc/grafana
|
||||
- "{{ alertmanager_data_dir }}"
|
||||
- "{{ prometheus_data_dir }}"
|
||||
- /var/lib/grafana
|
||||
|
||||
- name: Purge ceph dashboard
|
||||
hosts: "{{ groups[mgr_group_name] | default(groups[mon_group_name]) | default(omit) }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
- name: Remove the dashboard admin user
|
||||
ceph_dashboard_user:
|
||||
name: "{{ dashboard_admin_user }}"
|
||||
cluster: "{{ cluster }}"
|
||||
state: absent
|
||||
run_once: true
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
|
||||
- name: Remove radosgw system user
|
||||
radosgw_user:
|
||||
name: "{{ dashboard_rgw_api_user_id }}"
|
||||
cluster: "{{ cluster }}"
|
||||
state: absent
|
||||
run_once: true
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
when: groups.get(rgw_group_name, []) | length > 0
|
||||
|
||||
- name: Disable mgr dashboard and prometheus modules
|
||||
ceph_mgr_module:
|
||||
name: "{{ item }}"
|
||||
cluster: "{{ cluster }}"
|
||||
state: disable
|
||||
run_once: true
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
loop:
|
||||
- dashboard
|
||||
- prometheus
|
||||
|
||||
- name: Remove TLS certificate and key files
|
||||
ansible.builtin.file:
|
||||
name: "/etc/ceph/ceph-dashboard.{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- crt
|
||||
- key
|
||||
when: dashboard_protocol == "https"
|
||||
|
||||
- name: Remove ceph-mgr-dashboard package
|
||||
ansible.builtin.package:
|
||||
name: ceph-mgr-dashboard
|
||||
state: absent
|
||||
when: not containerized_deployment | bool
|
||||
@@ -0,0 +1,65 @@
|
||||
# This example playbook is used to add rgw users and buckets
|
||||
#
|
||||
# This example is run on your local machine
|
||||
#
|
||||
# Ensure that your local machine can connect to rgw of your cluster
|
||||
#
|
||||
# You will need to update the following vars
|
||||
#
|
||||
# rgw_host
|
||||
# port
|
||||
# admin_access_key
|
||||
# admin_secret_key
|
||||
#
|
||||
# Additionally modify the users list and buckets list to create the
|
||||
# users and buckets you want
|
||||
#
|
||||
- name: Add rgw users and buckets
|
||||
connection: local
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Add rgw users and buckets
|
||||
ceph_add_users_buckets:
|
||||
rgw_host: '172.20.0.2'
|
||||
port: 8000
|
||||
admin_access_key: '8W56BITCSX27CD555Z5B'
|
||||
admin_secret_key: 'JcrsUNDNPAvnAWHiBmwKOzMNreOIw2kJWAclQQ20'
|
||||
users:
|
||||
- username: 'test1'
|
||||
fullname: 'tester'
|
||||
email: 'dan1@email.com'
|
||||
maxbucket: 666
|
||||
suspend: false
|
||||
autogenkey: false
|
||||
accesskey: 'B3AR4Q33L59YV56A9A2F'
|
||||
secretkey: 'd84BRnMysnVGSyZiRlYUMduVgIarQWiNMdKzrF76'
|
||||
userquota: true
|
||||
usermaxsize: '1000'
|
||||
usermaxobjects: 3
|
||||
bucketquota: true
|
||||
bucketmaxsize: '1000'
|
||||
bucketmaxobjects: 3
|
||||
- username: 'test2'
|
||||
fullname: 'tester'
|
||||
buckets:
|
||||
- bucket: 'bucket1'
|
||||
user: 'test2'
|
||||
- bucket: 'bucket2'
|
||||
user: 'test1'
|
||||
- bucket: 'bucket3'
|
||||
user: 'test1'
|
||||
- bucket: 'bucket4'
|
||||
user: 'test1'
|
||||
- bucket: 'bucket5'
|
||||
user: 'test1'
|
||||
- bucket: 'bucket6'
|
||||
user: 'test2'
|
||||
- bucket: 'bucket7'
|
||||
user: 'test2'
|
||||
- bucket: 'bucket8'
|
||||
user: 'test2'
|
||||
- bucket: 'bucket9'
|
||||
user: 'test2'
|
||||
- bucket: 'bucket10'
|
||||
user: 'test2'
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,177 @@
|
||||
---
|
||||
# This playbook removes the Ceph MDS from your cluster.
|
||||
#
|
||||
# Use it like this:
|
||||
# ansible-playbook shrink-mds.yml -e mds_to_kill=ceph-mds01
|
||||
# Prompts for confirmation to shrink, defaults to no and
|
||||
# doesn't shrink the cluster. yes shrinks the cluster.
|
||||
#
|
||||
# ansible-playbook -e ireallymeanit=yes|no shrink-mds.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
- name: Gather facts and check the init system
|
||||
hosts:
|
||||
- "{{ mon_group_name | default('mons') }}"
|
||||
- "{{ mds_group_name | default('mdss') }}"
|
||||
become: true
|
||||
tasks:
|
||||
- name: Gather facts on all Ceph hosts for following reference
|
||||
ansible.builtin.debug:
|
||||
msg: gather facts on all Ceph hosts for following reference
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
- name: Perform checks, remove mds and print cluster health
|
||||
hosts: mons[0]
|
||||
become: true
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to shrink the cluster?
|
||||
default: 'no'
|
||||
private: false
|
||||
pre_tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Exit playbook, if no mds was given
|
||||
when: mds_to_kill is not defined
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
mds_to_kill must be declared.
|
||||
Exiting shrink-cluster playbook, no MDS was removed. On the command
|
||||
line when invoking the playbook, you can use
|
||||
"-e mds_to_kill=ceph-mds1" argument. You can only remove a single
|
||||
MDS each time the playbook runs."
|
||||
|
||||
- name: Exit playbook, if the mds is not part of the inventory
|
||||
when: mds_to_kill not in groups[mds_group_name]
|
||||
ansible.builtin.fail:
|
||||
msg: "It seems that the host given is not part of your inventory,
|
||||
please make sure it is."
|
||||
|
||||
- name: Exit playbook, if user did not mean to shrink cluster
|
||||
when: ireallymeanit != 'yes'
|
||||
ansible.builtin.fail:
|
||||
msg: "Exiting shrink-mds playbook, no mds was removed.
|
||||
To shrink the cluster, either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
|
||||
- name: Set_fact container_exec_cmd for mon0
|
||||
ansible.builtin.set_fact:
|
||||
container_exec_cmd: "{{ container_binary }} exec ceph-mon-{{ ansible_facts['hostname'] }}"
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Exit playbook, if can not connect to the cluster
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} timeout 5 ceph --cluster {{ cluster }} health"
|
||||
changed_when: false
|
||||
register: ceph_health
|
||||
until: ceph_health is succeeded
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Set_fact mds_to_kill_hostname
|
||||
ansible.builtin.set_fact:
|
||||
mds_to_kill_hostname: "{{ hostvars[mds_to_kill]['ansible_facts']['hostname'] }}"
|
||||
|
||||
tasks:
|
||||
# get rid of this as soon as "systemctl stop ceph-msd@$HOSTNAME" also
|
||||
# removes the MDS from the FS map.
|
||||
- name: Exit mds when containerized deployment
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph tell mds.{{ mds_to_kill_hostname }} exit"
|
||||
changed_when: false
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Get ceph status
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} -s -f json"
|
||||
register: ceph_status
|
||||
changed_when: false
|
||||
|
||||
- name: Set_fact current_max_mds
|
||||
ansible.builtin.set_fact:
|
||||
current_max_mds: "{{ (ceph_status.stdout | from_json)['fsmap']['max'] }}"
|
||||
|
||||
- name: Fail if removing that mds node wouldn't satisfy max_mds anymore
|
||||
ansible.builtin.fail:
|
||||
msg: "Can't remove more mds as it won't satisfy current max_mds setting"
|
||||
when:
|
||||
- ((((ceph_status.stdout | from_json)['fsmap']['up'] | int) + ((ceph_status.stdout | from_json)['fsmap']['up:standby'] | int)) - 1) < current_max_mds | int
|
||||
- (ceph_status.stdout | from_json)['fsmap']['up'] | int > 1
|
||||
|
||||
- name: Stop mds service and verify it
|
||||
block:
|
||||
- name: Stop mds service
|
||||
ansible.builtin.service:
|
||||
name: ceph-mds@{{ mds_to_kill_hostname }}
|
||||
state: stopped
|
||||
enabled: false
|
||||
delegate_to: "{{ mds_to_kill }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Ensure that the mds is stopped
|
||||
ansible.builtin.command: "systemctl is-active ceph-mds@{{ mds_to_kill_hostname }}" # noqa command-instead-of-module
|
||||
register: mds_to_kill_status
|
||||
failed_when: mds_to_kill_status.rc == 0
|
||||
delegate_to: "{{ mds_to_kill }}"
|
||||
retries: 5
|
||||
delay: 2
|
||||
changed_when: false
|
||||
|
||||
- name: Fail if the mds is reported as active or standby
|
||||
block:
|
||||
- name: Get new ceph status
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} -s -f json"
|
||||
register: ceph_status
|
||||
changed_when: false
|
||||
|
||||
- name: Get active mds nodes list
|
||||
ansible.builtin.set_fact:
|
||||
active_mdss: "{{ active_mdss | default([]) + [item.name] }}"
|
||||
with_items: "{{ (ceph_status.stdout | from_json)['fsmap']['by_rank'] }}"
|
||||
|
||||
- name: Get ceph fs dump status
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} fs dump -f json"
|
||||
register: ceph_fs_status
|
||||
changed_when: false
|
||||
|
||||
- name: Create a list of standby mdss
|
||||
ansible.builtin.set_fact:
|
||||
standby_mdss: (ceph_fs_status.stdout | from_json)['standbys'] | map(attribute='name') | list
|
||||
|
||||
- name: Fail if mds just killed is being reported as active or standby
|
||||
ansible.builtin.fail:
|
||||
msg: "mds node {{ mds_to_kill }} still up and running."
|
||||
when:
|
||||
- (mds_to_kill in active_mdss | default([])) or
|
||||
(mds_to_kill in standby_mdss | default([]))
|
||||
|
||||
- name: Delete the filesystem when killing last mds
|
||||
ceph_fs:
|
||||
name: "{{ cephfs }}"
|
||||
cluster: "{{ cluster }}"
|
||||
state: absent
|
||||
when:
|
||||
- (ceph_status.stdout | from_json)['fsmap']['up'] | int == 0
|
||||
- (ceph_status.stdout | from_json)['fsmap']['up:standby'] | int == 0
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
|
||||
- name: Purge mds store
|
||||
ansible.builtin.file:
|
||||
path: /var/lib/ceph/mds/{{ cluster }}-{{ mds_to_kill_hostname }}
|
||||
state: absent
|
||||
delegate_to: "{{ mds_to_kill }}"
|
||||
|
||||
post_tasks:
|
||||
- name: Show ceph health
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} -s"
|
||||
changed_when: false
|
||||
@@ -0,0 +1,138 @@
|
||||
---
|
||||
# This playbook shrinks the Ceph manager from your cluster
|
||||
#
|
||||
# Use it like this:
|
||||
# ansible-playbook shrink-mgr.yml -e mgr_to_kill=ceph-mgr1
|
||||
# Prompts for confirmation to shrink, defaults to no and
|
||||
# doesn't shrink the cluster and yes shrinks the cluster.
|
||||
#
|
||||
# ansible-playbook -e ireallymeanit=yes|no shrink-mgr.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
|
||||
|
||||
- name: Gather facts and check the init system
|
||||
hosts:
|
||||
- "{{ mon_group_name | default('mons') }}"
|
||||
- "{{ mgr_group_name | default('mgrs') }}"
|
||||
become: true
|
||||
tasks:
|
||||
- name: Gather facts on all Ceph hosts for following reference
|
||||
ansible.builtin.debug:
|
||||
msg: gather facts on all Ceph hosts for following reference
|
||||
|
||||
- name: Confirm if user really meant to remove manager from the ceph cluster
|
||||
hosts: mons[0]
|
||||
become: true
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to shrink the cluster?
|
||||
default: 'no'
|
||||
private: false
|
||||
pre_tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
- name: Set_fact container_exec_cmd
|
||||
when: containerized_deployment | bool
|
||||
ansible.builtin.set_fact:
|
||||
container_exec_cmd: "{{ container_binary }} exec ceph-mon-{{ ansible_facts['hostname'] }}"
|
||||
|
||||
- name: Exit playbook, if can not connect to the cluster
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} timeout 5 ceph --cluster {{ cluster }} health"
|
||||
register: ceph_health
|
||||
changed_when: false
|
||||
until: ceph_health is succeeded
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Get total number of mgrs in cluster
|
||||
block:
|
||||
- name: Save mgr dump output
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} mgr dump -f json"
|
||||
register: mgr_dump
|
||||
changed_when: false
|
||||
|
||||
- name: Get active and standbys mgr list
|
||||
ansible.builtin.set_fact:
|
||||
active_mgr: "{{ [mgr_dump.stdout | from_json] | map(attribute='active_name') | list }}"
|
||||
standbys_mgr: "{{ (mgr_dump.stdout | from_json)['standbys'] | map(attribute='name') | list }}"
|
||||
|
||||
- name: Exit playbook, if there's no standby manager
|
||||
ansible.builtin.fail:
|
||||
msg: "You are about to shrink the only manager present in the cluster."
|
||||
when: standbys_mgr | length | int < 1
|
||||
|
||||
- name: Exit playbook, if no manager was given
|
||||
ansible.builtin.fail:
|
||||
msg: "mgr_to_kill must be declared
|
||||
Exiting shrink-cluster playbook, no manager was removed.
|
||||
On the command line when invoking the playbook, you can use
|
||||
-e mgr_to_kill=ceph-mgr01 argument. You can only remove a single
|
||||
manager each time the playbook runs."
|
||||
when: mgr_to_kill is not defined
|
||||
|
||||
- name: Exit playbook, if user did not mean to shrink cluster
|
||||
ansible.builtin.fail:
|
||||
msg: "Exiting shrink-mgr playbook, no manager was removed.
|
||||
To shrink the cluster, either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
when: ireallymeanit != 'yes'
|
||||
|
||||
- name: Set_fact mgr_to_kill_hostname
|
||||
ansible.builtin.set_fact:
|
||||
mgr_to_kill_hostname: "{{ hostvars[mgr_to_kill]['ansible_facts']['hostname'] }}"
|
||||
|
||||
- name: Exit playbook, if the selected manager is not present in the cluster
|
||||
ansible.builtin.fail:
|
||||
msg: "It seems that the host given is not present in the cluster."
|
||||
when:
|
||||
- mgr_to_kill_hostname not in active_mgr
|
||||
- mgr_to_kill_hostname not in standbys_mgr
|
||||
|
||||
tasks:
|
||||
- name: Stop manager services and verify it
|
||||
block:
|
||||
- name: Stop manager service
|
||||
ansible.builtin.service:
|
||||
name: ceph-mgr@{{ mgr_to_kill_hostname }}
|
||||
state: stopped
|
||||
enabled: false
|
||||
delegate_to: "{{ mgr_to_kill }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Ensure that the mgr is stopped
|
||||
ansible.builtin.command: "systemctl is-active ceph-mgr@{{ mgr_to_kill_hostname }}" # noqa command-instead-of-module
|
||||
register: mgr_to_kill_status
|
||||
failed_when: mgr_to_kill_status.rc == 0
|
||||
delegate_to: "{{ mgr_to_kill }}"
|
||||
changed_when: false
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Fail if the mgr is reported in ceph mgr dump
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} mgr dump -f json"
|
||||
register: mgr_dump
|
||||
changed_when: false
|
||||
failed_when: mgr_to_kill_hostname in (([mgr_dump.stdout | from_json] | map(attribute='active_name') | list) + (mgr_dump.stdout | from_json)['standbys'] | map(attribute='name') | list)
|
||||
until: mgr_to_kill_hostname not in (([mgr_dump.stdout | from_json] | map(attribute='active_name') | list) + (mgr_dump.stdout | from_json)['standbys'] | map(attribute='name') | list)
|
||||
retries: 12
|
||||
delay: 10
|
||||
|
||||
- name: Purge manager store
|
||||
ansible.builtin.file:
|
||||
path: /var/lib/ceph/mgr/{{ cluster }}-{{ mgr_to_kill_hostname }}
|
||||
state: absent
|
||||
delegate_to: "{{ mgr_to_kill }}"
|
||||
|
||||
post_tasks:
|
||||
- name: Show ceph health
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} -s"
|
||||
changed_when: false
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
# This playbook shrinks the Ceph monitors from your cluster
|
||||
# It can remove a Ceph of monitor from the cluster and ALL ITS DATA
|
||||
#
|
||||
# Use it like this:
|
||||
# ansible-playbook shrink-mon.yml -e mon_to_kill=ceph-mon01
|
||||
# Prompts for confirmation to shrink, defaults to no and
|
||||
# doesn't shrink the cluster. yes shrinks the cluster.
|
||||
#
|
||||
# ansible-playbook -e ireallymeanit=yes|no shrink-mon.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
|
||||
|
||||
- name: Gather facts and check the init system
|
||||
|
||||
hosts: "{{ mon_group_name|default('mons') }}"
|
||||
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Gather facts on all Ceph hosts for following reference
|
||||
ansible.builtin.debug:
|
||||
msg: "gather facts on all Ceph hosts for following reference"
|
||||
|
||||
- name: Confirm whether user really meant to remove monitor from the ceph cluster
|
||||
hosts: mons[0]
|
||||
become: true
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to shrink the cluster?
|
||||
default: 'no'
|
||||
private: false
|
||||
vars:
|
||||
mon_group_name: mons
|
||||
|
||||
pre_tasks:
|
||||
- name: Exit playbook, if only one monitor is present in cluster
|
||||
ansible.builtin.fail:
|
||||
msg: "You are about to shrink the only monitor present in the cluster.
|
||||
If you really want to do that, please use the purge-cluster playbook."
|
||||
when: groups[mon_group_name] | length | int == 1
|
||||
|
||||
- name: Exit playbook, if no monitor was given
|
||||
ansible.builtin.fail:
|
||||
msg: "mon_to_kill must be declared
|
||||
Exiting shrink-cluster playbook, no monitor was removed.
|
||||
On the command line when invoking the playbook, you can use
|
||||
-e mon_to_kill=ceph-mon01 argument. You can only remove a single monitor each time the playbook runs."
|
||||
when: mon_to_kill is not defined
|
||||
|
||||
- name: Exit playbook, if the monitor is not part of the inventory
|
||||
ansible.builtin.fail:
|
||||
msg: "It seems that the host given is not part of your inventory, please make sure it is."
|
||||
when: mon_to_kill not in groups[mon_group_name]
|
||||
|
||||
- name: Exit playbook, if user did not mean to shrink cluster
|
||||
ansible.builtin.fail:
|
||||
msg: "Exiting shrink-mon playbook, no monitor was removed.
|
||||
To shrink the cluster, either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
when: ireallymeanit != 'yes'
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
tasks:
|
||||
- name: Pick a monitor different than the one we want to remove
|
||||
ansible.builtin.set_fact:
|
||||
mon_host: "{{ item }}"
|
||||
with_items: "{{ groups[mon_group_name] }}"
|
||||
when: item != mon_to_kill
|
||||
|
||||
- name: Set container_exec_cmd fact
|
||||
ansible.builtin.set_fact:
|
||||
container_exec_cmd: "{{ container_binary }} exec ceph-mon-{{ hostvars[mon_host]['ansible_facts']['hostname'] }}"
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Exit playbook, if can not connect to the cluster
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} timeout 5 ceph --cluster {{ cluster }} health"
|
||||
register: ceph_health
|
||||
changed_when: false
|
||||
until: ceph_health.stdout.find("HEALTH") > -1
|
||||
delegate_to: "{{ mon_host }}"
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Set_fact mon_to_kill_hostname
|
||||
ansible.builtin.set_fact:
|
||||
mon_to_kill_hostname: "{{ hostvars[mon_to_kill]['ansible_facts']['hostname'] }}"
|
||||
|
||||
- name: Stop monitor service(s)
|
||||
ansible.builtin.service:
|
||||
name: ceph-mon@{{ mon_to_kill_hostname }}
|
||||
state: stopped
|
||||
enabled: false
|
||||
delegate_to: "{{ mon_to_kill }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Purge monitor store
|
||||
ansible.builtin.file:
|
||||
path: /var/lib/ceph/mon/{{ cluster }}-{{ mon_to_kill_hostname }}
|
||||
state: absent
|
||||
delegate_to: "{{ mon_to_kill }}"
|
||||
|
||||
- name: Remove monitor from the quorum
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} ceph --cluster {{ cluster }} mon remove {{ mon_to_kill_hostname }}"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
delegate_to: "{{ mon_host }}"
|
||||
|
||||
post_tasks:
|
||||
- name: Verify the monitor is out of the cluster
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} ceph --cluster {{ cluster }} quorum_status -f json"
|
||||
delegate_to: "{{ mon_host }}"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: result
|
||||
until: mon_to_kill_hostname not in (result.stdout | from_json)['quorum_names']
|
||||
retries: 2
|
||||
delay: 10
|
||||
|
||||
- name: Please remove the monitor from your ceph configuration file
|
||||
ansible.builtin.debug:
|
||||
msg: "The monitor has been successfully removed from the cluster.
|
||||
Please remove the monitor entry from the rest of your ceph configuration files, cluster wide."
|
||||
run_once: true
|
||||
when: mon_to_kill_hostname not in (result.stdout | from_json)['quorum_names']
|
||||
|
||||
- name: Fail if monitor is still part of the cluster
|
||||
ansible.builtin.fail:
|
||||
msg: "Monitor appears to still be part of the cluster, please check what happened."
|
||||
run_once: true
|
||||
when: mon_to_kill_hostname in (result.stdout | from_json)['quorum_names']
|
||||
|
||||
- name: Show ceph health
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} ceph --cluster {{ cluster }} -s"
|
||||
delegate_to: "{{ mon_host }}"
|
||||
changed_when: false
|
||||
|
||||
- name: Show ceph mon status
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} ceph --cluster {{ cluster }} mon stat"
|
||||
delegate_to: "{{ mon_host }}"
|
||||
changed_when: false
|
||||
@@ -0,0 +1,379 @@
|
||||
---
|
||||
# This playbook shrinks Ceph OSDs that have been created with ceph-volume.
|
||||
# It can remove any number of OSD(s) from the cluster and ALL THEIR DATA
|
||||
#
|
||||
# Use it like this:
|
||||
# ansible-playbook shrink-osd.yml -e osd_to_kill=0,2,6
|
||||
# Prompts for confirmation to shrink, defaults to no and
|
||||
# doesn't shrink the cluster. yes shrinks the cluster.
|
||||
#
|
||||
# ansible-playbook -e ireallymeanit=yes|no shrink-osd.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
|
||||
- name: Gather facts and check the init system
|
||||
hosts:
|
||||
- mons
|
||||
- osds
|
||||
|
||||
become: true
|
||||
tasks:
|
||||
- name: Gather facts on all Ceph hosts for following reference
|
||||
ansible.builtin.debug:
|
||||
msg: "gather facts on all Ceph hosts for following reference"
|
||||
|
||||
- name: Confirm whether user really meant to remove osd(s) from the cluster
|
||||
hosts: mons[0]
|
||||
become: true
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to shrink the cluster?
|
||||
default: 'no'
|
||||
private: false
|
||||
vars:
|
||||
mon_group_name: mons
|
||||
osd_group_name: osds
|
||||
|
||||
pre_tasks:
|
||||
- name: Exit playbook, if user did not mean to shrink cluster
|
||||
ansible.builtin.fail:
|
||||
msg: "Exiting shrink-osd playbook, no osd(s) was/were removed..
|
||||
To shrink the cluster, either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
when: ireallymeanit != 'yes'
|
||||
|
||||
- name: Exit playbook, if no osd(s) was/were given
|
||||
ansible.builtin.fail:
|
||||
msg: "osd_to_kill must be declared
|
||||
Exiting shrink-osd playbook, no OSD(s) was/were removed.
|
||||
On the command line when invoking the playbook, you can use
|
||||
-e osd_to_kill=0,1,2,3 argument."
|
||||
when: osd_to_kill is not defined
|
||||
|
||||
- name: Check the osd ids passed have the correct format
|
||||
ansible.builtin.fail:
|
||||
msg: "The id {{ item }} has wrong format, please pass the number only"
|
||||
with_items: "{{ osd_to_kill.split(',') }}"
|
||||
when: not item is regex("^\d+$")
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
post_tasks:
|
||||
- name: Set_fact container_exec_cmd build docker exec command (containerized)
|
||||
ansible.builtin.set_fact:
|
||||
container_exec_cmd: "{{ container_binary }} exec ceph-mon-{{ ansible_facts['hostname'] }}"
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Exit playbook, if can not connect to the cluster
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} timeout 5 ceph --cluster {{ cluster }} health"
|
||||
register: ceph_health
|
||||
changed_when: false
|
||||
until: ceph_health.stdout.find("HEALTH") > -1
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Find the host(s) where the osd(s) is/are running on
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} ceph --cluster {{ cluster }} osd find {{ item }}"
|
||||
changed_when: false
|
||||
with_items: "{{ osd_to_kill.split(',') }}"
|
||||
register: find_osd_hosts
|
||||
|
||||
- name: Set_fact osd_hosts
|
||||
ansible.builtin.set_fact:
|
||||
osd_hosts: "{{ osd_hosts | default([]) + [[(item.stdout | from_json).crush_location.host, (item.stdout | from_json).osd_fsid, item.item]] }}"
|
||||
with_items: "{{ find_osd_hosts.results }}"
|
||||
|
||||
- name: Set_fact _osd_hosts
|
||||
ansible.builtin.set_fact:
|
||||
_osd_hosts: "{{ _osd_hosts | default([]) + [ [ item.0, item.2, item.3 ] ] }}"
|
||||
with_nested:
|
||||
- "{{ groups.get(osd_group_name) }}"
|
||||
- "{{ osd_hosts }}"
|
||||
when: hostvars[item.0]['ansible_facts']['hostname'] == item.1
|
||||
|
||||
- name: Set_fact host_list
|
||||
ansible.builtin.set_fact:
|
||||
host_list: "{{ host_list | default([]) | union([item.0]) }}"
|
||||
loop: "{{ _osd_hosts }}"
|
||||
|
||||
- name: Get ceph-volume lvm list data
|
||||
ceph_volume:
|
||||
cluster: "{{ cluster }}"
|
||||
action: list
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
register: _lvm_list_data
|
||||
delegate_to: "{{ item }}"
|
||||
loop: "{{ host_list }}"
|
||||
|
||||
- name: Set_fact _lvm_list
|
||||
ansible.builtin.set_fact:
|
||||
_lvm_list: "{{ _lvm_list | default({}) | combine(item.stdout | from_json) }}"
|
||||
with_items: "{{ _lvm_list_data.results }}"
|
||||
|
||||
- name: Refresh /etc/ceph/osd files non containerized_deployment
|
||||
ceph_volume_simple_scan:
|
||||
cluster: "{{ cluster }}"
|
||||
force: true
|
||||
delegate_to: "{{ item }}"
|
||||
loop: "{{ host_list }}"
|
||||
when: not containerized_deployment | bool
|
||||
|
||||
- name: Get osd unit status
|
||||
ansible.builtin.systemd:
|
||||
name: ceph-osd@{{ item.2 }}
|
||||
register: osd_status
|
||||
delegate_to: "{{ item.0 }}"
|
||||
loop: "{{ _osd_hosts }}"
|
||||
when:
|
||||
- containerized_deployment | bool
|
||||
|
||||
- name: Refresh /etc/ceph/osd files containerized_deployment
|
||||
ansible.builtin.command: "{{ container_binary }} exec ceph-osd-{{ item.2 }} ceph-volume simple scan --force /var/lib/ceph/osd/{{ cluster }}-{{ item.2 }}"
|
||||
changed_when: false
|
||||
delegate_to: "{{ item.0 }}"
|
||||
loop: "{{ _osd_hosts }}"
|
||||
when:
|
||||
- containerized_deployment | bool
|
||||
- item.2 not in _lvm_list.keys()
|
||||
- osd_status.results[0].status.ActiveState == 'active'
|
||||
|
||||
- name: Refresh /etc/ceph/osd files containerized_deployment when OSD container is down
|
||||
when:
|
||||
- containerized_deployment | bool
|
||||
- osd_status.results[0].status.ActiveState != 'active'
|
||||
block:
|
||||
- name: Create tmp osd folder
|
||||
ansible.builtin.file:
|
||||
path: /var/lib/ceph/tmp/{{ cluster }}-{{ item.2 }}
|
||||
state: directory
|
||||
mode: '0755'
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: item.2 not in _lvm_list.keys()
|
||||
loop: "{{ _osd_hosts }}"
|
||||
|
||||
- name: Activate OSD
|
||||
ansible.builtin.command: |
|
||||
{{ container_binary }} run -ti --pids-limit=-1 --rm --net=host --privileged=true --pid=host --ipc=host --cpus=1
|
||||
-v /dev:/dev -v /etc/localtime:/etc/localtime:ro
|
||||
-v /var/lib/ceph/tmp/:/var/lib/ceph/osd:z,rshared
|
||||
-v /etc/ceph:/etc/ceph:z -v /var/run/ceph:/var/run/ceph:z
|
||||
-v /var/run/udev/:/var/run/udev/ -v /var/log/ceph:/var/log/ceph:z
|
||||
-e OSD_BLUESTORE=1 -e OSD_FILESTORE=0 -e OSD_DMCRYPT=0 -e CLUSTER=ceph -e DEBUG=verbose
|
||||
-e TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=134217728 -v /run/lvm/:/run/lvm/
|
||||
-e CEPH_DAEMON=OSD_CEPH_VOLUME_ACTIVATE -e CONTAINER_IMAGE={{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag }}
|
||||
-e OSD_ID={{ item.2 }}
|
||||
--entrypoint=ceph-volume
|
||||
{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag }}
|
||||
simple activate {{ item.2 }} {{ item.1 }} --no-systemd
|
||||
changed_when: false
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: item.2 not in _lvm_list.keys()
|
||||
loop: "{{ _osd_hosts }}"
|
||||
|
||||
- name: Simple scan
|
||||
ansible.builtin.command: |
|
||||
{{ container_binary }} run -ti --pids-limit=-1 --rm --net=host --privileged=true --pid=host --ipc=host --cpus=1
|
||||
-v /dev:/dev -v /etc/localtime:/etc/localtime:ro
|
||||
-v /var/lib/ceph/tmp/:/var/lib/ceph/osd:z,rshared
|
||||
-v /etc/ceph:/etc/ceph:z -v /var/run/ceph:/var/run/ceph:z
|
||||
-v /var/run/udev/:/var/run/udev/ -v /var/log/ceph:/var/log/ceph:z
|
||||
-e OSD_BLUESTORE=1 -e OSD_FILESTORE=0 -e OSD_DMCRYPT=0 -e CLUSTER=ceph -e DEBUG=verbose
|
||||
-e TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=134217728 -v /run/lvm/:/run/lvm/
|
||||
-e CEPH_DAEMON=OSD_CEPH_VOLUME_ACTIVATE -e CONTAINER_IMAGE={{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag }}
|
||||
-e OSD_ID={{ item.2 }}
|
||||
--entrypoint=ceph-volume
|
||||
{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag }}
|
||||
simple scan --force /var/lib/ceph/osd/{{ cluster }}-{{ item.2 }}
|
||||
changed_when: false
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: item.2 not in _lvm_list.keys()
|
||||
loop: "{{ _osd_hosts }}"
|
||||
|
||||
- name: Umount OSD temp folder
|
||||
ansible.posix.mount:
|
||||
path: /var/lib/ceph/tmp/{{ cluster }}-{{ item.2 }}
|
||||
state: unmounted
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: item.2 not in _lvm_list.keys()
|
||||
loop: "{{ _osd_hosts }}"
|
||||
|
||||
- name: Remove OSD temp folder
|
||||
ansible.builtin.file:
|
||||
path: /var/lib/ceph/tmp/{{ cluster }}-{{ item.2 }}
|
||||
state: absent
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: item.2 not in _lvm_list.keys()
|
||||
loop: "{{ _osd_hosts }}"
|
||||
|
||||
- name: Find /etc/ceph/osd files
|
||||
ansible.builtin.find:
|
||||
paths: /etc/ceph/osd
|
||||
pattern: "{{ item.2 }}-*"
|
||||
register: ceph_osd_data
|
||||
delegate_to: "{{ item.0 }}"
|
||||
loop: "{{ _osd_hosts }}"
|
||||
when: item.2 not in _lvm_list.keys()
|
||||
|
||||
- name: Slurp ceph osd files content
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ item['files'][0]['path'] }}"
|
||||
delegate_to: "{{ item.item.0 }}"
|
||||
register: ceph_osd_files_content
|
||||
loop: "{{ ceph_osd_data.results }}"
|
||||
when:
|
||||
- item.skipped is undefined
|
||||
- item.matched > 0
|
||||
|
||||
- name: Set_fact ceph_osd_files_json
|
||||
ansible.builtin.set_fact:
|
||||
ceph_osd_data_json: "{{ ceph_osd_data_json | default({}) | combine({ item.item.item.2: item.content | b64decode | from_json}) }}"
|
||||
with_items: "{{ ceph_osd_files_content.results }}"
|
||||
when: item.skipped is undefined
|
||||
|
||||
- name: Mark osd(s) out of the cluster
|
||||
ceph_osd:
|
||||
ids: "{{ osd_to_kill.split(',') }}"
|
||||
cluster: "{{ cluster }}"
|
||||
state: out
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
run_once: true
|
||||
|
||||
- name: Stop osd(s) service
|
||||
ansible.builtin.service:
|
||||
name: ceph-osd@{{ item.2 }}
|
||||
state: stopped
|
||||
enabled: false
|
||||
loop: "{{ _osd_hosts }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
|
||||
- name: Umount osd lockbox
|
||||
ansible.posix.mount:
|
||||
path: "/var/lib/ceph/osd-lockbox/{{ ceph_osd_data_json[item.2]['data']['uuid'] }}"
|
||||
state: absent
|
||||
loop: "{{ _osd_hosts }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when:
|
||||
- not containerized_deployment | bool
|
||||
- item.2 not in _lvm_list.keys()
|
||||
- ceph_osd_data_json[item.2]['encrypted'] | default(False) | bool
|
||||
- ceph_osd_data_json[item.2]['data']['uuid'] is defined
|
||||
|
||||
- name: Umount osd data
|
||||
ansible.posix.mount:
|
||||
path: "/var/lib/ceph/osd/{{ cluster }}-{{ item.2 }}"
|
||||
state: absent
|
||||
loop: "{{ _osd_hosts }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: not containerized_deployment | bool
|
||||
|
||||
- name: Get parent device for data partition
|
||||
ansible.builtin.command: lsblk --noheadings --output PKNAME --nodeps "{{ ceph_osd_data_json[item.2]['data']['path'] }}"
|
||||
register: parent_device_data_part
|
||||
loop: "{{ _osd_hosts }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
changed_when: false
|
||||
when:
|
||||
- item.2 not in _lvm_list.keys()
|
||||
- ceph_osd_data_json[item.2]['data']['path'] is defined
|
||||
|
||||
- name: Add pkname information in ceph_osd_data_json
|
||||
ansible.builtin.set_fact:
|
||||
ceph_osd_data_json: "{{ ceph_osd_data_json | default({}) | combine({item.item[2]: {'pkname_data': '/dev/' + item.stdout}}, recursive=True) }}"
|
||||
loop: "{{ parent_device_data_part.results }}"
|
||||
when: item.skipped is undefined
|
||||
|
||||
- name: Close dmcrypt close on devices if needed
|
||||
ansible.builtin.command: "cryptsetup close {{ ceph_osd_data_json[item.2][item.3]['uuid'] }}"
|
||||
with_nested:
|
||||
- "{{ _osd_hosts }}"
|
||||
- ['block_dmcrypt', 'block.db_dmcrypt', 'block.wal_dmcrypt', 'data', 'journal_dmcrypt']
|
||||
delegate_to: "{{ item.0 }}"
|
||||
failed_when: false
|
||||
register: result
|
||||
until: result is succeeded
|
||||
changed_when: false
|
||||
when:
|
||||
- item.2 not in _lvm_list.keys()
|
||||
- ceph_osd_data_json[item.2]['encrypted'] | default(False) | bool
|
||||
- ceph_osd_data_json[item.2][item.3] is defined
|
||||
|
||||
- name: Use ceph-volume lvm zap to destroy all partitions
|
||||
ceph_volume:
|
||||
cluster: "{{ cluster }}"
|
||||
action: zap
|
||||
destroy: true
|
||||
data: "{{ ceph_osd_data_json[item.2]['pkname_data'] if item.3 == 'data' else ceph_osd_data_json[item.2][item.3]['path'] }}"
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
with_nested:
|
||||
- "{{ _osd_hosts }}"
|
||||
- ['block', 'block.db', 'block.wal', 'journal', 'data']
|
||||
delegate_to: "{{ item.0 }}"
|
||||
failed_when: false
|
||||
register: result
|
||||
when:
|
||||
- item.2 not in _lvm_list.keys()
|
||||
- ceph_osd_data_json[item.2][item.3] is defined
|
||||
|
||||
- name: Zap osd devices
|
||||
ceph_volume:
|
||||
action: "zap"
|
||||
osd_fsid: "{{ item.1 }}"
|
||||
environment:
|
||||
CEPH_VOLUME_DEBUG: "{{ ceph_volume_debug }}"
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
loop: "{{ _osd_hosts }}"
|
||||
when: item.2 in _lvm_list.keys()
|
||||
|
||||
- name: Ensure osds are marked down
|
||||
ceph_osd:
|
||||
ids: "{{ osd_to_kill.split(',') }}"
|
||||
cluster: "{{ cluster }}"
|
||||
state: down
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
run_once: true
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
|
||||
- name: Purge osd(s) from the cluster
|
||||
ceph_osd:
|
||||
ids: "{{ item }}"
|
||||
cluster: "{{ cluster }}"
|
||||
state: purge
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
run_once: true
|
||||
with_items: "{{ osd_to_kill.split(',') }}"
|
||||
|
||||
- name: Remove osd data dir
|
||||
ansible.builtin.file:
|
||||
path: "/var/lib/ceph/osd/{{ cluster }}-{{ item.2 }}"
|
||||
state: absent
|
||||
loop: "{{ _osd_hosts }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
|
||||
- name: Show ceph health
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} ceph --cluster {{ cluster }} -s"
|
||||
changed_when: false
|
||||
|
||||
- name: Show ceph osd tree
|
||||
ansible.builtin.command: "{{ container_exec_cmd }} ceph --cluster {{ cluster }} osd tree"
|
||||
changed_when: false
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
# This playbook removes the Ceph RBD mirror from your cluster on the given
|
||||
# node.
|
||||
#
|
||||
# Use it like this:
|
||||
# ansible-playbook shrink-rbdmirror.yml -e rbdmirror_to_kill=ceph-rbdmirror01
|
||||
# Prompts for confirmation to shrink, defaults to no and
|
||||
# doesn't shrink the cluster. yes shrinks the cluster.
|
||||
#
|
||||
# ansible-playbook -e ireallymeanit=yes|no shrink-rbdmirror.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
|
||||
- name: Gather facts and check the init system
|
||||
hosts:
|
||||
- mons
|
||||
- rbdmirrors
|
||||
become: true
|
||||
tasks:
|
||||
- name: Gather facts on MONs and RBD mirrors
|
||||
ansible.builtin.debug:
|
||||
msg: gather facts on MONs and RBD mirrors
|
||||
|
||||
- name: Confirm whether user really meant to remove rbd mirror from the ceph
|
||||
cluster
|
||||
hosts: mons[0]
|
||||
become: true
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to shrink the cluster?
|
||||
default: 'no'
|
||||
private: false
|
||||
pre_tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
- name: Exit playbook, if no rbdmirror was given
|
||||
ansible.builtin.fail:
|
||||
msg: "rbdmirror_to_kill must be declared
|
||||
Exiting shrink-cluster playbook, no RBD mirror was removed.
|
||||
On the command line when invoking the playbook, you can use
|
||||
-e rbdmirror_to_kill=rbd-mirror01 argument. You can only remove a
|
||||
single rbd mirror each time the playbook runs."
|
||||
when: rbdmirror_to_kill is not defined
|
||||
|
||||
- name: Exit playbook, if the rbdmirror is not part of the inventory
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
It seems that the host given is not part of your inventory,
|
||||
please make sure it is.
|
||||
when: rbdmirror_to_kill not in groups[rbdmirror_group_name]
|
||||
|
||||
- name: Exit playbook, if user did not mean to shrink cluster
|
||||
ansible.builtin.fail:
|
||||
msg: "Exiting shrink-rbdmirror playbook, no rbd-mirror was removed.
|
||||
To shrink the cluster, either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
when: ireallymeanit != 'yes'
|
||||
|
||||
- name: Set_fact container_exec_cmd for mon0
|
||||
when: containerized_deployment | bool
|
||||
ansible.builtin.set_fact:
|
||||
container_exec_cmd: "{{ container_binary }} exec ceph-mon-{{ ansible_facts['hostname'] }}"
|
||||
|
||||
- name: Exit playbook, if can not connect to the cluster
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} timeout 5 ceph --cluster {{ cluster }} service dump -f json"
|
||||
register: ceph_health
|
||||
changed_when: false
|
||||
until: ceph_health is succeeded
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Set_fact rbdmirror_to_kill_hostname
|
||||
ansible.builtin.set_fact:
|
||||
rbdmirror_to_kill_hostname: "{{ hostvars[rbdmirror_to_kill]['ansible_facts']['hostname'] }}"
|
||||
|
||||
- name: Set_fact rbdmirror_gids
|
||||
ansible.builtin.set_fact:
|
||||
rbdmirror_gids: "{{ rbdmirror_gids | default([]) + [item] }}"
|
||||
with_items: "{{ (ceph_health.stdout | from_json)['services']['rbd-mirror']['daemons'].keys() | list }}"
|
||||
when: item != 'summary'
|
||||
|
||||
- name: Set_fact rbdmirror_to_kill_gid
|
||||
ansible.builtin.set_fact:
|
||||
rbdmirror_to_kill_gid: "{{ (ceph_health.stdout | from_json)['services']['rbd-mirror']['daemons'][item]['gid'] }}"
|
||||
with_items: "{{ rbdmirror_gids }}"
|
||||
when: (ceph_health.stdout | from_json)['services']['rbd-mirror']['daemons'][item]['metadata']['id'] == rbdmirror_to_kill_hostname
|
||||
|
||||
tasks:
|
||||
- name: Stop rbdmirror service
|
||||
ansible.builtin.service:
|
||||
name: ceph-rbd-mirror@rbd-mirror.{{ rbdmirror_to_kill_hostname }}
|
||||
state: stopped
|
||||
enabled: false
|
||||
delegate_to: "{{ rbdmirror_to_kill }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Purge related directories
|
||||
ansible.builtin.file:
|
||||
path: /var/lib/ceph/bootstrap-rbd-mirror/{{ cluster }}-{{ rbdmirror_to_kill_hostname }}
|
||||
state: absent
|
||||
delegate_to: "{{ rbdmirror_to_kill }}"
|
||||
|
||||
post_tasks:
|
||||
- name: Get servicemap details
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} timeout 5 ceph --cluster {{ cluster }} service dump -f json"
|
||||
register: ceph_health
|
||||
failed_when:
|
||||
- "'rbd-mirror' in (ceph_health.stdout | from_json)['services'].keys() | list"
|
||||
- rbdmirror_to_kill_gid in (ceph_health.stdout | from_json)['services']['rbd-mirror']['daemons'].keys() | list
|
||||
until:
|
||||
- "'rbd-mirror' in (ceph_health.stdout | from_json)['services'].keys() | list"
|
||||
- rbdmirror_to_kill_gid not in (ceph_health.stdout | from_json)['services']['rbd-mirror']['daemons'].keys() | list
|
||||
changed_when: false
|
||||
when: rbdmirror_to_kill_gid is defined
|
||||
retries: 12
|
||||
delay: 10
|
||||
|
||||
- name: Show ceph health
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} -s"
|
||||
changed_when: false
|
||||
@@ -0,0 +1,141 @@
|
||||
---
|
||||
# This playbook shrinks the Ceph RGW from your cluster
|
||||
#
|
||||
# Use it like this:
|
||||
# ansible-playbook shrink-rgw.yml -e rgw_to_kill=ceph-rgw01
|
||||
# Prompts for confirmation to shrink, defaults to no and
|
||||
# doesn't shrink the cluster. yes shrinks the cluster.
|
||||
#
|
||||
# ansible-playbook -e ireallymeanit=yes|no shrink-rgw.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
|
||||
|
||||
- name: Confirm whether user really meant to remove rgw from the ceph cluster
|
||||
hosts: localhost
|
||||
become: false
|
||||
gather_facts: false
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to shrink the cluster?
|
||||
default: 'no'
|
||||
private: false
|
||||
tasks:
|
||||
- name: Exit playbook, if no rgw was given
|
||||
when: rgw_to_kill is not defined or rgw_to_kill | length == 0
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
rgw_to_kill must be declared.
|
||||
Exiting shrink-cluster playbook, no RGW was removed. On the command
|
||||
line when invoking the playbook, you can use
|
||||
"-e rgw_to_kill=ceph.rgw0 argument". You can only remove a single
|
||||
RGW each time the playbook runs.
|
||||
|
||||
- name: Exit playbook, if user did not mean to shrink cluster
|
||||
when: ireallymeanit != 'yes'
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
Exiting shrink-mon playbook, no monitor was removed. To shrink the
|
||||
cluster, either say 'yes' on the prompt or use
|
||||
'-e ireallymeanit=yes' on the command line when invoking the playbook
|
||||
|
||||
- name: Gather facts and mons and rgws
|
||||
hosts:
|
||||
- "{{ mon_group_name | default('mons') }}[0]"
|
||||
- "{{ rgw_group_name | default('rgws') }}"
|
||||
become: true
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Gather facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'all'
|
||||
- '!facter'
|
||||
- '!ohai'
|
||||
|
||||
- name: Shrink rgw service
|
||||
hosts: mons[0]
|
||||
become: true
|
||||
gather_facts: false
|
||||
pre_tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary
|
||||
|
||||
- name: Set_fact container_exec_cmd for mon0
|
||||
ansible.builtin.set_fact:
|
||||
container_exec_cmd: "{{ container_binary }} exec ceph-mon-{{ ansible_facts['hostname'] }}"
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Exit playbook, if can not connect to the cluster
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} timeout 5 ceph --cluster {{ cluster }} health"
|
||||
register: ceph_health
|
||||
changed_when: false
|
||||
until: ceph_health is succeeded
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Get rgw instances
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} service dump -f json"
|
||||
register: rgw_instances
|
||||
changed_when: false
|
||||
|
||||
|
||||
- name: Exit playbook, if the rgw_to_kill doesn't exist
|
||||
when: rgw_to_kill not in (rgw_instances.stdout | from_json).services.rgw.daemons.keys() | list
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
It seems that the rgw instance given is not part of the ceph cluster. Please
|
||||
make sure it is.
|
||||
The rgw instance format is $(hostname}.rgw$(instance number).
|
||||
tasks:
|
||||
- name: Get rgw host running the rgw instance to kill
|
||||
ansible.builtin.set_fact:
|
||||
rgw_host: '{{ item }}'
|
||||
with_items: '{{ groups[rgw_group_name] }}'
|
||||
when: hostvars[item]['ansible_facts']['hostname'] == rgw_to_kill.split('.')[0]
|
||||
|
||||
- name: Stop rgw service
|
||||
ansible.builtin.service:
|
||||
name: ceph-radosgw@rgw.{{ rgw_to_kill }}
|
||||
state: stopped
|
||||
enabled: false
|
||||
delegate_to: "{{ rgw_host }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Ensure that the rgw is stopped
|
||||
ansible.builtin.command: "systemctl is-active ceph-radosgw@rgw.{{ rgw_to_kill }}" # noqa command-instead-of-module
|
||||
register: rgw_to_kill_status
|
||||
failed_when: rgw_to_kill_status.rc == 0
|
||||
changed_when: false
|
||||
delegate_to: "{{ rgw_host }}"
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Exit if rgw_to_kill is reported in ceph status
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} service dump -f json"
|
||||
register: ceph_status
|
||||
changed_when: false
|
||||
failed_when:
|
||||
- (ceph_status.stdout | from_json).services.rgw is defined
|
||||
- rgw_to_kill in (ceph_status.stdout | from_json).services.rgw.daemons.keys() | list
|
||||
until:
|
||||
- (ceph_status.stdout | from_json).services.rgw is defined
|
||||
- rgw_to_kill not in (ceph_status.stdout | from_json).services.rgw.daemons.keys() | list
|
||||
retries: 3
|
||||
delay: 3
|
||||
|
||||
- name: Purge directories related to rgw
|
||||
ansible.builtin.file:
|
||||
path: /var/lib/ceph/radosgw/{{ cluster }}-rgw.{{ rgw_to_kill }}
|
||||
state: absent
|
||||
delegate_to: "{{ rgw_host }}"
|
||||
post_tasks:
|
||||
- name: Show ceph health
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} -s"
|
||||
changed_when: false
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
# This playbook queries each OSD using `ceph-volume inventory` to report the
|
||||
# entire storage device inventory of a cluster.
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook storage-inventory.yml
|
||||
|
||||
- name: Gather facts and check the init system
|
||||
hosts: osds
|
||||
become: true
|
||||
tasks:
|
||||
- name: Gather facts on all Ceph hosts
|
||||
ansible.builtin.debug:
|
||||
msg: "gather facts on all Ceph hosts for following reference"
|
||||
|
||||
- name: Query each host for storage device inventory
|
||||
hosts: osds
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: List storage inventory
|
||||
ceph_volume:
|
||||
action: "inventory"
|
||||
environment:
|
||||
CEPH_VOLUME_DEBUG: "{{ ceph_volume_debug }}"
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
+808
@@ -0,0 +1,808 @@
|
||||
---
|
||||
# This playbook switches from non-containerized to containerized Ceph daemons
|
||||
|
||||
- name: Confirm whether user really meant to switch from non-containerized to containerized ceph daemons
|
||||
|
||||
hosts: localhost
|
||||
|
||||
gather_facts: false
|
||||
any_errors_fatal: true
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to switch from non-containerized to containerized ceph daemons?
|
||||
default: 'no'
|
||||
private: false
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Fail when less than three monitors
|
||||
ansible.builtin.fail:
|
||||
msg: "This playbook requires at least three monitors."
|
||||
when: groups[mon_group_name] | length | int < 3
|
||||
|
||||
- name: Exit playbook, if user did not mean to switch from non-containerized to containerized daemons?
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
"Exiting switch-from-non-containerized-to-containerized-ceph-daemons.yml playbook,
|
||||
cluster did not switch from non-containerized to containerized ceph daemons.
|
||||
To switch from non-containerized to containerized ceph daemons, either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
when: ireallymeanit != 'yes'
|
||||
|
||||
|
||||
- name: Gather facts
|
||||
|
||||
hosts:
|
||||
- "{{ mon_group_name|default('mons') }}"
|
||||
- "{{ mgr_group_name|default('mgrs') }}"
|
||||
- "{{ osd_group_name|default('osds') }}"
|
||||
- "{{ mds_group_name|default('mdss') }}"
|
||||
- "{{ rgw_group_name|default('rgws') }}"
|
||||
- "{{ rbdmirror_group_name|default('rbdmirrors') }}"
|
||||
- "{{ nfs_group_name|default('nfss') }}"
|
||||
|
||||
become: true
|
||||
|
||||
vars:
|
||||
delegate_facts_host: true
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Gather and delegate facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'all'
|
||||
- '!facter'
|
||||
- '!ohai'
|
||||
delegate_to: "{{ item }}"
|
||||
delegate_facts: true
|
||||
with_items: "{{ groups['all'] | difference(groups.get(client_group_name, [])) }}"
|
||||
run_once: true
|
||||
when: delegate_facts_host | bool
|
||||
tags: always
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
- name: Import ceph-validate role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-validate
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph mon
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
switch_to_containers: true
|
||||
mon_group_name: mons
|
||||
hosts: "{{ mon_group_name|default('mons') }}"
|
||||
serial: 1
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: Select a running monitor
|
||||
ansible.builtin.set_fact:
|
||||
mon_host: "{{ item }}"
|
||||
with_items: "{{ groups[mon_group_name] }}"
|
||||
when: item != inventory_hostname
|
||||
|
||||
- name: Stop non-containerized ceph mon
|
||||
ansible.builtin.service:
|
||||
name: "ceph-mon@{{ ansible_facts['hostname'] }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
|
||||
- name: Remove old systemd unit files
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- /usr/lib/systemd/system/ceph-mon@.service
|
||||
- /usr/lib/systemd/system/ceph-mon.target
|
||||
- /lib/systemd/system/ceph-mon@.service
|
||||
- /lib/systemd/system/ceph-mon.target
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
# NOTE: changed from file module to raw find command for performance reasons
|
||||
# The file module has to run checks on current ownership of all directories and files. This is unnecessary
|
||||
# as in this case we know we want all owned by ceph user
|
||||
- name: Set proper ownership on ceph directories
|
||||
ansible.builtin.command: "find /var/lib/ceph/mon /etc/ceph -not -( -user {{ ceph_uid }} -or -group {{ ceph_uid }} -) -execdir chown -h {{ ceph_uid }}:{{ ceph_uid }} {} +"
|
||||
changed_when: false
|
||||
|
||||
- name: Check for existing old leveldb file extension (ldb)
|
||||
ansible.builtin.shell: stat /var/lib/ceph/mon/*/store.db/*.ldb
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: ldb_files
|
||||
|
||||
- name: Rename leveldb extension from ldb to sst
|
||||
ansible.builtin.shell: rename -v .ldb .sst /var/lib/ceph/mon/*/store.db/*.ldb
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ldb_files.rc == 0
|
||||
|
||||
- name: Copy mon initial keyring in /etc/ceph to satisfy fetch config task in ceph-container-common
|
||||
ansible.builtin.command: cp /var/lib/ceph/mon/{{ cluster }}-{{ ansible_facts['hostname'] }}/keyring /etc/ceph/{{ cluster }}.mon.keyring
|
||||
args:
|
||||
creates: /etc/ceph/{{ cluster }}.mon.keyring
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-container-engine role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
|
||||
- name: Import ceph-mon role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-mon
|
||||
|
||||
post_tasks:
|
||||
- name: Waiting for the monitor to join the quorum...
|
||||
ansible.builtin.command: "{{ container_binary }} run --rm -v /etc/ceph:/etc/ceph:z --entrypoint=ceph {{ ceph_docker_registry }}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }} --cluster {{ cluster }} quorum_status --format json"
|
||||
register: ceph_health_raw
|
||||
until: ansible_facts['hostname'] in (ceph_health_raw.stdout | trim | from_json)["quorum_names"]
|
||||
changed_when: false
|
||||
retries: "{{ health_mon_check_retries }}"
|
||||
delay: "{{ health_mon_check_delay }}"
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph mgr
|
||||
|
||||
hosts: "{{ mgr_group_name|default('mgrs') }}"
|
||||
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
mgr_group_name: mgrs
|
||||
|
||||
serial: 1
|
||||
become: true
|
||||
pre_tasks:
|
||||
# failed_when: false is here because if we're
|
||||
# working with a jewel cluster then ceph mgr
|
||||
# will not exist
|
||||
- name: Stop non-containerized ceph mgr(s)
|
||||
ansible.builtin.service:
|
||||
name: "ceph-mgr@{{ ansible_facts['hostname'] }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
failed_when: false
|
||||
|
||||
- name: Remove old systemd unit files
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- /usr/lib/systemd/system/ceph-mgr@.service
|
||||
- /usr/lib/systemd/system/ceph-mgr.target
|
||||
- /lib/systemd/system/ceph-mgr@.service
|
||||
- /lib/systemd/system/ceph-mgr.target
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
# NOTE: changed from file module to raw find command for performance reasons
|
||||
# The file module has to run checks on current ownership of all directories and files. This is unnecessary
|
||||
# as in this case we know we want all owned by ceph user
|
||||
- name: Set proper ownership on ceph directories
|
||||
ansible.builtin.command: "find /var/lib/ceph/mgr /etc/ceph -not -( -user {{ ceph_uid }} -or -group {{ ceph_uid }} -) -execdir chown -h {{ ceph_uid }}:{{ ceph_uid }} {} +"
|
||||
changed_when: false
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-container-engine role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
|
||||
- name: Import ceph-mgr role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-mgr
|
||||
|
||||
|
||||
- name: Set osd flags
|
||||
hosts: "{{ mon_group_name | default('mons') }}[0]"
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary.yml
|
||||
|
||||
- name: Get pool list
|
||||
ansible.builtin.command: "{{ ceph_cmd }} --cluster {{ cluster }} osd pool ls detail -f json"
|
||||
register: pool_list
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Get balancer module status
|
||||
ansible.builtin.command: "{{ ceph_cmd }} --cluster {{ cluster }} balancer status -f json"
|
||||
register: balancer_status_switch
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Set_fact pools_pgautoscaler_mode
|
||||
ansible.builtin.set_fact:
|
||||
pools_pgautoscaler_mode: "{{ pools_pgautoscaler_mode | default([]) | union([{'name': item.pool_name, 'mode': item.pg_autoscale_mode}]) }}"
|
||||
with_items: "{{ pool_list.stdout | default('{}') | from_json }}"
|
||||
|
||||
- name: Disable balancer
|
||||
ansible.builtin.command: "{{ ceph_cmd }} --cluster {{ cluster }} balancer off"
|
||||
changed_when: false
|
||||
when: (balancer_status_switch.stdout | from_json)['active'] | bool
|
||||
|
||||
- name: Disable pg autoscale on pools
|
||||
ceph_pool:
|
||||
name: "{{ item.name }}"
|
||||
cluster: "{{ cluster }}"
|
||||
pg_autoscale_mode: false
|
||||
with_items: "{{ pools_pgautoscaler_mode }}"
|
||||
when:
|
||||
- pools_pgautoscaler_mode is defined
|
||||
- item.mode == 'on'
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
|
||||
- name: Set osd flags
|
||||
ceph_osd_flag:
|
||||
name: "{{ item }}"
|
||||
cluster: "{{ cluster }}"
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
with_items:
|
||||
- noout
|
||||
- nodeep-scrub
|
||||
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph osd
|
||||
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
osd_group_name: osds
|
||||
switch_to_containers: true
|
||||
|
||||
hosts: "{{ osd_group_name|default('osds') }}"
|
||||
|
||||
serial: 1
|
||||
become: true
|
||||
pre_tasks:
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Collect running osds
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail;
|
||||
systemctl list-units | grep -E "loaded * active" | grep -Eo 'ceph-osd@[0-9]+.service|ceph-volume'
|
||||
register: running_osds
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
# systemd module does not support --runtime option
|
||||
- name: Disable ceph-osd@.service runtime-enabled
|
||||
ansible.builtin.command: "systemctl disable --runtime {{ item }}" # noqa command-instead-of-module
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
with_items: "{{ running_osds.stdout_lines | default([]) }}"
|
||||
when: item.startswith('ceph-osd@')
|
||||
|
||||
- name: Stop/disable/mask non-containerized ceph osd(s) (if any)
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ item }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
with_items: "{{ running_osds.stdout_lines | default([]) }}"
|
||||
when: running_osds != []
|
||||
|
||||
- name: Disable ceph.target
|
||||
ansible.builtin.systemd:
|
||||
name: ceph.target
|
||||
enabled: false
|
||||
|
||||
- name: Remove old ceph-osd systemd units
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- /usr/lib/systemd/system/ceph-osd.target
|
||||
- /usr/lib/systemd/system/ceph-osd@.service
|
||||
- /usr/lib/systemd/system/ceph-volume@.service
|
||||
- /lib/systemd/system/ceph-osd.target
|
||||
- /lib/systemd/system/ceph-osd@.service
|
||||
- /lib/systemd/system/ceph-volume@.service
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
# NOTE: changed from file module to raw find command for performance reasons
|
||||
# The file module has to run checks on current ownership of all directories and files. This is unnecessary
|
||||
# as in this case we know we want all owned by ceph user
|
||||
- name: Set proper ownership on ceph directories
|
||||
ansible.builtin.command: "find /var/lib/ceph/osd /etc/ceph -not -( -user {{ ceph_uid }} -or -group {{ ceph_uid }} -) -execdir chown -h {{ ceph_uid }}:{{ ceph_uid }} {} +"
|
||||
changed_when: false
|
||||
|
||||
- name: Check for existing old leveldb file extension (ldb)
|
||||
ansible.builtin.shell: stat /var/lib/ceph/osd/*/current/omap/*.ldb
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: ldb_files
|
||||
|
||||
- name: Rename leveldb extension from ldb to sst
|
||||
ansible.builtin.shell: rename -v .ldb .sst /var/lib/ceph/osd/*/current/omap/*.ldb
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ldb_files.rc == 0
|
||||
|
||||
- name: Check if containerized osds are already running
|
||||
ansible.builtin.command: >
|
||||
{{ container_binary }} ps -q --filter='name=ceph-osd'
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: osd_running
|
||||
|
||||
- name: Get osd directories
|
||||
ansible.builtin.command: >
|
||||
find /var/lib/ceph/osd {% if dmcrypt | bool %}/var/lib/ceph/osd-lockbox{% endif %} -maxdepth 1 -mindepth 1 -type d
|
||||
register: osd_dirs
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Unmount all the osd directories
|
||||
ansible.builtin.command: >
|
||||
umount {{ item }}
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
with_items: "{{ osd_dirs.stdout_lines }}"
|
||||
when: osd_running.rc != 0 or osd_running.stdout_lines | length == 0
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
|
||||
- name: Import ceph-osd role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-osd
|
||||
|
||||
post_tasks:
|
||||
- name: Container - waiting for clean pgs...
|
||||
ansible.builtin.command: >
|
||||
{{ container_binary }} exec ceph-mon-{{ hostvars[groups[mon_group_name][0]]['ansible_facts']['hostname'] }} ceph --cluster {{ cluster }} pg stat --format json
|
||||
register: ceph_health_post
|
||||
until: >
|
||||
(((ceph_health_post.stdout | from_json).pg_summary.num_pg_by_state | length) > 0)
|
||||
and
|
||||
(((ceph_health_post.stdout | from_json).pg_summary.num_pg_by_state | selectattr('name', 'search', '^active\\+clean') | map(attribute='num') | list | sum) == (ceph_health_post.stdout | from_json).pg_summary.num_pgs)
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
retries: "{{ health_osd_check_retries }}"
|
||||
delay: "{{ health_osd_check_delay }}"
|
||||
changed_when: false
|
||||
|
||||
|
||||
- name: Unset osd flags
|
||||
hosts: "{{ mon_group_name | default('mons') }}[0]"
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary.yml
|
||||
|
||||
- name: Re-enable pg autoscale on pools
|
||||
ceph_pool:
|
||||
name: "{{ item.name }}"
|
||||
cluster: "{{ cluster }}"
|
||||
pg_autoscale_mode: true
|
||||
with_items: "{{ pools_pgautoscaler_mode }}"
|
||||
when:
|
||||
- pools_pgautoscaler_mode is defined
|
||||
- item.mode == 'on'
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
|
||||
- name: Unset osd flags
|
||||
ceph_osd_flag:
|
||||
name: "{{ item }}"
|
||||
cluster: "{{ cluster }}"
|
||||
state: absent
|
||||
environment:
|
||||
CEPH_CONTAINER_IMAGE: "{{ ceph_docker_registry + '/' + ceph_docker_image + ':' + ceph_docker_image_tag if containerized_deployment | bool else None }}"
|
||||
CEPH_CONTAINER_BINARY: "{{ container_binary }}"
|
||||
with_items:
|
||||
- noout
|
||||
- nodeep-scrub
|
||||
|
||||
- name: Re-enable balancer
|
||||
ansible.builtin.command: "{{ ceph_cmd }} --cluster {{ cluster }} balancer on"
|
||||
changed_when: false
|
||||
when: (balancer_status_switch.stdout | from_json)['active'] | bool
|
||||
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph mds
|
||||
|
||||
hosts: "{{ mds_group_name|default('mdss') }}"
|
||||
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
mds_group_name: mdss
|
||||
|
||||
serial: 1
|
||||
become: true
|
||||
pre_tasks:
|
||||
|
||||
- name: Stop non-containerized ceph mds(s)
|
||||
ansible.builtin.service:
|
||||
name: "ceph-mds@{{ ansible_facts['hostname'] }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
|
||||
- name: Remove old systemd unit files
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- /usr/lib/systemd/system/ceph-mds@.service
|
||||
- /usr/lib/systemd/system/ceph-mds.target
|
||||
- /lib/systemd/system/ceph-mds@.service
|
||||
- /lib/systemd/system/ceph-mds.target
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
# NOTE: changed from file module to raw find command for performance reasons
|
||||
# The file module has to run checks on current ownership of all directories and files. This is unnecessary
|
||||
# as in this case we know we want all owned by ceph user
|
||||
- name: Set proper ownership on ceph directories
|
||||
ansible.builtin.command: "find /var/lib/ceph/mds /etc/ceph -not -( -user {{ ceph_uid }} -or -group {{ ceph_uid }} -) -execdir chown {{ ceph_uid }}:{{ ceph_uid }} {} +"
|
||||
changed_when: false
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-container-engine role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
|
||||
- name: Import ceph-mds role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-mds
|
||||
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph rgw
|
||||
|
||||
hosts: "{{ rgw_group_name|default('rgws') }}"
|
||||
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
rgw_group_name: rgws
|
||||
|
||||
serial: 1
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
- name: Import ceph-config role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-config
|
||||
tasks_from: rgw_systemd_environment_file.yml
|
||||
|
||||
# NOTE: changed from file module to raw find command for performance reasons
|
||||
# The file module has to run checks on current ownership of all directories and files. This is unnecessary
|
||||
# as in this case we know we want all owned by ceph user
|
||||
- name: Set proper ownership on ceph directories
|
||||
ansible.builtin.command: "find /var/lib/ceph/radosgw /etc/ceph -not -( -user {{ ceph_uid }} -or -group {{ ceph_uid }} -) -execdir chown {{ ceph_uid }}:{{ ceph_uid }} {} +"
|
||||
changed_when: false
|
||||
|
||||
tasks:
|
||||
- name: Stop non-containerized ceph rgw(s)
|
||||
ansible.builtin.service:
|
||||
name: "ceph-radosgw@rgw.{{ rgw_zone }}.{{ ansible_facts['hostname'] }}.{{ item.instance_name }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
with_items: "{{ rgw_instances }}"
|
||||
|
||||
- name: Remove old systemd unit files
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- /usr/lib/systemd/system/ceph-radosgw@.service
|
||||
- /usr/lib/systemd/system/ceph-radosgw.target
|
||||
- /lib/systemd/system/ceph-radosgw@.service
|
||||
- /lib/systemd/system/ceph-radosgw.target
|
||||
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-container-engine role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
|
||||
- name: Import ceph-rgw role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-rgw
|
||||
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph rbd-mirror
|
||||
|
||||
hosts: "{{ rbdmirror_group_name|default('rbdmirrors') }}"
|
||||
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
rbdmirror_group_name: rbdmirrors
|
||||
|
||||
serial: 1
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: Check for ceph rbd mirror services
|
||||
ansible.builtin.command: systemctl show --no-pager --property=Id ceph-rbd-mirror@* # noqa: command-instead-of-module
|
||||
changed_when: false
|
||||
register: rbdmirror_services
|
||||
|
||||
- name: Stop non-containerized ceph rbd mirror(s) # noqa: ignore-errors
|
||||
ansible.builtin.service:
|
||||
name: "{{ item.split('=')[1] }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
ignore_errors: true
|
||||
loop: "{{ rbdmirror_services.stdout_lines }}"
|
||||
|
||||
- name: Remove old systemd unit files
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- /usr/lib/systemd/system/ceph-rbd-mirror@.service
|
||||
- /usr/lib/systemd/system/ceph-rbd-mirror.target
|
||||
- /lib/systemd/system/ceph-rbd-mirror@.service
|
||||
- /lib/systemd/system/ceph-rbd-mirror.target
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
# NOTE: changed from file module to raw find command for performance reasons
|
||||
# The file module has to run checks on current ownership of all directories and files. This is unnecessary
|
||||
# as in this case we know we want all owned by ceph user
|
||||
- name: Set proper ownership on ceph directories
|
||||
ansible.builtin.command: "find /var/lib/ceph /etc/ceph -not -( -user {{ ceph_uid }} -or -group {{ ceph_uid }} -) -execdir chown {{ ceph_uid }}:{{ ceph_uid }} {} +"
|
||||
changed_when: false
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-container-engine role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
|
||||
- name: Import ceph-rbd-mirror role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-rbd-mirror
|
||||
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph nfs
|
||||
|
||||
hosts: "{{ nfs_group_name|default('nfss') }}"
|
||||
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
nfs_group_name: nfss
|
||||
|
||||
serial: 1
|
||||
become: true
|
||||
pre_tasks:
|
||||
|
||||
# failed_when: false is here because if we're
|
||||
# working with a jewel cluster then ceph nfs
|
||||
# will not exist
|
||||
- name: Stop non-containerized ceph nfs(s)
|
||||
ansible.builtin.service:
|
||||
name: nfs-ganesha
|
||||
state: stopped
|
||||
enabled: false
|
||||
failed_when: false
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
|
||||
# NOTE: changed from file module to raw find command for performance reasons
|
||||
# The file module has to run checks on current ownership of all directories and files. This is unnecessary
|
||||
# as in this case we know we want all owned by ceph user
|
||||
- name: Set proper ownership on ceph directories
|
||||
ansible.builtin.command: "find /var/lib/ceph /etc/ceph -not -( -user {{ ceph_uid }} -or -group {{ ceph_uid }} -) -execdir chown {{ ceph_uid }}:{{ ceph_uid }} {} +"
|
||||
changed_when: false
|
||||
|
||||
tasks:
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-container-engine role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-engine
|
||||
|
||||
- name: Import ceph-container-common role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-container-common
|
||||
|
||||
- name: Import ceph-nfs role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-nfs
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph-crash
|
||||
|
||||
hosts:
|
||||
- "{{ mon_group_name | default('mons') }}"
|
||||
- "{{ osd_group_name | default('osds') }}"
|
||||
- "{{ mds_group_name | default('mdss') }}"
|
||||
- "{{ rgw_group_name | default('rgws') }}"
|
||||
- "{{ rbdmirror_group_name | default('rbdmirrors') }}"
|
||||
- "{{ mgr_group_name | default('mgrs') }}"
|
||||
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
become: true
|
||||
tasks:
|
||||
- name: Stop non-containerized ceph-crash
|
||||
ansible.builtin.service:
|
||||
name: ceph-crash
|
||||
state: stopped
|
||||
enabled: false
|
||||
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary.yml
|
||||
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-crash role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-crash
|
||||
|
||||
- name: Switching from non-containerized to containerized ceph-exporter
|
||||
|
||||
hosts:
|
||||
- "{{ mon_group_name | default('mons') }}"
|
||||
- "{{ osd_group_name | default('osds') }}"
|
||||
- "{{ mds_group_name | default('mdss') }}"
|
||||
- "{{ rgw_group_name | default('rgws') }}"
|
||||
- "{{ rbdmirror_group_name | default('rbdmirrors') }}"
|
||||
- "{{ mgr_group_name | default('mgrs') }}"
|
||||
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-facts role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-facts
|
||||
tasks_from: container_binary.yml
|
||||
|
||||
- name: Import ceph-handler role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-handler
|
||||
|
||||
- name: Import ceph-exporter role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-exporter
|
||||
|
||||
- name: Final task
|
||||
hosts:
|
||||
- "{{ mon_group_name|default('mons') }}"
|
||||
- "{{ mgr_group_name|default('mgrs') }}"
|
||||
- "{{ osd_group_name|default('osds') }}"
|
||||
- "{{ mds_group_name|default('mdss') }}"
|
||||
- "{{ rgw_group_name|default('rgws') }}"
|
||||
vars:
|
||||
containerized_deployment: true
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
# NOTE: changed from file module to raw find command for performance reasons
|
||||
# The file module has to run checks on current ownership of all directories and files. This is unnecessary
|
||||
# as in this case we know we want all owned by ceph user
|
||||
- name: Set proper ownership on ceph directories
|
||||
ansible.builtin.command: "find /var/lib/ceph /etc/ceph -not -( -user {{ ceph_uid }} -or -group {{ ceph_uid }} -) -execdir chown {{ ceph_uid }}:{{ ceph_uid }} {} +"
|
||||
changed_when: false
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
# NOTE (leseb):
|
||||
# The playbook aims to takeover a cluster that was not configured with
|
||||
# ceph-ansible.
|
||||
#
|
||||
# The procedure is as follows:
|
||||
#
|
||||
# 1. Install Ansible and add your monitors and osds hosts in it. For more detailed information you can read the [Ceph Ansible Wiki](https://github.com/ceph/ceph-ansible/wiki)
|
||||
# 2. Set `generate_fsid: false` in `group_vars`
|
||||
# 3. Get your current cluster fsid with `ceph fsid` and set `fsid` accordingly in `group_vars`
|
||||
# 4. Run the playbook called: `take-over-existing-cluster.yml` like this `ansible-playbook take-over-existing-cluster.yml`.
|
||||
# 5. Eventually run Ceph Ansible to validate everything by doing: `ansible-playbook site.yml`.
|
||||
|
||||
- name: Fetch keys
|
||||
hosts: mons
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
- name: Import ceph-fetch-keys role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-fetch-keys
|
||||
|
||||
- name: Take over existing cluster
|
||||
hosts:
|
||||
- mons
|
||||
- osds
|
||||
- mdss
|
||||
- rgws
|
||||
- nfss
|
||||
- rbdmirrors
|
||||
- clients
|
||||
- mgrs
|
||||
become: true
|
||||
tasks:
|
||||
- name: Import ceph-defaults role
|
||||
ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
post_tasks:
|
||||
- name: Get the name of the existing ceph cluster
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail;
|
||||
basename $(grep --exclude '*.bak' -R fsid /etc/ceph/ | egrep -o '^[^.]*' | head -n 1)
|
||||
changed_when: false
|
||||
register: cluster_name
|
||||
|
||||
- name: Run stat module on Ceph configuration file
|
||||
ansible.builtin.stat:
|
||||
path: "/etc/ceph/{{ cluster_name.stdout }}.conf"
|
||||
register: ceph_conf_stat
|
||||
|
||||
# Creates a backup of original ceph conf file in 'cluster_name-YYYYMMDDTHHMMSS.conf.bak' format
|
||||
- name: Make a backup of original Ceph configuration file
|
||||
ansible.builtin.copy:
|
||||
src: "/etc/ceph/{{ cluster_name.stdout }}.conf"
|
||||
dest: "/etc/ceph/{{ cluster_name.stdout }}-{{ ansible_date_time.iso8601_basic_short }}.conf.bak"
|
||||
remote_src: true
|
||||
owner: "{{ ceph_conf_stat.stat.pw_name }}"
|
||||
group: "{{ ceph_conf_stat.stat.gr_name }}"
|
||||
mode: "{{ ceph_conf_stat.stat.mode }}"
|
||||
|
||||
- name: Generate ceph configuration file
|
||||
openstack.config_template.config_template:
|
||||
src: "roles/ceph-config/templates/ceph.conf.j2"
|
||||
dest: "/etc/ceph/{{ cluster_name.stdout }}.conf"
|
||||
owner: "{{ ceph_conf_stat.stat.pw_name }}"
|
||||
group: "{{ ceph_conf_stat.stat.gr_name }}"
|
||||
mode: "{{ ceph_conf_stat.stat.mode }}"
|
||||
config_overrides: "{{ ceph_conf_overrides }}"
|
||||
config_type: ini
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
# This playbook was made to automate Ceph servers maintenance
|
||||
# Typical use case: hardware change
|
||||
# By running this playbook you will set the 'noout' flag on your
|
||||
# cluster, which means that OSD **can't** be marked as out
|
||||
# of the CRUSH map, but they will be marked as down.
|
||||
# Basically we tell the cluster to don't move any data since
|
||||
# the operation won't last for too long.
|
||||
|
||||
- hosts: <your_host>
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
|
||||
- name: Set the noout flag
|
||||
ansible.builtin.command: ceph osd set noout
|
||||
delegate_to: <your_monitor>
|
||||
|
||||
- name: Turn off the server
|
||||
ansible.builtin.command: poweroff
|
||||
|
||||
- name: Wait for the server to go down
|
||||
local_action:
|
||||
module: wait_for
|
||||
host: <your_host>
|
||||
port: 22
|
||||
state: stopped
|
||||
|
||||
- name: Wait for the server to come up
|
||||
local_action:
|
||||
module: wait_for
|
||||
host: <your_host>
|
||||
port: 22
|
||||
delay: 10
|
||||
timeout: 3600
|
||||
|
||||
- name: Unset the noout flag
|
||||
ansible.builtin.command: ceph osd unset noout
|
||||
delegate_to: <your_monitor>
|
||||
@@ -0,0 +1,552 @@
|
||||
---
|
||||
# This playbook was meant to upgrade a node from Ubuntu to RHEL.
|
||||
# We are performing a set of actions prior to reboot the node.
|
||||
# The node reboots via PXE and gets its new operating system.
|
||||
# This playbook only works for monitors and OSDs.
|
||||
# Note that some of the checks are ugly:
|
||||
# ie: the when migration_completed.stat.exists
|
||||
# can be improved with includes, however I wanted to keep a single file...
|
||||
#
|
||||
|
||||
- hosts: mons
|
||||
serial: 1
|
||||
sudo: true
|
||||
|
||||
vars:
|
||||
backup_dir: /tmp/
|
||||
|
||||
tasks:
|
||||
|
||||
- name: Check if the node has be migrated already
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/mon/ceph-{{ ansible_facts['hostname'] }}/migration_completed
|
||||
register: migration_completed
|
||||
failed_when: false
|
||||
|
||||
- name: Check for failed run
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/{{ ansible_facts['hostname'] }}.tar
|
||||
register: mon_archive_leftover
|
||||
|
||||
- fail: msg="Looks like an archive is already there, please remove it!"
|
||||
when: migration_completed.stat.exists == False and mon_archive_leftover.stat.exists == True
|
||||
|
||||
- name: Compress the store as much as possible
|
||||
ansible.builtin.command: ceph tell mon.{{ ansible_facts['hostname'] }} compact
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Check if sysvinit
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/mon/ceph-{{ ansible_facts['hostname'] }}/sysvinit
|
||||
register: monsysvinit
|
||||
changed_when: false
|
||||
|
||||
- name: Check if upstart
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/mon/ceph-{{ ansible_facts['hostname'] }}/upstart
|
||||
register: monupstart
|
||||
changed_when: false
|
||||
|
||||
- name: Check if init does what it is supposed to do (Sysvinit)
|
||||
ansible.builtin.shell: >
|
||||
ps faux|grep -sq [c]eph-mon && service ceph status mon >> /dev/null
|
||||
register: ceph_status_sysvinit
|
||||
changed_when: false
|
||||
|
||||
# can't complete the condition since the previous taks never ran...
|
||||
- fail: msg="Something is terribly wrong here, sysvinit is configured, the service is started BUT the init script does not return 0, GO FIX YOUR SETUP!"
|
||||
when: ceph_status_sysvinit.rc != 0 and migration_completed.stat.exists == False and monsysvinit.stat.exists == True
|
||||
|
||||
- name: Check if init does what it is supposed to do (upstart)
|
||||
ansible.builtin.shell: >
|
||||
ps faux|grep -sq [c]eph-mon && status ceph-mon-all >> /dev/null
|
||||
register: ceph_status_upstart
|
||||
changed_when: false
|
||||
|
||||
- fail: msg="Something is terribly wrong here, upstart is configured, the service is started BUT the init script does not return 0, GO FIX YOUR SETUP!"
|
||||
when: ceph_status_upstart.rc != 0 and migration_completed.stat.exists == False and monupstart.stat.exists == True
|
||||
|
||||
- name: Restart the Monitor after compaction (Upstart)
|
||||
service: >
|
||||
name=ceph-mon
|
||||
state=restarted
|
||||
args=id={{ ansible_facts['hostname'] }}
|
||||
when: monupstart.stat.exists == True and migration_completed.stat.exists == False
|
||||
|
||||
- name: Restart the Monitor after compaction (Sysvinit)
|
||||
service: >
|
||||
name=ceph
|
||||
state=restarted
|
||||
args=mon
|
||||
when: monsysvinit.stat.exists == True and migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for the monitor to be up again
|
||||
local_action:
|
||||
module: wait_for
|
||||
host: "{{ ansible_ssh_host | default(inventory_hostname) }}"
|
||||
port: 6789
|
||||
timeout: 10
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Stop the monitor (Upstart)
|
||||
service: >
|
||||
name=ceph-mon
|
||||
state=stopped
|
||||
args=id={{ ansible_facts['hostname'] }}
|
||||
when: monupstart.stat.exists == True and migration_completed.stat.exists == False
|
||||
|
||||
- name: Stop the monitor (Sysvinit)
|
||||
service: >
|
||||
name=ceph
|
||||
state=stopped
|
||||
args=mon
|
||||
when: monsysvinit.stat.exists == True and migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for the monitor to be down
|
||||
local_action:
|
||||
module: wait_for
|
||||
host: "{{ ansible_ssh_host | default(inventory_hostname) }}"
|
||||
port: 6789
|
||||
timeout: 10
|
||||
state: stopped
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Create a backup directory
|
||||
file: >
|
||||
path={{ backup_dir }}/monitors-backups
|
||||
state=directory
|
||||
owner=root
|
||||
group=root
|
||||
mode=0644
|
||||
delegate_to: "{{ item }}"
|
||||
with_items: "{{ groups.backup[0] }}"
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
# NOTE (leseb): should we convert upstart to sysvinit here already?
|
||||
- name: Archive monitor stores
|
||||
ansible.builtin.shell: >
|
||||
tar -cpvzf - --one-file-system . /etc/ceph/* | cat > {{ ansible_facts['hostname'] }}.tar
|
||||
chdir=/var/lib/ceph/
|
||||
creates={{ ansible_facts['hostname'] }}.tar
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Scp the Monitor store
|
||||
fetch: >
|
||||
src=/var/lib/ceph/{{ ansible_facts['hostname'] }}.tar
|
||||
dest={{ backup_dir }}/monitors-backups/{{ ansible_facts['hostname'] }}.tar
|
||||
flat=yes
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Reboot the server
|
||||
ansible.builtin.command: reboot
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for the server to come up
|
||||
local_action:
|
||||
module: wait_for
|
||||
port: 22
|
||||
delay: 10
|
||||
timeout: 3600
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait a bit more to be sure that the server is ready
|
||||
pause: seconds=20
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Check if sysvinit
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/mon/ceph-{{ ansible_facts['hostname'] }}/sysvinit
|
||||
register: monsysvinit
|
||||
changed_when: false
|
||||
|
||||
- name: Check if upstart
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/mon/ceph-{{ ansible_facts['hostname'] }}/upstart
|
||||
register: monupstart
|
||||
changed_when: false
|
||||
|
||||
- name: Make sure the monitor is stopped (Upstart)
|
||||
service: >
|
||||
name=ceph-mon
|
||||
state=stopped
|
||||
args=id={{ ansible_facts['hostname'] }}
|
||||
when: monupstart.stat.exists == True and migration_completed.stat.exists == False
|
||||
|
||||
- name: Make sure the monitor is stopped (Sysvinit)
|
||||
service: >
|
||||
name=ceph
|
||||
state=stopped
|
||||
args=mon
|
||||
when: monsysvinit.stat.exists == True and migration_completed.stat.exists == False
|
||||
|
||||
# NOTE (leseb): 'creates' was added in Ansible 1.6
|
||||
- name: Copy and unarchive the monitor store
|
||||
unarchive: >
|
||||
src={{ backup_dir }}/monitors-backups/{{ ansible_facts['hostname'] }}.tar
|
||||
dest=/var/lib/ceph/
|
||||
copy=yes
|
||||
mode=0600
|
||||
creates=etc/ceph/ceph.conf
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Copy keys and configs
|
||||
ansible.builtin.shell: >
|
||||
cp etc/ceph/* /etc/ceph/
|
||||
chdir=/var/lib/ceph/
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Configure RHEL7 for sysvinit
|
||||
ansible.builtin.shell: find -L /var/lib/ceph/mon/ -mindepth 1 -maxdepth 1 -regextype posix-egrep -regex '.*/[A-Za-z0-9]+-[A-Za-z0-9._-]+' -exec touch {}/sysvinit \; -exec rm {}/upstart \;
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
# NOTE (leseb): at this point the upstart and sysvinit checks are not necessary
|
||||
# so we directly call sysvinit
|
||||
- name: Start the monitor
|
||||
service: >
|
||||
name=ceph
|
||||
state=started
|
||||
args=mon
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for the Monitor to be up again
|
||||
local_action:
|
||||
module: wait_for
|
||||
host: "{{ ansible_ssh_host | default(inventory_hostname) }}"
|
||||
port: 6789
|
||||
timeout: 10
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Waiting for the monitor to join the quorum...
|
||||
ansible.builtin.shell: >
|
||||
ceph -s | grep monmap | sed 's/.*quorum//' | egrep -q {{ ansible_facts['hostname'] }}
|
||||
register: result
|
||||
until: result.rc == 0
|
||||
retries: 5
|
||||
delay: 10
|
||||
delegate_to: "{{ item }}"
|
||||
with_items: "{{ groups.backup[0] }}"
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Done moving to the next monitor
|
||||
file: >
|
||||
path=/var/lib/ceph/mon/ceph-{{ ansible_facts['hostname'] }}/migration_completed
|
||||
state=touch
|
||||
owner=root
|
||||
group=root
|
||||
mode=0600
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- hosts: osds
|
||||
serial: 1
|
||||
sudo: true
|
||||
|
||||
vars:
|
||||
backup_dir: /tmp/
|
||||
|
||||
tasks:
|
||||
- name: Check if the node has be migrated already
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/migration_completed
|
||||
register: migration_completed
|
||||
failed_when: false
|
||||
|
||||
- name: Check for failed run
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/{{ ansible_facts['hostname'] }}.tar
|
||||
register: osd_archive_leftover
|
||||
|
||||
- fail: msg="Looks like an archive is already there, please remove it!"
|
||||
when: migration_completed.stat.exists == False and osd_archive_leftover.stat.exists == True
|
||||
|
||||
- name: Check if init does what it is supposed to do (Sysvinit)
|
||||
ansible.builtin.shell: >
|
||||
ps faux|grep -sq [c]eph-osd && service ceph status osd >> /dev/null
|
||||
register: ceph_status_sysvinit
|
||||
changed_when: false
|
||||
|
||||
# can't complete the condition since the previous taks never ran...
|
||||
- fail: msg="Something is terribly wrong here, sysvinit is configured, the services are started BUT the init script does not return 0, GO FIX YOUR SETUP!"
|
||||
when: ceph_status_sysvinit.rc != 0 and migration_completed.stat.exists == False and monsysvinit.stat.exists == True
|
||||
|
||||
- name: Check if init does what it is supposed to do (upstart)
|
||||
ansible.builtin.shell: >
|
||||
ps faux|grep -sq [c]eph-osd && initctl list|egrep -sq "ceph-osd \(ceph/.\) start/running, process [0-9][0-9][0-9][0-9]"
|
||||
register: ceph_status_upstart
|
||||
changed_when: false
|
||||
|
||||
- fail: msg="Something is terribly wrong here, upstart is configured, the services are started BUT the init script does not return 0, GO FIX YOUR SETUP!"
|
||||
when: ceph_status_upstart.rc != 0 and migration_completed.stat.exists == False and monupstart.stat.exists == True
|
||||
|
||||
- name: Set the noout flag
|
||||
ansible.builtin.command: ceph osd set noout
|
||||
delegate_to: "{{ item }}"
|
||||
with_items: "{{ groups[mon_group_name][0] }}"
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Check if sysvinit
|
||||
ansible.builtin.shell: stat /var/lib/ceph/osd/ceph-*/sysvinit
|
||||
register: osdsysvinit
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Check if upstart
|
||||
ansible.builtin.shell: stat /var/lib/ceph/osd/ceph-*/upstart
|
||||
register: osdupstart
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Archive ceph configs
|
||||
ansible.builtin.shell: >
|
||||
tar -cpvzf - --one-file-system . /etc/ceph/ceph.conf | cat > {{ ansible_facts['hostname'] }}.tar
|
||||
chdir=/var/lib/ceph/
|
||||
creates={{ ansible_facts['hostname'] }}.tar
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Create backup directory
|
||||
file: >
|
||||
path={{ backup_dir }}/osds-backups
|
||||
state=directory
|
||||
owner=root
|
||||
group=root
|
||||
mode=0644
|
||||
delegate_to: "{{ item }}"
|
||||
with_items: "{{ groups.backup[0] }}"
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Scp OSDs dirs and configs
|
||||
fetch: >
|
||||
src=/var/lib/ceph/{{ ansible_facts['hostname'] }}.tar
|
||||
dest={{ backup_dir }}/osds-backups/
|
||||
flat=yes
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Collect OSD ports
|
||||
ansible.builtin.shell: netstat -tlpn | awk -F ":" '/ceph-osd/ { sub (" .*", "", $2); print $2 }' | uniq
|
||||
register: osd_ports
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Gracefully stop the OSDs (Upstart)
|
||||
service: >
|
||||
name=ceph-osd-all
|
||||
state=stopped
|
||||
when: osdupstart.rc == 0 and migration_completed.stat.exists == False
|
||||
|
||||
- name: Gracefully stop the OSDs (Sysvinit)
|
||||
service: >
|
||||
name=ceph
|
||||
state=stopped
|
||||
args=mon
|
||||
when: osdsysvinit.rc == 0 and migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for the OSDs to be down
|
||||
local_action:
|
||||
module: wait_for
|
||||
host: "{{ ansible_ssh_host | default(inventory_hostname) }}"
|
||||
port: {{ item }}
|
||||
timeout: 10
|
||||
state: stopped
|
||||
with_items: "{{ osd_ports.stdout_lines }}"
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Configure RHEL with sysvinit
|
||||
ansible.builtin.shell: find -L /var/lib/ceph/osd/ -mindepth 1 -maxdepth 1 -regextype posix-egrep -regex '.*/[A-Za-z0-9]+-[A-Za-z0-9._-]+' -exec touch {}/sysvinit \; -exec rm {}/upstart \;
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Reboot the server
|
||||
ansible.builtin.command: reboot
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for the server to come up
|
||||
local_action:
|
||||
module: wait_for
|
||||
port: 22
|
||||
delay: 10
|
||||
timeout: 3600
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait a bit to be sure that the server is ready for scp
|
||||
pause: seconds=20
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
# NOTE (leseb): 'creates' was added in Ansible 1.6
|
||||
- name: Copy and unarchive the OSD configs
|
||||
unarchive: >
|
||||
src={{ backup_dir }}/osds-backups/{{ ansible_facts['hostname'] }}.tar
|
||||
dest=/var/lib/ceph/
|
||||
copy=yes
|
||||
mode=0600
|
||||
creates=etc/ceph/ceph.conf
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Copy keys and configs
|
||||
ansible.builtin.shell: >
|
||||
cp etc/ceph/* /etc/ceph/
|
||||
chdir=/var/lib/ceph/
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
# NOTE (leseb): at this point the upstart and sysvinit checks are not necessary
|
||||
# so we directly call sysvinit
|
||||
- name: Start all the OSDs
|
||||
service: >
|
||||
name=ceph-osd-all
|
||||
state=started
|
||||
args=osd
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
# NOTE (leseb): this is tricky unless this is set into the ceph.conf
|
||||
# listened ports can be predicted, thus they will change after each restart
|
||||
# - name: Wait for the OSDs to be up again
|
||||
# local_action: >
|
||||
# wait_for
|
||||
# host={{ ansible_ssh_host | default(inventory_hostname) }}
|
||||
# port={{ item }}
|
||||
# timeout=30
|
||||
# with_items:
|
||||
# - "{{ osd_ports.stdout_lines }}"
|
||||
|
||||
- name: Waiting for clean PGs...
|
||||
ansible.builtin.shell: >
|
||||
test "[""$(ceph -s -f json | python -c 'import sys, json; print(json.load(sys.stdin)["pgmap"]["num_pgs"])')""]" = "$(ceph -s -f json | python -c 'import sys, json; print([ i["count"] for i in json.load(sys.stdin)["pgmap"]["pgs_by_state"] if i["state_name"] == "active+clean"])')"
|
||||
register: result
|
||||
until: result.rc == 0
|
||||
retries: 10
|
||||
delay: 10
|
||||
delegate_to: "{{ item }}"
|
||||
with_items: "{{ groups.backup[0] }}"
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Done moving to the next OSD
|
||||
file: >
|
||||
path=/var/lib/ceph/migration_completed
|
||||
state=touch
|
||||
owner=root
|
||||
group=root
|
||||
mode=0600
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Unset the noout flag
|
||||
ansible.builtin.command: ceph osd unset noout
|
||||
delegate_to: "{{ item }}"
|
||||
with_items: "{{ groups[mon_group_name][0] }}"
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- hosts: rgws
|
||||
serial: 1
|
||||
sudo: true
|
||||
|
||||
vars:
|
||||
backup_dir: /tmp/
|
||||
|
||||
tasks:
|
||||
- name: Check if the node has be migrated already
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/radosgw/migration_completed
|
||||
register: migration_completed
|
||||
failed_when: false
|
||||
|
||||
- name: Check for failed run
|
||||
ansible.builtin.stat: >
|
||||
path=/var/lib/ceph/{{ ansible_facts['hostname'] }}.tar
|
||||
register: rgw_archive_leftover
|
||||
|
||||
- fail: msg="Looks like an archive is already there, please remove it!"
|
||||
when: migration_completed.stat.exists == False and rgw_archive_leftover.stat.exists == True
|
||||
|
||||
- name: Archive rados gateway configs
|
||||
ansible.builtin.shell: >
|
||||
tar -cpvzf - --one-file-system . /etc/ceph/* | cat > {{ ansible_facts['hostname'] }}.tar
|
||||
chdir=/var/lib/ceph/
|
||||
creates={{ ansible_facts['hostname'] }}.tar
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Create backup directory
|
||||
file: >
|
||||
path={{ backup_dir }}/rgws-backups
|
||||
state=directory
|
||||
owner=root
|
||||
group=root
|
||||
mode=0644
|
||||
delegate_to: "{{ item }}"
|
||||
with_items: "{{ groups.backup[0] }}"
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Scp RGWs dirs and configs
|
||||
fetch: >
|
||||
src=/var/lib/ceph/{{ ansible_facts['hostname'] }}.tar
|
||||
dest={{ backup_dir }}/rgws-backups/
|
||||
flat=yes
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Gracefully stop the rados gateway
|
||||
service: >
|
||||
name={{ item }}
|
||||
state=stopped
|
||||
with_items: radosgw
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for radosgw to be down
|
||||
local_action:
|
||||
module: wait_for
|
||||
host: "{{ ansible_ssh_host | default(inventory_hostname) }}"
|
||||
path: /tmp/radosgw.sock
|
||||
state: absent
|
||||
timeout: 30
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Reboot the server
|
||||
ansible.builtin.command: reboot
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for the server to come up
|
||||
local_action:
|
||||
module: wait_for
|
||||
port: 22
|
||||
delay: 10
|
||||
timeout: 3600
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait a bit to be sure that the server is ready for scp
|
||||
pause: seconds=20
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
# NOTE (leseb): 'creates' was added in Ansible 1.6
|
||||
- name: Copy and unarchive the OSD configs
|
||||
unarchive: >
|
||||
src={{ backup_dir }}/rgws-backups/{{ ansible_facts['hostname'] }}.tar
|
||||
dest=/var/lib/ceph/
|
||||
copy=yes
|
||||
mode=0600
|
||||
creates=etc/ceph/ceph.conf
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Copy keys and configs
|
||||
ansible.builtin.shell: >
|
||||
{{ item }}
|
||||
chdir=/var/lib/ceph/
|
||||
with_items: cp etc/ceph/* /etc/ceph/
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Start rados gateway
|
||||
service: >
|
||||
name={{ item }}
|
||||
state=started
|
||||
with_items: radosgw
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Wait for radosgw to be up again
|
||||
local_action:
|
||||
module: wait_for
|
||||
host: "{{ ansible_ssh_host | default(inventory_hostname) }}"
|
||||
path: /tmp/radosgw.sock
|
||||
state: present
|
||||
timeout: 30
|
||||
when: migration_completed.stat.exists == False
|
||||
|
||||
- name: Done moving to the next rados gateway
|
||||
file: >
|
||||
path=/var/lib/ceph/radosgw/migration_completed
|
||||
state=touch
|
||||
owner=root
|
||||
group=root
|
||||
mode=0600
|
||||
when: migration_completed.stat.exists == False
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
# This playbook will make custom partition layout for your osd hosts.
|
||||
# You should define `devices` variable for every host.
|
||||
#
|
||||
# For example, in host_vars/hostname1
|
||||
#
|
||||
# devices:
|
||||
# - device_name: sdb
|
||||
# partitions:
|
||||
# - index: 1
|
||||
# size: 10G
|
||||
# type: data
|
||||
# - index: 2
|
||||
# size: 5G
|
||||
# type: journal
|
||||
# - device_name: sdc
|
||||
# partitions:
|
||||
# - index: 1
|
||||
# size: 10G
|
||||
# type: data
|
||||
# - index: 2
|
||||
# size: 5G
|
||||
# type: journal
|
||||
#
|
||||
- vars:
|
||||
osd_group_name: osds
|
||||
journal_typecode: 45b0969e-9b03-4f30-b4c6-b4b80ceff106
|
||||
data_typecode: 4fbd7e29-9d25-41b8-afd0-062c0ceff05d
|
||||
devices: []
|
||||
hosts: "{{ osd_group_name }}"
|
||||
|
||||
tasks:
|
||||
|
||||
- name: Load a variable file for devices partition
|
||||
include_vars: "{{ item }}"
|
||||
with_first_found:
|
||||
- files:
|
||||
- "host_vars/{{ ansible_facts['hostname'] }}.yml"
|
||||
- "host_vars/default.yml"
|
||||
skip: true
|
||||
|
||||
- name: Exit playbook, if devices not defined
|
||||
ansible.builtin.fail:
|
||||
msg: "devices must be define in host_vars/default.yml or host_vars/{{ ansible_facts['hostname'] }}.yml"
|
||||
when: devices is not defined
|
||||
|
||||
- name: Install sgdisk(gdisk)
|
||||
ansible.builtin.package:
|
||||
name: gdisk
|
||||
state: present
|
||||
register: result
|
||||
until: result is succeeded
|
||||
|
||||
- name: Erase all previous partitions(dangerous!!!)
|
||||
ansible.builtin.shell: sgdisk --zap-all -- /dev/{{item.device_name}}
|
||||
with_items: "{{ devices }}"
|
||||
|
||||
- name: Make osd partitions
|
||||
ansible.builtin.shell: >
|
||||
sgdisk --new={{item.1.index}}:0:+{{item.1.size}} "--change-name={{item.1.index}}:ceph {{item.1.type}}"
|
||||
"--typecode={{item.1.index}}:{% if item.1.type=='data' %}{{data_typecode}}{% else %}{{journal_typecode}}{% endif %}"
|
||||
--mbrtogpt -- /dev/{{item.0.device_name}}
|
||||
with_subelements:
|
||||
- "{{ devices }}"
|
||||
- partitions
|
||||
|
||||
- set_fact:
|
||||
owner: 167
|
||||
group: 167
|
||||
when: ansible_facts['os_family'] == "RedHat"
|
||||
|
||||
- set_fact:
|
||||
owner: 64045
|
||||
group: 64045
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
|
||||
- name: Change partitions ownership
|
||||
ansible.builtin.file:
|
||||
path: "/dev/{{item.0.device_name}}{{item.1.index}}"
|
||||
owner: "{{ owner | default('root')}}"
|
||||
group: "{{ group | default('disk')}}"
|
||||
with_subelements:
|
||||
- "{{ devices }}"
|
||||
- partitions
|
||||
when:
|
||||
item.0.device_name | match('/dev/([hsv]d[a-z]{1,2}){1,2}$')
|
||||
|
||||
- name: Change partitions ownership
|
||||
ansible.builtin.file:
|
||||
path: "/dev/{{item.0.device_name}}p{{item.1.index}}"
|
||||
owner: "{{ owner | default('root')}}"
|
||||
group: "{{ group | default('disk')}}"
|
||||
with_subelements:
|
||||
- "{{ devices }}"
|
||||
- partitions
|
||||
when: item.0.device_name | match('/dev/(cciss/c[0-9]d[0-9]|nvme[0-9]n[0-9]){1,2}$')
|
||||
...
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
# This playbook use to migrate activity osd(s) journal to SSD.
|
||||
#
|
||||
# You should define `osds_journal_devices` variable for host which osd(s) journal migrate to.
|
||||
#
|
||||
# For example in host_vars/hostname1.yml
|
||||
#
|
||||
# osds_journal_devices:
|
||||
# - device_name: /dev/sdd
|
||||
# partitions:
|
||||
# - index: 1
|
||||
# size: 10G
|
||||
# osd_id: 0
|
||||
# - index: 2
|
||||
# size: 10G
|
||||
# osd_id: 1
|
||||
# - device_name: /dev/sdf
|
||||
# partitions:
|
||||
# - index: 1
|
||||
# size: 10G
|
||||
# osd_id: 2
|
||||
#
|
||||
# @param device_name: The full device path of new ssd.
|
||||
# @param partitions: The custom partition layout of ssd.
|
||||
# @param index: The index of this partition.
|
||||
# @param size: The size of this partition.
|
||||
# @param osd_id: Which osds's journal this partition for.
|
||||
#
|
||||
# ansible-playbook migrate-journal-to-ssd.yml
|
||||
# The playbook will migrate osd(s) journal to ssd device which you define in host_vars.
|
||||
|
||||
- vars:
|
||||
osd_group_name: osds
|
||||
journal_typecode: 45b0969e-9b03-4f30-b4c6-b4b80ceff106
|
||||
osds_journal_devices: []
|
||||
hosts: "{{ osd_group_name }}"
|
||||
serial: 1
|
||||
tasks:
|
||||
|
||||
- name: Get osd(s) if directory stat
|
||||
ansible.builtin.stat:
|
||||
path: "/var/lib/ceph/osd/{{ cluster }}-{{ item.1.osd_id }}/journal_uuid"
|
||||
register: osds_dir_stat
|
||||
with_subelements:
|
||||
- "{{ osds_journal_devices }}"
|
||||
- partitions
|
||||
|
||||
- name: Exit playbook osd(s) is not on this host
|
||||
ansible.builtin.fail:
|
||||
msg: exit playbook osd(s) is not on this host
|
||||
with_items:
|
||||
osds_dir_stat.results
|
||||
when: osds_dir_stat is defined and item.stat.exists == false
|
||||
|
||||
- name: Install sgdisk(gdisk)
|
||||
ansible.builtin.package:
|
||||
name: gdisk
|
||||
state: present
|
||||
register: result
|
||||
until: result is succeeded
|
||||
when: osds_journal_devices is defined
|
||||
|
||||
- name: Generate uuid for osds journal
|
||||
ansible.builtin.command: uuidgen
|
||||
register: osds
|
||||
with_subelements:
|
||||
- "{{ osds_journal_devices }}"
|
||||
- partitions
|
||||
|
||||
- name: Make osd partitions on ssd
|
||||
ansible.builtin.shell: >
|
||||
sgdisk --new={{item.item[1].index}}:0:+{{item.item[1].size}} "--change-name={{ item.item[1].index }}:ceph journal"
|
||||
--typecode={{ item.item[1].index }}:{{ journal_typecode }}
|
||||
--partition-guid={{ item.item[1].index }}:{{ item.stdout }}
|
||||
--mbrtogpt -- {{ item.item[0].device_name }}
|
||||
with_items: "{{ osds.results }}"
|
||||
|
||||
- name: Stop osd(s) service
|
||||
ansible.builtin.service:
|
||||
name: "ceph-osd@{{ item.item[1].osd_id }}"
|
||||
state: stopped
|
||||
with_items: "{{ osds.results }}"
|
||||
|
||||
- name: Flush osd(s) journal
|
||||
ansible.builtin.command: ceph-osd -i {{ item.item[1].osd_id }} --flush-journal --cluster {{ cluster }}
|
||||
with_items: "{{ osds.results }}"
|
||||
when: osds_journal_devices is defined
|
||||
|
||||
- name: Update osd(s) journal soft link
|
||||
ansible.builtin.command: ln -sf /dev/disk/by-partuuid/{{ item.stdout }} /var/lib/ceph/osd/{{ cluster }}-{{ item.item[1].osd_id }}/journal
|
||||
with_items: "{{ osds.results }}"
|
||||
|
||||
- name: Update osd(s) journal uuid
|
||||
ansible.builtin.command: echo {{ item.stdout }} > /var/lib/ceph/osd/{{ cluster }}-{{ item.item[1].osd_id }}/journal_uuid
|
||||
with_items: "{{ osds.results }}"
|
||||
|
||||
- name: Initialize osd(s) new journal
|
||||
ansible.builtin.command: ceph-osd -i {{ item.item[1].osd_id }} --mkjournal --cluster {{ cluster }}
|
||||
with_items: "{{ osds.results }}"
|
||||
|
||||
- name: Start osd(s) service
|
||||
ansible.builtin.service:
|
||||
name: "ceph-osd@{{ item.item[1].osd_id }}"
|
||||
state: started
|
||||
with_items: "{{ osds.results }}"
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
# Nukes a multisite config
|
||||
- hosts: rgws
|
||||
become: true
|
||||
tasks:
|
||||
- include_tasks: roles/ceph-rgw/tasks/multisite/destroy.yml
|
||||
|
||||
handlers:
|
||||
# Ansible 2.1.0 bug will ignore included handlers without this
|
||||
- name: Import_tasks roles/ceph-rgw/handlers/main.yml
|
||||
import_tasks: roles/ceph-rgw/handlers/main.yml
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
# This playbook use to recover Ceph OSDs after ssd journal failure.
|
||||
# You will also realise that it’s really simple to bring your
|
||||
# OSDs back to life after replacing your faulty SSD with a new one.
|
||||
#
|
||||
# You should define `dev_ssds` variable for host which changes ssds after
|
||||
# failure.
|
||||
#
|
||||
# For example in host_vars/hostname1.yml
|
||||
#
|
||||
# dev_ssds:
|
||||
# - device_name: /dev/sdd
|
||||
# partitions:
|
||||
# - index: 1
|
||||
# size: 10G
|
||||
# osd_id: 0
|
||||
# - index: 2
|
||||
# size: 10G
|
||||
# osd_id: 1
|
||||
# - device_name: /dev/sdf
|
||||
# partitions:
|
||||
# - index: 1
|
||||
# size: 10G
|
||||
# osd_id: 2
|
||||
#
|
||||
# @param device_name: The full device path of new ssd
|
||||
# @param partitions: The custom partition layout of new ssd
|
||||
# @param index: The index of this partition
|
||||
# @param size: The size of this partition
|
||||
# @param osd_id: Which osds's journal this partition for.
|
||||
#
|
||||
# ansible-playbook recover-osds-after-ssd-journal-failure.yml
|
||||
# Prompts for select which host to recover, defaults to null,
|
||||
# doesn't select host the recover ssd. Input the hostname
|
||||
# which to recover osds after ssd journal failure
|
||||
#
|
||||
# ansible-playbook -e target_host=hostname \
|
||||
# recover-osds-after-ssd-journal-failure.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
|
||||
- hosts: localhost
|
||||
gather_facts: false
|
||||
vars_prompt:
|
||||
- name: target_host # noqa: name[casing]
|
||||
prompt: please enter the target hostname which to recover osds after ssd journal failure
|
||||
private: false
|
||||
tasks:
|
||||
- add_host:
|
||||
name: "{{ target_host }}"
|
||||
groups: dynamically_created_hosts
|
||||
|
||||
- hosts: dynamically_created_hosts
|
||||
vars:
|
||||
journal_typecode: 45b0969e-9b03-4f30-b4c6-b4b80ceff106
|
||||
dev_ssds: []
|
||||
|
||||
tasks:
|
||||
- fail: msg="please define dev_ssds variable"
|
||||
when: dev_ssds|length <= 0
|
||||
|
||||
- name: Get osd(s) if directory stat
|
||||
ansible.builtin.stat:
|
||||
path: "/var/lib/ceph/osd/{{ cluster }}-{{ item.1.osd_id }}/journal_uuid"
|
||||
register: osds_dir_stat
|
||||
with_subelements:
|
||||
- "{{ dev_ssds }}"
|
||||
- partitions
|
||||
|
||||
- name: Exit playbook osd(s) is not on this host
|
||||
ansible.builtin.fail:
|
||||
msg: exit playbook osds is not no this host
|
||||
with_items:
|
||||
osds_dir_stat.results
|
||||
when:
|
||||
- osds_dir_stat is defined | bool
|
||||
- item.stat.exists == false
|
||||
|
||||
- name: Install sgdisk(gdisk)
|
||||
ansible.builtin.package:
|
||||
name: gdisk
|
||||
state: present
|
||||
register: result
|
||||
until: result is succeeded
|
||||
|
||||
- name: Get osd(s) journal uuid
|
||||
ansible.builtin.command: cat "/var/lib/ceph/osd/{{ cluster }}-{{ item.1.osd_id }}/journal_uuid"
|
||||
register: osds_uuid
|
||||
with_subelements:
|
||||
- "{{ dev_ssds }}"
|
||||
- partitions
|
||||
|
||||
- name: Make partitions on new ssd
|
||||
ansible.builtin.shell: >
|
||||
sgdisk --new={{item.item[1].index}}:0:+{{item.item[1].size}} "--change-name={{ item.item[1].index }}:ceph journal"
|
||||
--typecode={{ item.item[1].index }}:{{ journal_typecode }}
|
||||
--partition-guid={{ item.item[1].index }}:{{ item.stdout }}
|
||||
--mbrtogpt -- {{ item.item[0].device_name }}
|
||||
with_items: "{{ osds_uuid.results }}"
|
||||
|
||||
- name: Stop osd(s) service
|
||||
ansible.builtin.service:
|
||||
name: "ceph-osd@{{ item.item[1].osd_id }}"
|
||||
state: stopped
|
||||
with_items: "{{ osds_uuid.results }}"
|
||||
|
||||
- name: Reinitialize osd(s) journal in new ssd
|
||||
ansible.builtin.command: ceph-osd -i {{ item.item[1].osd_id }} --mkjournal --cluster {{ cluster }}
|
||||
with_items: "{{ osds_uuid.results }}"
|
||||
|
||||
- name: Start osd(s) service
|
||||
ansible.builtin.service:
|
||||
name: "ceph-osd@{{ item.item[1].osd_id }}"
|
||||
state: started
|
||||
with_items: "{{ osds_uuid.results }}"
|
||||
@@ -0,0 +1,190 @@
|
||||
---
|
||||
# This playbook replaces Ceph OSDs.
|
||||
# It can replace any number of OSD(s) from the cluster and ALL THEIR DATA
|
||||
#
|
||||
# When disks fail, or if an admnistrator wants to reprovision OSDs with a new backend,
|
||||
# for instance, for switching from FileStore to BlueStore, OSDs need to be replaced.
|
||||
# Unlike Removing the OSD, replaced OSD’s id and CRUSH map entry need to be keep intact after the OSD is destroyed for replacement.
|
||||
#
|
||||
# Use it like this:
|
||||
# ansible-playbook replace-osd.yml -e osd_to_replace=0,2,6
|
||||
# Prompts for confirmation to replace, defaults to no and
|
||||
# doesn't replace the osd(s). yes replaces the osd(s).
|
||||
#
|
||||
# ansible-playbook -e ireallymeanit=yes|no replace-osd.yml
|
||||
# Overrides the prompt using -e option. Can be used in
|
||||
# automation scripts to avoid interactive prompt.
|
||||
|
||||
- name: Gather facts and check the init system
|
||||
|
||||
hosts:
|
||||
- "{{ mon_group_name|default('mons') }}"
|
||||
- "{{ osd_group_name|default('osds') }}"
|
||||
|
||||
become: true
|
||||
tasks:
|
||||
- ansible.builtin.debug: msg="gather facts on all Ceph hosts for following reference"
|
||||
|
||||
- name: Confirm whether user really meant to replace osd(s)
|
||||
hosts: localhost
|
||||
become: true
|
||||
vars_prompt:
|
||||
- name: ireallymeanit # noqa: name[casing]
|
||||
prompt: Are you sure you want to replace the osd(s)?
|
||||
default: 'no'
|
||||
private: false
|
||||
vars:
|
||||
mon_group_name: mons
|
||||
osd_group_name: osds
|
||||
pre_tasks:
|
||||
- name: Exit playbook, if user did not mean to replace the osd(s)
|
||||
ansible.builtin.fail:
|
||||
msg: "Exiting replace-osd playbook, no osd(s) was/were replaced..
|
||||
To replace the osd(s), either say 'yes' on the prompt or
|
||||
or use `-e ireallymeanit=yes` on the command line when
|
||||
invoking the playbook"
|
||||
when: ireallymeanit != 'yes'
|
||||
|
||||
- name: Exit playbook, if no osd(s) was/were given
|
||||
ansible.builtin.fail:
|
||||
msg: "osd_to_replace must be declared
|
||||
Exiting replace-osd playbook, no OSD(s) was/were replaced.
|
||||
On the command line when invoking the playbook, you can use
|
||||
-e osd_to_replace=0,1,2,3 argument."
|
||||
when: osd_to_replace is not defined
|
||||
|
||||
tasks:
|
||||
- ansible.builtin.import_role:
|
||||
name: ceph-defaults
|
||||
|
||||
post_tasks:
|
||||
- name: Set_fact container_exec_cmd build docker exec command (containerized)
|
||||
ansible.builtin.set_fact:
|
||||
container_exec_cmd: "docker exec ceph-mon-{{ hostvars[groups[mon_group_name][0]]['ansible_facts']['hostname'] }}"
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Exit playbook, if can not connect to the cluster
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} timeout 5 ceph --cluster {{ cluster }} health"
|
||||
register: ceph_health
|
||||
until: ceph_health.stdout.find("HEALTH") > -1
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
retries: 5
|
||||
delay: 2
|
||||
|
||||
- name: Find the host(s) where the osd(s) is/are running on
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} osd find {{ item }}"
|
||||
with_items: "{{ osd_to_replace.split(',') }}"
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
register: find_osd_hosts
|
||||
|
||||
- name: Set_fact osd_hosts
|
||||
ansible.builtin.set_fact:
|
||||
osd_hosts: "{{ osd_hosts | default([]) + [ (item.stdout | from_json).crush_location.host ] }}"
|
||||
with_items: "{{ find_osd_hosts.results }}"
|
||||
|
||||
- name: Check if ceph admin key exists on the osd nodes
|
||||
ansible.builtin.stat:
|
||||
path: "/etc/ceph/{{ cluster }}.client.admin.keyring"
|
||||
register: ceph_admin_key
|
||||
with_items: "{{ osd_hosts }}"
|
||||
delegate_to: "{{ item }}"
|
||||
failed_when: false
|
||||
when: not containerized_deployment | bool
|
||||
|
||||
- name: Fail when admin key is not present
|
||||
ansible.builtin.fail:
|
||||
msg: "The Ceph admin key is not present on the OSD node, please add it and remove it after the playbook is done."
|
||||
with_items: "{{ ceph_admin_key.results }}"
|
||||
when:
|
||||
- not containerized_deployment | bool
|
||||
- item.stat.exists == false
|
||||
|
||||
# NOTE(leseb): using '>' is the only way I could have the command working
|
||||
- name: Find osd device based on the id
|
||||
ansible.builtin.shell: >
|
||||
docker run --privileged=true -v /dev:/dev --entrypoint /usr/sbin/ceph-disk
|
||||
{{ ceph_docker_registry}}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}
|
||||
list | awk -v pattern=osd.{{ item.1 }} '$0 ~ pattern {print $1}'
|
||||
with_together:
|
||||
- "{{ osd_hosts }}"
|
||||
- "{{ osd_to_replace.split(',') }}"
|
||||
register: osd_to_replace_disks
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Zapping osd(s) - container
|
||||
ansible.builtin.shell: >
|
||||
docker run --privileged=true -v /dev:/dev --entrypoint /usr/sbin/ceph-disk
|
||||
{{ ceph_docker_registry}}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}
|
||||
zap {{ item.1 }}
|
||||
run_once: true
|
||||
with_together:
|
||||
- "{{ osd_hosts }}"
|
||||
- "{{ osd_to_replace_disks.results }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: containerized_deployment | bool
|
||||
|
||||
- name: Zapping osd(s) - non container
|
||||
ansible.builtin.command: ceph-disk zap --cluster {{ cluster }} {{ item.1 }}
|
||||
run_once: true
|
||||
with_together:
|
||||
- "{{ osd_hosts }}"
|
||||
- "{{ osd_to_replace_disks.results }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: not containerized_deployment | bool
|
||||
|
||||
- name: Destroying osd(s)
|
||||
ansible.builtin.command: ceph-disk destroy --cluster {{ cluster }} --destroy-by-id {{ item.1 }} --zap
|
||||
run_once: true
|
||||
with_together:
|
||||
- "{{ osd_hosts }}"
|
||||
- "{{ osd_to_replace.split(',') }}"
|
||||
delegate_to: "{{ item.0 }}"
|
||||
when: not containerized_deployment | bool
|
||||
|
||||
- name: Replace osd(s) - prepare - non container
|
||||
ansible.builtin.command: ceph-disk prepare {{ item.1 }} --osd-id {{ item.2 }} --osd-uuid $(uuidgen)
|
||||
run_once: true
|
||||
delegate_to: "{{ item.0 }}"
|
||||
with_together:
|
||||
- "{{ osd_hosts }}"
|
||||
- "{{ osd_to_replace_disks.results }}"
|
||||
- "{{ osd_to_replace.split(',') }}"
|
||||
|
||||
- name: Replace osd(s) - prepare - container
|
||||
ansible.builtin.shell: >
|
||||
docker run --privileged=true -v /dev:/dev --entrypoint /usr/sbin/ceph-disk
|
||||
{{ ceph_docker_registry}}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}
|
||||
prepare {{ item.1 }}
|
||||
run_once: true
|
||||
delegate_to: "{{ item.0 }}"
|
||||
with_together:
|
||||
- "{{ osd_hosts }}"
|
||||
- "{{ osd_to_replace_disks.results }}"
|
||||
|
||||
- name: Replace osd(s) - activate - non container
|
||||
ansible.builtin.command: ceph-disk activate {{ item.1 }}1
|
||||
run_once: true
|
||||
delegate_to: "{{ item.0 }}"
|
||||
with_together:
|
||||
- "{{ osd_hosts }}"
|
||||
- "{{ osd_to_replace_disks.results }}"
|
||||
|
||||
- name: Replace osd(s) - activate - container
|
||||
ansible.builtin.shell: >
|
||||
docker run --privileged=true -v /dev:/dev --entrypoint /usr/sbin/ceph-disk
|
||||
{{ ceph_docker_registry}}/{{ ceph_docker_image }}:{{ ceph_docker_image_tag }}
|
||||
activate {{ item.1 }}1
|
||||
run_once: true
|
||||
delegate_to: "{{ item.0 }}"
|
||||
with_together:
|
||||
- "{{ osd_hosts }}"
|
||||
- "{{ osd_to_replace_disks.results }}"
|
||||
|
||||
- name: Show ceph health
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} -s"
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
|
||||
- name: Show ceph osd tree
|
||||
ansible.builtin.command: "{{ container_exec_cmd | default('') }} ceph --cluster {{ cluster }} osd tree"
|
||||
delegate_to: "{{ groups[mon_group_name][0] }}"
|
||||
@@ -0,0 +1,57 @@
|
||||
# This file configures logical volume creation for FS Journals on NVMe, a NVMe based bucket index, and HDD based OSDs.
|
||||
# This playbook configures one NVMe device at a time. If your OSD systems contain multiple NVMe devices, you will need to edit the key variables ("nvme_device", "hdd_devices") for each run.
|
||||
# It is meant to be used when osd_objectstore=filestore and it outputs the necessary input for group_vars/osds.yml.
|
||||
# The LVs for journals are created first then the LVs for data. All LVs for journals correspond to a LV for data.
|
||||
#
|
||||
## CHANGE THESE VARS ##
|
||||
#
|
||||
# The NVMe device and the hdd devices must be raw and not have any GPT, FS, or RAID signatures.
|
||||
# GPT, FS, & RAID signatures should be removed from a device prior to running the lv-create.yml playbook.
|
||||
#
|
||||
# Having leftover signatures can result in ansible errors that say "device $device_name excluded by a filter" after running the lv-create.yml playbook.
|
||||
# This can be done by running `wipefs -a $device_name`.
|
||||
|
||||
# Path of nvme device primed for LV creation for journals and data. Only one NVMe device is allowed at a time. Providing a list will not work in this case.
|
||||
nvme_device: dummy
|
||||
|
||||
# Path of hdd devices designated for LV creation.
|
||||
hdd_devices:
|
||||
- /dev/sdd
|
||||
- /dev/sde
|
||||
- /dev/sdf
|
||||
- /dev/sdg
|
||||
- /dev/sdh
|
||||
|
||||
# Per the lvol module documentation, "size" and "journal_size" is the size of the logical volume, according to lvcreate(8) --size.
|
||||
# This is by default in megabytes or optionally with one of [bBsSkKmMgGtTpPeE] units; or according to lvcreate(8) --extents as a percentage of [VG|PVS|FREE]; Float values must begin with a digit.
|
||||
# For further reading and examples see: https://docs.ansible.com/ansible/2.6/modules/lvol_module.html
|
||||
|
||||
# Suggested journal size is 5500
|
||||
journal_size: 5500
|
||||
|
||||
# This var is a list of bucket index LVs created on the NVMe device. We recommend one be created but you can add others
|
||||
nvme_device_lvs:
|
||||
- lv_name: "ceph-bucket-index-1"
|
||||
size: 100%FREE
|
||||
journal_name: "ceph-journal-bucket-index-1-{{ nvme_device_basename }}"
|
||||
|
||||
## TYPICAL USERS WILL NOT NEED TO CHANGE VARS FROM HERE DOWN ##
|
||||
|
||||
# the path to where to save the logfile for lv-create.yml
|
||||
logfile_path: ./lv-create.log
|
||||
|
||||
# all hdd's have to be the same size and the LVs on them are dedicated for OSD data
|
||||
hdd_lv_size: 100%FREE
|
||||
|
||||
# Since this playbook can be run multiple times across different devices, {{ var.split('/')[-1] }} is used quite frequently in this play-book.
|
||||
# This is used to strip the device name away from its path (ex: sdc from /dev/sdc) to differenciate the names of vgs, journals, or lvs if the prefixes are not changed across multiple runs.
|
||||
nvme_device_basename: "{{ nvme_device.split('/')[-1] }}"
|
||||
|
||||
# Only one volume group is created in the playbook for all the LVs on NVMe. This volume group takes up the entire device specified in "nvme_device".
|
||||
nvme_vg_name: "ceph-nvme-vg-{{ nvme_device_basename }}"
|
||||
|
||||
hdd_vg_prefix: "ceph-hdd-vg"
|
||||
hdd_lv_prefix: "ceph-hdd-lv"
|
||||
hdd_journal_prefix: "ceph-journal"
|
||||
|
||||
# Journals are created on NVMe device
|
||||
Reference in New Issue
Block a user