class CortxReposParams(ResourceParams): # TODO EOS-12076 validate it is a file or dir or url cortx: Union[str, Path] = attr_ib( 'path_exists', cli_spec='repos/cortx', # FIXME allow url as well # XXX copy validation routine from SetSWUpdateRepo ) dist_type: config.DistrType = attr_ib( cli_spec='repos/dist_type', default=config.DistrType.BUNDLE.value, # TODO EOS-12076 better validation converter=config.DistrType) deps: Union[str, Path] = attr_ib( 'path_exists', cli_spec='repos/deps', default=None, # FIXME allow url as well # XXX copy validation routine from SetSWUpdateRepo ) os: Union[str, Path] = attr_ib( 'path_exists', cli_spec='repos/os', default=None, # FIXME allow url as well # XXX copy validation routine from SetSWUpdateRepo ) py_index: bool = attr_ib(cli_spec='repos/py_index', default=False)
class RunArgsSWUpgradeNode(RunArgsBase): flow: Union[config.CortxFlows, str] = attr_ib( cli_spec='mini_api/flow', validator=attr.validators.in_(config.CortxFlows), converter=config.CortxFlows) targets: str = RunArgs.targets sw: List = attr_ib(cli_spec='upgrade/provisioner/sw', default=None) no_hooks: bool = attr_ib(cli_spec='upgrade/provisioner/no_hooks', default=False)
class SaltMasterParams(ResourceParams): lvm2_first: bool = attr_ib( cli_spec='salt_master/lvm2_first', default=False ) updated_keys: List[str] = attr_ib( cli_spec='salt_master/onchanges', default=attr.Factory(list) ) onchanges: str = attr_ib( cli_spec='salt_master/onchanges', default='restart' )
class SaltMinionParams(ResourceParams): masters: Union[List[str], _PrvsnrValue] = attr_ib( cli_spec='salt_minion/masters', default=UNCHANGED ) cluster_uuid: Union[str, _PrvsnrValue] = attr_ib( cli_spec='salt_minion/cluster_uuid', default=UNCHANGED ) onchanges: str = attr_ib( cli_spec='salt_minion/onchanges', default='restart' ) rediscover: bool = attr_ib( cli_spec='salt_minion/rediscover', default=False )
class ProvisionerParams(ResourceParams): install_dir: Union[str, Path] = attr_ib('path_resolved', cli_spec='provisioner/install_dir', special_values=[UNCHANGED], default=UNCHANGED) repo_tgz: Union[str, Path] = attr_ib('path_exists', cli_spec='provisioner/repo/tgz', default=None) repo: Union[str, Path] = attr_ib('path_exists', cli_spec='provisioner/repo/path', default=config.PROJECT_PATH) repo_version: str = attr_ib(cli_spec='provisioner/repo/version', converter=(lambda v: v if v else config.REPO_VERSION_RAW), default=None)
class CortxReposSetup(CortxReposState): name = 'setup' dist_type = CortxReposParams.dist_type cortx = CortxReposParams.cortx deps = CortxReposParams.deps os = CortxReposParams.os py_index = CortxReposParams.py_index target_build: Path = attr_ib(init=False, default=None) # XXX - for UNCHANCGED values we may resolve real values here # and validate only after that def __attrs_post_init__(self): # noqa: C901 # TODO check that ISOs are not the same if self.dist_type == config.DistrType.BUNDLE: self.target_build = ('file://{}'.format( config.PRVSNR_CORTX_REPOS_BASE_DIR / config.CORTX_SINGLE_ISO_DIR)) else: if self.cortx is ('ISO' or 'dir'): # FIXME self.target_build = 'file://{}'.format( config.PRVSNR_CORTX_REPOS_BASE_DIR / config.CORTX_ISO_DIR) else: # url self.target_build = self.cortx
class UpgradeParams(ResourceParams): old_version: Union[str, Version] = attr_ib( 'version', cli_spec='upgrade/old_version', ) new_version: Union[str, Version] = attr_ib( 'version', cli_spec='upgrade/new_version', ) iteration: Union[str, int] = attr_ib(cli_spec='upgrade/iteration', default=1, converter=int) level: config.ConfigLevelT = attr_ib( cli_spec='upgrade/level', default=config.ConfigLevelT.NODE.value, converter=config.ConfigLevelT)
class MiniAPIParams: spec: Union[Path, str] = attr_ib('path_exists', cli_spec='mini_api/spec') hook: str = attr_ib(cli_spec='mini_api/hook', validator=attr.validators.in_(config.MiniAPIHooks), converter=config.MiniAPIHooks) flow: Union[config.CortxFlows, str] = attr_ib( cli_spec='mini_api/flow', validator=attr.validators.in_(config.CortxFlows), converter=config.CortxFlows) level: Union[config.MiniAPILevels, str] = attr_ib( cli_spec='mini_api/level', validator=attr.validators.in_(config.MiniAPILevels), converter=config.MiniAPILevels) fail_fast: bool = attr_ib(cli_spec='mini_api/fail_fast', default=False) sw: Optional[List] = attr_ib(cli_spec='mini_api/sw', default=None) ctx_vars: Optional[Dict] = attr_ib(cli_spec='mini_api/ctx_vars', default=None) confstore: str = attr_ib(cli_spec='mini_api/confstore', default='""') normalize: bool = attr_ib(cli_spec='mini_api/normalize', default=False)
class SetRelease(CommandParserFillerMixin): description = ("A command to set CORTX release.") release: str = attr_ib(cli_spec='release/version') def run(self): url = CortxRelease(version=self.release).metadata_uri logger.debug(f"Found url '{url}' for the release '{self.release}'") StateFunExecuter.execute( 'file.managed', fun_kwargs=dict(name=str(config.CORTX_RELEASE_INFO_PATH), source=(url.path if url.is_local else str(url)), skip_verify=True, create=True, replace=True, user='******', group='root', mode=444))
class ConsulParams(UpgradeParams, VendorParamsMixin): server: bool = attr_ib(cli_spec='consul/server', default=True) bind_addr: IPv4Address = attr_ib('ipv4', cli_spec='consul/bind_addr', default='0.0.0.0') bootstrap_expect: Optional[int] = attr_ib( cli_spec='consul/bootstrap_expect', default=None, converter=attr.converters.optional(int), # TODO check positives only validator=attr.validators.optional(attr.validators.instance_of(int))) # TODO List[ip4, domain] ??? retry_join: List[str] = attr_ib(cli_spec='consul/retry_join', default=[]) version: Union[str, Version] = attr_ib('version', cli_spec='consul/version', default=None, validator=attr.validators.optional( attr_gen.validator__version)) service: bool = attr_ib(init=False, default=True)
class RunArgsSWUpgrade: # Note. targets are not considered, all the cluster always offline: bool = attr_ib(cli_spec='upgrade/orchestrator/offline', default=False) noprepare: bool = attr_ib(cli_spec='upgrade/orchestrator/noprepare', default=False)
class VersionRange: old_versions: Union[str, SpecifierSet] = attr_ib('version_specifier') new_version: Union[str, Version] = attr_ib('version')
class VendorParamsMixin: vendored: bool = attr_ib(cli_spec='setup/vendored', default=False)
class GetRelease(CommandParserFillerMixin): description = ("A command to get CORTX release.") factory: bool = attr_ib(cli_spec='release/factory', default=False) _installed_rpms: List = attr.ib(init=False, default=None) @classmethod def cortx_version(cls, release_metadata: Optional[Union[str, dict]] = None): if release_metadata is None: release = cls().cortx_release() else: release = CortxRelease(metadata=release_metadata) return release.version @property def installed_rpms(self) -> List: if self._installed_rpms is None: exclude_rpms = config.EXCLUDE_RPMS_RELEASE_VERSION res = cmd_run(f"rpm -qa|grep '^cortx-'|grep -Ev '{exclude_rpms}'", targets=local_minion_id()) rpms = res[next(iter(res))].split("\n") self._installed_rpms = [f'{rpm}.rpm' for rpm in rpms if rpm] return self._installed_rpms def _get_rpms_from_release(self, source): return utils.load_yaml(source)['COMPONENTS'] # TODO (deprecated) the following logic fails in many cases, e.g.: # - installed pkg is not listed in upgrade bundle def _compare_rpms_info(self, release_rpms): return (release_rpms and set(self.installed_rpms).issubset(release_rpms)) def _get_release_info_path(self): release_info = None update_repo = PillarKey('release/upgrade') pillar = PillarResolver(local_minion_id()).get([update_repo]) pillar = next(iter(pillar.values())) upgrade_data = pillar[update_repo] base_dir = Path(upgrade_data['base_dir']) repos = upgrade_data['repos'] for version in reversed(list(repos)): if version == config.REPO_CANDIDATE_NAME: continue release_info = base_dir / f'{version}/RELEASE.INFO' # Note. upgrade iso now may lack release file on top level if not release_info.exists(): release_info = ( base_dir / f'{version}/{config.CORTX_ISO_DIR}/RELEASE.INFO') if release_info.exists(): release_rpms = self._get_rpms_from_release(release_info) if self._compare_rpms_info(release_rpms): return release_info def cortx_release(self, factory=False): if factory: return CortxRelease.factory_release() if config.CORTX_RELEASE_INFO_PATH.exists(): source = config.CORTX_RELEASE_INFO_PATH else: # fallback to legacy logic source = (self._get_release_info_path() or config.CORTX_RELEASE_FACTORY_INFO_PATH) if not source.exists(): raise errors.ReleaseFileNotFoundError() return CortxRelease(metadata_uri=source) def run(self, factory=False): return self.cortx_release(factory=factory).metadata
class SaltClusterParams(ResourceParams): regen_keys: bool = attr_ib( cli_spec='salt_cluster/regen_keys', default=False )
class ProvisionerAPIParams(ResourceParams): # TODO better to use different sources, e.g. # pip index, system pkg, provisioner installation from /opt etc. api_distr: str = attr_ib(cli_spec='provisioner/api/distr', default='pkg')