From a918f6e3b435e2fc899e03f89206914d2957cb6c Mon Sep 17 00:00:00 2001 From: Raphael Lima Date: Thu, 21 Mar 2024 16:17:03 -0300 Subject: [PATCH] Move sysinv bootstrap from Puppet to Ansible Add sysinv_bootstrap task file to apply_bootstrap_manifest role to reduce bootstrap time. The corresponding sysinv bootstrap implementation in puppet will be removed. Changes include: - Create a template for sysinv.conf and sysinv/api-paste.ini files - Ensure the installation of sysinv packages - Ensure the execution of sysinv-api, sysinv-conductor and sysinv-agent services Test plan: 1. PASS: Deploy a DC system with one system controller and two subclouds and ensure the subclouds can be managed 2. PASS: Deploy an AIO-SX system and verify the host unlocks 3. PASS: Perform bootstrap replay and ensure the host unlocks after re-execution 4. PASS: Verify the openstack user, role, service and endpoints configuration for sysinv after bootstrap for each deployment type 5. PASS: Verify the sysinv.conf and api-paste.ini file for each deployment type 6. PASS: Validate the sql dump of the keystone database generated in a subcloud deployment in relation to the one generated before the changes Depends-On: https://review.opendev.org/c/starlingx/config/+/915365 Story: 2011035 Task: 49764 Change-Id: I7cc9b7d45b770b454178da3f6c974bdbf7fc1e57 Signed-off-by: Raphael Lima --- .../files/create_sysinv_endpoints.py | 125 +++++++++++++ .../tasks/apply_bootstrap_manifest.yml | 9 +- .../apply-manifest/tasks/sysinv_bootstrap.yml | 176 ++++++++++++++++++ .../apply-manifest/templates/api-paste.ini.j2 | 2 +- .../templates/sysinv/api-paste.ini.j2 | 9 + .../templates/sysinv/sysinv.conf.j2 | 86 +++++++++ 6 files changed, 403 insertions(+), 4 deletions(-) create mode 100644 playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/files/create_sysinv_endpoints.py create mode 100644 playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/tasks/sysinv_bootstrap.yml create mode 100644 playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/sysinv/api-paste.ini.j2 create mode 100644 playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/sysinv/sysinv.conf.j2 diff --git a/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/files/create_sysinv_endpoints.py b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/files/create_sysinv_endpoints.py new file mode 100644 index 000000000..1eafb9518 --- /dev/null +++ b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/files/create_sysinv_endpoints.py @@ -0,0 +1,125 @@ +#!/usr/bin/python +# +# Copyright (c) 2024 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +""" +Creates the sysinv's user, grant it admin role and setup its services and endpoints. +After the setup, the ignore_lockout_failure_attempts option is set up for both the +sysinv and admin users. + +It's necessary to perform the sysinv endpoint creation outside the +openstack_config_endpoints.py script because all of the other endpoints are created +in sysinv, requiring it to be configured priorly in order to provide access to the +API. +""" + +import os +import sys +from subprocess import Popen, PIPE + +from sysinv.common import openstack_config_endpoints + +from keystoneauth1 import loading, session +from keystoneclient.v3 import client + + +SYSINV_USER_TO_CREATE = [ + { + "name": "sysinv", + "password": "", + "email": "sysinv@localhost", + } +] + +SERVICES_TO_CREATE = [ + { + "name": "sysinv", + "description": "SysInvService", + "type": "platform", + } +] + +ENDPOINTS_TO_CREATE = [ + { + "service": "sysinv", + "region": "RegionOne", + "endpoints": { + "admin": "http://127.0.0.1:6385/v1/", + "internal": "http://127.0.0.1:6385/v1/", + "public": "http://127.0.0.1:6385/v1/" + } + } +] + +IGNORE_LOCKOUT_FAILURE_ATTEMPTS_OPTION = {"ignore_lockout_failure_attempts": True} + + +def _retrieve_environment_variables(username, password): + with open(os.devnull, "w") as fnull: + process = Popen( + ["bash", "-c", "source /etc/platform/openrc --no_credentials && env"], + stdout=PIPE, stderr=fnull, universal_newlines=True + ) + + env_vars = {} + env_vars["username"] = username + env_vars["password"] = password + env_vars["user_domain_name"] = "Default" + env_vars["project_domain_name"] = "Default" + + for line in process.stdout: + key, _, value = line.partition("=") + if key == "OS_AUTH_URL": + env_vars["auth_url"] = value.strip() + elif key == "OS_REGION_NAME": + env_vars["region_name"] = value.strip() + elif key == "OS_PROJECT_NAME": + env_vars["project_name"] = value.strip() + elif key == "OS_USER_DOMAIN_NAME": + env_vars["user_domain_name"] = value.strip() + elif key == "OS_PROJECT_DOMAIN_NAME": + env_vars["project_domain_name"] = value.strip() + + process.communicate() + + return env_vars + + +def _generate_auth(env_vars): + loader = loading.get_plugin_loader("password") + + return loader.load_from_options( + auth_url=env_vars["auth_url"], username=env_vars["username"], + password=env_vars["password"], project_name=env_vars["project_name"], + user_domain_name=env_vars["user_domain_name"], + project_domain_name=env_vars["project_domain_name"] + ) + + +def _create_keystone_client(env_vars): + return client.Client(session=session.Session(auth=_generate_auth(env_vars))) + + +if __name__ == "__main__": + username = sys.argv[1] + password = sys.argv[2] + SYSINV_USER_TO_CREATE[0]["password"] = sys.argv[3] + admin_username = sys.argv[4] + + env_vars = _retrieve_environment_variables(username, password) + ENDPOINTS_TO_CREATE[0]["region"] = env_vars["region_name"] + + keystone = _create_keystone_client(env_vars) + + openstack_config_endpoints.create_users(keystone, SYSINV_USER_TO_CREATE) + openstack_config_endpoints.grant_admin_role( + keystone, SYSINV_USER_TO_CREATE, "services" + ) + openstack_config_endpoints.create_services(keystone, SERVICES_TO_CREATE) + openstack_config_endpoints.create_endpoints(keystone, ENDPOINTS_TO_CREATE) + openstack_config_endpoints.set_users_options( + keystone, ["sysinv", admin_username], IGNORE_LOCKOUT_FAILURE_ATTEMPTS_OPTION + ) diff --git a/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/tasks/apply_bootstrap_manifest.yml b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/tasks/apply_bootstrap_manifest.yml index cf0a51201..faaf7bc7b 100644 --- a/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/tasks/apply_bootstrap_manifest.yml +++ b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/tasks/apply_bootstrap_manifest.yml @@ -320,10 +320,13 @@ for details. when: bootstrap_manifest.rc != 0 -- name: Configure Barbican bootstrap +- name: Import barbican bootstrap tasks import_tasks: barbican_bootstrap.yml -- name: Import mtce bootstrap +- name: Import sysinv bootstrap tasks + import_tasks: sysinv_bootstrap.yml + +- name: Import mtce bootstrap tasks import_tasks: mtce_bootstrap.yml - block: @@ -338,7 +341,7 @@ become_user: postgres when: distributed_cloud_role == 'subcloud' -- name: Prepare FM Manager +- name: Import fm bootstrap tasks import_tasks: fm_bootstrap.yml - name: Remove runtime hieradata diff --git a/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/tasks/sysinv_bootstrap.yml b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/tasks/sysinv_bootstrap.yml new file mode 100644 index 000000000..04b3ac5c0 --- /dev/null +++ b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/tasks/sysinv_bootstrap.yml @@ -0,0 +1,176 @@ +--- +# +# Copyright (c) 2024 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# SUB-TASK DESCRIPTION: +# These tasks create and configure sysinv. +# +# Steps: +# - Store sysinv's variables and convert them to a dictionary +# - Create the database connection string and setup the database and user +# - Setup sysinv's openstack user, role, service and enpoint and set the +# ignore_lockout_failure_attempts option to true for both sysinv and admin users +# - Update the database's actor_id and user id to match the system controller's +# when bootstrapping a subcloud +# - Ensure sysinv-agent is running and enabled +# - Configure sysinv's group, user and directory +# - Generate sysinv.conf and api-paste.ini +# - Check controller's software version +# - Execute sysinv-dbsync +# - Ensure sysinv-api, sysinv-conductor and sysinv-agent are running and enabled + +- name: Retrieve sysinv's variables + shell: >- + grep -h "sysinv::" secure_static.yaml static.yaml && + grep -h "keystone::roles::admin::admin_tenant:" personality.yaml && + grep -h "platform::client::params::admin_username" static.yaml && + grep -h "platform::client::params::admin_password:" secure_static.yaml && + grep -h "platform::client::params::identity_auth_url" personality.yaml + args: + chdir: /tmp/puppet/hieradata + register: sysinv_variables + +- name: Convert sysinv variables to a dictionary + set_fact: + sysinv_var_dict: "{{ sysinv_variables.stdout | from_yaml }}" + +- name: Create database connection string + set_fact: + database_connection: "{{ sysinv_var_dict['sysinv::database_connection'] | + regex_replace('^postgresql:', 'postgresql+psycopg2:') }}" + +- name: Ensure PostgreSQL database and user are created + postgresql_db: + name: sysinv + state: present + +- name: Set PostgreSQL user password + postgresql_user: + db: sysinv + name: "{{ sysinv_var_dict['sysinv::db::postgresql::user'] }}" + password: "{{ sysinv_var_dict['sysinv::db::postgresql::password'] }}" + priv: ALL + +- name: Create sysinv endpoints + script: > + create_sysinv_endpoints.py {{ OS_USERNAME }} {{ OS_PASSWORD }} {{ sysinv_password }} {{ admin_username }} + vars: + - OS_USERNAME: "{{ sysinv_var_dict['keystone::roles::admin::admin_tenant'] }}" + - OS_PASSWORD: "{{ sysinv_var_dict['platform::client::params::admin_password'] }}" + - sysinv_password: "{{ sysinv_var_dict['sysinv::api::keystone_password'] }}" + - admin_username: "{{ sysinv_var_dict['platform::client::params::admin_username'] }}" + +- block: + - name: Retrieve dc_sysinv_user_id_dict + command: grep -h "platform::sysinv::bootstrap::dc_sysinv_user_id" static.yaml + args: + chdir: /tmp/puppet/hieradata + register: dc_sysinv_user_id_yaml + + - name: Store dc_sysinv_user_id_dict + set_fact: + dc_sysinv_user_id_dict: "{{ dc_sysinv_user_id_yaml.stdout | from_yaml }}" + + - name: Store dc_sysinv_user_id + set_fact: + dc_sysinv_user_id: "{{ dc_sysinv_user_id_dict['platform::sysinv::bootstrap::dc_sysinv_user_id'] }}" + + - name: Update keystone sysinv assignment actor_id to match system controller + command: >- + psql -d keystone -c "update public.assignment set actor_id='{{ dc_sysinv_user_id }}' + from public.local_user where public.assignment.actor_id=public.local_user.user_id and + public.local_user.name='sysinv'" + become_user: postgres + + # The create_sysinv_endpoints.py as the last step, configures the + # ignore_lockout_failure_attempts option for both the sysinv and admin users, + # which creates entries in the public.user_option table. + # Because its foreign key does not have the on update cascade configuration, + # it's necessary to remove it, update the tables and recreate the constraint. + - name: Update keystone sysinv user id to match system controller + command: >- + psql -d keystone + -c "alter table public.user_option drop constraint user_option_user_id_fkey" + -c "update public.user_option set user_id='{{ dc_sysinv_user_id }}' from + public.local_user where public.local_user.user_id=public.user_option.user_id + and public.local_user.name='sysinv'" + -c "update public.user set id='{{ dc_sysinv_user_id }}' + from public.local_user where public.user.id=public.local_user.user_id and + public.local_user.name='sysinv'" + -c "alter table public.user_option add constraint user_option_user_id_fkey + foreign key (user_id) references public."user"(id) on delete cascade" + become_user: postgres + when: distributed_cloud_role == "subcloud" + +- name: Configure sysinv group + group: + name: sysinv + state: present + gid: 168 + +- name: Configure sysinv user + user: + name: sysinv + state: present + comment: sysinv Daemons + group: sysinv + groups: nobody, sysinv, sys_protected + home: /var/lib/sysinv + shell: /sbin/nologin + uid: 168 + +- name: Configure sysinv directory + file: + path: /etc/sysinv + state: directory + owner: sysinv + group: sysinv + mode: 0750 + +- name: Generate sysinv.conf + template: + src: sysinv/sysinv.conf.j2 + dest: /etc/sysinv/sysinv.conf + owner: sysinv + group: sysinv + mode: 0600 + +- name: Generate api-paste.ini + template: + src: sysinv/api-paste.ini.j2 + dest: /etc/sysinv/api-paste.ini + owner: sysinv + group: sysinv + mode: 0600 + +- name: Check if controllers software version mismatch + command: echo $CONTROLLER_SW_VERSIONS_MISMATCH + register: controller_sw_versions_mismatch + +- name: Execute sysinv-dbsync + command: + cmd: sysinv-dbsync + chdir: /usr/bin + become: true + become_user: sysinv + when: controller_sw_versions_mismatch.stdout != 'true' + +- name: Ensure sysinv-api service is running and enabled + service: + name: sysinv-api + state: started + enabled: yes + +- name: Ensure sysinv-conductor service is running and enabled + systemd: + name: sysinv-conductor + state: started + enabled: yes + +- name: Ensure sysinv-agent service is running and enabled + service: + name: sysinv-agent + state: started + enabled: yes diff --git a/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/api-paste.ini.j2 b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/api-paste.ini.j2 index ff0dd680e..093194955 100644 --- a/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/api-paste.ini.j2 +++ b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/api-paste.ini.j2 @@ -9,4 +9,4 @@ acl_public_routes={{ acl_public_routes }} paste.filter_factory={{ authtoken_filter_factory }} [app:api_v1] -paste.app_factory={{ app_factory }} \ No newline at end of file +paste.app_factory={{ app_factory }} diff --git a/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/sysinv/api-paste.ini.j2 b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/sysinv/api-paste.ini.j2 new file mode 100644 index 000000000..38e131162 --- /dev/null +++ b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/sysinv/api-paste.ini.j2 @@ -0,0 +1,9 @@ +[filter:authtoken] +region_name= +auth_url=http://localhost:5000 +auth_uri=http://localhost:5000 +project_name=services +username=sysinv +password={{ sysinv_var_dict['sysinv::api::keystone_password'] }} +user_domain_name=Default +project_domain_name=Default diff --git a/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/sysinv/sysinv.conf.j2 b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/sysinv/sysinv.conf.j2 new file mode 100644 index 000000000..1b594ca7b --- /dev/null +++ b/playbookconfig/src/playbooks/roles/bootstrap/apply-manifest/templates/sysinv/sysinv.conf.j2 @@ -0,0 +1,86 @@ +[lldp] +drivers=ldpd + +[DEFAULT] +control_exchange=openstack +verbose=True +debug=False +api_paste_config=/etc/sysinv/api-paste.ini +syslog_log_facility=local6 +sysinv_api_port=6385 +MTC_INV_LABEL=/v1/hosts/ +logging_context_format_string=sysinv %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s%(message)s +logging_default_format_string=sysinv %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s +sysinv_api_bind_ip=:: +auth_strategy=keystone +sysinv_api_pxeboot_ip= +sysinv_api_workers=1 + +[database] +connection={{ database_connection }} +connection_recycle_time=60 +max_pool_size=1 +max_overflow=64 + +[journal] +journal_max_size=51200 +journal_min_size=1024 +journal_default_size=1024 + +[keystone_authtoken] +region_name= +auth_url=http://localhost:5000 +auth_uri=http://localhost:5000 +auth_type=password +project_name=services +username=sysinv +password={{ sysinv_var_dict['sysinv::keystone::auth::password'] }} +user_domain_name=Default +project_domain_name=Default +interface=internal + +[openstack_keystone_authtoken] +region_name= +neutron_region_name= +cinder_region_name= +nova_region_name= +barbican_region_name= +auth_url=http://localhost:5000 +auth_uri=http://localhost:5000 +auth_type=password +project_name=admin +username=admin +user_domain_name=Default +project_domain_name=Default +keyring_service=CGCS + +[fm] +catalog_info=faultmanagement:fm:internalURL +os_region_name= + +[fernet_repo] +key_repository=/opt/platform/keystone/fernet-keys + +[conductor_periodic_task_intervals] +default=60 +agent_update_request=60 +kubernetes_local_secrets=86400 +deferred_runtime_config=60 +controller_config_active_apply=60 +upgrade_status=180 +install_states=60 +kubernetes_labels=180 +image_conversion=60 +storage_backend_failure=400 +k8s_application=60 +device_image_update=300 +k8s_cluster_health=180 + +[agent_periodic_task_intervals] +default=60 +inventory_audit=60 +lldp_audit=300 + +[app_framework] +fluxcd_hr_reconcile_check_delay=60 +missing_auto_update=True