Esempio n. 1
0
    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.'
            )
Esempio n. 2
0
    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
Esempio n. 3
0
    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)
Esempio n. 4
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')
                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}'
            )
Esempio n. 5
0
    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.'
                        )
Esempio n. 6
0
 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
Esempio n. 7
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}'
            )
Esempio n. 8
0
    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
Esempio n. 9
0
    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
Esempio n. 10
0
    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}')
Esempio n. 11
0
    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)
Esempio n. 12
0
    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.')
Esempio n. 13
0
    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}")
Esempio n. 14
0
    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
Esempio n. 15
0
    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)
Esempio n. 16
0
 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
Esempio n. 17
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)
Esempio n. 18
0
 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
Esempio n. 19
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}."
                )
Esempio n. 20
0
    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}')
Esempio n. 21
0
 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
Esempio n. 22
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
Esempio n. 23
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}'
            )
Esempio n. 24
0
    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)