def process(*args): """Process input parameters""" if len(args) < 2: raise CortxProvisionerError( errno.EINVAL, 'Please provide solution_config and conf_store ' 'url as input parameters.') elif len(args) >= 2: solution_conf_url = args[0] cortx_conf_url = args[1] ConfigValidator.load_config(solution_conf_url, cortx_conf_url) if Conf.get(ConfigValidator._solution_index, 'cluster') is not None: ConfigValidator()._check_storage_sets() ConfigValidator()._check_number_of_nodes() ConfigValidator()._validate_components() if Conf.get(ConfigValidator._solution_index, 'cortx') is not None: ConfigValidator()._check_external_services() # if cluster/cortx both keys are not present in file means file is # empty or file doesn't have required config. if (Conf.get(ConfigValidator._solution_index, 'cluster') is None and Conf.get(ConfigValidator._solution_index, 'cortx') is None): raise CortxProvisionerError( errno.EINVAL, 'File is empty OR Cluster config and cortx config is not present in file.' )
def _validate(self): """Validate cluster command args.""" if self._args.action not in ['bootstrap', 'upgrade']: raise CortxProvisionerError(errno.EINVAL, 'Invalid action type') log_level = self._args.log_level if not log_level: log_level = os.getenv('CORTX_PROVISIONER_DEBUG_LEVEL', const.DEFAULT_LOG_LEVEL) if log_level not in const.SUPPORTED_LOG_LEVELS: raise CortxProvisionerError(errno.EINVAL, 'Invalid log level') os.environ['CORTX_PROVISIONER_DEBUG_LEVEL'] = log_level
def _validate(self): """ Validate config command args """ if self._args.action not in ['apply', 'validate']: raise CortxProvisionerError(errno.EINVAL, 'Invalid action type') log_level = self._args.log_level if not log_level: log_level = os.getenv('CORTX_PROVISIONER_DEBUG_LEVEL', const.DEFAULT_LOG_LEVEL) if log_level not in const.SUPPORTED_LOG_LEVELS: raise CortxProvisionerError(errno.EINVAL, 'Invalid log level') Log.logger.setLevel(log_level)
def save(self, cortx_conf): """ Saves cluster information onto the conf store """ kvs = [] try: for node in self._node_list: node_id = node.pop('id') key_prefix = f'node>{node_id}' # confstore keys kvs.extend( ((f'{key_prefix}>cluster_id', node['cluster_id']), (f'{key_prefix}>name', node['name']), (f'{key_prefix}>hostname', node['hostname']), (f'{key_prefix}>type', node['type']), (f'{key_prefix}>storage_set', node['storage_set']))) component_list = node['components'] kvs.extend(self._get_component_kv_list(component_list, node_id)) storage_spec = node.get('storage') if storage_spec: kvs.extend(self._get_storage_kv_list( storage_spec, node_id)) cortx_conf.set_kvs(kvs) except (KeyError, IndexError) as e: raise CortxProvisionerError( errno.EINVAL, f'Error occurred while adding node information into the confstore {e}' )
def _validate(cortx_solution_config: dict): """ Validates a given node to have required properties Raises exception if there is any entry missing """ required_keys_for_cortx_conf = ['external', 'common'] for k in required_keys_for_cortx_conf: if cortx_solution_config.get(k) is None: raise VError( errno.EINVAL, f"'{k}' property is unspecified in cortx_config.") if k == 'external': required_external_keys = const.REQUIRED_EXTERNAL_SW for e_key in required_external_keys: try: if cortx_solution_config[k][e_key]['endpoints'] is None: raise VError( errno.EINVAL, f"'Endpoint for {e_key}' is unspecified in cortx_config." ) except KeyError as e: raise CortxProvisionerError( errno.EINVAL, f'{str(e)} is unspecified for external in cortx_config.' )
def _check_external_services(self): """Validate external services and its endpoints in cortx config.""" # Get external services from config.yaml solution_config_services = self._get_config( ConfigValidator._key_ext_service) for service in solution_config_services.keys(): key_prefix = f'{ConfigValidator._key_ext_service}>{service}' if self._get_value_from_conf_store( f'{key_prefix}>admin') is not None: counter = 0 endpoints_in_confstore = [] while self.cortx_conf.get( f'{key_prefix}>endpoints[{counter}]') is not None: endpoints_in_confstore.append( self._get_value_from_conf_store( f'{key_prefix}>endpoints[{counter}]')) counter = counter + 1 # Check endpoints if (endpoints_in_confstore != solution_config_services[service]['endpoints']): raise CortxProvisionerError( errno.EINVAL, f'{service} endpoints define in {self.cortx_conf_url} and ' f'{self.solution_conf_url} is not equal.') return 0
def save(self, cortx_conf, cortx_solution_config): """Save cortx-config into confstore""" try: cortx_solution_config_keys = filter( lambda x: x.startswith('cortx'), Conf.get_keys(cortx_solution_config)) cortx_conf.copy(cortx_solution_config, cortx_solution_config_keys) # Change environment_type to setup_type # TODO: remove this code once setup_type key is deleted. cortx_conf.set('cortx>common>setup_type', cortx_conf.get('cortx>common>environment_type')) cortx_conf.delete('cortx>common>environment_type') # Check for release key. release_spec = self._cortx_solution_config.get('common').get( 'release') is_valid, release_info = self._cortx_release.validate(release_spec) if is_valid is False: for key in release_info.keys(): release_key_path = f'cortx>common>release>{key}' Log.warn( f'Release key {release_key_path} is missing or has ' 'incorrect value.') Log.info(f'Adding key "{release_key_path}" ' f'and value "{release_info[key]}" in confstore.') cortx_conf.set(release_key_path, release_info[key]) except KeyError as e: raise CortxProvisionerError( errno.EINVAL, f'Error occurred while adding CORTX config information into confstore {e}' )
def _get_config(self, key): """Read config value for key from config.yaml or cluster.yaml.""" config_value = Conf.get(ConfigValidator._solution_index, key) if config_value is None: raise CortxProvisionerError( errno.EINVAL, f'{key} key is unspecified for {self.solution_conf_url}') return config_value
def _get_value_from_conf_store(self, key): """ Read config value from conf_store """ config_value = self.cortx_conf.get(key) if config_value is None: raise CortxProvisionerError( errno.EINVAL, f'{key} key is unspecified for {self.cortx_conf_url}') return config_value
def apply_cluster_config(cortx_conf, cortx_release): node_map = {} try: node_types = Conf.get(CortxProvisioner._solution_index, 'cluster>node_types') cluster_id = Conf.get(CortxProvisioner._solution_index, 'cluster>id') cluster_name = Conf.get(CortxProvisioner._solution_index, 'cluster>name') storage_sets = Conf.get(CortxProvisioner._solution_index, 'cluster>storage_sets') for key in [cluster_id, cluster_name, storage_sets, node_types]: if key is None: raise CortxProvisionerError( errno.EINVAL, f"One of the key [id, name,storage_sets,node_types]" " is unspecified for cluster.") for node_type in node_types: node_map[node_type['name']] = node_type cluster_keys = [('cluster>id', cluster_id), ('cluster>name', cluster_name), ('cluster>storage_set_count', len(storage_sets))] cortx_conf.set_kvs(cluster_keys) nodes = [] for storage_set in storage_sets: for node in storage_set['nodes']: node_type = node['type'] node = dict(node_map[node_type], **node) node['storage_set'] = storage_set['name'] node['cluster_id'] = cluster_id nodes.append(node) solution_config_nodes = CortxCluster(nodes, cortx_release) solution_config_nodes.save(cortx_conf) solution_config_storagesets = CortxStorageSet(storage_sets) solution_config_storagesets.save(cortx_conf) except KeyError as e: raise CortxProvisionerError( errno.EINVAL, f'Error occurred while applying cluster_config {e}')
def _provision_components(cortx_conf_url: str, _conf_idx: str, interfaces: Enum, apply_phase: str): """Invoke Mini Provisioners of cluster components.""" node_id, _ = CortxProvisioner._get_node_info(_conf_idx) num_components = int(Conf.get(_conf_idx, f'node>{node_id}>num_components')) for interface in interfaces: for comp_idx in range(0, num_components): key_prefix = f'node>{node_id}>components[{comp_idx}]' component_name = Conf.get(_conf_idx, f'{key_prefix}>name') # Check if RPM exists for the component, if it does exist get the build version component_version = CortxProvisioner.cortx_release.get_component_version( component_name) # Get services. service_idx = 0 services = [] while (Conf.get(_conf_idx, f'{key_prefix}>services[{service_idx}]') is not None): services.append(Conf.get(_conf_idx, f'{key_prefix}>services[{service_idx}]')) service_idx = service_idx + 1 service = 'all' if service_idx == 0 else ','.join(services) if apply_phase == ProvisionerStages.UPGRADE.value: version = Conf.get(_conf_idx, f'{key_prefix}>version') # Skip update for component if it is already updated. is_updated = CortxProvisioner._is_component_updated(component_name, version) if is_updated is True: Log.info(f'{component_name} is already updated with {version} version.') continue CortxProvisioner._update_provisioning_status( _conf_idx, node_id, apply_phase, ProvisionerStatus.PROGRESS.value) if interface.value == 'upgrade': # TODO: add --changeset parameter once all components support config upgrade cmd = ( f"/opt/seagate/cortx/{component_name}/bin/{component_name}_setup {interface.value}" f" --config {cortx_conf_url} --services {service}") else: cmd = ( f"/opt/seagate/cortx/{component_name}/bin/{component_name}_setup {interface.value}" f" --config {cortx_conf_url} --services {service}") Log.info(f"{cmd}") cmd_proc = SimpleProcess(cmd) _, err, rc = cmd_proc.run() if rc != 0: CortxProvisioner._update_provisioning_status( _conf_idx, node_id, apply_phase, ProvisionerStatus.ERROR.value) raise CortxProvisionerError( rc, "%s phase of %s, failed. %s", interface.value, component_name, err) # Update version for each component if Provisioning successful. Conf.set(_conf_idx, f'{key_prefix}>version', component_version) # TODO: Remove the following code when gconf is completely moved to consul. CortxProvisioner._load_consul_conf(CortxProvisioner._cortx_gconf_consul_index) Conf.set(CortxProvisioner._cortx_gconf_consul_index, f'{key_prefix}>version', component_version) Conf.save(CortxProvisioner._cortx_gconf_consul_index)
def cluster_bootstrap(cortx_conf_url: str, force_override: bool = False): """ Description: Configures Cluster Components 1. Compares current installed version with New version 2. Invoke Mini Provisioners of cluster components deploy/upgrade based on version compatibility Paramaters: [IN] CORTX Config URL """ Conf.load(CortxProvisioner._conf_index, cortx_conf_url) Conf.load(CortxProvisioner._tmp_index, CortxProvisioner._tmp_cortx_conf_url) tmp_conf_keys = Conf.get_keys(CortxProvisioner._tmp_index) node_id = Conf.machine_id installed_version = Conf.get(CortxProvisioner._conf_index, f'node>{node_id}>provisioning>version') release_version = CortxProvisioner.cortx_release.get_release_version() if installed_version is None: Conf.copy(CortxProvisioner._tmp_index, CortxProvisioner._conf_index, tmp_conf_keys) Conf.save(CortxProvisioner._conf_index) CortxProvisioner._apply_consul_config(CortxProvisioner._conf_index) CortxProvisioner.cluster_deploy(cortx_conf_url, force_override) else: # TODO: add a case where release_version > installed_version but is not compatible. ret_code = CortxProvisioner.cortx_release.version_check( release_version, installed_version) if ret_code == 1: CortxProvisioner._prepare_diff(CortxProvisioner._conf_index, CortxProvisioner._tmp_index, CortxProvisioner._changeset_index) CortxProvisioner.cluster_upgrade(cortx_conf_url, force_override) # TODO: update_conf needs to be removed once gconf moves to consul. # Gconf update after upgrade should not be handled here if gconf is in consul. CortxProvisioner._update_conf(CortxProvisioner._conf_index, CortxProvisioner._tmp_index) # TODO: This will be removed once downgrade is also supported. elif ret_code == -1: raise CortxProvisionerError(errno.EINVAL, 'Downgrade is Not Supported') elif ret_code == 0: Conf.copy(CortxProvisioner._tmp_index, CortxProvisioner._conf_index, tmp_conf_keys) Conf.save(CortxProvisioner._conf_index) CortxProvisioner._apply_consul_config(CortxProvisioner._conf_index) CortxProvisioner.cluster_deploy(cortx_conf_url, force_override) else: raise CortxProvisionerError(errno.EINVAL, 'Internal error. Could not determine version. Invalid image.')
def _validate(self, node: dict): """ validates a give node to have required properties Raises exception if there is any entry missing """ node_name = node.get('name') if node_name is None: raise CortxProvisionerError(errno.EINVAL, 'Missing name for the node entry') Log.debug("Validating node '%s' properties" % node_name) required_keys_for_node = [ 'id', 'components', 'storage_set', 'hostname' ] for k in required_keys_for_node: if node.get(k) is None: raise CortxProvisionerError( errno.EINVAL, f"'{k}' property is unspecified for node {node_name}")
def _get_node_info(_conf_idx: str): """To get the node information.""" node_id = Conf.machine_id if node_id is None: raise CortxProvisionerError(errno.EINVAL, "Invalid node_id: %s", \ node_id) # Reinitialize logging with configured log path log_path = os.path.join( Conf.get(_conf_idx, 'cortx>common>storage>log'), const.APP_NAME, node_id) log_level = os.getenv('CORTX_PROVISIONER_DEBUG_LEVEL', const.DEFAULT_LOG_LEVEL) CortxProvisionerLog.reinitialize( const.SERVICE_NAME, log_path, level=log_level) if Conf.get(_conf_idx, f'node>{node_id}>name') is None: raise CortxProvisionerError( errno.EINVAL, f'Node name not found in cortx config for node {node_id}.') node_name = Conf.get(_conf_idx, f'node>{node_id}>name') return node_id, node_name
def _provision_components(cortx_conf: MappedConf, interfaces: Enum, apply_phase: str): """Invoke Mini Provisioners of cluster components.""" node_id, node_name = CortxProvisioner._get_node_info(cortx_conf) num_components = int(cortx_conf.get(f'node>{node_id}>num_components')) for interface in interfaces: for comp_idx in range(0, num_components): key_prefix = f'node>{node_id}>components[{comp_idx}]' component_name = cortx_conf.get(f'{key_prefix}>name') # Get services. service_idx = 0 services = [] while (cortx_conf.get(f'{key_prefix}>services[{service_idx}]') is not None): services.append( cortx_conf.get( f'{key_prefix}>services[{service_idx}]')) service_idx = service_idx + 1 service = 'all' if service_idx == 0 else ','.join(services) if apply_phase == ProvisionerStages.UPGRADE.value: version = cortx_conf.get(f'{key_prefix}>version') # Skip update for component if it is already updated. is_updated = CortxProvisioner._is_component_updated( component_name, version) if is_updated is True: Log.info( f'{component_name} is already updated with {version} version.' ) continue CortxProvisioner._update_provisioning_status( cortx_conf, node_id, apply_phase, ProvisionerStatus.PROGRESS.value) cmd = ( f"/opt/seagate/cortx/{component_name}/bin/{component_name}_setup {interface.value}" f" --config {cortx_conf._conf_url} --services {service}") Log.info(f"{cmd}") cmd_proc = SimpleProcess(cmd) _, err, rc = cmd_proc.run() if rc != 0: CortxProvisioner._update_provisioning_status( cortx_conf, node_id, apply_phase, ProvisionerStatus.ERROR.value) raise CortxProvisionerError(rc, "%s phase of %s, failed. %s", interface.value, component_name, err) # Update version for each component if Provisioning successful. component_version = CortxProvisioner.cortx_release.get_component_version( component_name) cortx_conf.set(f'{key_prefix}>version', component_version)
def _validate_services(self, service_list, component_name): """Verify services defined in cluster.yaml is supported in constant file.""" for service in service_list: # check if service name is define in utils const.py file. if service not in Const._value2member_map_: raise CortxProvisionerError(errno.EINVAL, f'{service} is not supported.') # Verify service_name is define for the specific component. # Get all keys from constant file which has same 'service_name'. constant_service_keys = [ key for key, enum_ele in Const.__members__.items() if enum_ele.value.lower() == service.lower() ] if not any(component_name.upper() in key for key in constant_service_keys): Log.debug( f'"{service}" service defined in "{self.solution_conf_url}" for ' f'"{component_name}", is not supported.') raise CortxProvisionerError( errno.EINVAL, f'Component "{component_name}" does not support service "{service}".' ) return 0
def _apply_consul_config(_conf_idx: str): try: num_endpoints = int(Conf.get(_conf_idx, 'cortx>external>consul>num_endpoints')) if num_endpoints == 0: raise CortxProvisionerError(errno.EINVAL, f"Invalid value for num_endpoints '{num_endpoints}'") for idx in range(0, num_endpoints): consul_endpoint = Conf.get(_conf_idx, f'cortx>external>consul>endpoints[{idx}]') if not consul_endpoint: raise CortxProvisionerError(errno.EINVAL, "Consul Endpoint can't be empty.") if urlparse(consul_endpoint).scheme not in ['http', 'https', 'tcp']: raise CortxProvisionerError(errno.EINVAL, f"Invalid Consul Endpoint {consul_endpoint}") if 'http' in consul_endpoint: break except ConfError as e: raise CortxProvisionerError(errno.EINVAL, f"Unable to get consul endpoint detail , Error:{e}") gconf_consul_url = consul_endpoint.replace('http','consul') + '/conf' Conf.load(CortxProvisioner._cortx_gconf_consul_index, gconf_consul_url) Conf.copy(_conf_idx, CortxProvisioner._cortx_gconf_consul_index, Conf.get_keys(_conf_idx)) Conf.save(CortxProvisioner._cortx_gconf_consul_index) # TODO: place the below code at a proper location when this function is removed. with open(const.CONSUL_CONF_URL, 'w') as f: f.write(gconf_consul_url)
def _validate_components(self): """Verify components defined in cluster.yaml is supported in constant file.""" node_types = self._get_config('cluster>node_types') for node_type in node_types: component_list = node_type['components'] for component in component_list: # check component_name exist in Utils Const cls. component_name = component['name'] if component_name not in Const._value2member_map_: raise CortxProvisionerError( errno.EINVAL, f'{component_name} is not supported.') service_list = component.get('services') if service_list is not None: self._validate_services(service_list, component_name) return 0
def _validate(self, s_set: dict): """ validates a give storage_sets to have required properties Raises exception if there is any entry missing """ s_set_name = s_set.get('name') if s_set_name is None: raise CortxProvisionerError( errno.EINVAL, 'Missing name for the storage_set entry') Log.debug("Validating storage set '%s' properties" % s_set_name) required_keys_for_storage_set = ['durability', 'nodes'] for k in required_keys_for_storage_set: if s_set.get(k) is None: raise VError( errno.EINVAL, f"'{k}' property is unspecified for storage_set {s_set_name}." )
def save(self, cortx_conf): """ Converts storage_set confstore keys and add into conf_store. confstore representation for storage_set key: storage_set: - durability: dix: data: '1' parity: '7' spare: '0' sns: data: '8' parity: '7' spare: '0' name: storage-set-1 """ kvs = [] try: for index, storage_set in enumerate(self._storage_sets): key_prefix = f'cluster>storage_set[{index}]' kvs.append((f'{key_prefix}>name', storage_set['name'])) nodes = storage_set['nodes'] for node_idx, node in enumerate(nodes): # confstore keys machine_id = CortxCluster.get_machine_id(node['id']) kvs.append((f'{key_prefix}>nodes[{node_idx}]', machine_id)) # Read sns and dix value from storage_set durability = storage_set['durability'] for k, v in durability.items(): res = v.split('+') # confstore keys durability_key_prefix = f'{key_prefix}>durability>{k}' kvs.extend(((f'{durability_key_prefix}>data', res[0]), (f'{durability_key_prefix}>parity', res[1]), (f'{durability_key_prefix}>spare', res[2]))) cortx_conf.set_kvs(kvs) except KeyError as e: raise CortxProvisionerError( errno.EINVAL, f'Error occurred while adding storage_sets to confstore {e}')
def _check_number_of_nodes(self): """Validate number of nodes specified in cortx_conf.""" solution_config_storage_sets = self._get_config( ConfigValidator._key_storage_set_sc) for storage_set in solution_config_storage_sets: storage_set_name = storage_set['name'] solution_config_nodes = storage_set['nodes'] # Get number of nodes from confstore which has same storage_set_name. conf_store_nodes = self.cortx_conf.search('node', 'storage_set', storage_set_name) if len(solution_config_nodes) != len(conf_store_nodes): Log.debug( f'Number of nodes define in {self.solution_conf_url} is ' f'{len(solution_config_nodes)} and {self.cortx_conf_url} is ' f'{len(conf_store_nodes)}') raise CortxProvisionerError( errno.EINVAL, f'Number of nodes define in {self.cortx_conf_url} and ' f'{self.solution_conf_url} is not equal.') return 0
def _check_storage_sets(self): """Validate storage_sets present in cortx_conf.""" solution_config_storage_sets = self._get_config( ConfigValidator._key_storage_set_sc) storage_set_counter = 0 while self.cortx_conf.get( f'cluster>storage_set[{storage_set_counter}]>name' ) is not None: storage_set_counter = storage_set_counter + 1 if len(solution_config_storage_sets) != storage_set_counter: Log.debug( f'Number of storage_sets define in {self.solution_conf_url} is ' f'{len(solution_config_storage_sets)} and in {self.cortx_conf_url} ' f'is {storage_set_counter}') raise CortxProvisionerError( errno.EINVAL, f'Number of storage_sets define in {self.cortx_conf_url} ' f'and {self.solution_conf_url} is not equal.') return 0
def save(self, cortx_conf): """Saves cluster information onto the conf store""" kvs = [] try: for node in self._node_list: node_id = node.pop('id') machine_id = CortxCluster.get_machine_id(node_id) key_prefix = f'node>{machine_id}' os.makedirs(const.CONFIG_PATH, exist_ok=True) if socket.getfqdn() == node['hostname']: with open(const.MACHINE_ID_PATH, 'w') as machine_id_path: machine_id_path.write(machine_id) if node.get('storage'): kvs.append((f'{key_prefix}>node_group', os.getenv('NODE_NAME'))) # confstore keys kvs.extend( ((f'{key_prefix}>cluster_id', node['cluster_id']), (f'{key_prefix}>name', node['name']), (f'{key_prefix}>hostname', node['hostname']), (f'{key_prefix}>node_id', node_id), (f'{key_prefix}>type', node['type']), (f'{key_prefix}>storage_set', node['storage_set']))) component_list = node['components'] kvs.extend( CortxCluster._get_component_kv_list( component_list, machine_id)) storage_spec = node.get('storage') if storage_spec: kvs.extend( self._get_storage_kv_list(storage_spec, machine_id)) cortx_conf.set_kvs(kvs) except (KeyError, IndexError) as e: raise CortxProvisionerError( errno.EINVAL, f'Error occurred while adding node information into the confstore {e}' )
def config_apply(solution_config_url: str, cortx_conf_url: str = None, force_override: bool = False): """ Description: Parses input config and store in CORTX config location Parameters: [IN] Solution Config URL [OUT] CORTX Config URL """ if Log.logger is None: CortxProvisionerLog.initialize(const.SERVICE_NAME, const.TMP_LOG_PATH) if cortx_conf_url is None: cortx_conf_url = CortxProvisioner._cortx_conf_url cortx_conf = MappedConf(CortxProvisioner._tmp_cortx_conf_url) # Load same config again if force_override is True try: cs_option = {"fail_reload": False} if force_override else {"skip_reload": True} Log.info('Applying config %s' % solution_config_url) Conf.load(CortxProvisioner._solution_index, solution_config_url, **cs_option) except ConfError as e: Log.error(f'Unable to load {solution_config_url} url, Error:{e}') # Secrets path from config file if cortx_conf.get('cortx>common>storage>local'): CortxProvisioner._secrets_path = cortx_conf.get('cortx>common>storage>local')+CortxProvisioner._rel_secret_path # source code for encrypting and storing secret key if Conf.get(CortxProvisioner._solution_index, 'cluster') is not None: CortxProvisioner.apply_cluster_config(cortx_conf, CortxProvisioner.cortx_release) if Conf.get(CortxProvisioner._solution_index, 'cortx') is not None: # generating cipher key cipher_key = None cluster_id = Conf.get(CortxProvisioner._solution_index, 'cluster>id') if cluster_id is None: cluster_id = cortx_conf.get('cluster>id') if cluster_id is None: raise CortxProvisionerError(errno.EINVAL, 'Cluster ID not specified') cipher_key = Cipher.gen_key(cluster_id, 'cortx') if cipher_key is None: raise CortxProvisionerError(errno.EINVAL, 'Cipher key not specified') for key in Conf.get_keys(CortxProvisioner._solution_index): # using path /etc/cortx/solution/secret to confirm secret if key.endswith('secret'): secret_val = Conf.get(CortxProvisioner._solution_index, key) val = None with open(os.path.join(CortxProvisioner._secrets_path, secret_val), 'rb') as secret: val = secret.read() if val is None: raise CortxProvisionerError(errno.EINVAL, f'Could not find the Secret in {CortxProvisioner._secrets_path}') val = Cipher.encrypt(cipher_key, val) # decoding the byte string in val variable Conf.set(CortxProvisioner._solution_index, key, val.decode('utf-8')) CortxProvisioner.apply_cortx_config(cortx_conf, CortxProvisioner.cortx_release) # Adding array count key in conf cortx_conf.add_num_keys() Conf.save(cortx_conf._conf_idx)