From 74e2b560209d47f932e3a14de6a3ab580748fe3c Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 25 Sep 2025 14:56:14 +0300 Subject: [PATCH 01/53] More debug messages for workload --- plugins/modules/workload.py | 9 +++++++++ roles/packages/tasks/main.yaml | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/plugins/modules/workload.py b/plugins/modules/workload.py index 7943b24..80d1ff2 100644 --- a/plugins/modules/workload.py +++ b/plugins/modules/workload.py @@ -35,18 +35,21 @@ def main(): results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) ydb_cmd = ['workload', 'topic', 'run', 'read'] rc, stdout, stderr = ydb_cli(ydb_cmd) results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) ydb_cmd = ['workload', 'topic', 'run', 'full'] rc, stdout, stderr = ydb_cli(ydb_cmd) results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) else: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') @@ -63,18 +66,21 @@ def main(): results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) ydb_cmd = ['workload', 'kv', 'run', 'insert'] rc, stdout, stderr = ydb_cli(ydb_cmd) results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) ydb_cmd = ['workload', 'kv', 'run', 'select'] rc, stdout, stderr = ydb_cli(ydb_cmd) results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) else: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') @@ -91,18 +97,21 @@ def main(): results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) ydb_cmd = ['workload', 'stock', 'run', 'rand-user-hist'] rc, stdout, stderr = ydb_cli(ydb_cmd) results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) ydb_cmd = ['workload', 'stock', 'run', 'add-rand-order'] rc, stdout, stderr = ydb_cli(ydb_cmd) results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') + result['msg'] = stderr module.fail_json(**result) else: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') diff --git a/roles/packages/tasks/main.yaml b/roles/packages/tasks/main.yaml index a97e688..e5f5367 100644 --- a/roles/packages/tasks/main.yaml +++ b/roles/packages/tasks/main.yaml @@ -40,10 +40,14 @@ tags: libxcrypt-compat - name: install required packages + become: true + become_user: root ansible.builtin.package: pkg: "{{ vars_for_distribution_version.packages_required }}" state: present timeout: 900 + tags: + - packages - name: install cpufrequtils ansible.builtin.package: From 055450a7ba1174d5e06ef7b5adedf3f4ecbe57e2 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 25 Sep 2025 14:58:04 +0300 Subject: [PATCH 02/53] topic read test is useless here --- plugins/modules/workload.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/plugins/modules/workload.py b/plugins/modules/workload.py index 80d1ff2..3e65a9d 100644 --- a/plugins/modules/workload.py +++ b/plugins/modules/workload.py @@ -33,13 +33,6 @@ def main(): ydb_cmd = ['workload', 'topic', 'run', 'write'] #, '--threads', '10', '--byte-rate 8M'] rc, stdout, stderr = ydb_cli(ydb_cmd) results.append(stdout) - if rc != 0: - module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') - result['msg'] = stderr - module.fail_json(**result) - ydb_cmd = ['workload', 'topic', 'run', 'read'] - rc, stdout, stderr = ydb_cli(ydb_cmd) - results.append(stdout) if rc != 0: module.log(f'workload failed with rc: {rc}, stdout: {stdout}, stderr: {stderr}') result['msg'] = stderr From 9343804d5d2924b73121dd5753b014a7e2319f66 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 25 Sep 2025 18:09:12 +0300 Subject: [PATCH 03/53] + AltLinux 10.4 --- .../distributions/Altlinux/10.4/main.yaml | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 roles/packages/vars/distributions/Altlinux/10.4/main.yaml diff --git a/roles/packages/vars/distributions/Altlinux/10.4/main.yaml b/roles/packages/vars/distributions/Altlinux/10.4/main.yaml new file mode 100644 index 0000000..56fbc10 --- /dev/null +++ b/roles/packages/vars/distributions/Altlinux/10.4/main.yaml @@ -0,0 +1,26 @@ +--- + +repositories: [] + +preferences: [] + +configs: [] + +packages: + - bash-completion + - bind + - ca-certificates + - chrony + - curl + - gdisk + - iperf3 + - iptables + - jq + - logrotate + - lsof + - procps + - rsync + - strace + - tar + +packages_required: [] From 0991ee31f241291779f1f02ae24e406342eb60a8 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 26 Sep 2025 12:32:27 +0300 Subject: [PATCH 04/53] Fix for custom domain name in v2 (YDBOPS-12926) --- plugins/modules/patch_config.py | 11 ++++++++--- roles/ydbd_static/tasks/main.yaml | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/modules/patch_config.py b/plugins/modules/patch_config.py index 7379729..799b90a 100644 --- a/plugins/modules/patch_config.py +++ b/plugins/modules/patch_config.py @@ -68,7 +68,7 @@ def _generate_hosts_section(hostvars, ydb_disks, default_disk_type=None): return hosts -def patch_config_v2(config, hostvars=None, ydb_disks=None, groups=None, ydb_dir=None): +def patch_config_v2(config, hostvars=None, ydb_disks=None, groups=None, ydb_dir=None, ydb_domain=None): _ensure_config_path(config, 'yaml_config_enabled', True) _ensure_config_path(config, 'self_management_config.enabled', True) _ensure_config_path(config, 'actor_system_config.use_auto_config', True) @@ -82,6 +82,9 @@ def patch_config_v2(config, hostvars=None, ydb_disks=None, groups=None, ydb_dir= _ensure_config_path(config, 'grpc_config.key', f"{ydb_dir}/certs/node.key") _ensure_config_path(config, 'grpc_config.ca', f"{ydb_dir}/certs/ca.crt") _ensure_config_path(config, 'grpc_config.services_enabled', ['legacy','discovery']) + + if ydb_domain is not None: + _ensure_config_path(config, 'domains_config.domain', [{"name": f"{ydb_domain}"}]) # Generate hosts section if it's missing and we have the required data if 'hosts' not in config and hostvars and ydb_disks: @@ -105,6 +108,7 @@ def main(): ydb_disks=dict(type='list', required=False), groups=dict(type='dict', required=False), ydb_dir=dict(type='str', required=False, default=None), + ydb_domain=dict(type='str', required=False, default=None), ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) @@ -117,6 +121,7 @@ def main(): ydb_disks = module.params.get('ydb_disks') groups = module.params.get('groups') ydb_dir = module.params.get('ydb_dir') + ydb_domain = module.params.get('ydb_domain') # Handle different input types if isinstance(config_input, dict): @@ -139,10 +144,10 @@ def main(): # Apply the patch to the config section only original_config = copy.deepcopy(config) if 'config' in config: - patched_config_section = patch_config_v2(config['config'], hostvars, ydb_disks, groups, ydb_dir) + patched_config_section = patch_config_v2(config['config'], hostvars, ydb_disks, groups, ydb_dir, ydb_domain) config['config'] = patched_config_section else: - config = patch_config_v2(config, hostvars, ydb_disks, groups, ydb_dir) + config = patch_config_v2(config, hostvars, ydb_disks, groups, ydb_dir, ydb_domain) # Determine if changes were actually made result['changed'] = config != original_config diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index 3a2fdb5..9918fab 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -231,6 +231,7 @@ ydb_disks: "{{ ydb_disks }}" groups: "{{ groups }}" ydb_dir: "{{ ydb_dir }}" + ydb_domain: "{{ ydb_domain }}" become: true become_user: ydb From ecb380b7f1babc86a74c1edd9b7a6927e9be3674 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 30 Sep 2025 15:03:12 +0300 Subject: [PATCH 05/53] small fix for Ansible 2.19 --- roles/check_connectivity/tasks/check_ansible.yaml | 9 +++++++-- roles/check_connectivity/tasks/main.yaml | 2 ++ roles/preflight/tasks/main.yaml | 6 ------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/roles/check_connectivity/tasks/check_ansible.yaml b/roles/check_connectivity/tasks/check_ansible.yaml index 2541b62..fb97c33 100644 --- a/roles/check_connectivity/tasks/check_ansible.yaml +++ b/roles/check_connectivity/tasks/check_ansible.yaml @@ -1,6 +1,11 @@ --- -- name: Check ansible version +- name: Check Ansible version when: "ansible_version.full is version('2.11', '<=')" ansible.builtin.fail: - msg: "aborting playbook execution. Install Ansible 2.11 or newer. Current version is {{ ansible_version.full }}" + msg: "Aborting playbook execution. Install Ansible 2.11 or newer. Current version is {{ ansible_version.full }}" + +- name: Check Python + ydb_platform.ydb.warn: + msg: "Discovered ansible_python version is out of date and is not supported. https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix" + when: "ansible_python_version is version('3.7', '<')" diff --git a/roles/check_connectivity/tasks/main.yaml b/roles/check_connectivity/tasks/main.yaml index b5a3909..1b742f2 100644 --- a/roles/check_connectivity/tasks/main.yaml +++ b/roles/check_connectivity/tasks/main.yaml @@ -1,5 +1,7 @@ --- +- ansible.builtin.gather_facts: + - ansible.builtin.include_tasks: check_ansible.yaml tags: - checks diff --git a/roles/preflight/tasks/main.yaml b/roles/preflight/tasks/main.yaml index 977dbe2..6607ebd 100644 --- a/roles/preflight/tasks/main.yaml +++ b/roles/preflight/tasks/main.yaml @@ -19,12 +19,6 @@ ansible.builtin.service_facts: timeout: 300 -- name: check ansible_python - ydb_platform.ydb.warn: - msg: "discovered ansible_python version is out of date and is not supported" - that: - - "ansible_python_version is version_compare('3.7', '<')" - - name: assert usage of systemd as an init system ansible.builtin.assert: that: ansible_service_mgr == 'systemd' From dafeb539afcd8f1f69725ace0081e688a0ba57a2 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Wed, 8 Oct 2025 17:32:24 +0300 Subject: [PATCH 06/53] +inventory plugin --- meta/runtime.yaml | 6 ++ plugins/inventory/ydb_inventory.py | 106 +++++++++++++++++++++++ roles/check_connectivity/tasks/main.yaml | 1 + 3 files changed, 113 insertions(+) create mode 100644 plugins/inventory/ydb_inventory.py diff --git a/meta/runtime.yaml b/meta/runtime.yaml index 20f709e..4c025f2 100644 --- a/meta/runtime.yaml +++ b/meta/runtime.yaml @@ -50,3 +50,9 @@ # group_name: # - module1 # - module2 +plugin_routing: + inventory: + ydb_inventory: + name: ydb_platform.ydb.ydb_inventory + import_redirection: + redirect: plugins.inventory.ydb_inventory \ No newline at end of file diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py new file mode 100644 index 0000000..39d4a34 --- /dev/null +++ b/plugins/inventory/ydb_inventory.py @@ -0,0 +1,106 @@ +from ansible.plugins.inventory import BaseInventoryPlugin +import yaml +from ansible.errors import AnsibleError +# from ansible.template import Templar + +DOCUMENTATION = r''' + name: ydb_inventory + plugin_type: inventory + short_description: YDB inventory from config.yaml + description: | + This inventory plugin fetches hosts from a custom source (config.yaml). + options: + plugin: + description: The name of the plugin (must be 'ydb_inventory') + required: true + choices: ['ydb_platform.ydb.ydb_inventory'] + ydb_config: + description: YDB config (file or dictionary) + required: true + env: + - name: INVENTORY_YDB_CONFIG +''' + +class InventoryModule(BaseInventoryPlugin): + NAME = 'ydb_inventory' + + def verify_file(self, path): + # Проверяем, что это конфиг для нашего плагина + valid = super().verify_file(path) + return valid + + def parse(self, inventory, loader, path, cache=True): + super().parse(inventory, loader, path, cache) + # Загружаем конфиг плагина (YAML-файл) + config = self._read_config_data(path) + + # # Инициализация Templar + # templar = Templar(loader=loader) + + # try: + # # 3. Обрабатываем шаблоны во всех значениях конфигурации + # processed_config = {} + # for key, value in config.items(): + # if isinstance(value, str) and '{{' in value: + # # Обрабатываем строки с шаблонами + # processed_config[key] = templar.template(value, fail_on_undefined=True) + # else: + # # Простые значения копируем как есть + # processed_config[key] = value + + # # 4. Используем обработанные значения + # print(processed_config) + ydb_config = config.get('ydb_config') + + # # 5. Ваша логика загрузки инвентаря + # if isinstance(ydb_config, dict): + # # Обработка встроенной конфигурации + # self._load_from_dict(ydb_config) + # else: + # # Обработка файловой конфигурации + # self._load_from_file(ydb_config) + + # except Exception as e: + # raise AnsibleError(f"Template error: {str(e)}") + + # ydb_config = config.get('all')['children']['ydb']['vars']['ydb_config'] + print(f"Reading inventory from {ydb_config}") + + group = 'ydb' + self.inventory.add_group(group) + + ydb_vars = self.inventory.groups['ydb'].get_vars() + try: + with open(ydb_config, "r") as file: + yaml_config = yaml.safe_load(file) + # Read drives config + drive_configs = {} + drive_labels = {} + if 'ydb_disks' in ydb_vars: + for disk in ydb_vars['ydb_disks']: + drive_labels[disk['label']] = disk['name'] + if 'config' in yaml_config and 'host_configs' in yaml_config['config']: + for drive_config in yaml_config['config']['host_configs']: + for i, item in enumerate(drive_config['drive']): + label = item['path'].split('/')[-1] + drive_config['drive'][i]['label'] = label + if label in drive_labels: + drive_config['drive'][i]['disk'] = drive_labels[label] + else: + raise AnsibleError(f"Config parsing error, unable to find disk for label: {label}") + drive_configs[drive_config['host_config_id']] = drive_config['drive'] + # Read hosts and define variables for them + if 'config' in yaml_config and 'hosts' in yaml_config['config']: + for host in yaml_config['config']['hosts']: + self.inventory.add_host(host['host'], group=group) + # Set variables for hosts + for key, value in host.items(): + if key == 'host_config_id': + self.inventory.set_variable(host['host'], 'host_drives', drive_configs[value]) + else: + self.inventory.set_variable(host['host'], key, value) + + except Exception as e: + raise AnsibleError(f"Config parsing error: {str(e)}") + + diff --git a/roles/check_connectivity/tasks/main.yaml b/roles/check_connectivity/tasks/main.yaml index 1b742f2..6c4c683 100644 --- a/roles/check_connectivity/tasks/main.yaml +++ b/roles/check_connectivity/tasks/main.yaml @@ -3,6 +3,7 @@ - ansible.builtin.gather_facts: - ansible.builtin.include_tasks: check_ansible.yaml + run_once: true tags: - checks - check_ansible From 868c6ec58ef19d50ef7eef8513946e8c7b882507 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Wed, 8 Oct 2025 17:33:03 +0300 Subject: [PATCH 07/53] checks --- .../tasks/check_ansible.yaml | 29 ++++++++++++++ .../tasks/check_time_diff.yaml | 39 +++++++++---------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/roles/check_connectivity/tasks/check_ansible.yaml b/roles/check_connectivity/tasks/check_ansible.yaml index fb97c33..43306d3 100644 --- a/roles/check_connectivity/tasks/check_ansible.yaml +++ b/roles/check_connectivity/tasks/check_ansible.yaml @@ -9,3 +9,32 @@ ydb_platform.ydb.warn: msg: "Discovered ansible_python version is out of date and is not supported. https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix" when: "ansible_python_version is version('3.7', '<')" + +- name: Check config + assert: + that: + - ydb_config is string or ydb_config is mapping + fail_msg: "ydb_config must be either a path (string) or data (dict)" + +- name: Check if ydb_config is a file path + set_fact: + is_config_file: "{{ ydb_config is string }}" + +- name: Load configuration from file if path provided + when: is_config_file + block: + - name: Verify config file exists + ansible.builtin.stat: + path: "{{ ydb_config }}" + register: config_file + delegate_to: localhost # Проверяем файл на control node + + - name: Fail if file missing + ansible.builtin.fail: + msg: "Config file {{ ydb_config }} not found" + when: not config_file.stat.exists + + - name: Read configuration file + ansible.builtin.include_vars: + file: "{{ ydb_config }}" + name: ydb_config_parsed diff --git a/roles/check_connectivity/tasks/check_time_diff.yaml b/roles/check_connectivity/tasks/check_time_diff.yaml index 5b89e3c..cac191c 100644 --- a/roles/check_connectivity/tasks/check_time_diff.yaml +++ b/roles/check_connectivity/tasks/check_time_diff.yaml @@ -1,30 +1,29 @@ --- -- name: Record time on control node - delegate_to: localhost - become: false - run_once: true - command: "python3 -c 'import time; print(time.time())'" - register: start_time - changed_when: false +- block: + - name: Record time on control node + delegate_to: localhost + become: false + command: "python3 -c 'import time; print(time.time())'" + register: "start_time" + changed_when: false -- name: Record time on target nodes - become: false - command: "python3 -c 'import time; print(time.time())'" - register: remote_time - changed_when: false + - name: Record time on target nodes + become: false + command: "python3 -c 'import time; print(time.time())'" + register: remote_time + changed_when: false -- name: Record time on control node - delegate_to: localhost - run_once: true - become: false - command: "python3 -c 'import time; print(time.time())'" - register: end_time - changed_when: false + - name: Record time on control node + delegate_to: localhost + become: false + command: "python3 -c 'import time; print(time.time())'" + register: "end_time" + changed_when: false - name: Calculate time difference (with network delay) set_fact: - time_diff: "{{ (remote_time.stdout | float) - ((start_time.stdout | float) + (end_time.stdout | float)) / 2 }}" + time_diff: "{{ (remote_time.stdout | float) - ((start_time_{{ inventory_hostname }}.stdout | float) + (end_time_{{ inventory_hostname }}.stdout | float)) / 2 }}" - name: Time difference debug: From ea80df27676a2d29ebcfb7c3909b045e8689e8ce Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 9 Oct 2025 14:02:00 +0300 Subject: [PATCH 08/53] YDBOPS-12926 Fix user --- playbooks/healthcheck.yaml | 8 +++++--- roles/ydbd/tasks/main.yaml | 19 +++++++++--------- roles/ydbd_static/defaults/main.yaml | 2 ++ roles/ydbd_static/tasks/main.yaml | 29 ++++++++++++++-------------- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/playbooks/healthcheck.yaml b/playbooks/healthcheck.yaml index b3f3f8e..037b625 100644 --- a/playbooks/healthcheck.yaml +++ b/playbooks/healthcheck.yaml @@ -2,6 +2,8 @@ - name: Healthcheck cluster hosts: "{{ ansible_play_hosts | default(groups['ydbd_static']) }}" run_once: true + vars: + ydb_host_user: ydb tasks: - name: prepare @@ -23,7 +25,7 @@ retries: 25 delay: 20 become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" tags: - token @@ -36,7 +38,7 @@ token: "{{ ydb_credentials.token }}" any_errors_fatal: true become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" tags: - discovery @@ -54,6 +56,6 @@ retries: 30 delay: 10 become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" tags: - healthcheck diff --git a/roles/ydbd/tasks/main.yaml b/roles/ydbd/tasks/main.yaml index 01d8f92..097896b 100644 --- a/roles/ydbd/tasks/main.yaml +++ b/roles/ydbd/tasks/main.yaml @@ -14,13 +14,13 @@ - name: create ydb group group: - name: ydb + name: "{{ ydb_host_group }}" system: true - name: create ydb user user: - name: ydb - group: ydb + name: "{{ ydb_host_user }}" + group: "{{ ydb_host_group }}" groups: [disk, certs] system: true create_home: true @@ -32,8 +32,9 @@ path: "{{ ydb_dir }}/home/.ansible/tmp" state: directory recurse: true - group: ydb - owner: ydb + owner: "{{ ydb_host_user }}" + group: "{{ ydb_host_group }}" + - name: Add aliases in bashrc lineinfile: @@ -141,8 +142,8 @@ copy: content: "{{ ydb_config | ydb_platform.ydb.ydb_config_to_yaml }}" dest: "{{ ydb_dir }}/cfg/ydbd-config.yaml" - owner: ydb - group: ydb + owner: "{{ ydb_host_user }}" + group: "{{ ydb_host_group }}" mode: 0440 when: ydb_config_is_map and not ydb_config_v2 | default(false) @@ -150,8 +151,8 @@ copy: src: "{{ ydb_config }}" dest: "{{ ydb_dir }}/cfg/ydbd-config.yaml" - owner: ydb - group: ydb + owner: "{{ ydb_host_user }}" + group: "{{ ydb_host_group }}" mode: 0440 when: not ydb_config_is_map and not ydb_config_v2 | default(false) diff --git a/roles/ydbd_static/defaults/main.yaml b/roles/ydbd_static/defaults/main.yaml index 51d78b5..85a5a09 100644 --- a/roles/ydbd_static/defaults/main.yaml +++ b/roles/ydbd_static/defaults/main.yaml @@ -7,3 +7,5 @@ ydb_storage_update_config: false ydb_use_dynamic_config: false ydb_custom_dynconfig: ydbd-dyn-config.yaml.j2 ydb_config_v2: false +ydb_host_user: ydb +ydb_host_group: ydb \ No newline at end of file diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index 9918fab..94425a6 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -209,8 +209,8 @@ copy: content: "{{ ydb_config | ydb_platform.ydb.ydb_config_to_yaml }}" dest: "{{ ydb_temp_config_path }}" - owner: ydb - group: ydb + owner: "{{ ydb_host_user }}" + group: "{{ ydb_host_group }}" mode: 0644 when: ydb_config_is_map @@ -218,8 +218,8 @@ copy: src: "{{ ydb_config }}" dest: "{{ ydb_temp_config_path }}" - owner: ydb - group: ydb + owner: "{{ ydb_host_user }}" + group: "{{ ydb_host_group }}" mode: 0644 when: not ydb_config_is_map @@ -233,7 +233,7 @@ ydb_dir: "{{ ydb_dir }}" ydb_domain: "{{ ydb_domain }}" become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" - name: update configuration with selectors ydb_platform.ydb.apply_config_selectors: @@ -242,7 +242,7 @@ database_cores: "{{ ydb_database_node_cores | default(ydb_cores_dynamic) | default(omit) }}" storage_cores: "{{ ydb_storage_node_cores | default(ydb_cores_static) | default(omit) }}" become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" when: ydb_config_v2 and (ydb_database_node_cores is defined or ydb_storage_node_cores is defined or ydb_cores_dynamic is defined or ydb_cores_static is defined) - name: init YDB node configuration (V2 only - before ydbd start) @@ -254,7 +254,7 @@ endpoint: "grpcs://{{ ydb_brokers | flatten(levels=1) | first }}:2135" database: "/{{ ydb_domain }}" become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" when: ydb_config_v2|bool - name: cleanup temp config file after node init @@ -323,7 +323,7 @@ retries: 5 delay: 5 become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" when: not ydb_config_v2 - name: init YDB storage if not initialized (non-v2 configuration) @@ -342,7 +342,7 @@ register: init_storage_nonv2 run_once: true when: not ydb_config_v2 - become_user: ydb + become_user: "{{ ydb_host_user }}" # For v2 configs, initialize storage after the server is running - name: init YDB storage if not initialized (v2 configuration) @@ -358,7 +358,7 @@ register: init_storage_v2 run_once: true when: ydb_config_v2 - become_user: ydb + become_user: "{{ ydb_host_user }}" - name: get ydb token with user credentials ydb_platform.ydb.get_token: @@ -375,7 +375,7 @@ retries: 25 delay: 20 become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" - name: wait for ydb discovery to start working locally ydb_platform.ydb.wait_discovery: @@ -386,7 +386,7 @@ token: "{{ ydb_credentials.token }}" any_errors_fatal: true become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" tags: - discovery @@ -404,9 +404,10 @@ retries: 30 delay: 10 become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" tags: - healthcheck + # when: "ydb_version is version('25.1', '<')" - name: set cluster root password ydb_platform.ydb.set_user_password: @@ -419,7 +420,7 @@ token: "{{ ydb_credentials.token }}" run_once: true become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" register: password_result retries: 30 delay: 15 From ce3850ed8b941ad1636f81232f4191dd75558b8c Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 9 Oct 2025 14:03:37 +0300 Subject: [PATCH 09/53] YDBOPS-12647 Quotas --- plugins/inventory/ydb_inventory.py | 13 ++- .../tasks/check_ansible.yaml | 5 +- roles/preflight/tasks/main.yaml | 33 +++++++ roles/ydbd/defaults/main.yaml | 2 + roles/ydbd_dynamic/tasks/main.yaml | 48 ++++++---- roles/ydbd_newdb/tasks/main.yml | 2 +- .../ydbd_static/templates/create_database.j2 | 95 ++++++++++++++++++- 7 files changed, 168 insertions(+), 30 deletions(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 39d4a34..8bfe68b 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -1,5 +1,6 @@ from ansible.plugins.inventory import BaseInventoryPlugin import yaml +import copy from ansible.errors import AnsibleError # from ansible.template import Templar @@ -73,6 +74,10 @@ def parse(self, inventory, loader, path, cache=True): try: with open(ydb_config, "r") as file: yaml_config = yaml.safe_load(file) + self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config) + if 'config' in yaml_config and 'self_management_config' in yaml_config['config']: + if 'enabled' in yaml_config['config']['self_management_config'] and yaml_config['config']['self_management_config']['enabled']: + self.inventory.groups['ydb'].set_variable('ydb_config_v2', True) # Read drives config drive_configs = {} drive_labels = {} @@ -83,12 +88,12 @@ def parse(self, inventory, loader, path, cache=True): for drive_config in yaml_config['config']['host_configs']: for i, item in enumerate(drive_config['drive']): label = item['path'].split('/')[-1] - drive_config['drive'][i]['label'] = label + drive_configs[drive_config['host_config_id']] = copy.deepcopy(drive_config['drive']) + drive_configs[drive_config['host_config_id']][i]['label'] = label if label in drive_labels: - drive_config['drive'][i]['disk'] = drive_labels[label] + drive_configs[drive_config['host_config_id']][i]['name'] = drive_labels[label] else: raise AnsibleError(f"Config parsing error, unable to find disk for label: {label}") - drive_configs[drive_config['host_config_id']] = drive_config['drive'] # Read hosts and define variables for them if 'config' in yaml_config and 'hosts' in yaml_config['config']: for host in yaml_config['config']['hosts']: @@ -96,7 +101,7 @@ def parse(self, inventory, loader, path, cache=True): # Set variables for hosts for key, value in host.items(): if key == 'host_config_id': - self.inventory.set_variable(host['host'], 'host_drives', drive_configs[value]) + self.inventory.set_variable(host['host'], 'ydb_disks', drive_configs[value]) else: self.inventory.set_variable(host['host'], key, value) diff --git a/roles/check_connectivity/tasks/check_ansible.yaml b/roles/check_connectivity/tasks/check_ansible.yaml index 43306d3..72a6db0 100644 --- a/roles/check_connectivity/tasks/check_ansible.yaml +++ b/roles/check_connectivity/tasks/check_ansible.yaml @@ -22,6 +22,7 @@ - name: Load configuration from file if path provided when: is_config_file + become: false block: - name: Verify config file exists ansible.builtin.stat: @@ -34,7 +35,3 @@ msg: "Config file {{ ydb_config }} not found" when: not config_file.stat.exists - - name: Read configuration file - ansible.builtin.include_vars: - file: "{{ ydb_config }}" - name: ydb_config_parsed diff --git a/roles/preflight/tasks/main.yaml b/roles/preflight/tasks/main.yaml index 6607ebd..9faf903 100644 --- a/roles/preflight/tasks/main.yaml +++ b/roles/preflight/tasks/main.yaml @@ -36,3 +36,36 @@ ansible.builtin.fail: msg: "Impossible to use ydb_enforce_user_token_requirement and ydb_request_client_certificate together" when: ydb_use_dynamic_config is defined and ydb_use_dynamic_config|bool and ydb_enforce_user_token_requirement|bool and ydb_request_client_certificate|bool + +- name: Load configuration from file if path provided + when: ydb_config_dict is not defined + become: false + run_once: true + block: + + - name: Check if ydb_config is a file path + set_fact: + is_config_file: "{{ ydb_config is string }}" + + - name: Register ydb_config_dict from ydb_config var + ansible.builtin.set_fact: + ydb_config_dict: "{{ ydb_config }}" + when: not is_config_file|bool + + - name: Verify config file exists + ansible.builtin.stat: + path: "{{ ydb_config }}" + register: config_file + delegate_to: localhost # Проверяем файл на control node + when: is_config_file|bool + + - name: Fail if file missing + ansible.builtin.fail: + msg: "Config file {{ ydb_config }} not found" + when: is_config_file|bool and not config_file.stat.exists + + - name: Read configuration file + ansible.builtin.include_vars: + file: "{{ ydb_config }}" + name: ydb_config_dict + when: is_config_file|bool diff --git a/roles/ydbd/defaults/main.yaml b/roles/ydbd/defaults/main.yaml index 123aaf7..5a848f3 100644 --- a/roles/ydbd/defaults/main.yaml +++ b/roles/ydbd/defaults/main.yaml @@ -1,2 +1,4 @@ ydb_transparent_hugepages_enable: true ydb_config_v2: false +ydb_host_user: ydb +ydb_host_group: ydb \ No newline at end of file diff --git a/roles/ydbd_dynamic/tasks/main.yaml b/roles/ydbd_dynamic/tasks/main.yaml index 403a3df..715a211 100644 --- a/roles/ydbd_dynamic/tasks/main.yaml +++ b/roles/ydbd_dynamic/tasks/main.yaml @@ -113,8 +113,6 @@ ydb_database_node_cores | default(ydb_cores_dynamic, true) }} - - - name: create dynamic node configuration file command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-dynamic.yaml COMPUTE {{ ydb_database_node_cores | default(ydb_cores_dynamic, true) }}" changed_when: false @@ -125,6 +123,7 @@ src: ydbd-dynnode.service dest: "/etc/systemd/system/ydbd-{{ item.dbname | default(ydb_database_name, true) }}-{{ item.instance }}.service" loop: "{{ ydb_dynnodes }}" + when: "item.hosts is not defined or '{{ inventory_hostname }}' in item.hosts" notify: - daemon reload @@ -137,6 +136,7 @@ state: started enabled: true loop: "{{ ydb_dynnodes }}" + when: "item.hosts is not defined or '{{ inventory_hostname }}' in item.hosts" - name: Get YDB token ydb_platform.ydb.get_token: @@ -148,7 +148,7 @@ password: "{{ ydb_password }}" retry_on_ssl_error: true become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" run_once: true register: ydb_credentials until: "'token' in ydb_credentials" @@ -162,28 +162,36 @@ endpoint: "grpcs://{{ ydb_front | default(ydb_brokers) | flatten(levels=1) | first }}:2135" token: "{{ root_token.token | default('') }}" run_once: true - become_user: ydb + become_user: "{{ ydb_host_user }}" tags: - create_database - name: Create YDB database - ydb_platform.ydb.create_database: - ydbd_bin: "{{ ydb_dir }}/bin/ydbd" - ld_library_path: "{{ ydb_dir }}/lib" - ca_file: "{{ ydb_dir }}/certs/ca.crt" - endpoint: "grpcs://{{ ydb_front | default(ydb_brokers) | flatten(levels=1) | first }}:2135" - database: "/{{ ydb_domain }}/{{ ydb_dbname | default(ydb_database_name, true) }}" - token: "{{ ydb_credentials.token }}" - pool_kind: "{{ ydb_pool_kind }}" - groups: "{{ ydb_database_storage_groups | default(ydb_database_groups) }}" - become: true - become_user: ydb + ansible.builtin.import_role: + name: ydbd_newdb run_once: true - retries: 50 - delay: 15 + become: true tags: - create_database +# - name: Create YDB database +# ydb_platform.ydb.create_database: +# ydbd_bin: "{{ ydb_dir }}/bin/ydbd" +# ld_library_path: "{{ ydb_dir }}/lib" +# ca_file: "{{ ydb_dir }}/certs/ca.crt" +# endpoint: "grpcs://{{ ydb_front | default(ydb_brokers) | flatten(levels=1) | first }}:2135" +# database: "/{{ ydb_domain }}/{{ ydb_dbname | default(ydb_database_name, true) }}" +# token: "{{ ydb_credentials.token }}" +# pool_kind: "{{ ydb_pool_kind }}" +# groups: "{{ ydb_database_storage_groups | default(ydb_database_groups) }}" +# become: true +# become_user: "{{ ydb_host_user }}" +# run_once: true +# retries: 50 +# delay: 15 +# tags: +# - create_database + - name: Wait for ydb discovery to start working locally ydb_platform.ydb.wait_discovery: ydb_bin: "{{ ydb_dir }}/bin/ydb" @@ -193,8 +201,9 @@ database: "/{{ ydb_domain }}/{{ item.dbname | default(ydb_database_name, true) }}" token: "{{ ydb_credentials.token }}" become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" loop: "{{ ydb_dynnodes }}" + when: "item.hosts is not defined or '{{ inventory_hostname }}' in item.hosts" retries: 5 - name: Delay for 1 min @@ -211,8 +220,9 @@ user: "{{ ydb_user }}" password: "{{ ydb_password }}" become: true - become_user: ydb + become_user: "{{ ydb_host_user }}" loop: "{{ ydb_dynnodes }}" + when: "item.hosts is not defined or '{{ inventory_hostname }}' in item.hosts" throttle: 1 tags: - tests diff --git a/roles/ydbd_newdb/tasks/main.yml b/roles/ydbd_newdb/tasks/main.yml index a5e5655..6e4c2c4 100644 --- a/roles/ydbd_newdb/tasks/main.yml +++ b/roles/ydbd_newdb/tasks/main.yml @@ -9,7 +9,7 @@ src: "secret.j2" dest: "{{ ydb_dir }}/certs/secret" - name: Run the database creation script - command: "{{ ydb_dir }}/home/create_database.sh {{ ydb_brokers | default(groups['ydb']) | flatten(levels=1) | first }} {{ ydb_database_name | default(ydb_dbname, true) }} {{ ydb_database_storage_groups | default(ydb_database_groups) }}" + command: "{{ ydb_dir }}/home/create_database.sh {{ ydb_brokers | default(groups['ydb']) | flatten(levels=1) | first }} {{ ydb_database_name | default(ydb_dbname, true) }} {{ ydb_database_storage_groups | default(ydb_database_groups) }} {{ '1' if ydb_database_quotas else '0' }}" - name: Cleanup the transferred secrets file: state=absent path={{ ydb_dir }}/certs/secret run_once: true diff --git a/roles/ydbd_static/templates/create_database.j2 b/roles/ydbd_static/templates/create_database.j2 index e93a2fc..1c98b7d 100644 --- a/roles/ydbd_static/templates/create_database.j2 +++ b/roles/ydbd_static/templates/create_database.j2 @@ -1,9 +1,10 @@ #! /bin/sh -# Create the YDB database. +# Create the YDB database and set quotas # Parameters: # * static node fqdn # * database name # * initial number of storage groups +# * set quotas (1) set +e set +u @@ -16,6 +17,12 @@ TOKEN={{ ydb_dir }}/home/ydbd-token-file PASSFILE={{ ydb_dir }}/certs/secret DB_NAME="$2" DB_GROUPS="$3" +# +# First device for YDB on the host for estimating storage size +# YDBOPS-12647 +# +DISK_DEVICE="{{ ydb_disks[0].name }}" +YDB_SCHEMA="{{ ydb_config_dict.static_erasure }}" LD_LIBRARY_PATH={{ ydb_dir }}/lib export LD_LIBRARY_PATH @@ -29,6 +36,7 @@ set -u if [ -f ${PASSFILE} ]; then # Username and password are passed in file for reconfiguration. . ${PASSFILE} + ydb version --disable-checks > /dev/null ydb --ca-file ${CAFILE} -e ${DB_ENDPOINT} -d ${DB_DOMAIN} \ auth get-token -f > ${TOKEN} else @@ -42,7 +50,90 @@ TMPLOG=`mktemp /tmp/ydbd.createdb.XXXXXX` trap "rm -f ${TMPLOG}" EXIT ydbd --ca-file ${CAFILE} -s ${DB_ENDPOINT} -f ${TOKEN} \ - admin database /{{ ydb_domain }}/${DB_NAME} create ${DB_POOL}:${DB_GROUPS} >>${TMPLOG} 2>&1 + admin database /{{ ydb_domain }}/${DB_NAME} \ + create ${DB_POOL}:${DB_GROUPS} >>${TMPLOG} 2>&1 + +# If quotas are required +# YDBOPS-12647 +# Format for human-readable output +human_readable() { + local bytes=$1 + if (( bytes >= 1099511627776 )); then + echo "$(echo "scale=2; $bytes / 1099511627776" | bc) TB" + elif (( bytes >= 1073741824 )); then + echo "$(echo "scale=2; $bytes / 1073741824" | bc) GB" + elif (( bytes >= 1048576 )); then + echo "$(echo "scale=2; $bytes / 1048576" | bc) MB" + elif (( bytes >= 1024 )); then + echo "$(echo "scale=2; $bytes / 1024" | bc) KB" + else + echo "$bytes bytes" + fi +} + +if [ "$4" -eq "1" ]; then + + if [ ! -b "$DISK_DEVICE" ]; then + echo "ERROR: Device $DISK_DEVICE does not exist or is not a block device" >&2 + exit 1 + fi + + disk_size_bytes=$(blockdev --getsize64 "$DISK_DEVICE") + if [ $? -ne 0 ]; then + echo "ERROR: Failed to get size of device $DISK_DEVICE" >&2 + exit 1 + fi + + DISK_SIZE_GB=$(echo "scale=10; $disk_size_bytes / (1024*1024*1024)" | bc | cut -f 1 -d '.') + + # Set formula parameters based on YDB schema + case "$YDB_SCHEMA" in + mirror-3-dc) + D=9 + K=5 + N=16 + ;; + block-4-2) + D=8 + K=2 + N=16 + ;; + *) + echo "ERROR: Unknown pool type: $YDB_SCHEMA" >&2 + exit 1 + ;; + esac + + # Calculate base value + base_value=$(echo "scale=10; 0.995 * $DISK_SIZE_GB * $DB_GROUPS * $D / ($K * $N)" | bc ) + + # Round down to tens of GB + rounded_value=$(echo "($base_value / 10) * 10" | bc | awk -F. '{print int($1)}') + + # Convert to bytes + hard_quota_bytes=$(echo "$rounded_value * 1073741824" | bc | awk -F. '{print $1}') + soft_quota_bytes=$(echo "$hard_quota_bytes * 0.95" | bc | awk -F. '{print $1}') + + # Display disk info and calculated quotas + echo "Disk Information:" + echo "-----------------" + echo "Device: $DISK_DEVICE" + echo "Raw Size: $DISK_SIZE_GB Gb" + echo "" + + echo "Calculated quotas for database '$DB_NAME':" + echo "-------------------------------------------" + printf "%-20s | %-15s | %s\n" "Quota Type" "Raw Bytes" "Human Readable" + echo "-------------------------------------------" + printf "%-20s | %-15s | %s\n" "Hard Quota" "$hard_quota_bytes" "$(human_readable $hard_quota_bytes)" + printf "%-20s | %-15s | %s\n" "Soft Quota" "$soft_quota_bytes" "$(human_readable $soft_quota_bytes)" + echo "-------------------------------------------" + echo "" + + ydbd --ca-file ${CAFILE} -s ${DB_ENDPOINT} -f ${TOKEN} \ + admin database /{{ ydb_domain }}/${DB_NAME} \ + quotas change --data-size-hard-quota $hard_quota_bytes --data-size-soft-quota $soft_quota_bytes >>${TMPLOG} 2>&1 +fi # Ensure success, e.g. no error messages even when the exit code is zero. set +e From e54141275a853ffe006e4c6ea39ce438162e5ceb Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 9 Oct 2025 14:18:56 +0300 Subject: [PATCH 10/53] New version of collection --- galaxy.yml | 3 +-- .../ydbd_static/templates/create_database.j2 | 21 +++---------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/galaxy.yml b/galaxy.yml index 12a176e..af2aabf 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -8,7 +8,7 @@ namespace: ydb_platform name: ydb # The version of the collection. Must be compatible with semantic versioning -version: 1.2.0 +version: 1.2.5 # The path to the Markdown (.md) readme file. This path is relative to the root of the collection readme: README.md @@ -20,7 +20,6 @@ authors: - Eugene Arbatsky elabpro - Maksim Zinal zinal - ### OPTIONAL but strongly recommended # A short summary description of the collection description: Collection for YDB cluster management. diff --git a/roles/ydbd_static/templates/create_database.j2 b/roles/ydbd_static/templates/create_database.j2 index 1c98b7d..e16fab4 100644 --- a/roles/ydbd_static/templates/create_database.j2 +++ b/roles/ydbd_static/templates/create_database.j2 @@ -55,21 +55,6 @@ ydbd --ca-file ${CAFILE} -s ${DB_ENDPOINT} -f ${TOKEN} \ # If quotas are required # YDBOPS-12647 -# Format for human-readable output -human_readable() { - local bytes=$1 - if (( bytes >= 1099511627776 )); then - echo "$(echo "scale=2; $bytes / 1099511627776" | bc) TB" - elif (( bytes >= 1073741824 )); then - echo "$(echo "scale=2; $bytes / 1073741824" | bc) GB" - elif (( bytes >= 1048576 )); then - echo "$(echo "scale=2; $bytes / 1048576" | bc) MB" - elif (( bytes >= 1024 )); then - echo "$(echo "scale=2; $bytes / 1024" | bc) KB" - else - echo "$bytes bytes" - fi -} if [ "$4" -eq "1" ]; then @@ -123,10 +108,10 @@ if [ "$4" -eq "1" ]; then echo "Calculated quotas for database '$DB_NAME':" echo "-------------------------------------------" - printf "%-20s | %-15s | %s\n" "Quota Type" "Raw Bytes" "Human Readable" + printf "%-20s | %-15s | %s\n" "Quota Type" "Raw Bytes" echo "-------------------------------------------" - printf "%-20s | %-15s | %s\n" "Hard Quota" "$hard_quota_bytes" "$(human_readable $hard_quota_bytes)" - printf "%-20s | %-15s | %s\n" "Soft Quota" "$soft_quota_bytes" "$(human_readable $soft_quota_bytes)" + printf "%-20s | %-15s | %s\n" "Hard Quota" "$hard_quota_bytes" + printf "%-20s | %-15s | %s\n" "Soft Quota" "$soft_quota_bytes" echo "-------------------------------------------" echo "" From ffc94e9cfd2c39ffb321a239acf60c0519c89e5f Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 9 Oct 2025 15:18:19 +0300 Subject: [PATCH 11/53] +variable for quotas --- roles/ydbd_static/defaults/main.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/roles/ydbd_static/defaults/main.yaml b/roles/ydbd_static/defaults/main.yaml index 85a5a09..e4a7813 100644 --- a/roles/ydbd_static/defaults/main.yaml +++ b/roles/ydbd_static/defaults/main.yaml @@ -8,4 +8,6 @@ ydb_use_dynamic_config: false ydb_custom_dynconfig: ydbd-dyn-config.yaml.j2 ydb_config_v2: false ydb_host_user: ydb -ydb_host_group: ydb \ No newline at end of file +ydb_host_group: ydb +# ydb_database_quotas - set hard/soft quotas on every DB during creation +ydb_database_quotas: false \ No newline at end of file From 096982f9d799d500874ff71b8ef9d916eb89d1f5 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 9 Oct 2025 16:53:25 +0300 Subject: [PATCH 12/53] variable for new db role --- roles/ydbd_newdb/defaults/main.yaml | 1 + 1 file changed, 1 insertion(+) create mode 100644 roles/ydbd_newdb/defaults/main.yaml diff --git a/roles/ydbd_newdb/defaults/main.yaml b/roles/ydbd_newdb/defaults/main.yaml new file mode 100644 index 0000000..488b8af --- /dev/null +++ b/roles/ydbd_newdb/defaults/main.yaml @@ -0,0 +1 @@ +ydb_database_quotas: false From 2b28cd8e062411651ed6a40471ec1f552269717c Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 10 Oct 2025 09:24:59 +0300 Subject: [PATCH 13/53] More errors in db creation --- roles/ydbd_static/templates/create_database.j2 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/roles/ydbd_static/templates/create_database.j2 b/roles/ydbd_static/templates/create_database.j2 index e16fab4..2f19138 100644 --- a/roles/ydbd_static/templates/create_database.j2 +++ b/roles/ydbd_static/templates/create_database.j2 @@ -53,6 +53,11 @@ ydbd --ca-file ${CAFILE} -s ${DB_ENDPOINT} -f ${TOKEN} \ admin database /{{ ydb_domain }}/${DB_NAME} \ create ${DB_POOL}:${DB_GROUPS} >>${TMPLOG} 2>&1 +if grep -qE '^ERROR: ' ${TMPLOG}; then + cat ${TMPLOG}; + exit 1 +fi + # If quotas are required # YDBOPS-12647 From 81a917f639e558e5575e26af65873f80213b0e21 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 10 Oct 2025 09:43:43 +0300 Subject: [PATCH 14/53] Clean-up --- plugins/inventory/ydb_inventory.py | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 8bfe68b..4e4a06d 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -35,36 +35,7 @@ def parse(self, inventory, loader, path, cache=True): # Загружаем конфиг плагина (YAML-файл) config = self._read_config_data(path) - # # Инициализация Templar - # templar = Templar(loader=loader) - - # try: - # # 3. Обрабатываем шаблоны во всех значениях конфигурации - # processed_config = {} - # for key, value in config.items(): - # if isinstance(value, str) and '{{' in value: - # # Обрабатываем строки с шаблонами - # processed_config[key] = templar.template(value, fail_on_undefined=True) - # else: - # # Простые значения копируем как есть - # processed_config[key] = value - - # # 4. Используем обработанные значения - # print(processed_config) ydb_config = config.get('ydb_config') - - # # 5. Ваша логика загрузки инвентаря - # if isinstance(ydb_config, dict): - # # Обработка встроенной конфигурации - # self._load_from_dict(ydb_config) - # else: - # # Обработка файловой конфигурации - # self._load_from_file(ydb_config) - - # except Exception as e: - # raise AnsibleError(f"Template error: {str(e)}") - - # ydb_config = config.get('all')['children']['ydb']['vars']['ydb_config'] print(f"Reading inventory from {ydb_config}") group = 'ydb' From cf278d9374276f4611eec8d9ee1df998e507ed69 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 10 Oct 2025 12:27:05 +0300 Subject: [PATCH 15/53] Fix HC for 25.* --- roles/ydbd_rolling_static/tasks/check_static.yaml | 1 + roles/ydbd_static/tasks/main.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/roles/ydbd_rolling_static/tasks/check_static.yaml b/roles/ydbd_rolling_static/tasks/check_static.yaml index b629e9f..f90f084 100644 --- a/roles/ydbd_rolling_static/tasks/check_static.yaml +++ b/roles/ydbd_rolling_static/tasks/check_static.yaml @@ -25,3 +25,4 @@ run_once: true tags: - healthcheck + when: "ydb_version is version('25.1', '<')" # Hack until YDB HC will handle 3-nodes-mirror-3-dc in 25.* diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index 94425a6..5df1bbb 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -407,7 +407,7 @@ become_user: "{{ ydb_host_user }}" tags: - healthcheck - # when: "ydb_version is version('25.1', '<')" + when: "ydb_version is version('25.1', '<')" # Hack until YDB HC will handle 3-nodes-mirror-3-dc in 25.* - name: set cluster root password ydb_platform.ydb.set_user_password: From 7792d3081c672460fe599c1334fe07cb2646b90c Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 10 Oct 2025 13:02:10 +0300 Subject: [PATCH 16/53] Hack for HC --- playbooks/healthcheck.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/playbooks/healthcheck.yaml b/playbooks/healthcheck.yaml index 037b625..add79c6 100644 --- a/playbooks/healthcheck.yaml +++ b/playbooks/healthcheck.yaml @@ -59,3 +59,4 @@ become_user: "{{ ydb_host_user }}" tags: - healthcheck + when: "ydb_version is version('25.1', '<')" # Hack until YDB HC will handle 3-nodes-mirror-3-dc in 25.* From bb4549f052cf5c8c8e5cabdcceb03d1c1a027317 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 10 Oct 2025 13:57:26 +0300 Subject: [PATCH 17/53] Fix ydb_disks in inventory plugin --- plugins/inventory/ydb_inventory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 4e4a06d..7cee5ac 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -57,9 +57,9 @@ def parse(self, inventory, loader, path, cache=True): drive_labels[disk['label']] = disk['name'] if 'config' in yaml_config and 'host_configs' in yaml_config['config']: for drive_config in yaml_config['config']['host_configs']: + drive_configs[drive_config['host_config_id']] = copy.deepcopy(drive_config['drive']) for i, item in enumerate(drive_config['drive']): label = item['path'].split('/')[-1] - drive_configs[drive_config['host_config_id']] = copy.deepcopy(drive_config['drive']) drive_configs[drive_config['host_config_id']][i]['label'] = label if label in drive_labels: drive_configs[drive_config['host_config_id']][i]['name'] = drive_labels[label] From 21a161524cbcf35317ae32408c707bf357471f13 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Mon, 13 Oct 2025 13:14:10 +0300 Subject: [PATCH 18/53] remove quotas, more imporoved inventory --- plugins/inventory/ydb_inventory.py | 13 ++- .../tasks/check_ansible.yaml | 2 +- roles/ydbd_newdb/defaults/main.yaml | 3 +- roles/ydbd_newdb/tasks/main.yml | 2 +- .../ydbd_static/templates/create_database.j2 | 80 ------------------- 5 files changed, 15 insertions(+), 85 deletions(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 7cee5ac..588eea5 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -46,9 +46,18 @@ def parse(self, inventory, loader, path, cache=True): with open(ydb_config, "r") as file: yaml_config = yaml.safe_load(file) self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config) - if 'config' in yaml_config and 'self_management_config' in yaml_config['config']: - if 'enabled' in yaml_config['config']['self_management_config'] and yaml_config['config']['self_management_config']['enabled']: + if 'config' in yaml_config: + + if 'default_disk_type' in yaml_config['config']: + self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['config']['default_disk_type']) + + if 'self_management_config' in yaml_config['config'] and 'enabled' in yaml_config['config']['self_management_config'] and yaml_config['config']['self_management_config']['enabled']: self.inventory.groups['ydb'].set_variable('ydb_config_v2', True) + self.inventory.groups['ydb'].set_variable('ydb_config', yaml_config) + + # Default domain is Root + self.inventory.groups['ydb'].set_variable('ydb_domain','Root') + # Read drives config drive_configs = {} drive_labels = {} diff --git a/roles/check_connectivity/tasks/check_ansible.yaml b/roles/check_connectivity/tasks/check_ansible.yaml index 72a6db0..bfb7deb 100644 --- a/roles/check_connectivity/tasks/check_ansible.yaml +++ b/roles/check_connectivity/tasks/check_ansible.yaml @@ -21,7 +21,7 @@ is_config_file: "{{ ydb_config is string }}" - name: Load configuration from file if path provided - when: is_config_file + when: "is_config_file|bool" become: false block: - name: Verify config file exists diff --git a/roles/ydbd_newdb/defaults/main.yaml b/roles/ydbd_newdb/defaults/main.yaml index 488b8af..cd21505 100644 --- a/roles/ydbd_newdb/defaults/main.yaml +++ b/roles/ydbd_newdb/defaults/main.yaml @@ -1 +1,2 @@ -ydb_database_quotas: false +--- + diff --git a/roles/ydbd_newdb/tasks/main.yml b/roles/ydbd_newdb/tasks/main.yml index 6e4c2c4..a5e5655 100644 --- a/roles/ydbd_newdb/tasks/main.yml +++ b/roles/ydbd_newdb/tasks/main.yml @@ -9,7 +9,7 @@ src: "secret.j2" dest: "{{ ydb_dir }}/certs/secret" - name: Run the database creation script - command: "{{ ydb_dir }}/home/create_database.sh {{ ydb_brokers | default(groups['ydb']) | flatten(levels=1) | first }} {{ ydb_database_name | default(ydb_dbname, true) }} {{ ydb_database_storage_groups | default(ydb_database_groups) }} {{ '1' if ydb_database_quotas else '0' }}" + command: "{{ ydb_dir }}/home/create_database.sh {{ ydb_brokers | default(groups['ydb']) | flatten(levels=1) | first }} {{ ydb_database_name | default(ydb_dbname, true) }} {{ ydb_database_storage_groups | default(ydb_database_groups) }}" - name: Cleanup the transferred secrets file: state=absent path={{ ydb_dir }}/certs/secret run_once: true diff --git a/roles/ydbd_static/templates/create_database.j2 b/roles/ydbd_static/templates/create_database.j2 index 2f19138..05d0e68 100644 --- a/roles/ydbd_static/templates/create_database.j2 +++ b/roles/ydbd_static/templates/create_database.j2 @@ -17,12 +17,6 @@ TOKEN={{ ydb_dir }}/home/ydbd-token-file PASSFILE={{ ydb_dir }}/certs/secret DB_NAME="$2" DB_GROUPS="$3" -# -# First device for YDB on the host for estimating storage size -# YDBOPS-12647 -# -DISK_DEVICE="{{ ydb_disks[0].name }}" -YDB_SCHEMA="{{ ydb_config_dict.static_erasure }}" LD_LIBRARY_PATH={{ ydb_dir }}/lib export LD_LIBRARY_PATH @@ -57,80 +51,6 @@ if grep -qE '^ERROR: ' ${TMPLOG}; then cat ${TMPLOG}; exit 1 fi - -# If quotas are required -# YDBOPS-12647 - -if [ "$4" -eq "1" ]; then - - if [ ! -b "$DISK_DEVICE" ]; then - echo "ERROR: Device $DISK_DEVICE does not exist or is not a block device" >&2 - exit 1 - fi - - disk_size_bytes=$(blockdev --getsize64 "$DISK_DEVICE") - if [ $? -ne 0 ]; then - echo "ERROR: Failed to get size of device $DISK_DEVICE" >&2 - exit 1 - fi - - DISK_SIZE_GB=$(echo "scale=10; $disk_size_bytes / (1024*1024*1024)" | bc | cut -f 1 -d '.') - - # Set formula parameters based on YDB schema - case "$YDB_SCHEMA" in - mirror-3-dc) - D=9 - K=5 - N=16 - ;; - block-4-2) - D=8 - K=2 - N=16 - ;; - *) - echo "ERROR: Unknown pool type: $YDB_SCHEMA" >&2 - exit 1 - ;; - esac - - # Calculate base value - base_value=$(echo "scale=10; 0.995 * $DISK_SIZE_GB * $DB_GROUPS * $D / ($K * $N)" | bc ) - - # Round down to tens of GB - rounded_value=$(echo "($base_value / 10) * 10" | bc | awk -F. '{print int($1)}') - - # Convert to bytes - hard_quota_bytes=$(echo "$rounded_value * 1073741824" | bc | awk -F. '{print $1}') - soft_quota_bytes=$(echo "$hard_quota_bytes * 0.95" | bc | awk -F. '{print $1}') - - # Display disk info and calculated quotas - echo "Disk Information:" - echo "-----------------" - echo "Device: $DISK_DEVICE" - echo "Raw Size: $DISK_SIZE_GB Gb" - echo "" - - echo "Calculated quotas for database '$DB_NAME':" - echo "-------------------------------------------" - printf "%-20s | %-15s | %s\n" "Quota Type" "Raw Bytes" - echo "-------------------------------------------" - printf "%-20s | %-15s | %s\n" "Hard Quota" "$hard_quota_bytes" - printf "%-20s | %-15s | %s\n" "Soft Quota" "$soft_quota_bytes" - echo "-------------------------------------------" - echo "" - - ydbd --ca-file ${CAFILE} -s ${DB_ENDPOINT} -f ${TOKEN} \ - admin database /{{ ydb_domain }}/${DB_NAME} \ - quotas change --data-size-hard-quota $hard_quota_bytes --data-size-soft-quota $soft_quota_bytes >>${TMPLOG} 2>&1 -fi - -# Ensure success, e.g. no error messages even when the exit code is zero. -set +e -if grep -qE '^ERROR: ' ${TMPLOG}; then - cat ${TMPLOG}; - exit 1 -fi exit 0 # End Of File \ No newline at end of file From b5953caaeb962426f60a8d0e60415dac42b5e2ec Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Mon, 13 Oct 2025 13:40:24 +0300 Subject: [PATCH 19/53] remove ydb_database_name --- roles/monitoring_services/tasks/main.yaml | 2 +- roles/ydb_fq_connector/tasks/main.yaml | 4 ++-- .../templates/ydb-fq-connector.service | 2 +- roles/ydbd_dynamic/defaults/main.yaml | 1 - roles/ydbd_dynamic/tasks/main.yaml | 12 ++++++------ roles/ydbd_dynamic/templates/ydbd-dynnode.service | 4 ++-- roles/ydbd_dynamic_start/defaults/main.yaml | 2 +- roles/ydbd_dynamic_start/tasks/main.yaml | 2 +- roles/ydbd_dynamic_stop/defaults/main.yaml | 2 +- roles/ydbd_dynamic_stop/tasks/main.yaml | 2 +- roles/ydbd_newdb/tasks/main.yml | 2 +- roles/ydbd_static/defaults/main.yaml | 3 +-- 12 files changed, 18 insertions(+), 20 deletions(-) diff --git a/roles/monitoring_services/tasks/main.yaml b/roles/monitoring_services/tasks/main.yaml index d93da93..fcce788 100644 --- a/roles/monitoring_services/tasks/main.yaml +++ b/roles/monitoring_services/tasks/main.yaml @@ -43,7 +43,7 @@ - name: create database file_sd targets ansible.builtin.template: src: "file-sd-ydbd-database.yml" - dest: "{{ ydb_prometheus_config_dir }}/file_sd/ydbd-database-{{ ydb_database_name | default(ydb_dbname, true) }}.yml" + dest: "{{ ydb_prometheus_config_dir }}/file_sd/ydbd-database-{{ ydb_dbname }}.yml" force: true owner: root group: prometheus diff --git a/roles/ydb_fq_connector/tasks/main.yaml b/roles/ydb_fq_connector/tasks/main.yaml index 266762b..b7f9d2a 100644 --- a/roles/ydb_fq_connector/tasks/main.yaml +++ b/roles/ydb_fq_connector/tasks/main.yaml @@ -107,7 +107,7 @@ - name: create ydb-fq-connector instance systemd units template: src: ydb-fq-connector.service - dest: "/etc/systemd/system/ydb-fq-connector-{{ ydb_database_name | default(ydb_dbname, true) }}-{{ item.instance }}.service" + dest: "/etc/systemd/system/ydb-fq-connector-{{ ydb_dbname }}-{{ item.instance }}.service" loop: "{{ ydb_fq_connectors_list }}" notify: - daemon reload @@ -117,7 +117,7 @@ - name: start ydb-fq-connector instances ansible.builtin.systemd: - name: "ydb-fq-connector-{{ ydb_database_name | default(ydb_dbname, true) }}-{{ item.instance }}.service" + name: "ydb-fq-connector-{{ ydb_dbname }}-{{ item.instance }}.service" state: started enabled: true loop: "{{ ydb_fq_connectors_list }}" diff --git a/roles/ydb_fq_connector/templates/ydb-fq-connector.service b/roles/ydb_fq_connector/templates/ydb-fq-connector.service index 799020c..e79c4af 100644 --- a/roles/ydb_fq_connector/templates/ydb-fq-connector.service +++ b/roles/ydb_fq_connector/templates/ydb-fq-connector.service @@ -1,5 +1,5 @@ [Unit] -Description=YDB FQ connector for YDB dynamic node / {{ ydb_database_name | default(ydb_dbname, true) }} / {{ item.instance }} +Description=YDB FQ connector for YDB dynamic node / {{ ydb_dbname }} / {{ item.instance }} StartLimitInterval=10 StartLimitBurst=15 After=network-online.target diff --git a/roles/ydbd_dynamic/defaults/main.yaml b/roles/ydbd_dynamic/defaults/main.yaml index 2fc207d..e1f957e 100644 --- a/roles/ydbd_dynamic/defaults/main.yaml +++ b/roles/ydbd_dynamic/defaults/main.yaml @@ -4,4 +4,3 @@ ydb_request_client_certificate: false # ydb_use_dynamic_config - define how to configure dynamic nodes - static or dynamic configs # Default value: false ydb_use_dynamic_config: false -ydb_database_name: "{{ ydb_dbname }}" diff --git a/roles/ydbd_dynamic/tasks/main.yaml b/roles/ydbd_dynamic/tasks/main.yaml index 715a211..19feb5a 100644 --- a/roles/ydbd_dynamic/tasks/main.yaml +++ b/roles/ydbd_dynamic/tasks/main.yaml @@ -7,7 +7,7 @@ - ydb_dir - ydb_domain - ydb_database_node_cores | default(ydb_cores_dynamic, 1) - - ydb_database_name | default(ydb_dbname, true) + - ydb_dbname # Simple default broker selection - name: Set default ydb_brokers (first three nodes) @@ -121,7 +121,7 @@ - name: Create dynamic node systemd unit template: src: ydbd-dynnode.service - dest: "/etc/systemd/system/ydbd-{{ item.dbname | default(ydb_database_name, true) }}-{{ item.instance }}.service" + dest: "/etc/systemd/system/ydbd-{{ item.dbname | default(ydb_dbname, true) }}-{{ item.instance }}.service" loop: "{{ ydb_dynnodes }}" when: "item.hosts is not defined or '{{ inventory_hostname }}' in item.hosts" notify: @@ -132,7 +132,7 @@ - name: start dynamic nodes ansible.builtin.systemd: - name: "ydbd-{{ item.dbname | default(ydb_database_name, true) }}-{{ item.instance }}.service" + name: "ydbd-{{ item.dbname }}-{{ item.instance }}.service" state: started enabled: true loop: "{{ ydb_dynnodes }}" @@ -180,7 +180,7 @@ # ld_library_path: "{{ ydb_dir }}/lib" # ca_file: "{{ ydb_dir }}/certs/ca.crt" # endpoint: "grpcs://{{ ydb_front | default(ydb_brokers) | flatten(levels=1) | first }}:2135" -# database: "/{{ ydb_domain }}/{{ ydb_dbname | default(ydb_database_name, true) }}" +# database: "/{{ ydb_domain }}/{{ ydb_dbname }}" # token: "{{ ydb_credentials.token }}" # pool_kind: "{{ ydb_pool_kind }}" # groups: "{{ ydb_database_storage_groups | default(ydb_database_groups) }}" @@ -198,7 +198,7 @@ ld_library_path: "{{ ydb_dir }}/lib" ca_file: "{{ ydb_dir }}/certs/ca.crt" endpoint: "grpcs://{{ ydb_front | default(ydb_brokers) | flatten(levels=1) | first }}:{{ 2136 + (item.offset | default(ydb_dynnodes.index(item))) }}" - database: "/{{ ydb_domain }}/{{ item.dbname | default(ydb_database_name, true) }}" + database: "/{{ ydb_domain }}/{{ item.dbname | default(ydb_dbname, true) }}" token: "{{ ydb_credentials.token }}" become: true become_user: "{{ ydb_host_user }}" @@ -216,7 +216,7 @@ ld_library_path: "{{ ydb_dir }}/lib" ca_file: "{{ ydb_dir }}/certs/ca.crt" endpoint: "grpcs://{{ ydb_front | default(ydb_brokers) | flatten(levels=1) | first }}:{{ 2136 + (item.offset | default(ydb_dynnodes.index(item))) }}" - database: "/{{ ydb_domain }}/{{ item.dbname | default(ydb_database_name, true) }}" + database: "/{{ ydb_domain }}/{{ item.dbname | default(ydb_dbname, true) }}" user: "{{ ydb_user }}" password: "{{ ydb_password }}" become: true diff --git a/roles/ydbd_dynamic/templates/ydbd-dynnode.service b/roles/ydbd_dynamic/templates/ydbd-dynnode.service index 7baa3d8..d50e34d 100644 --- a/roles/ydbd_dynamic/templates/ydbd-dynnode.service +++ b/roles/ydbd_dynamic/templates/ydbd-dynnode.service @@ -1,5 +1,5 @@ [Unit] -Description=YDB dynamic node / {{ ydb_database_name | default(ydb_dbname, true) }} / {{ item.instance }} +Description=YDB dynamic node / {{ ydb_dbname }} / {{ item.instance }} StartLimitInterval=10 StartLimitBurst=15 After=network-online.target rc-local.service ydb-transparent-hugepages.service @@ -37,7 +37,7 @@ ExecStart={{ ydb_dir }}/bin/ydbd server \ --ic-port {{ 19002 + ydb_dynnodes.index(item) }} \ --mon-port {{ 8766 + ydb_dynnodes.index(item) }} \ {% endif %} - --tenant /{{ ydb_domain }}/{{ item.dbname | default(ydb_database_name, true) }} \ + --tenant /{{ ydb_domain }}/{{ item.dbname | default(ydb_dbname, true) }} \ {% if ydb_request_client_certificate|bool %} --node-broker-use-tls true \ {% endif %} diff --git a/roles/ydbd_dynamic_start/defaults/main.yaml b/roles/ydbd_dynamic_start/defaults/main.yaml index f467461..ed97d53 100644 --- a/roles/ydbd_dynamic_start/defaults/main.yaml +++ b/roles/ydbd_dynamic_start/defaults/main.yaml @@ -1 +1 @@ -ydb_database_name: "{{ ydb_dbname }}" +--- diff --git a/roles/ydbd_dynamic_start/tasks/main.yaml b/roles/ydbd_dynamic_start/tasks/main.yaml index 453379a..8fd2d5a 100644 --- a/roles/ydbd_dynamic_start/tasks/main.yaml +++ b/roles/ydbd_dynamic_start/tasks/main.yaml @@ -2,7 +2,7 @@ - name: start dynamic nodes ansible.builtin.systemd: - name: "ydbd-{{ item.dbname | default(ydb_database_name, true) }}-{{ item.instance }}.service" + name: "ydbd-{{ item.dbname | default(ydb_dbname, true) }}-{{ item.instance }}.service" state: started enabled: true loop: "{{ ydb_dynnodes }}" \ No newline at end of file diff --git a/roles/ydbd_dynamic_stop/defaults/main.yaml b/roles/ydbd_dynamic_stop/defaults/main.yaml index f467461..ed97d53 100644 --- a/roles/ydbd_dynamic_stop/defaults/main.yaml +++ b/roles/ydbd_dynamic_stop/defaults/main.yaml @@ -1 +1 @@ -ydb_database_name: "{{ ydb_dbname }}" +--- diff --git a/roles/ydbd_dynamic_stop/tasks/main.yaml b/roles/ydbd_dynamic_stop/tasks/main.yaml index b986e78..780ba58 100644 --- a/roles/ydbd_dynamic_stop/tasks/main.yaml +++ b/roles/ydbd_dynamic_stop/tasks/main.yaml @@ -2,7 +2,7 @@ - name: stop dynamic nodes ansible.builtin.systemd: - name: "ydbd-{{ item.dbname | default(ydb_database_name, true) }}-{{ item.instance }}.service" + name: "ydbd-{{ item.dbname | default(ydb_dbname, true) }}-{{ item.instance }}.service" state: stopped enabled: false loop: "{{ ydb_dynnodes }}" \ No newline at end of file diff --git a/roles/ydbd_newdb/tasks/main.yml b/roles/ydbd_newdb/tasks/main.yml index a5e5655..6ffaef6 100644 --- a/roles/ydbd_newdb/tasks/main.yml +++ b/roles/ydbd_newdb/tasks/main.yml @@ -9,7 +9,7 @@ src: "secret.j2" dest: "{{ ydb_dir }}/certs/secret" - name: Run the database creation script - command: "{{ ydb_dir }}/home/create_database.sh {{ ydb_brokers | default(groups['ydb']) | flatten(levels=1) | first }} {{ ydb_database_name | default(ydb_dbname, true) }} {{ ydb_database_storage_groups | default(ydb_database_groups) }}" + command: "{{ ydb_dir }}/home/create_database.sh {{ ydb_brokers | default(groups['ydb']) | flatten(levels=1) | first }} {{ ydb_dbname }} {{ ydb_database_storage_groups | default(ydb_database_groups) }}" - name: Cleanup the transferred secrets file: state=absent path={{ ydb_dir }}/certs/secret run_once: true diff --git a/roles/ydbd_static/defaults/main.yaml b/roles/ydbd_static/defaults/main.yaml index e4a7813..83d9056 100644 --- a/roles/ydbd_static/defaults/main.yaml +++ b/roles/ydbd_static/defaults/main.yaml @@ -9,5 +9,4 @@ ydb_custom_dynconfig: ydbd-dyn-config.yaml.j2 ydb_config_v2: false ydb_host_user: ydb ydb_host_group: ydb -# ydb_database_quotas - set hard/soft quotas on every DB during creation -ydb_database_quotas: false \ No newline at end of file + From 819f11f5a7c2fd9b099d40bd5a580b3006d06115 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Mon, 13 Oct 2025 13:46:33 +0300 Subject: [PATCH 20/53] Remove new variables definitions --- README.md | 6 +++--- playbooks/create_database.yaml | 2 +- playbooks/update_config.yaml | 14 +++++++------- playbooks/update_executable.yaml | 4 ++-- plugins/inventory/ydb_inventory.py | 4 ++-- roles/ydbd_dynamic/tasks/main.yaml | 6 +++--- .../tasks/restart_dynamic.yaml | 2 +- roles/ydbd_static/tasks/main.yaml | 12 ++++++------ 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index b4eca7e..33001c6 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ The meaning and format of the variables used are specified in the table below. | `ydb_disks` | Disk layout of storage nodes, defined as `ydbd_static` in the hosts file. Defined as list of structures having the following fields:
`name` - physical device name (like `/dev/sdb` or `/dev/vdb`);
`label` - the desired YDB data partition label, as used in the cluster configuration file (like `ydb_disk_1`) | | `ydb_dynnodes` | Set of dynamic nodes to be ran on each host listed as `ydbd_dynamic` in the hosts file. Defined as list of structures having the following fields:
`dbname` - name of the YDB database handled by the corresponding dynamic node;
`instance` - dynamic node service instance name, allowing to distinguish between multiple dynamic nodes for the same database running in the same host;
`offset` - integer number `0-N`, used as the offset for the standard network port numbers (`0` means using the standard ports). | | `ydb_brokers` | List of host names running the YDB static nodes, exactly 3 (three) host names must be specified | -| `ydb_storage_node_cores` | Number of cores to be used by thread pools of the storage nodes (alias: `ydb_cores_static`) | -| `ydb_database_node_cores` | Number of cores to be used by thread pools of the database nodes (alias: `ydb_cores_dynamic`) | +| `ydb_cores_static` | Number of cores to be used by thread pools of the storage nodes | +| `ydb_cores_dynamic` | Number of cores to be used by thread pools of the database nodes | | `ydb_config_v2` | Controls initialization method and configuration management: if `true` uses YDB configuration V2 with `node init` + `bootstrap` and `--config-dir` arg, if `false` uses configuration V1 with `actor_system_config` injection and `--yaml-config` arg. If not set, automatically determined based on YDB version (`true` for version 25.1 and above) | -| `ydb_database_name` | Database name, for database creation, dynamic nodes deployment and dynamic nodes rolling restart (alias: `ydb_dbname`) | +| `ydb_dbname` | Database name, for database creation, dynamic nodes deployment and dynamic nodes rolling restart | | `ydb_pool_kind` | YDB default storage pool kind, as specified in the static nodes configuration file in the `storage_pool_types.kind` field | | `ydb_database_storage_groups` | Initial number of storage groups in the newly created database (alias: `ydb_database_groups`) | | `ydb_dynnode_restart_sleep_seconds` | Number of seconds to sleep after startup of each dynamic node during the rolling restart. | diff --git a/playbooks/create_database.yaml b/playbooks/create_database.yaml index b7140e9..5cc321c 100644 --- a/playbooks/create_database.yaml +++ b/playbooks/create_database.yaml @@ -16,7 +16,7 @@ # ansible-playbook ydb_platform.ydb.create_database # # Create DB with new name -# ansible-playbook ydb_platform.ydb.create_database --extra-vars "ydb_database_name=newdbname" +# ansible-playbook ydb_platform.ydb.create_database --extra-vars "ydb_dbname=newdbname" # # WARNING: There will be no dynamic nodes for the new database. You have to create them by using # playbook `install_dynamic` diff --git a/playbooks/update_config.yaml b/playbooks/update_config.yaml index beee4a1..009e8b1 100644 --- a/playbooks/update_config.yaml +++ b/playbooks/update_config.yaml @@ -23,8 +23,8 @@ - "{{ item.var1 is defined or item.var2 is defined }}" fail_msg: "Either {{ item.var1 }} or {{ item.var2 }} variable is required" loop: - - { var1: "ydb_storage_node_cores", var2: "ydb_cores_static" } - - { var1: "ydb_database_node_cores", var2: "ydb_cores_dynamic" } + - { var1: "ydb_cores_static" } + - { var1: "ydb_cores_dynamic" } tags: - storage - static @@ -199,12 +199,12 @@ ydb_platform.ydb.apply_config_selectors: config: "{{ ydb_temp_config_path }}" output_file: "{{ ydb_temp_config_path }}" - database_cores: "{{ ydb_database_node_cores | default(ydb_cores_dynamic) | default(omit) }}" - storage_cores: "{{ ydb_storage_node_cores | default(ydb_cores_static) | default(omit) }}" + database_cores: "{{ ydb_cores_dynamic | default(omit) }}" + storage_cores: "{{ydb_cores_static | default(omit) }}" become: true become_user: ydb run_once: true - when: ydb_database_node_cores is defined or ydb_storage_node_cores is defined or ydb_cores_dynamic is defined or ydb_cores_static is defined + when: ydb_cores_dynamic is defined or ydb_cores_static is defined register: selectors_result until: selectors_result is succeeded retries: 5 @@ -293,7 +293,7 @@ - no_restart - name: update static node configuration file (V1 configuration only) - command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-static.yaml STORAGE {{ ydb_storage_node_cores | default(ydb_cores_static, true) }}" + command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-static.yaml STORAGE {{ ydb_cores_static | default(ydb_cores_static, true) }}" changed_when: false when: not ydb_config_v2 | default(false) tags: @@ -302,7 +302,7 @@ - no_restart - name: create dynamic node configuration file (V1 configuration only) - command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-dynamic.yaml COMPUTE {{ ydb_database_node_cores | default(ydb_cores_dynamic, true) }}" + command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-dynamic.yaml COMPUTE {{ ydb_cores_dynamic | default(ydb_cores_dynamic, true) }}" changed_when: false when: not ydb_config_v2 | default(false) tags: diff --git a/playbooks/update_executable.yaml b/playbooks/update_executable.yaml index f7710e7..4bbf476 100644 --- a/playbooks/update_executable.yaml +++ b/playbooks/update_executable.yaml @@ -9,8 +9,8 @@ - "{{ item.var1 is defined or item.var2 is defined }}" fail_msg: "Either {{ item.var1 }} or {{ item.var2 }} variable is required" loop: - - { var1: "ydb_storage_node_cores", var2: "ydb_cores_static" } - - { var1: "ydb_database_node_cores", var2: "ydb_cores_dynamic" } + - { var1: "ydb_cores_static" } + - { var1: "ydb_cores_dynamic" } tags: - storage - static diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 588eea5..2933ed2 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -45,15 +45,15 @@ def parse(self, inventory, loader, path, cache=True): try: with open(ydb_config, "r") as file: yaml_config = yaml.safe_load(file) - self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config) if 'config' in yaml_config: + self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config['config']) if 'default_disk_type' in yaml_config['config']: self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['config']['default_disk_type']) if 'self_management_config' in yaml_config['config'] and 'enabled' in yaml_config['config']['self_management_config'] and yaml_config['config']['self_management_config']['enabled']: self.inventory.groups['ydb'].set_variable('ydb_config_v2', True) - self.inventory.groups['ydb'].set_variable('ydb_config', yaml_config) + self.inventory.groups['ydb'].set_variable('ydb_config', yaml_config['config']) # Default domain is Root self.inventory.groups['ydb'].set_variable('ydb_domain','Root') diff --git a/roles/ydbd_dynamic/tasks/main.yaml b/roles/ydbd_dynamic/tasks/main.yaml index 19feb5a..5dd507d 100644 --- a/roles/ydbd_dynamic/tasks/main.yaml +++ b/roles/ydbd_dynamic/tasks/main.yaml @@ -6,7 +6,7 @@ loop: - ydb_dir - ydb_domain - - ydb_database_node_cores | default(ydb_cores_dynamic, 1) + - ydb_cores_dynamic - ydb_dbname # Simple default broker selection @@ -110,11 +110,11 @@ set_fact: ydbd_dynamic_cores: > {{ - ydb_database_node_cores | default(ydb_cores_dynamic, true) + ydb_cores_dynamic }} - name: create dynamic node configuration file - command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-dynamic.yaml COMPUTE {{ ydb_database_node_cores | default(ydb_cores_dynamic, true) }}" + command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-dynamic.yaml COMPUTE {{ ydb_cores_dynamic }}" changed_when: false when: not ydb_config_v2 diff --git a/roles/ydbd_rolling_dynamic/tasks/restart_dynamic.yaml b/roles/ydbd_rolling_dynamic/tasks/restart_dynamic.yaml index 6b8738c..a50901e 100644 --- a/roles/ydbd_rolling_dynamic/tasks/restart_dynamic.yaml +++ b/roles/ydbd_rolling_dynamic/tasks/restart_dynamic.yaml @@ -6,7 +6,7 @@ delay: 5 ansible.builtin.systemd: state: restarted - name: "ydbd-{{ ydb_database_name | default(ydb_dbname, true) }}-{{ item.instance }}" + name: "ydbd-{{ ydb_dbname }}-{{ item.instance }}" any_errors_fatal: true become: true become_method: sudo diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index 5df1bbb..13c823a 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -13,8 +13,8 @@ - "{{ item.var1 is defined or item.var2 is defined }}" fail_msg: "Either {{ item.var1 }} or {{ item.var2 }} variable is required" loop: - - { var1: "ydb_storage_node_cores", var2: "ydb_cores_static" } - - { var1: "ydb_database_node_cores", var2: "ydb_cores_dynamic" } + - { var1: "ydb_cores_static" } + - { var1: "ydb_cores_dynamic" } - { var1: "ydb_disks", var2: "ydb_disks" } - { var1: "ydb_domain", var2: "ydb_domain" } - { var1: "ydb_user", var2: "ydb_user" } @@ -153,7 +153,7 @@ when: ydb_config_v2 is not defined - name: create static node configuration file - command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-static.yaml STORAGE {{ ydb_storage_node_cores | default(ydb_cores_static) }}" + command: "{{ ydb_dir }}/home/update_config_file.sh ydbd-config.yaml ydbd-config-static.yaml STORAGE {{ ydb_cores_static }}" changed_when: false when: not ydb_config_v2 @@ -239,11 +239,11 @@ ydb_platform.ydb.apply_config_selectors: config: "{{ ydb_temp_config_path }}" output_file: "{{ ydb_temp_config_path }}" - database_cores: "{{ ydb_database_node_cores | default(ydb_cores_dynamic) | default(omit) }}" - storage_cores: "{{ ydb_storage_node_cores | default(ydb_cores_static) | default(omit) }}" + database_cores: "{{ ydb_cores_dynamic | default(omit) }}" + storage_cores: "{{ ydb_cores_static | default(omit) }}" become: true become_user: "{{ ydb_host_user }}" - when: ydb_config_v2 and (ydb_database_node_cores is defined or ydb_storage_node_cores is defined or ydb_cores_dynamic is defined or ydb_cores_static is defined) + when: ydb_config_v2 and (ydb_cores_dynamic is defined or ydb_cores_static is defined) - name: init YDB node configuration (V2 only - before ydbd start) ydb_platform.ydb.init_node_config: From aa70c51429188a6e26e00559330e461b023f8409 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Mon, 13 Oct 2025 13:58:12 +0300 Subject: [PATCH 21/53] + docs --- playbooks/update_config.yaml | 4 ++-- playbooks/update_executable.yaml | 4 ++-- plugins/modules/apply_config_selectors.py | 8 ++++++++ plugins/modules/cluster_config.py | 7 +++++++ plugins/modules/create_database.py | 7 +++++++ plugins/modules/drive_prepare.py | 8 ++++++++ plugins/modules/dynconfig_apply.py | 7 +++++++ plugins/modules/dynconfig_version.py | 8 ++++++++ roles/ydbd_static/tasks/main.yaml | 10 +++++----- 9 files changed, 54 insertions(+), 9 deletions(-) diff --git a/playbooks/update_config.yaml b/playbooks/update_config.yaml index 009e8b1..fd0d545 100644 --- a/playbooks/update_config.yaml +++ b/playbooks/update_config.yaml @@ -20,8 +20,8 @@ - ansible.builtin.assert: that: - - "{{ item.var1 is defined or item.var2 is defined }}" - fail_msg: "Either {{ item.var1 }} or {{ item.var2 }} variable is required" + - "{{ item.var1 is defined}}" + fail_msg: "Either {{ item.var1 }} variable is required" loop: - { var1: "ydb_cores_static" } - { var1: "ydb_cores_dynamic" } diff --git a/playbooks/update_executable.yaml b/playbooks/update_executable.yaml index 4bbf476..74be8ad 100644 --- a/playbooks/update_executable.yaml +++ b/playbooks/update_executable.yaml @@ -6,8 +6,8 @@ tasks: - ansible.builtin.assert: that: - - "{{ item.var1 is defined or item.var2 is defined }}" - fail_msg: "Either {{ item.var1 }} or {{ item.var2 }} variable is required" + - "{{ item.var1 is defined" + fail_msg: "Either {{ item.var1 }} variable is required" loop: - { var1: "ydb_cores_static" } - { var1: "ydb_cores_dynamic" } diff --git a/plugins/modules/apply_config_selectors.py b/plugins/modules/apply_config_selectors.py index 44ec1f5..8aa8647 100644 --- a/plugins/modules/apply_config_selectors.py +++ b/plugins/modules/apply_config_selectors.py @@ -9,6 +9,14 @@ from ansible_collections.ydb_platform.ydb.plugins.module_utils.yaml_utils import safe_dump +DOCUMENTATION = r''' + name: apply_config_selectors + plugin_type: module + short_description: Apply changes for storage selectors + description: | + Apply changes for storage selectors +''' + def run_module(): module_args = dict( config=dict(type='str', required=True), diff --git a/plugins/modules/cluster_config.py b/plugins/modules/cluster_config.py index e4c8f2a..cbc0f33 100644 --- a/plugins/modules/cluster_config.py +++ b/plugins/modules/cluster_config.py @@ -6,6 +6,13 @@ from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli from ansible_collections.ydb_platform.ydb.plugins.module_utils.yaml_utils import safe_dump +DOCUMENTATION = r''' + name: cluster_config + plugin_type: module + short_description: Work with ydb cluster config + description: | + Work with ydb cluster config (it's needed for V2 cluster configuration) +''' def fetch_cluster_config(ydb_cli, result): """Fetch current cluster configuration from YDB""" diff --git a/plugins/modules/create_database.py b/plugins/modules/create_database.py index 8ca98f0..be72b75 100644 --- a/plugins/modules/create_database.py +++ b/plugins/modules/create_database.py @@ -4,6 +4,13 @@ STDOUT_SUCCESS = 'OK' STDOUT_ALREADY_EXISTS = 'ERROR: ALREADY_EXISTS' +DOCUMENTATION = r''' + name: create_database + plugin_type: module + short_description: Create YDB database + description: | + Create YDB database +''' def main(): diff --git a/plugins/modules/drive_prepare.py b/plugins/modules/drive_prepare.py index 19030ad..a3e9f25 100644 --- a/plugins/modules/drive_prepare.py +++ b/plugins/modules/drive_prepare.py @@ -4,6 +4,14 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import drive, cli +DOCUMENTATION = r''' + name: drive_prepare + plugin_type: module + short_description: Oblitirate drives for YDB + description: | + Module for preparing hard drives for YDB, it's safe format of drive. Drives with YDB data will not be affected / changed. + Be aware: it won't format drives with some YDB data for your safety +''' def main(): argument_spec = dict( diff --git a/plugins/modules/dynconfig_apply.py b/plugins/modules/dynconfig_apply.py index d393d81..5bc4683 100644 --- a/plugins/modules/dynconfig_apply.py +++ b/plugins/modules/dynconfig_apply.py @@ -1,6 +1,13 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: dynconfig_apply + plugin_type: module + short_description: Change dynamic config + description: | + This module designed to replace dynamic config +''' def main(): argument_spec=dict( diff --git a/plugins/modules/dynconfig_version.py b/plugins/modules/dynconfig_version.py index abbabe4..2851f0b 100644 --- a/plugins/modules/dynconfig_version.py +++ b/plugins/modules/dynconfig_version.py @@ -7,6 +7,14 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: dynconfig_version + plugin_type: module + short_description: Get current version of dynamic config + description: | + Get current version of dynamic config +''' + def main(): argument_spec=dict( timeout=dict(type='int', default=180), diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index 13c823a..89bee28 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -10,14 +10,14 @@ - name: Check if required variables are defined ansible.builtin.assert: that: - - "{{ item.var1 is defined or item.var2 is defined }}" - fail_msg: "Either {{ item.var1 }} or {{ item.var2 }} variable is required" + - "{{ item.var1 is defined }}" + fail_msg: "Either {{ item.var1 }} variable is required" loop: - { var1: "ydb_cores_static" } - { var1: "ydb_cores_dynamic" } - - { var1: "ydb_disks", var2: "ydb_disks" } - - { var1: "ydb_domain", var2: "ydb_domain" } - - { var1: "ydb_user", var2: "ydb_user" } + - { var1: "ydb_disks" } + - { var1: "ydb_domain" } + - { var1: "ydb_user" } # Handle ydb_pool_kind if not defined - name: handle ydb_pool_kind if not defined From 7b3214b57c90b3756339f878a629340c34d60451 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Mon, 13 Oct 2025 14:18:09 +0300 Subject: [PATCH 22/53] pool_kind in inventory --- plugins/inventory/ydb_inventory.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 2933ed2..fbcd344 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -48,8 +48,8 @@ def parse(self, inventory, loader, path, cache=True): if 'config' in yaml_config: self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config['config']) - if 'default_disk_type' in yaml_config['config']: - self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['config']['default_disk_type']) + if 'default_disk_type' in yaml_config['config'] and 'ydb_pool_kind' not in ydb_vars: + self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['config']['default_disk_type'].lower()) if 'self_management_config' in yaml_config['config'] and 'enabled' in yaml_config['config']['self_management_config'] and yaml_config['config']['self_management_config']['enabled']: self.inventory.groups['ydb'].set_variable('ydb_config_v2', True) From be70f19429e13ad82727c47d8c22d6d2f0ad4a14 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Mon, 13 Oct 2025 14:29:43 +0300 Subject: [PATCH 23/53] Clean up variables --- README.md | 2 +- roles/ydbd_dynamic/defaults/main.yaml | 5 +++-- roles/ydbd_dynamic/tasks/main.yaml | 2 +- roles/ydbd_newdb/defaults/main.yaml | 1 + roles/ydbd_newdb/tasks/main.yml | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 33001c6..5c6f209 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ The meaning and format of the variables used are specified in the table below. | `ydb_config_v2` | Controls initialization method and configuration management: if `true` uses YDB configuration V2 with `node init` + `bootstrap` and `--config-dir` arg, if `false` uses configuration V1 with `actor_system_config` injection and `--yaml-config` arg. If not set, automatically determined based on YDB version (`true` for version 25.1 and above) | | `ydb_dbname` | Database name, for database creation, dynamic nodes deployment and dynamic nodes rolling restart | | `ydb_pool_kind` | YDB default storage pool kind, as specified in the static nodes configuration file in the `storage_pool_types.kind` field | -| `ydb_database_storage_groups` | Initial number of storage groups in the newly created database (alias: `ydb_database_groups`) | +| `ydb_database_groups` | Initial number of storage groups in the newly created database | | `ydb_dynnode_restart_sleep_seconds` | Number of seconds to sleep after startup of each dynamic node during the rolling restart. | ### Installing the YDB cluster using Ansible diff --git a/roles/ydbd_dynamic/defaults/main.yaml b/roles/ydbd_dynamic/defaults/main.yaml index e1f957e..6a288f1 100644 --- a/roles/ydbd_dynamic/defaults/main.yaml +++ b/roles/ydbd_dynamic/defaults/main.yaml @@ -1,5 +1,6 @@ -ydb_database_storage_groups: 1 -ydb_database_groups: "{{ ydb_database_storage_groups }}" +--- + +ydb_database_groups: 1 ydb_request_client_certificate: false # ydb_use_dynamic_config - define how to configure dynamic nodes - static or dynamic configs # Default value: false diff --git a/roles/ydbd_dynamic/tasks/main.yaml b/roles/ydbd_dynamic/tasks/main.yaml index 5dd507d..ed6a4b5 100644 --- a/roles/ydbd_dynamic/tasks/main.yaml +++ b/roles/ydbd_dynamic/tasks/main.yaml @@ -183,7 +183,7 @@ # database: "/{{ ydb_domain }}/{{ ydb_dbname }}" # token: "{{ ydb_credentials.token }}" # pool_kind: "{{ ydb_pool_kind }}" -# groups: "{{ ydb_database_storage_groups | default(ydb_database_groups) }}" +# groups: "{{ ydb_database_groups }}" # become: true # become_user: "{{ ydb_host_user }}" # run_once: true diff --git a/roles/ydbd_newdb/defaults/main.yaml b/roles/ydbd_newdb/defaults/main.yaml index cd21505..676de07 100644 --- a/roles/ydbd_newdb/defaults/main.yaml +++ b/roles/ydbd_newdb/defaults/main.yaml @@ -1,2 +1,3 @@ --- +ydb_database_groups: 1 \ No newline at end of file diff --git a/roles/ydbd_newdb/tasks/main.yml b/roles/ydbd_newdb/tasks/main.yml index 6ffaef6..776aaaa 100644 --- a/roles/ydbd_newdb/tasks/main.yml +++ b/roles/ydbd_newdb/tasks/main.yml @@ -9,7 +9,7 @@ src: "secret.j2" dest: "{{ ydb_dir }}/certs/secret" - name: Run the database creation script - command: "{{ ydb_dir }}/home/create_database.sh {{ ydb_brokers | default(groups['ydb']) | flatten(levels=1) | first }} {{ ydb_dbname }} {{ ydb_database_storage_groups | default(ydb_database_groups) }}" + command: "{{ ydb_dir }}/home/create_database.sh {{ ydb_brokers | default(groups['ydb']) | flatten(levels=1) | first }} {{ ydb_dbname }} {{ ydb_database_groups }}" - name: Cleanup the transferred secrets file: state=absent path={{ ydb_dir }}/certs/secret run_once: true From 7122f412b647288108e01d93b015abf7662b8673 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Mon, 13 Oct 2025 14:39:08 +0300 Subject: [PATCH 24/53] +docs --- plugins/modules/patch_config.py | 10 +++++++++- plugins/modules/workload.py | 9 +++++++++ plugins/modules/ydbd_cmd.py | 7 +++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/plugins/modules/patch_config.py b/plugins/modules/patch_config.py index 799b90a..e97765c 100644 --- a/plugins/modules/patch_config.py +++ b/plugins/modules/patch_config.py @@ -5,6 +5,14 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils.yaml_utils import safe_dump +DOCUMENTATION = r''' + name: patch_config + plugin_type: module + short_description: patch ydb config + description: | + patch ydb config +''' + def _ensure_config_path(config, path, default_value): """Helper function to ensure a nested config path exists with a default value.""" current = config @@ -83,7 +91,7 @@ def patch_config_v2(config, hostvars=None, ydb_disks=None, groups=None, ydb_dir= _ensure_config_path(config, 'grpc_config.ca', f"{ydb_dir}/certs/ca.crt") _ensure_config_path(config, 'grpc_config.services_enabled', ['legacy','discovery']) - if ydb_domain is not None: + if ydb_domain is not None and ydb_domain != "Root": _ensure_config_path(config, 'domains_config.domain', [{"name": f"{ydb_domain}"}]) # Generate hosts section if it's missing and we have the required data diff --git a/plugins/modules/workload.py b/plugins/modules/workload.py index 3e65a9d..81730a5 100644 --- a/plugins/modules/workload.py +++ b/plugins/modules/workload.py @@ -1,6 +1,15 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: workload + plugin_type: module + short_description: Run workload tests on YDB cluster + description: | + Run workload tests on YDB cluster + `workload` possible values: topic, kv, stock +''' + def main(): argument_spec=dict( workload=dict(type='str', default='stock'), diff --git a/plugins/modules/ydbd_cmd.py b/plugins/modules/ydbd_cmd.py index 7abfad2..5408baa 100644 --- a/plugins/modules/ydbd_cmd.py +++ b/plugins/modules/ydbd_cmd.py @@ -4,6 +4,13 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import drive, cli +DOCUMENTATION = r''' + name: ydbd_cmd + plugin_type: module + short_description: YDBD command executor + description: | + Module for running commands with YDBD +''' def main(): argument_spec = dict( From ad1af93728b4624d2c2ca3a5da38d4c7b6b8632d Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Mon, 13 Oct 2025 16:47:20 +0300 Subject: [PATCH 25/53] +ydb_dbname from ydb_dynnodes --- plugins/inventory/ydb_inventory.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index fbcd344..9a3e627 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -47,6 +47,12 @@ def parse(self, inventory, loader, path, cache=True): yaml_config = yaml.safe_load(file) if 'config' in yaml_config: self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config['config']) + + if 'ydb_dbname' not in ydb_vars and 'ydb_dynnodes' in ydb_vars: + for dynnode in ydb_vars['ydb_dynnodes']: + if 'dbname' in dynnode: + self.inventory.groups['ydb'].set_variable('ydb_dbname',dynnode['dbname']) + break if 'default_disk_type' in yaml_config['config'] and 'ydb_pool_kind' not in ydb_vars: self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['config']['default_disk_type'].lower()) From 63af4ed6ec5dfcb407e2b1672dae9f246c6393ee Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 14 Oct 2025 10:28:56 +0300 Subject: [PATCH 26/53] Configure brokers list in inventory --- plugins/inventory/ydb_inventory.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 9a3e627..45fbc2a 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -40,6 +40,7 @@ def parse(self, inventory, loader, path, cache=True): group = 'ydb' self.inventory.add_group(group) + brokers = [] ydb_vars = self.inventory.groups['ydb'].get_vars() try: @@ -53,7 +54,7 @@ def parse(self, inventory, loader, path, cache=True): if 'dbname' in dynnode: self.inventory.groups['ydb'].set_variable('ydb_dbname',dynnode['dbname']) break - + if 'default_disk_type' in yaml_config['config'] and 'ydb_pool_kind' not in ydb_vars: self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['config']['default_disk_type'].lower()) @@ -90,6 +91,11 @@ def parse(self, inventory, loader, path, cache=True): self.inventory.set_variable(host['host'], 'ydb_disks', drive_configs[value]) else: self.inventory.set_variable(host['host'], key, value) + if (brokers) < 3: + brokers.append(host['host']) + + if 'ydb_brokers' not in ydb_vars and len(brokers) > 0: + self.inventory.groups['ydb'].set_variable('ydb_brokers', brokers) except Exception as e: raise AnsibleError(f"Config parsing error: {str(e)}") From 33ac1f283cd178fbdb2b920123da9fcf2f2ca119 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 14 Oct 2025 10:30:42 +0300 Subject: [PATCH 27/53] +docs --- plugins/inventory/ydb_inventory.py | 2 +- plugins/modules/gen_tls_certs.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 45fbc2a..0628c20 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -91,7 +91,7 @@ def parse(self, inventory, loader, path, cache=True): self.inventory.set_variable(host['host'], 'ydb_disks', drive_configs[value]) else: self.inventory.set_variable(host['host'], key, value) - if (brokers) < 3: + if len(brokers) < 3: brokers.append(host['host']) if 'ydb_brokers' not in ydb_vars and len(brokers) > 0: diff --git a/plugins/modules/gen_tls_certs.py b/plugins/modules/gen_tls_certs.py index a572c37..3ef2276 100644 --- a/plugins/modules/gen_tls_certs.py +++ b/plugins/modules/gen_tls_certs.py @@ -5,6 +5,13 @@ import os import tempfile +DOCUMENTATION = r''' + name: get_tls_certs + plugin_type: module + short_description: Generate TLS certificates + description: | + Generate TLS certificates if needed +''' def write_file(atomic_move): def write_file_impl(path, content): From 6093ea2543b6a995e2fc79285b35d2ef2402ea88 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 14 Oct 2025 10:33:57 +0300 Subject: [PATCH 28/53] +var in inventory --- plugins/inventory/ydb_inventory.py | 3 +++ plugins/modules/get_token.py | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 0628c20..24fa71b 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -54,6 +54,9 @@ def parse(self, inventory, loader, path, cache=True): if 'dbname' in dynnode: self.inventory.groups['ydb'].set_variable('ydb_dbname',dynnode['dbname']) break + + if 'ydb_enforce_user_token_requirement' not in ydb_vars: + self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', False) if 'default_disk_type' in yaml_config['config'] and 'ydb_pool_kind' not in ydb_vars: self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['config']['default_disk_type'].lower()) diff --git a/plugins/modules/get_token.py b/plugins/modules/get_token.py index 1c86169..8b1a863 100644 --- a/plugins/modules/get_token.py +++ b/plugins/modules/get_token.py @@ -9,7 +9,13 @@ 'Ssl handshake failed', 'failed to connect to all addresses' ] - +DOCUMENTATION = r''' + name: get_token + plugin_type: module + short_description: Get YDB token + description: | + Get token from YDB cluster +''' def main(): argument_spec=dict( From d78cc8b76e8d7bfc50440df4c026e7ba97c8c06d Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 14 Oct 2025 11:33:00 +0300 Subject: [PATCH 29/53] Fix problem with dbname --- plugins/modules/update_metadata.py | 8 +++++++- roles/ydbd_dynamic/tasks/main.yaml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/modules/update_metadata.py b/plugins/modules/update_metadata.py index 5efb9a2..8a0b590 100644 --- a/plugins/modules/update_metadata.py +++ b/plugins/modules/update_metadata.py @@ -7,7 +7,13 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils.yaml_utils import safe_dump - +DOCUMENTATION = r''' + name: update_metadata + plugin_type: module + short_description: Update metadata in YDB config + description: | + Update metadata in YDB config +''' def run_module(): module_args = dict( diff --git a/roles/ydbd_dynamic/tasks/main.yaml b/roles/ydbd_dynamic/tasks/main.yaml index ed6a4b5..eed3c2f 100644 --- a/roles/ydbd_dynamic/tasks/main.yaml +++ b/roles/ydbd_dynamic/tasks/main.yaml @@ -132,7 +132,7 @@ - name: start dynamic nodes ansible.builtin.systemd: - name: "ydbd-{{ item.dbname }}-{{ item.instance }}.service" + name: "ydbd-{{ item.dbname | default(ydb_dbname, true) }}-{{ item.instance }}.service" state: started enabled: true loop: "{{ ydb_dynnodes }}" From b6af6c11b73e6b31a9bbaedd173a8322aa3e2c0f Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 14 Oct 2025 16:15:03 +0300 Subject: [PATCH 30/53] basicConfig fix --- plugins/modules/init_node_config.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/modules/init_node_config.py b/plugins/modules/init_node_config.py index 3df6b7f..6c102e4 100644 --- a/plugins/modules/init_node_config.py +++ b/plugins/modules/init_node_config.py @@ -9,6 +9,13 @@ from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli from ansible_collections.ydb_platform.ydb.plugins.module_utils.yaml_utils import safe_dump +DOCUMENTATION = r''' + name: init_node_config + plugin_type: module + short_description: Create init config for a node + description: | + Create initial config for a node with V2 configuration +''' def check_node_config_exists(config_dir, result): """Check if node configuration already exists""" @@ -30,7 +37,7 @@ def init_node_config(ydb_cli, config_file, config_dir, result): # Create the initial metadata structure original_config['metadata'] = { - 'kind': 'basicConfig', + 'kind': 'MainConfig', 'cluster': '', 'version': 0 } From aa7f6fe90cb2d6dbe0ac635e4f621ddc9f78e8fc Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 14 Oct 2025 16:42:54 +0300 Subject: [PATCH 31/53] Fix for update_config --- playbooks/update_config.yaml | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/playbooks/update_config.yaml b/playbooks/update_config.yaml index fd0d545..d34d146 100644 --- a/playbooks/update_config.yaml +++ b/playbooks/update_config.yaml @@ -144,37 +144,9 @@ retries: 30 delay: 15 - - name: check if ydb_config is a map - set_fact: - ydb_config_is_map: "{{ ydb_config is mapping }}" - run_once: true - - - name: handle ydb_config as map - block: - - name: parse ansible configuration from map - set_fact: - parsed_ansible_config: "{{ ydb_config }}" - run_once: true - when: ydb_config_is_map - - - name: handle ydb_config as file path - block: - - name: read ansible configuration file content - slurp: - src: "{{ ydb_config }}" - run_once: true - register: ansible_config_content - delegate_to: localhost - - - name: parse ansible configuration content - set_fact: - parsed_ansible_config: "{{ ansible_config_content.content | b64decode | from_yaml }}" - run_once: true - when: not ydb_config_is_map - - name: apply patch_config_v2 to configuration ydb_platform.ydb.patch_config: - config: "{{ parsed_ansible_config }}" + config: "{{ ydb_config_parsed }}" output_file: "{{ ydb_temp_config_path }}" hostvars: "{{ hostvars }}" ydb_disks: "{{ ydb_disks }}" From 75806ea502ed063b63d37229889ebaf23aae3e17 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 14 Oct 2025 17:20:42 +0300 Subject: [PATCH 32/53] Fix check version --- playbooks/healthcheck.yaml | 2 +- roles/ydbd_static/tasks/main.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/playbooks/healthcheck.yaml b/playbooks/healthcheck.yaml index add79c6..22ce385 100644 --- a/playbooks/healthcheck.yaml +++ b/playbooks/healthcheck.yaml @@ -59,4 +59,4 @@ become_user: "{{ ydb_host_user }}" tags: - healthcheck - when: "ydb_version is version('25.1', '<')" # Hack until YDB HC will handle 3-nodes-mirror-3-dc in 25.* + when: "(ydb_version is regex(\"\\d+\\..*\") or ydb_version is regex(\"\\d+-.*\")) and ydb_version is version('25.1', '<')" # Hack until YDB HC will handle 3-nodes-mirror-3-dc in 25.* diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index 89bee28..e162913 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -407,7 +407,7 @@ become_user: "{{ ydb_host_user }}" tags: - healthcheck - when: "ydb_version is version('25.1', '<')" # Hack until YDB HC will handle 3-nodes-mirror-3-dc in 25.* + when: "(ydb_version is regex(\"\\d+\\..*\") or ydb_version is regex(\"\\d+-.*\")) and ydb_version is version('25.1', '<')" # Hack until YDB HC will handle 3-nodes-mirror-3-dc in 25.* - name: set cluster root password ydb_platform.ydb.set_user_password: From 7a312406a354f91ecbcd9947522e3ac2ec2a957a Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 14 Oct 2025 17:41:19 +0300 Subject: [PATCH 33/53] remove ydb_config_parsed --- playbooks/update_config.yaml | 2 +- roles/ydbd_dynamic/tasks/main.yaml | 32 +++--------------------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/playbooks/update_config.yaml b/playbooks/update_config.yaml index d34d146..bfc3a2a 100644 --- a/playbooks/update_config.yaml +++ b/playbooks/update_config.yaml @@ -146,7 +146,7 @@ - name: apply patch_config_v2 to configuration ydb_platform.ydb.patch_config: - config: "{{ ydb_config_parsed }}" + config: "{{ ydb_config_dict }}" output_file: "{{ ydb_temp_config_path }}" hostvars: "{{ hostvars }}" ydb_disks: "{{ ydb_disks }}" diff --git a/roles/ydbd_dynamic/tasks/main.yaml b/roles/ydbd_dynamic/tasks/main.yaml index eed3c2f..67ab6ec 100644 --- a/roles/ydbd_dynamic/tasks/main.yaml +++ b/roles/ydbd_dynamic/tasks/main.yaml @@ -56,39 +56,13 @@ - ydb_dynnodes is defined fail_msg: "ydb_dynnodes variable with dynamic node instances list is required" -- name: check if ydb_config is a map - ansible.builtin.set_fact: - ydb_config_is_map: "{{ ydb_config is defined and ydb_config is mapping }}" - when: ydb_config is defined - -- name: check if ydb_config is a string (path) - ansible.builtin.set_fact: - ydb_config_is_path: "{{ ydb_config is defined and ydb_config is string }}" - when: ydb_config is defined - -- name: read config file when ydb_config is a path - ansible.builtin.slurp: - src: "{{ ydb_config }}" - register: ydb_config_content - when: - - ydb_pool_kind is not defined - - ydb_config_is_path is defined and ydb_config_is_path - -- name: parse config file content - ansible.builtin.set_fact: - ydb_config_parsed: "{{ ydb_config_content['content'] | b64decode | from_yaml }}" - when: - - ydb_pool_kind is not defined - - ydb_config_is_path is defined and ydb_config_is_path - - ydb_config_content is defined - - name: set default for ydb_pool_kind from parsed config file ansible.builtin.set_fact: - ydb_pool_kind: "{{ ydb_config_parsed.default_disk_type | lower }}" + ydb_pool_kind: "{{ ydb_config_dict.default_disk_type | lower }}" when: - ydb_pool_kind is not defined - - ydb_config_parsed is defined - - ydb_config_parsed.default_disk_type is defined + - ydb_config_dict is defined + - ydb_config_dict.default_disk_type is defined - name: set default for ydb_pool_kind when ydb_config is a map ansible.builtin.set_fact: From 8bd7951a2d5982ac1dfa89125b3d1cf0d77215b0 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 16 Oct 2025 11:36:36 +0300 Subject: [PATCH 34/53] Fix affinity --- roles/ydbd_dynamic/templates/ydbd-dynnode.service | 4 ++-- roles/ydbd_static/templates/ydbd-storage.service | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/roles/ydbd_dynamic/templates/ydbd-dynnode.service b/roles/ydbd_dynamic/templates/ydbd-dynnode.service index d50e34d..c49ea47 100644 --- a/roles/ydbd_dynamic/templates/ydbd-dynnode.service +++ b/roles/ydbd_dynamic/templates/ydbd-dynnode.service @@ -65,9 +65,9 @@ RestartSec=1 SyslogIdentifier=ydbd SyslogFacility=daemon SyslogLevel=err -{%- if 'affinity' in item %} +{% if 'affinity' in item %} CPUAffinity={{ item.affinity }} -{%- endif %} +{% endif %} [Install] WantedBy=multi-user.target diff --git a/roles/ydbd_static/templates/ydbd-storage.service b/roles/ydbd_static/templates/ydbd-storage.service index 80e8309..a03bf81 100644 --- a/roles/ydbd_static/templates/ydbd-storage.service +++ b/roles/ydbd_static/templates/ydbd-storage.service @@ -36,9 +36,9 @@ RestartSec=1 SyslogIdentifier=ydbd SyslogFacility=daemon SyslogLevel=err -{%- if ydb_affinity_static is defined %} +{% if ydb_affinity_static is defined %} CPUAffinity={{ ydb_affinity_static }} -{%- endif %} +{% endif %} [Install] WantedBy=multi-user.target From be3957124de7a3f040aec11cc257a3ae884ebea6 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 16 Oct 2025 11:39:45 +0300 Subject: [PATCH 35/53] Fix for update V2 config --- plugins/modules/update_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/update_metadata.py b/plugins/modules/update_metadata.py index 8a0b590..7c8377b 100644 --- a/plugins/modules/update_metadata.py +++ b/plugins/modules/update_metadata.py @@ -84,7 +84,7 @@ def run_module(): # Increment existing version try: current_version = int(config['metadata']['version']) - config['metadata']['version'] = current_version + 1 + # config['metadata']['version'] = current_version + 1 result['changed'] = True except (ValueError, TypeError): module.fail_json(msg='Version in metadata must be an integer') From f6d524558125809c33d0d59e9310764d8a11ae64 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 23 Oct 2025 11:09:43 +0300 Subject: [PATCH 36/53] Adjust inventory for V1 config.yaml --- plugins/inventory/ydb_inventory.py | 50 ++++++++++++++++-------------- plugins/modules/init_storage.py | 8 +++++ plugins/modules/pdisk_active.py | 9 ++++++ plugins/modules/restart_storage.py | 7 +++++ 4 files changed, 51 insertions(+), 23 deletions(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 24fa71b..db7be4d 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -46,36 +46,40 @@ def parse(self, inventory, loader, path, cache=True): try: with open(ydb_config, "r") as file: yaml_config = yaml.safe_load(file) + if 'config' in yaml_config: - self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config['config']) + """ V2 Config """ + yaml_config = yaml_config['config'] + + self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config) + + if 'ydb_dbname' not in ydb_vars and 'ydb_dynnodes' in ydb_vars: + for dynnode in ydb_vars['ydb_dynnodes']: + if 'dbname' in dynnode: + self.inventory.groups['ydb'].set_variable('ydb_dbname',dynnode['dbname']) + break + + if 'ydb_enforce_user_token_requirement' not in ydb_vars: + self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', False) + + if 'default_disk_type' in yaml_config and 'ydb_pool_kind' not in ydb_vars: + self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['default_disk_type'].lower()) - if 'ydb_dbname' not in ydb_vars and 'ydb_dynnodes' in ydb_vars: - for dynnode in ydb_vars['ydb_dynnodes']: - if 'dbname' in dynnode: - self.inventory.groups['ydb'].set_variable('ydb_dbname',dynnode['dbname']) - break - - if 'ydb_enforce_user_token_requirement' not in ydb_vars: - self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', False) - - if 'default_disk_type' in yaml_config['config'] and 'ydb_pool_kind' not in ydb_vars: - self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['config']['default_disk_type'].lower()) + if 'self_management_config' in yaml_config and 'enabled' in yaml_config['self_management_config'] and yaml_config['self_management_config']['enabled']: + self.inventory.groups['ydb'].set_variable('ydb_config_v2', True) - if 'self_management_config' in yaml_config['config'] and 'enabled' in yaml_config['config']['self_management_config'] and yaml_config['config']['self_management_config']['enabled']: - self.inventory.groups['ydb'].set_variable('ydb_config_v2', True) - self.inventory.groups['ydb'].set_variable('ydb_config', yaml_config['config']) - - # Default domain is Root - self.inventory.groups['ydb'].set_variable('ydb_domain','Root') - + self.inventory.groups['ydb'].set_variable('ydb_config', yaml_config) + + # Default domain is Root + self.inventory.groups['ydb'].set_variable('ydb_domain','Root') # Read drives config drive_configs = {} drive_labels = {} if 'ydb_disks' in ydb_vars: for disk in ydb_vars['ydb_disks']: drive_labels[disk['label']] = disk['name'] - if 'config' in yaml_config and 'host_configs' in yaml_config['config']: - for drive_config in yaml_config['config']['host_configs']: + if 'host_configs' in yaml_config: + for drive_config in yaml_config['host_configs']: drive_configs[drive_config['host_config_id']] = copy.deepcopy(drive_config['drive']) for i, item in enumerate(drive_config['drive']): label = item['path'].split('/')[-1] @@ -85,8 +89,8 @@ def parse(self, inventory, loader, path, cache=True): else: raise AnsibleError(f"Config parsing error, unable to find disk for label: {label}") # Read hosts and define variables for them - if 'config' in yaml_config and 'hosts' in yaml_config['config']: - for host in yaml_config['config']['hosts']: + if 'hosts' in yaml_config: + for host in yaml_config['hosts']: self.inventory.add_host(host['host'], group=group) # Set variables for hosts for key, value in host.items(): diff --git a/plugins/modules/init_storage.py b/plugins/modules/init_storage.py index 8265e77..474918d 100644 --- a/plugins/modules/init_storage.py +++ b/plugins/modules/init_storage.py @@ -7,6 +7,13 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: init_storage + plugin_type: module + short_description: Initialize blobstorage (BS) + description: | + Initialize blobstorage (BS) regarding config version +''' def check_storage_initialization(ydb_dstool, result): """Check if storage is already initialized using dstool""" @@ -33,6 +40,7 @@ def set_pdisk_active_status(ydb_dstool): dstool_result = json.loads(stdout) for pdisk in dstool_result: if "Status" in pdisk and pdisk["Status"] != "ACTIVE": + print(pdisk) ydb_dstool(['pdisk', 'set', '--status=ACTIVE', '--pdisk-ids', pdisk["NodeId:PDiskId"]]) except Exception: # Ignore errors in PDisk status setting as it's not critical diff --git a/plugins/modules/pdisk_active.py b/plugins/modules/pdisk_active.py index af559e2..c65cf43 100644 --- a/plugins/modules/pdisk_active.py +++ b/plugins/modules/pdisk_active.py @@ -7,6 +7,14 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: pdisk_active + plugin_type: module + short_description: Activate INACTIVE PDisks + description: | + In some cases some PDisks can become INACTIVE during cluster initialization. + This module changes their state to ACTIVE +''' def set_pdisk_active_status(ydb_dstool): """Set PDisk status to ACTIVE for any inactive PDisks""" @@ -16,6 +24,7 @@ def set_pdisk_active_status(ydb_dstool): dstool_result = json.loads(stdout) for pdisk in dstool_result: if "Status" in pdisk and pdisk["Status"] != "ACTIVE": + print(pdisk) ydb_dstool(['pdisk', 'set', '--status=ACTIVE', '--pdisk-ids', pdisk["NodeId:PDiskId"]]) except Exception: # Ignore errors in PDisk status setting as it's not critical diff --git a/plugins/modules/restart_storage.py b/plugins/modules/restart_storage.py index 30277a0..4d25f5d 100644 --- a/plugins/modules/restart_storage.py +++ b/plugins/modules/restart_storage.py @@ -1,6 +1,13 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: restart_storage + plugin_type: module + short_description: Restart storage nodes using ydbops + description: | + Restart storage nodes using YDBOps tool +''' def main(): argument_spec=dict( From 820eca8e7ac3faf8dd4084f72c065aa07d41cd6d Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 23 Oct 2025 11:20:44 +0300 Subject: [PATCH 37/53] +docs --- playbooks/install_dynamic.yaml | 2 +- plugins/inventory/ydb_inventory.py | 8 ++++++-- plugins/modules/run_test_queries.py | 7 +++++++ plugins/modules/wait_discovery.py | 7 +++++++ plugins/modules/wait_healthcheck.py | 7 +++++++ 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/playbooks/install_dynamic.yaml b/playbooks/install_dynamic.yaml index 871fa5c..a319516 100644 --- a/playbooks/install_dynamic.yaml +++ b/playbooks/install_dynamic.yaml @@ -2,7 +2,7 @@ # PLAYBOOK: ydb_platform.ydb.install_dynamic -# PROPOSE : This playbook is designed to create YDB database in YDB cluster. +# PROPOSE : This playbook is designed to install YDB dynamic(database) nodes in YDB cluster. # # HOW TO USE: # Use https://github.com/ydb-platform/ydb-ansible-examples as an example to prepare Ansible diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index db7be4d..5067f0f 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -62,8 +62,12 @@ def parse(self, inventory, loader, path, cache=True): if 'ydb_enforce_user_token_requirement' not in ydb_vars: self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', False) - if 'default_disk_type' in yaml_config and 'ydb_pool_kind' not in ydb_vars: - self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['default_disk_type'].lower()) + if 'ydb_pool_kind' not in ydb_vars: + if 'default_disk_type' in yaml_config: + self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['default_disk_type'].lower()) + if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: + if 'storage_pool_types' in yaml_config['domains_config']['domain'][0]: + self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['domains_config']['domain'][0]['storage_pool_types'][0]['kind']) if 'self_management_config' in yaml_config and 'enabled' in yaml_config['self_management_config'] and yaml_config['self_management_config']['enabled']: self.inventory.groups['ydb'].set_variable('ydb_config_v2', True) diff --git a/plugins/modules/run_test_queries.py b/plugins/modules/run_test_queries.py index ccdacd0..c656cc3 100644 --- a/plugins/modules/run_test_queries.py +++ b/plugins/modules/run_test_queries.py @@ -4,6 +4,13 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: run_test_queries + plugin_type: module + short_description: Run test queries to check YDB is ready for actions + description: | + Run test queries to check YDB is ready for actions +''' def main(): table_name = '`_ansible_test_table`' diff --git a/plugins/modules/wait_discovery.py b/plugins/modules/wait_discovery.py index 8dbce41..c1370ea 100644 --- a/plugins/modules/wait_discovery.py +++ b/plugins/modules/wait_discovery.py @@ -3,6 +3,13 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: wait_discover + plugin_type: module + short_description: Check until discovery become working + description: | + Check until discovery become working +''' def main(): argument_spec=dict( diff --git a/plugins/modules/wait_healthcheck.py b/plugins/modules/wait_healthcheck.py index 090b68e..edc709f 100644 --- a/plugins/modules/wait_healthcheck.py +++ b/plugins/modules/wait_healthcheck.py @@ -5,6 +5,13 @@ from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli INVALID_PASSWORD = 'CLIENT_UNAUTHENTICATED' +DOCUMENTATION = r''' + name: wait_healthcheck + plugin_type: module + short_description: Wait until healthcheck becomes GOOD + description: | + Wait until healthcheck becomes GOOD +''' def main(): argument_spec=dict( From e9d440ab0c718876ed8258b14bd3025e8d2ecb9d Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 23 Oct 2025 11:25:56 +0300 Subject: [PATCH 38/53] remove debug messages --- plugins/modules/init_storage.py | 1 - plugins/modules/pdisk_active.py | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/modules/init_storage.py b/plugins/modules/init_storage.py index 474918d..9204139 100644 --- a/plugins/modules/init_storage.py +++ b/plugins/modules/init_storage.py @@ -40,7 +40,6 @@ def set_pdisk_active_status(ydb_dstool): dstool_result = json.loads(stdout) for pdisk in dstool_result: if "Status" in pdisk and pdisk["Status"] != "ACTIVE": - print(pdisk) ydb_dstool(['pdisk', 'set', '--status=ACTIVE', '--pdisk-ids', pdisk["NodeId:PDiskId"]]) except Exception: # Ignore errors in PDisk status setting as it's not critical diff --git a/plugins/modules/pdisk_active.py b/plugins/modules/pdisk_active.py index c65cf43..17545fc 100644 --- a/plugins/modules/pdisk_active.py +++ b/plugins/modules/pdisk_active.py @@ -24,7 +24,6 @@ def set_pdisk_active_status(ydb_dstool): dstool_result = json.loads(stdout) for pdisk in dstool_result: if "Status" in pdisk and pdisk["Status"] != "ACTIVE": - print(pdisk) ydb_dstool(['pdisk', 'set', '--status=ACTIVE', '--pdisk-ids', pdisk["NodeId:PDiskId"]]) except Exception: # Ignore errors in PDisk status setting as it's not critical From 52d13a06f608045418511f81d405a876ebfaac68 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 23 Oct 2025 11:35:52 +0300 Subject: [PATCH 39/53] docs --- filter_plugins/yaml_filters.py | 8 +++++++- plugins/modules/get_token.py | 1 + plugins/modules/set_user_password.py | 7 +++++++ plugins/modules/update_metadata.py | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/filter_plugins/yaml_filters.py b/filter_plugins/yaml_filters.py index 30f20d8..0aca94e 100644 --- a/filter_plugins/yaml_filters.py +++ b/filter_plugins/yaml_filters.py @@ -5,7 +5,13 @@ from ansible_collections.ydb_platform.ydb.plugins.filter.yaml_filters import ydb_config_to_yaml, FilterModule as OrigFilterModule - +DOCUMENTATION = r''' + name: yaml_filters + plugin_type: filter + short_description: short desc + description: | + long description +''' class FilterModule(object): """ diff --git a/plugins/modules/get_token.py b/plugins/modules/get_token.py index 8b1a863..9107ad5 100644 --- a/plugins/modules/get_token.py +++ b/plugins/modules/get_token.py @@ -9,6 +9,7 @@ 'Ssl handshake failed', 'failed to connect to all addresses' ] + DOCUMENTATION = r''' name: get_token plugin_type: module diff --git a/plugins/modules/set_user_password.py b/plugins/modules/set_user_password.py index e835be0..f9bf1f7 100644 --- a/plugins/modules/set_user_password.py +++ b/plugins/modules/set_user_password.py @@ -4,6 +4,13 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils import cli +DOCUMENTATION = r''' + name: set_user_password + plugin_type: module + short_description: Set YDB user password + description: | + Set YDB user password +''' def validate_user(value): return re.fullmatch('[a-z0-9]+', value) is not None diff --git a/plugins/modules/update_metadata.py b/plugins/modules/update_metadata.py index 7c8377b..e7771a1 100644 --- a/plugins/modules/update_metadata.py +++ b/plugins/modules/update_metadata.py @@ -7,6 +7,7 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.ydb_platform.ydb.plugins.module_utils.yaml_utils import safe_dump + DOCUMENTATION = r''' name: update_metadata plugin_type: module From 89c804baddc33f045aa1fe73e979daab4f41bbb4 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 24 Oct 2025 11:26:10 +0300 Subject: [PATCH 40/53] YDBOPS-12926: Fix for domain names in v2 --- plugins/inventory/ydb_inventory.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 5067f0f..f5105d7 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -74,8 +74,13 @@ def parse(self, inventory, loader, path, cache=True): self.inventory.groups['ydb'].set_variable('ydb_config', yaml_config) - # Default domain is Root - self.inventory.groups['ydb'].set_variable('ydb_domain','Root') + if 'ydb_domain' not in ydb_vars: + if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: + self.inventory.groups['ydb'].set_variable('ydb_domain',yaml_config['domains_config']['domain'][0]['name']) + else: + # Default domain is Root + self.inventory.groups['ydb'].set_variable('ydb_domain','Root') + # Read drives config drive_configs = {} drive_labels = {} From f343786354bab35b0328dab869e5f7e13ab63b4d Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Tue, 28 Oct 2025 13:14:35 +0300 Subject: [PATCH 41/53] + enforce_user_token_requirement in inventory --- plugins/inventory/ydb_inventory.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index f5105d7..3340168 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -60,7 +60,10 @@ def parse(self, inventory, loader, path, cache=True): break if 'ydb_enforce_user_token_requirement' not in ydb_vars: - self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', False) + if 'domains_config' in yaml_config and 'security_config' in yaml_config['domains_config'] and 'enforce_user_token_requirement' in yaml_config['domains_config']['security_config']: + self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', yaml_config['domains_config']['security_config']['enforce_user_token_requirement']) + else: + self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', False) if 'ydb_pool_kind' not in ydb_vars: if 'default_disk_type' in yaml_config: From 3ecf236223b0e4283de8008e0b82f0494ea12a9f Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 30 Oct 2025 12:41:55 +0300 Subject: [PATCH 42/53] Some corrections --- plugins/filter/yaml_filters.py | 8 ++++++++ plugins/inventory/ydb_inventory.py | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/filter/yaml_filters.py b/plugins/filter/yaml_filters.py index baf435e..b0e8148 100644 --- a/plugins/filter/yaml_filters.py +++ b/plugins/filter/yaml_filters.py @@ -4,6 +4,14 @@ from ansible.module_utils.six import string_types from ansible.utils.display import Display +DOCUMENTATION = r''' + name: yaml_filters + plugin_type: filter + short_description: YAML config parsing + description: | + YAML config parsing +''' + display = Display() class YDBDynCustomYAMLDumper(yaml.SafeDumper): diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 3340168..f0e6445 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -7,12 +7,12 @@ DOCUMENTATION = r''' name: ydb_inventory plugin_type: inventory - short_description: YDB inventory from config.yaml + short_description: Get YDB inventory from config.yaml description: | This inventory plugin fetches hosts from a custom source (config.yaml). options: plugin: - description: The name of the plugin (must be 'ydb_inventory') + description: The name of the plugin (it should always be set to 'ydb_platform.ydb.ydb_inventory') required: true choices: ['ydb_platform.ydb.ydb_inventory'] ydb_config: From 161f4ee226350cc1cf9b9a9d42ba6099d5ec3dc3 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 30 Oct 2025 16:11:46 +0300 Subject: [PATCH 43/53] Changing inventory plugin --- playbooks/format_cluster.yaml | 9 +++++++-- playbooks/format_drives.yaml | 9 +++++++-- plugins/inventory/ydb_inventory.py | 9 +++++---- roles/ydbd_static/tasks/main.yaml | 9 +++++++-- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/playbooks/format_cluster.yaml b/playbooks/format_cluster.yaml index c647171..b4a7065 100644 --- a/playbooks/format_cluster.yaml +++ b/playbooks/format_cluster.yaml @@ -68,9 +68,14 @@ msg: "aborting playbook execution" when: prompt.user_input != "yes" + - name: Register ydb_drives + ansible.builtin.set_fact: + ydb_drives: "{{ ydb_disks }}" + when: ydb_drives is not defined + - name: Erase disk with dd become: true - shell: dd if=/dev/zero of={{ item.name }} bs=1M count=100 status=none - loop: "{{ ydb_disks }}" + shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none + loop: "{{ ydb_drives }}" tags: - format diff --git a/playbooks/format_drives.yaml b/playbooks/format_drives.yaml index f507f49..3f02ab4 100644 --- a/playbooks/format_drives.yaml +++ b/playbooks/format_drives.yaml @@ -30,9 +30,14 @@ msg: "aborting playbook execution" when: prompt.user_input != "yes" + - name: Register ydb_drives + ansible.builtin.set_fact: + ydb_drives: "{{ ydb_disks }}" + when: ydb_drives is not defined + - name: Erase disk with dd become: true - shell: dd if=/dev/zero of={{ item.name }} bs=1M count=100 status=none - loop: "{{ ydb_disks }}" + shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none + loop: "{{ ydb_drives }}" tags: - format diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index f0e6445..032c755 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -27,7 +27,10 @@ class InventoryModule(BaseInventoryPlugin): def verify_file(self, path): # Проверяем, что это конфиг для нашего плагина - valid = super().verify_file(path) + valid = False + if super(InventoryModule, self).verify_file(path): + if path.endswith(('ydb_inventory.yaml', 'ydb_inventory.yml', 'inventory.yaml', 'inventory.yml')): + valid = True return valid def parse(self, inventory, loader, path, cache=True): @@ -98,8 +101,6 @@ def parse(self, inventory, loader, path, cache=True): drive_configs[drive_config['host_config_id']][i]['label'] = label if label in drive_labels: drive_configs[drive_config['host_config_id']][i]['name'] = drive_labels[label] - else: - raise AnsibleError(f"Config parsing error, unable to find disk for label: {label}") # Read hosts and define variables for them if 'hosts' in yaml_config: for host in yaml_config['hosts']: @@ -107,7 +108,7 @@ def parse(self, inventory, loader, path, cache=True): # Set variables for hosts for key, value in host.items(): if key == 'host_config_id': - self.inventory.set_variable(host['host'], 'ydb_disks', drive_configs[value]) + self.inventory.set_variable(host['host'], 'ydb_drives', drive_configs[value]) else: self.inventory.set_variable(host['host'], key, value) if len(brokers) < 3: diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index e162913..419b102 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -181,16 +181,21 @@ msg: "aborting playbook execution" when: prompt.user_input != "yes" +- name: Register ydb_drives + ansible.builtin.set_fact: + ydb_drives: "{{ ydb_disks }}" + when: ydb_drives is not defined + - name: prepare drives ydb_platform.ydb.drive_prepare: - name: "{{ item['name'] }}" + name: "{{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }}" label: "{{ item['label'] }}" ydbd_bin: "{{ ydb_dir }}/bin/ydbd" ld_library_path: "{{ ydb_dir }}/lib" ca_file: "{{ ydb_dir }}/certs/ca.crt" endpoint: "grpcs://{{ ydb_brokers | flatten(levels=1) | first }}:2135" allow_format: "{{ ydb_allow_format_drives }}" - with_items: "{{ ydb_disks }}" + with_items: "{{ ydb_drives }}" become: true - name: generate random temporary config file path for v2 node init From 939d44ca711aafdc200d9cd71289cb1049079e33 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 31 Oct 2025 11:01:15 +0300 Subject: [PATCH 44/53] refactoring inventory --- docs/docsite/extra-docs.yml | 5 +++++ docs/docsite/links.yml | 12 ++++++++++++ plugins/inventory/ydb_inventory.py | 23 +++++++++-------------- 3 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 docs/docsite/extra-docs.yml create mode 100644 docs/docsite/links.yml diff --git a/docs/docsite/extra-docs.yml b/docs/docsite/extra-docs.yml new file mode 100644 index 0000000..226aadd --- /dev/null +++ b/docs/docsite/extra-docs.yml @@ -0,0 +1,5 @@ +--- +sections: +- title: Scenario Guide + toctree: + - scenario_guide diff --git a/docs/docsite/links.yml b/docs/docsite/links.yml new file mode 100644 index 0000000..333a356 --- /dev/null +++ b/docs/docsite/links.yml @@ -0,0 +1,12 @@ +--- + +extra_links: + - description: YDB official website + url: https://ydb.tech + - description: YDB repository + url: https://github.com/ydb-platform/ydb + - description: YDB Ansible Collection repository + url: https://github.com/ydb-platform/ydb-ansible + - description: Examples with YDB Ansible configurations + url: https://github.com/ydb-platform/ydb-ansible-examples + diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 032c755..5964ef6 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -56,18 +56,16 @@ def parse(self, inventory, loader, path, cache=True): self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config) + # Set default database name if it's not defined if 'ydb_dbname' not in ydb_vars and 'ydb_dynnodes' in ydb_vars: for dynnode in ydb_vars['ydb_dynnodes']: if 'dbname' in dynnode: self.inventory.groups['ydb'].set_variable('ydb_dbname',dynnode['dbname']) break - if 'ydb_enforce_user_token_requirement' not in ydb_vars: - if 'domains_config' in yaml_config and 'security_config' in yaml_config['domains_config'] and 'enforce_user_token_requirement' in yaml_config['domains_config']['security_config']: - self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', yaml_config['domains_config']['security_config']['enforce_user_token_requirement']) - else: - self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', False) - + ydb_enforce_user_token_requirement = yaml_config.get('domains_config', {}).get('security_config', {}).get('enforce_user_token_requirement', False) + self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', ydb_enforce_user_token_requirement) + if 'ydb_pool_kind' not in ydb_vars: if 'default_disk_type' in yaml_config: self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['default_disk_type'].lower()) @@ -80,12 +78,10 @@ def parse(self, inventory, loader, path, cache=True): self.inventory.groups['ydb'].set_variable('ydb_config', yaml_config) - if 'ydb_domain' not in ydb_vars: - if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: - self.inventory.groups['ydb'].set_variable('ydb_domain',yaml_config['domains_config']['domain'][0]['name']) - else: - # Default domain is Root - self.inventory.groups['ydb'].set_variable('ydb_domain','Root') + domain = 'Root' + if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: + domain = yaml_config['domains_config']['domain'][0]['name'] + self.inventory.groups['ydb'].set_variable('ydb_domain',domain) # Read drives config drive_configs = {} @@ -114,8 +110,7 @@ def parse(self, inventory, loader, path, cache=True): if len(brokers) < 3: brokers.append(host['host']) - if 'ydb_brokers' not in ydb_vars and len(brokers) > 0: - self.inventory.groups['ydb'].set_variable('ydb_brokers', brokers) + self.inventory.groups['ydb'].set_variable('ydb_brokers', brokers) except Exception as e: raise AnsibleError(f"Config parsing error: {str(e)}") From 79514d1013d692cda7709d478df386f5b0d2a59a Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 31 Oct 2025 11:10:37 +0300 Subject: [PATCH 45/53] + custom group names in inventory --- plugins/inventory/ydb_inventory.py | 31 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 5964ef6..a727a78 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -20,6 +20,11 @@ required: true env: - name: INVENTORY_YDB_CONFIG + ydb_hostgroup_name: + description: The name of group of hosts (default name is 'ydb') + required: false + env: + - name: INVENTORY_YDB_HOSTGROUP_NAME ''' class InventoryModule(BaseInventoryPlugin): @@ -41,11 +46,11 @@ def parse(self, inventory, loader, path, cache=True): ydb_config = config.get('ydb_config') print(f"Reading inventory from {ydb_config}") - group = 'ydb' - self.inventory.add_group(group) + group_name = config.get('ydb_hostgroup_name','ydb') + self.inventory.add_group(group_name) brokers = [] - ydb_vars = self.inventory.groups['ydb'].get_vars() + ydb_vars = self.inventory.groups[group_name].get_vars() try: with open(ydb_config, "r") as file: yaml_config = yaml.safe_load(file) @@ -54,34 +59,34 @@ def parse(self, inventory, loader, path, cache=True): """ V2 Config """ yaml_config = yaml_config['config'] - self.inventory.groups['ydb'].set_variable('ydb_config_dict', yaml_config) + self.inventory.groups[group_name].set_variable('ydb_config_dict', yaml_config) # Set default database name if it's not defined if 'ydb_dbname' not in ydb_vars and 'ydb_dynnodes' in ydb_vars: for dynnode in ydb_vars['ydb_dynnodes']: if 'dbname' in dynnode: - self.inventory.groups['ydb'].set_variable('ydb_dbname',dynnode['dbname']) + self.inventory.groups[group_name].set_variable('ydb_dbname',dynnode['dbname']) break ydb_enforce_user_token_requirement = yaml_config.get('domains_config', {}).get('security_config', {}).get('enforce_user_token_requirement', False) - self.inventory.groups['ydb'].set_variable('ydb_enforce_user_token_requirement', ydb_enforce_user_token_requirement) + self.inventory.groups[group_name].set_variable('ydb_enforce_user_token_requirement', ydb_enforce_user_token_requirement) if 'ydb_pool_kind' not in ydb_vars: if 'default_disk_type' in yaml_config: - self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['default_disk_type'].lower()) + self.inventory.groups[group_name].set_variable('ydb_pool_kind', yaml_config['default_disk_type'].lower()) if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: if 'storage_pool_types' in yaml_config['domains_config']['domain'][0]: - self.inventory.groups['ydb'].set_variable('ydb_pool_kind', yaml_config['domains_config']['domain'][0]['storage_pool_types'][0]['kind']) + self.inventory.groups[group_name].set_variable('ydb_pool_kind', yaml_config['domains_config']['domain'][0]['storage_pool_types'][0]['kind']) if 'self_management_config' in yaml_config and 'enabled' in yaml_config['self_management_config'] and yaml_config['self_management_config']['enabled']: - self.inventory.groups['ydb'].set_variable('ydb_config_v2', True) + self.inventory.groups[group_name].set_variable('ydb_config_v2', True) - self.inventory.groups['ydb'].set_variable('ydb_config', yaml_config) + self.inventory.groups[group_name].set_variable('ydb_config', yaml_config) domain = 'Root' if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: domain = yaml_config['domains_config']['domain'][0]['name'] - self.inventory.groups['ydb'].set_variable('ydb_domain',domain) + self.inventory.groups[group_name].set_variable('ydb_domain',domain) # Read drives config drive_configs = {} @@ -100,7 +105,7 @@ def parse(self, inventory, loader, path, cache=True): # Read hosts and define variables for them if 'hosts' in yaml_config: for host in yaml_config['hosts']: - self.inventory.add_host(host['host'], group=group) + self.inventory.add_host(host['host'], group=group_name) # Set variables for hosts for key, value in host.items(): if key == 'host_config_id': @@ -110,7 +115,7 @@ def parse(self, inventory, loader, path, cache=True): if len(brokers) < 3: brokers.append(host['host']) - self.inventory.groups['ydb'].set_variable('ydb_brokers', brokers) + self.inventory.groups[group_name].set_variable('ydb_brokers', brokers) except Exception as e: raise AnsibleError(f"Config parsing error: {str(e)}") From 61f93ab6dd48e631faa267539106ece989f3d8b2 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Fri, 31 Oct 2025 11:17:02 +0300 Subject: [PATCH 46/53] remove vars definions by default --- plugins/inventory/ydb_inventory.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index a727a78..4d8f4f8 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -60,23 +60,15 @@ def parse(self, inventory, loader, path, cache=True): yaml_config = yaml_config['config'] self.inventory.groups[group_name].set_variable('ydb_config_dict', yaml_config) - - # Set default database name if it's not defined - if 'ydb_dbname' not in ydb_vars and 'ydb_dynnodes' in ydb_vars: - for dynnode in ydb_vars['ydb_dynnodes']: - if 'dbname' in dynnode: - self.inventory.groups[group_name].set_variable('ydb_dbname',dynnode['dbname']) - break ydb_enforce_user_token_requirement = yaml_config.get('domains_config', {}).get('security_config', {}).get('enforce_user_token_requirement', False) self.inventory.groups[group_name].set_variable('ydb_enforce_user_token_requirement', ydb_enforce_user_token_requirement) - if 'ydb_pool_kind' not in ydb_vars: - if 'default_disk_type' in yaml_config: - self.inventory.groups[group_name].set_variable('ydb_pool_kind', yaml_config['default_disk_type'].lower()) - if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: - if 'storage_pool_types' in yaml_config['domains_config']['domain'][0]: - self.inventory.groups[group_name].set_variable('ydb_pool_kind', yaml_config['domains_config']['domain'][0]['storage_pool_types'][0]['kind']) + if 'default_disk_type' in yaml_config: + self.inventory.groups[group_name].set_variable('ydb_pool_kind', yaml_config['default_disk_type'].lower()) + if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: + if 'storage_pool_types' in yaml_config['domains_config']['domain'][0]: + self.inventory.groups[group_name].set_variable('ydb_pool_kind', yaml_config['domains_config']['domain'][0]['storage_pool_types'][0]['kind']) if 'self_management_config' in yaml_config and 'enabled' in yaml_config['self_management_config'] and yaml_config['self_management_config']['enabled']: self.inventory.groups[group_name].set_variable('ydb_config_v2', True) @@ -91,6 +83,7 @@ def parse(self, inventory, loader, path, cache=True): # Read drives config drive_configs = {} drive_labels = {} + if 'ydb_disks' in ydb_vars: for disk in ydb_vars['ydb_disks']: drive_labels[disk['label']] = disk['name'] From d943d6a0a243c2a655b9df67820987b391962b02 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Sat, 1 Nov 2025 17:38:16 +0300 Subject: [PATCH 47/53] Playbook for preparing a drive --- filter_plugins/yaml_filters.py | 4 +-- playbooks/prepare_drives.yaml | 51 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 playbooks/prepare_drives.yaml diff --git a/filter_plugins/yaml_filters.py b/filter_plugins/yaml_filters.py index 0aca94e..dbb7f54 100644 --- a/filter_plugins/yaml_filters.py +++ b/filter_plugins/yaml_filters.py @@ -8,9 +8,9 @@ DOCUMENTATION = r''' name: yaml_filters plugin_type: filter - short_description: short desc + short_description: YAML config parsing description: | - long description + YAML config parsing ''' class FilterModule(object): diff --git a/playbooks/prepare_drives.yaml b/playbooks/prepare_drives.yaml new file mode 100644 index 0000000..1c8bed7 --- /dev/null +++ b/playbooks/prepare_drives.yaml @@ -0,0 +1,51 @@ +--- + +# PLAYBOOK: ydb_platform.ydb.prepare_drives +# PROPOSE : This playbook is designed to format drives for YDB +# +# HOW TO USE: +# Use https://github.com/ydb-platform/ydb-ansible-examples as an example to prepare Ansible +# You will need proper: +# - inventory +# +# EXAMPLE: +# +# ansible-playbook ydb_platform.ydb.prepare_drives --extra-vars "ydb_disk_prepare=ydb_disk_1" +# +# WARNING: +# This will destroy ALL DATA on all drives defined in inventory + +- name: Format storage drives, erase metadata + hosts: "{{ ansible_play_hosts | default('ydb') }}" + become: true + roles: + - role: preflight + + tasks: + + - name: Check variable + run_once: true + ansible.builtin.assert: + that: + - "ydb_disk_prepare is defined" + fail_msg: "Usage: ansible-playbook ydb_platform.ydb.prepare_drives --extra-vars 'ydb_disk_prepare=ydb_disk_1'" + + - name: Register ydb_drives + run_once: true + ansible.builtin.set_fact: + ydb_drives: "{{ ydb_disks }}" + when: ydb_drives is not defined + + - name: "Prepare drive {{ ydb_disk_prepare }}" + ydb_platform.ydb.drive_prepare: + name: "{{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }}" + label: "{{ item['label'] }}" + ydbd_bin: "{{ ydb_dir }}/bin/ydbd" + ld_library_path: "{{ ydb_dir }}/lib" + ca_file: "{{ ydb_dir }}/certs/ca.crt" + endpoint: "grpcs://{{ ydb_brokers | flatten(levels=1) | first }}:2135" + allow_format: true + when: item.label == ydb_disk_prepare + with_items: "{{ ydb_drives }}" + become: true + \ No newline at end of file From 5c6e0c13b07968bbdeca6f5ee690beb7a8bb7978 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Wed, 5 Nov 2025 06:58:28 +0000 Subject: [PATCH 48/53] YDBOPS-13208: Fix restart for dynnodes --- playbooks/restart.yaml | 4 +++ playbooks/rolling_restart_dynamic.yaml | 1 + playbooks/update_executable.yaml | 33 ++++++++++++++----- roles/ydbd_rolling_dynamic/tasks/main.yaml | 1 + .../tasks/restart_dynamic.yaml | 9 +---- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/playbooks/restart.yaml b/playbooks/restart.yaml index ca72e86..2181236 100644 --- a/playbooks/restart.yaml +++ b/playbooks/restart.yaml @@ -28,6 +28,10 @@ - storage - static +- hosts: "{{ ansible_play_hosts | default('ydb') }}" + serial: "{{ ydb_restart_serial | default(1) }}" + + roles: - role: ydbd_rolling_dynamic tags: - database diff --git a/playbooks/rolling_restart_dynamic.yaml b/playbooks/rolling_restart_dynamic.yaml index fda1411..6e04483 100644 --- a/playbooks/rolling_restart_dynamic.yaml +++ b/playbooks/rolling_restart_dynamic.yaml @@ -13,6 +13,7 @@ # - hosts: "{{ groups['ydbd_dynamic'] if 'ydbd_dynamic' in groups else groups['ydb'] }}" + serial: "{{ ydb_restart_serial | default(1) }}" roles: - role: ydbd_rolling_dynamic tags: diff --git a/playbooks/update_executable.yaml b/playbooks/update_executable.yaml index 74be8ad..2ff1d65 100644 --- a/playbooks/update_executable.yaml +++ b/playbooks/update_executable.yaml @@ -1,4 +1,17 @@ --- +# PLAYBOOK: ydb_platform.ydb.update_executable +# PROPOSE : This playbook is designed for updating executable files and restarting cluster +# +# EXAMPLE: +# +# Update and restart all nodes +# ansible-playbook ydb_platform.ydb.update_executable +# +# Only update executable on all nodes +# ansible-playbook ydb_platform.ydb.update_executable -t no_restart +# +# Update and restart all nodes with FORCE mode +# ansible-playbook ydb_platform.ydb.update_executable --extra-vars "availability_mode=force" - name: check if required variables are defined hosts: "{{ ansible_play_hosts | default('ydb') }}" @@ -6,11 +19,11 @@ tasks: - ansible.builtin.assert: that: - - "{{ item.var1 is defined" - fail_msg: "Either {{ item.var1 }} variable is required" + - "{{ item is defined }}" + fail_msg: "Either {{ item }} variable is required" loop: - - { var1: "ydb_cores_static" } - - { var1: "ydb_cores_dynamic" } + - "ydb_cores_static" + - "ydb_cores_dynamic" tags: - storage - static @@ -61,8 +74,10 @@ tags: - no_restart -- name: Restart YDB cluster - become: true - ansible.builtin.import_playbook: restart.yaml - tags: - - restart +- hosts: "{{ ansible_play_hosts | default('ydb') }}" + tasks: + - name: Restart YDB cluster + become: true + ansible.builtin.import_playbook: restart.yaml + tags: + - restart diff --git a/roles/ydbd_rolling_dynamic/tasks/main.yaml b/roles/ydbd_rolling_dynamic/tasks/main.yaml index 8459154..eac438f 100644 --- a/roles/ydbd_rolling_dynamic/tasks/main.yaml +++ b/roles/ydbd_rolling_dynamic/tasks/main.yaml @@ -3,3 +3,4 @@ - name: YDB database nodes rolling restart include_tasks: "restart_dynamic.yaml" + loop: "{{ ydb_dynnodes }}" diff --git a/roles/ydbd_rolling_dynamic/tasks/restart_dynamic.yaml b/roles/ydbd_rolling_dynamic/tasks/restart_dynamic.yaml index a50901e..40624e3 100644 --- a/roles/ydbd_rolling_dynamic/tasks/restart_dynamic.yaml +++ b/roles/ydbd_rolling_dynamic/tasks/restart_dynamic.yaml @@ -2,24 +2,17 @@ # YDB restart dynamic nodes on a single host - name: Restart the dynamic nodes on {{ inventory_hostname }} - throttle: 1 - delay: 5 ansible.builtin.systemd: state: restarted - name: "ydbd-{{ ydb_dbname }}-{{ item.instance }}" + name: "ydbd-{{ item.dbname | default(ydb_dbname, true) }}-{{ item.instance }}" any_errors_fatal: true become: true become_method: sudo become_user: root - loop: "{{ ydb_dynnodes }}" - name: Wait for dynamic nodes on {{ inventory_hostname }} to start listening - throttle: 1 ansible.builtin.wait_for: port: "{{ 2136 + (item.offset | default(ydb_dynnodes.index(item))) }}" - delay: 3 - sleep: 3 - loop: "{{ ydb_dynnodes }}" - name: Additional delay to settle the dynamic nodes ansible.builtin.pause: seconds={{ ydb_dynnode_restart_sleep_seconds | default(5) }} From c2446f0f809d693692b141dde4278cf23504217c Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Wed, 5 Nov 2025 11:30:08 +0300 Subject: [PATCH 49/53] Safe format --- playbooks/format_drives.yaml | 47 +++++++++++++------ playbooks/prepare_drives.yaml | 1 - plugins/inventory/ydb_inventory.py | 13 ++--- plugins/modules/check_drives_presence.py | 60 ++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 23 deletions(-) create mode 100644 plugins/modules/check_drives_presence.py diff --git a/playbooks/format_drives.yaml b/playbooks/format_drives.yaml index 3f02ab4..1186fad 100644 --- a/playbooks/format_drives.yaml +++ b/playbooks/format_drives.yaml @@ -17,27 +17,46 @@ - name: Format storage drives, erase metadata hosts: "{{ ansible_play_hosts | default('ydb') }}" + any_errors_fatal: true tasks: + - name: Register ydb_drives + ansible.builtin.set_fact: + ydb_drives: "{{ ydb_disks }}" + when: ydb_drives is not defined + + - name: "Not all drives described in Ansible configuration" + ansible.builtin.assert: + that: + - "ydb_drives|length <= ydb_disks|length" + fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" + quiet: true + + - name: "Get list of block devices on a host" + command: lsblk -d --noheadings --output NAME + register: local_disks + + - name: Check YDB drives + ydb_platform.ydb.check_drives_presence: + ydb_drives: "{{ ydb_drives }}" + ydb_disks: "{{ ydb_disks }}" + host_drives: "{{ local_disks.stdout_lines }}" + - name: ask user confirmation for format drives ansible.builtin.pause: prompt: 'DATA LOSS: this will cause data loss if not handled with care! Enter "yes" to continue.' register: prompt run_once: true - - name: stop execution - ansible.builtin.fail: - msg: "aborting playbook execution" - when: prompt.user_input != "yes" + # - name: stop execution + # ansible.builtin.fail: + # msg: "aborting playbook execution" + # when: prompt.user_input != "yes" - - name: Register ydb_drives - ansible.builtin.set_fact: - ydb_drives: "{{ ydb_disks }}" - when: ydb_drives is not defined - - name: Erase disk with dd - become: true - shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none - loop: "{{ ydb_drives }}" - tags: - - format + # - name: Erase disk with dd + # become: true + # shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none + # loop: "{{ ydb_drives }}" + # tags: + # - format diff --git a/playbooks/prepare_drives.yaml b/playbooks/prepare_drives.yaml index 1c8bed7..ccf07a8 100644 --- a/playbooks/prepare_drives.yaml +++ b/playbooks/prepare_drives.yaml @@ -31,7 +31,6 @@ fail_msg: "Usage: ansible-playbook ydb_platform.ydb.prepare_drives --extra-vars 'ydb_disk_prepare=ydb_disk_1'" - name: Register ydb_drives - run_once: true ansible.builtin.set_fact: ydb_drives: "{{ ydb_disks }}" when: ydb_drives is not defined diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 4d8f4f8..3d53ebd 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -50,7 +50,6 @@ def parse(self, inventory, loader, path, cache=True): self.inventory.add_group(group_name) brokers = [] - ydb_vars = self.inventory.groups[group_name].get_vars() try: with open(ydb_config, "r") as file: yaml_config = yaml.safe_load(file) @@ -84,17 +83,15 @@ def parse(self, inventory, loader, path, cache=True): drive_configs = {} drive_labels = {} - if 'ydb_disks' in ydb_vars: - for disk in ydb_vars['ydb_disks']: - drive_labels[disk['label']] = disk['name'] if 'host_configs' in yaml_config: for drive_config in yaml_config['host_configs']: drive_configs[drive_config['host_config_id']] = copy.deepcopy(drive_config['drive']) for i, item in enumerate(drive_config['drive']): - label = item['path'].split('/')[-1] - drive_configs[drive_config['host_config_id']][i]['label'] = label - if label in drive_labels: - drive_configs[drive_config['host_config_id']][i]['name'] = drive_labels[label] + if '/dev/disk/by-partlabel/' in item['path']: + label = item['path'].split('/')[-1] + drive_configs[drive_config['host_config_id']][i]['label'] = label + if label in drive_labels: + drive_configs[drive_config['host_config_id']][i]['name'] = drive_labels[label] # Read hosts and define variables for them if 'hosts' in yaml_config: for host in yaml_config['hosts']: diff --git a/plugins/modules/check_drives_presence.py b/plugins/modules/check_drives_presence.py new file mode 100644 index 0000000..3482f1e --- /dev/null +++ b/plugins/modules/check_drives_presence.py @@ -0,0 +1,60 @@ +from ansible.module_utils.basic import AnsibleModule + +DOCUMENTATION = r''' + name: check_drives_presence + plugin_type: module + short_description: Check presence of drives on hosts + description: | + This plugins check that YDB Config drives are described in Ansible config and they present on a host +''' + +def run_module(): + module_args = dict( + ydb_drives=dict(type='list', required=True), + ydb_disks=dict(type='list', required=True), + host_drives=dict(type='list', required=True) + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True + ) + + result = dict( + changed=False, + ) + + ydb_drives = module.params['ydb_drives'] + ydb_disks = module.params['ydb_disks'] + host_drives = module.params['host_drives'] + + errors = [] + ydb_disks_labels = {disk['label']: disk['name'] for disk in ydb_disks} + host_drives_set = set(host_drives) + for drive in ydb_drives: + label = drive.get('label') + if not label: + errors.append("Drive must have a 'label' field.") + continue + + if label not in ydb_disks_labels: + errors.append(f"Label '{label}' is not found in ydb_disks.") + continue + + name = ydb_disks_labels[label] + device_name = name.split('/')[-1] # Extract device name like 'vdb' + + if device_name not in host_drives_set: + errors.append(f"Device '{device_name}' is not found in host_drives.") + + result['changed'] = False + if errors: + module.fail_json(msg="There are problems with drives: " + ",".join(errors)) + + module.exit_json(**result) + +def main(): + run_module() + +if __name__ == '__main__': + main() \ No newline at end of file From b09b0a31179951e034966d056bc42f2ede2b02e1 Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Wed, 5 Nov 2025 12:29:26 +0300 Subject: [PATCH 50/53] Safe format --- playbooks/format_cluster.yaml | 45 ++++++++++++++++++++++--------- playbooks/format_drives.yaml | 24 +++++++++-------- playbooks/prepare_drives.yaml | 21 +++++++++++++++ roles/ydbd_static/tasks/main.yaml | 21 +++++++++++++-- 4 files changed, 85 insertions(+), 26 deletions(-) diff --git a/playbooks/format_cluster.yaml b/playbooks/format_cluster.yaml index b4a7065..7916cc7 100644 --- a/playbooks/format_cluster.yaml +++ b/playbooks/format_cluster.yaml @@ -15,25 +15,26 @@ # WARNING: # This will destroy ALL DATA on all drives defined in inventory # This will delete all `bin` and `cfg` folders for YDB on hosts +# +# REQUIRED SOFTWARE: lsblk, dd, xargs, awk, rm +# - hosts: "{{ ansible_play_hosts | default('ydb') }}" become: true + + roles: + - role: preflight + tasks: - - name: stop services + - name: "Stop services" ansible.builtin.shell: cmd: "systemctl list-units | grep ydbd | awk '{print $1;}' | xargs systemctl stop" ignore_errors: True tags: - services -- hosts: "{{ ansible_play_hosts | default('ydb') }}" - become: true - roles: - - role: preflight - - tasks: - - name: Remove config dir + - name: "Remove config dir" ansible.builtin.file: path: "{{ ydb_dir }}/cfg" state: absent @@ -53,27 +54,45 @@ tags: - services -- name: Format storage drives, erase metadata +- name: "Format storage drives, erase metadata " hosts: "{{ groups['ydbd_static'] if 'ydbd_static' in groups else groups['ydb'] }}" + any_errors_fatal: true tasks: - - name: ask user confirmation for format drives + - name: "Not all drives described in Ansible configuration" + ansible.builtin.assert: + that: + - "ydb_drives|length <= ydb_disks|length" + fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" + quiet: true + + - name: "Get list of block devices on a host" + command: lsblk -d --noheadings --output NAME + register: local_disks + + - name: "Check YDB drives" + ydb_platform.ydb.check_drives_presence: + ydb_drives: "{{ ydb_drives }}" + ydb_disks: "{{ ydb_disks }}" + host_drives: "{{ local_disks.stdout_lines }}" + + - name: "Ask user confirmation for format drives" ansible.builtin.pause: prompt: 'DATA LOSS: this will cause data loss if not handled with care! Enter "yes" to continue.' register: prompt run_once: true - - name: stop execution + - name: "Stop execution" ansible.builtin.fail: msg: "aborting playbook execution" when: prompt.user_input != "yes" - - name: Register ydb_drives + - name: "Register ydb_drives" ansible.builtin.set_fact: ydb_drives: "{{ ydb_disks }}" when: ydb_drives is not defined - - name: Erase disk with dd + - name: "Erase disk with dd" become: true shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none loop: "{{ ydb_drives }}" diff --git a/playbooks/format_drives.yaml b/playbooks/format_drives.yaml index 1186fad..f78e4a1 100644 --- a/playbooks/format_drives.yaml +++ b/playbooks/format_drives.yaml @@ -14,6 +14,9 @@ # # WARNING: # This will destroy ALL DATA on all drives defined in inventory +# +# REQUIRED SOFTWARE: lsblk, dd +# - name: Format storage drives, erase metadata hosts: "{{ ansible_play_hosts | default('ydb') }}" @@ -48,15 +51,14 @@ register: prompt run_once: true - # - name: stop execution - # ansible.builtin.fail: - # msg: "aborting playbook execution" - # when: prompt.user_input != "yes" - + - name: stop execution + ansible.builtin.fail: + msg: "aborting playbook execution" + when: prompt.user_input != "yes" - # - name: Erase disk with dd - # become: true - # shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none - # loop: "{{ ydb_drives }}" - # tags: - # - format + - name: Erase disk with dd + become: true + shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none + loop: "{{ ydb_drives }}" + tags: + - format diff --git a/playbooks/prepare_drives.yaml b/playbooks/prepare_drives.yaml index ccf07a8..6f88951 100644 --- a/playbooks/prepare_drives.yaml +++ b/playbooks/prepare_drives.yaml @@ -14,9 +14,13 @@ # # WARNING: # This will destroy ALL DATA on all drives defined in inventory +# +# REQUIRED SOFTWARE: lsblk, dd +# - name: Format storage drives, erase metadata hosts: "{{ ansible_play_hosts | default('ydb') }}" + any_errors_fatal: true become: true roles: - role: preflight @@ -35,6 +39,23 @@ ydb_drives: "{{ ydb_disks }}" when: ydb_drives is not defined + - name: "Not all drives described in Ansible configuration" + ansible.builtin.assert: + that: + - "ydb_drives|length <= ydb_disks|length" + fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" + quiet: true + + - name: "Get list of block devices on a host" + command: lsblk -d --noheadings --output NAME + register: local_disks + + - name: "Check YDB drives" + ydb_platform.ydb.check_drives_presence: + ydb_drives: "{{ ydb_drives }}" + ydb_disks: "{{ ydb_disks }}" + host_drives: "{{ local_disks.stdout_lines }}" + - name: "Prepare drive {{ ydb_disk_prepare }}" ydb_platform.ydb.drive_prepare: name: "{{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }}" diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index 419b102..f62270b 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -181,12 +181,29 @@ msg: "aborting playbook execution" when: prompt.user_input != "yes" -- name: Register ydb_drives +- name: "Register ydb_drives" ansible.builtin.set_fact: ydb_drives: "{{ ydb_disks }}" when: ydb_drives is not defined -- name: prepare drives +- name: "Not all drives described in Ansible configuration" + ansible.builtin.assert: + that: + - "ydb_drives|length <= ydb_disks|length" + fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" + quiet: true + +- name: "Get list of block devices on a host" + command: lsblk -d --noheadings --output NAME + register: local_disks + +- name: "Check YDB drives" + ydb_platform.ydb.check_drives_presence: + ydb_drives: "{{ ydb_drives }}" + ydb_disks: "{{ ydb_disks }}" + host_drives: "{{ local_disks.stdout_lines }}" + +- name: "Prepare drives" ydb_platform.ydb.drive_prepare: name: "{{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }}" label: "{{ item['label'] }}" From e2815b5d74aecb71f3a39a7b017893d3d0912fef Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Wed, 5 Nov 2025 12:32:39 +0300 Subject: [PATCH 51/53] Safe format --- playbooks/format_cluster.yaml | 2 +- playbooks/format_drives.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/playbooks/format_cluster.yaml b/playbooks/format_cluster.yaml index 7916cc7..355876f 100644 --- a/playbooks/format_cluster.yaml +++ b/playbooks/format_cluster.yaml @@ -94,7 +94,7 @@ - name: "Erase disk with dd" become: true - shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none + shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join(),"/dev/null") }} bs=1M count=100 status=none loop: "{{ ydb_drives }}" tags: - format diff --git a/playbooks/format_drives.yaml b/playbooks/format_drives.yaml index f78e4a1..f64baf5 100644 --- a/playbooks/format_drives.yaml +++ b/playbooks/format_drives.yaml @@ -58,7 +58,7 @@ - name: Erase disk with dd become: true - shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }} bs=1M count=100 status=none + shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join(),"/dev/null") }} bs=1M count=100 status=none loop: "{{ ydb_drives }}" tags: - format From 31ebf16664b647aafa78ffbc1f5ddc632735782c Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Wed, 5 Nov 2025 12:44:52 +0300 Subject: [PATCH 52/53] Safe format + docs in inventory --- playbooks/format_cluster.yaml | 1 + playbooks/format_drives.yaml | 1 + plugins/inventory/ydb_inventory.py | 15 +++++++++------ roles/ydbd_static/tasks/main.yaml | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/playbooks/format_cluster.yaml b/playbooks/format_cluster.yaml index 355876f..2a167fd 100644 --- a/playbooks/format_cluster.yaml +++ b/playbooks/format_cluster.yaml @@ -63,6 +63,7 @@ ansible.builtin.assert: that: - "ydb_drives|length <= ydb_disks|length" + - "ydb_drives|length > 0" fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" quiet: true diff --git a/playbooks/format_drives.yaml b/playbooks/format_drives.yaml index f64baf5..6701969 100644 --- a/playbooks/format_drives.yaml +++ b/playbooks/format_drives.yaml @@ -32,6 +32,7 @@ ansible.builtin.assert: that: - "ydb_drives|length <= ydb_disks|length" + - "ydb_drives|length > 0" fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" quiet: true diff --git a/plugins/inventory/ydb_inventory.py b/plugins/inventory/ydb_inventory.py index 3d53ebd..5212e7f 100644 --- a/plugins/inventory/ydb_inventory.py +++ b/plugins/inventory/ydb_inventory.py @@ -14,15 +14,18 @@ plugin: description: The name of the plugin (it should always be set to 'ydb_platform.ydb.ydb_inventory') required: true + type: str choices: ['ydb_platform.ydb.ydb_inventory'] ydb_config: description: YDB config (file or dictionary) required: true + type: str env: - name: INVENTORY_YDB_CONFIG ydb_hostgroup_name: - description: The name of group of hosts (default name is 'ydb') + description: The name of group of hosts required: false + default: 'ydb' env: - name: INVENTORY_YDB_HOSTGROUP_NAME ''' @@ -59,7 +62,7 @@ def parse(self, inventory, loader, path, cache=True): yaml_config = yaml_config['config'] self.inventory.groups[group_name].set_variable('ydb_config_dict', yaml_config) - + ydb_enforce_user_token_requirement = yaml_config.get('domains_config', {}).get('security_config', {}).get('enforce_user_token_requirement', False) self.inventory.groups[group_name].set_variable('ydb_enforce_user_token_requirement', ydb_enforce_user_token_requirement) @@ -73,12 +76,12 @@ def parse(self, inventory, loader, path, cache=True): self.inventory.groups[group_name].set_variable('ydb_config_v2', True) self.inventory.groups[group_name].set_variable('ydb_config', yaml_config) - + domain = 'Root' if 'domains_config' in yaml_config and 'domain' in yaml_config['domains_config']: domain = yaml_config['domains_config']['domain'][0]['name'] self.inventory.groups[group_name].set_variable('ydb_domain',domain) - + # Read drives config drive_configs = {} drive_labels = {} @@ -104,9 +107,9 @@ def parse(self, inventory, loader, path, cache=True): self.inventory.set_variable(host['host'], key, value) if len(brokers) < 3: brokers.append(host['host']) - + self.inventory.groups[group_name].set_variable('ydb_brokers', brokers) - + except Exception as e: raise AnsibleError(f"Config parsing error: {str(e)}") diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index f62270b..e90a317 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -190,6 +190,7 @@ ansible.builtin.assert: that: - "ydb_drives|length <= ydb_disks|length" + - "ydb_drives|length > 0" fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" quiet: true From b4ed33573a820b83e9e6e1773b648e4b36ed318c Mon Sep 17 00:00:00 2001 From: Eugene Arbatsky Date: Thu, 6 Nov 2025 10:44:13 +0300 Subject: [PATCH 53/53] Refactoring for drives --- playbooks/format_cluster.yaml | 46 +++-------------------- playbooks/format_drives.yaml | 46 +++-------------------- playbooks/prepare_drives.yaml | 42 ++++----------------- roles/format_drives/meta/main.yaml | 1 + roles/format_drives/tasks/main.yaml | 58 +++++++++++++++++++++++++++++ roles/ydbd_static/tasks/main.yaml | 52 +++----------------------- 6 files changed, 83 insertions(+), 162 deletions(-) create mode 100644 roles/format_drives/meta/main.yaml create mode 100644 roles/format_drives/tasks/main.yaml diff --git a/playbooks/format_cluster.yaml b/playbooks/format_cluster.yaml index 2a167fd..5d2a699 100644 --- a/playbooks/format_cluster.yaml +++ b/playbooks/format_cluster.yaml @@ -57,45 +57,9 @@ - name: "Format storage drives, erase metadata " hosts: "{{ groups['ydbd_static'] if 'ydbd_static' in groups else groups['ydb'] }}" any_errors_fatal: true - tasks: - - - name: "Not all drives described in Ansible configuration" - ansible.builtin.assert: - that: - - "ydb_drives|length <= ydb_disks|length" - - "ydb_drives|length > 0" - fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" - quiet: true - - - name: "Get list of block devices on a host" - command: lsblk -d --noheadings --output NAME - register: local_disks - - - name: "Check YDB drives" - ydb_platform.ydb.check_drives_presence: - ydb_drives: "{{ ydb_drives }}" - ydb_disks: "{{ ydb_disks }}" - host_drives: "{{ local_disks.stdout_lines }}" - - - name: "Ask user confirmation for format drives" - ansible.builtin.pause: - prompt: 'DATA LOSS: this will cause data loss if not handled with care! Enter "yes" to continue.' - register: prompt - run_once: true - - - name: "Stop execution" - ansible.builtin.fail: - msg: "aborting playbook execution" - when: prompt.user_input != "yes" - - - name: "Register ydb_drives" - ansible.builtin.set_fact: - ydb_drives: "{{ ydb_disks }}" - when: ydb_drives is not defined + vars: + ydb_format_disk: True + ydb_format_disk_prepare: False + roles: - - name: "Erase disk with dd" - become: true - shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join(),"/dev/null") }} bs=1M count=100 status=none - loop: "{{ ydb_drives }}" - tags: - - format + - role: ydb_platform.ydb.format_drives \ No newline at end of file diff --git a/playbooks/format_drives.yaml b/playbooks/format_drives.yaml index 6701969..8083cf6 100644 --- a/playbooks/format_drives.yaml +++ b/playbooks/format_drives.yaml @@ -21,45 +21,11 @@ - name: Format storage drives, erase metadata hosts: "{{ ansible_play_hosts | default('ydb') }}" any_errors_fatal: true - tasks: + vars: + ydb_format_disk: True + ydb_format_disk_prepare: False - - name: Register ydb_drives - ansible.builtin.set_fact: - ydb_drives: "{{ ydb_disks }}" - when: ydb_drives is not defined + roles: - - name: "Not all drives described in Ansible configuration" - ansible.builtin.assert: - that: - - "ydb_drives|length <= ydb_disks|length" - - "ydb_drives|length > 0" - fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" - quiet: true - - - name: "Get list of block devices on a host" - command: lsblk -d --noheadings --output NAME - register: local_disks - - - name: Check YDB drives - ydb_platform.ydb.check_drives_presence: - ydb_drives: "{{ ydb_drives }}" - ydb_disks: "{{ ydb_disks }}" - host_drives: "{{ local_disks.stdout_lines }}" - - - name: ask user confirmation for format drives - ansible.builtin.pause: - prompt: 'DATA LOSS: this will cause data loss if not handled with care! Enter "yes" to continue.' - register: prompt - run_once: true - - - name: stop execution - ansible.builtin.fail: - msg: "aborting playbook execution" - when: prompt.user_input != "yes" - - - name: Erase disk with dd - become: true - shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join(),"/dev/null") }} bs=1M count=100 status=none - loop: "{{ ydb_drives }}" - tags: - - format + - role: ydb_platform.ydb.format_drives + \ No newline at end of file diff --git a/playbooks/prepare_drives.yaml b/playbooks/prepare_drives.yaml index 6f88951..1641e35 100644 --- a/playbooks/prepare_drives.yaml +++ b/playbooks/prepare_drives.yaml @@ -22,6 +22,10 @@ hosts: "{{ ansible_play_hosts | default('ydb') }}" any_errors_fatal: true become: true + vars: + ydb_format_disk: False + ydb_format_disk_prepare: True + roles: - role: preflight @@ -34,38 +38,6 @@ - "ydb_disk_prepare is defined" fail_msg: "Usage: ansible-playbook ydb_platform.ydb.prepare_drives --extra-vars 'ydb_disk_prepare=ydb_disk_1'" - - name: Register ydb_drives - ansible.builtin.set_fact: - ydb_drives: "{{ ydb_disks }}" - when: ydb_drives is not defined - - - name: "Not all drives described in Ansible configuration" - ansible.builtin.assert: - that: - - "ydb_drives|length <= ydb_disks|length" - fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" - quiet: true - - - name: "Get list of block devices on a host" - command: lsblk -d --noheadings --output NAME - register: local_disks - - - name: "Check YDB drives" - ydb_platform.ydb.check_drives_presence: - ydb_drives: "{{ ydb_drives }}" - ydb_disks: "{{ ydb_disks }}" - host_drives: "{{ local_disks.stdout_lines }}" - - - name: "Prepare drive {{ ydb_disk_prepare }}" - ydb_platform.ydb.drive_prepare: - name: "{{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }}" - label: "{{ item['label'] }}" - ydbd_bin: "{{ ydb_dir }}/bin/ydbd" - ld_library_path: "{{ ydb_dir }}/lib" - ca_file: "{{ ydb_dir }}/certs/ca.crt" - endpoint: "grpcs://{{ ydb_brokers | flatten(levels=1) | first }}:2135" - allow_format: true - when: item.label == ydb_disk_prepare - with_items: "{{ ydb_drives }}" - become: true - \ No newline at end of file + - name: Prepare drives + ansible.builtin.import_role: + name: ydb_platform.ydb.format_drives \ No newline at end of file diff --git a/roles/format_drives/meta/main.yaml b/roles/format_drives/meta/main.yaml new file mode 100644 index 0000000..dd7ee2d --- /dev/null +++ b/roles/format_drives/meta/main.yaml @@ -0,0 +1 @@ +allow_duplicates: false \ No newline at end of file diff --git a/roles/format_drives/tasks/main.yaml b/roles/format_drives/tasks/main.yaml new file mode 100644 index 0000000..dc57edf --- /dev/null +++ b/roles/format_drives/tasks/main.yaml @@ -0,0 +1,58 @@ +--- + +- name: "Register ydb_drives" + ansible.builtin.set_fact: + ydb_drives: "{{ ydb_disks }}" + when: ydb_drives is not defined + +- name: "Not all drives described in Ansible configuration" + ansible.builtin.assert: + that: + - "ydb_drives|length <= ydb_disks|length" + fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" + quiet: true + +- name: "Get list of block devices on a host" + command: lsblk -d --noheadings --output NAME + register: local_disks + +- name: "Check YDB drives" + ydb_platform.ydb.check_drives_presence: + ydb_drives: "{{ ydb_drives }}" + ydb_disks: "{{ ydb_disks }}" + host_drives: "{{ local_disks.stdout_lines }}" + +- name: format drives confirmation block + when: ydb_allow_format_drives and not ydb_skip_data_loss_confirmation_prompt + block: + - name: ask user confirmation for format drives + ansible.builtin.pause: + prompt: 'RISK OF DATA LOSS: "ydb_allow_format_drives" is set to "true": this may cause data loss if not handled with care! Enter "yes" to continue.' + register: prompt + run_once: true + + - name: stop execution + ansible.builtin.fail: + msg: "aborting playbook execution" + when: prompt.user_input != "yes" + +- name: "Erase disk with dd" + become: true + shell: dd if=/dev/zero of={{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join(),"/dev/null") }} bs=1M count=100 status=none + loop: "{{ ydb_drives }}" + when: ydb_format_disk|bool is defined and ydb_format_disk|bool == True + tags: + - format + +- name: "Prepare drives" + ydb_platform.ydb.drive_prepare: + name: "{{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }}" + label: "{{ item['label'] }}" + ydbd_bin: "{{ ydb_dir }}/bin/ydbd" + ld_library_path: "{{ ydb_dir }}/lib" + ca_file: "{{ ydb_dir }}/certs/ca.crt" + endpoint: "grpcs://{{ ydb_brokers | flatten(levels=1) | first }}:2135" + allow_format: "{{ ydb_allow_format_drives }}" + with_items: "{{ ydb_drives }}" + when: ydb_format_disk_prepare|bool is defined and ydb_format_disk_prepare|bool == True + become: true \ No newline at end of file diff --git a/roles/ydbd_static/tasks/main.yaml b/roles/ydbd_static/tasks/main.yaml index e90a317..fcb192d 100644 --- a/roles/ydbd_static/tasks/main.yaml +++ b/roles/ydbd_static/tasks/main.yaml @@ -167,54 +167,14 @@ - name: flush handlers meta: flush_handlers -- name: format drives confirmation block - when: ydb_allow_format_drives and not ydb_skip_data_loss_confirmation_prompt - block: - - name: ask user confirmation for format drives - ansible.builtin.pause: - prompt: 'RISK OF DATA LOSS: "ydb_allow_format_drives" is set to "true": this may cause data loss if not handled with care! Enter "yes" to continue.' - register: prompt - run_once: true - - - name: stop execution - ansible.builtin.fail: - msg: "aborting playbook execution" - when: prompt.user_input != "yes" - -- name: "Register ydb_drives" +- name: Set variable ansible.builtin.set_fact: - ydb_drives: "{{ ydb_disks }}" - when: ydb_drives is not defined + ydb_format_disk: False + ydb_format_disk_prepare: True -- name: "Not all drives described in Ansible configuration" - ansible.builtin.assert: - that: - - "ydb_drives|length <= ydb_disks|length" - - "ydb_drives|length > 0" - fail_msg: "YDB Config for {{ inventory_hostname }} has more drives than Ansible configuration" - quiet: true - -- name: "Get list of block devices on a host" - command: lsblk -d --noheadings --output NAME - register: local_disks - -- name: "Check YDB drives" - ydb_platform.ydb.check_drives_presence: - ydb_drives: "{{ ydb_drives }}" - ydb_disks: "{{ ydb_disks }}" - host_drives: "{{ local_disks.stdout_lines }}" - -- name: "Prepare drives" - ydb_platform.ydb.drive_prepare: - name: "{{ item.name | default(ydb_disks|selectattr('label','match',item.label)|map(attribute='name')|join()) }}" - label: "{{ item['label'] }}" - ydbd_bin: "{{ ydb_dir }}/bin/ydbd" - ld_library_path: "{{ ydb_dir }}/lib" - ca_file: "{{ ydb_dir }}/certs/ca.crt" - endpoint: "grpcs://{{ ydb_brokers | flatten(levels=1) | first }}:2135" - allow_format: "{{ ydb_allow_format_drives }}" - with_items: "{{ ydb_drives }}" - become: true +- name: Format drives + ansible.builtin.import_role: + name: ydb_platform.ydb.format_drives - name: generate random temporary config file path for v2 node init set_fact: