def validate(self): """Validate test command arguments.""" if not self.args.config: msg = "%s - Argument validation failure. %s" % ( self.name, "Global config is required.") logger.error(msg) raise SetupError(errno.EINVAL, msg) if not self.args.plan: msg = "%s - Argument validation failure. Test plan is needed" % ( self.name) logger.error(msg) raise SetupError(errno.EINVAL, msg) result = PkgV().validate("rpms", "sspl-test") if result == -1: msg = "'sspl-test' rpm pkg not found." logger.error(msg) raise SetupError(1, msg) # Service restart is required for coverage. # Hence it can be enabled only with test plans # which are present in TEST_REQ_SERVICE_RESTART list. if self.args.coverage and self.args.plan[ 0] not in TEST_REQ_SERVICE_RESTART: msg = "Code coverage can not be enabled for %s test plan." \ % self.args.plan[0] logger.error(msg) raise SetupError(errno.EINVAL, "%s - Argument validation failure. %s", self.name, msg) logger.info("%s - Validation done" % self.name)
def validate(self): """Check for below requirement. 1. Validate input configs 2. Validate sspl conf is created 3. Check if message bus is accessible """ if os.geteuid() != 0: msg = "Run this command with root privileges." logger.error(msg) raise SetupError(errno.EINVAL, msg) # Validate input/provisioner configs machine_id = Utility.get_machine_id() Utility.get_config_value(consts.PRVSNR_CONFIG_INDEX, "server_node>%s>cluster_id" % machine_id) self.node_type = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "server_node>%s>type" % machine_id) enclosure_id = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "server_node>%s>storage>enclosure_id" % machine_id) self.enclosure_type = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "storage_enclosure>%s>type" % enclosure_id) # Validate sspl conf is created if not os.path.isfile(consts.file_store_config_path): msg = "Missing configuration - %s !! Create and rerun." % ( consts.file_store_config_path) logger.error(msg) raise SetupError(errno.EINVAL, msg) # Validate message bus is accessible self.mb = MessageBus()
def validate(self): """Check below requirements are met in setup. 1. Check if given product is supported by SSPL 2. Check if given setup is supported by SSPL 3. Check if required pre-requisites softwares are installed. 4. Validate BMC connectivity 5. Validate storage controller connectivity """ machine_id = Utility.get_machine_id() # Validate input/provisioner configs self.product = Utility.get_config_value(consts.PRVSNR_CONFIG_INDEX, "cortx>release>product") self.setup = Utility.get_config_value(consts.PRVSNR_CONFIG_INDEX, "cortx>release>setup") node_type = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "server_node>%s>type" % machine_id) if node_type.lower() not in ["vm", "virtual"]: bmc_ip = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "server_node>%s>bmc>ip" % machine_id) enclosure_id = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "server_node>%s>storage>enclosure_id" % machine_id) Utility.get_config_value(consts.PRVSNR_CONFIG_INDEX, "storage_enclosure>%s>type" % enclosure_id) primary_ip = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "storage_enclosure>%s>controller>primary>ip" % enclosure_id) secondary_ip = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "storage_enclosure>%s>controller>secondary>ip" % enclosure_id) # Validate product support if self.product not in consts.enabled_products: msg = "Product '%s' is not in sspl supported product list: %s" % ( self.product, consts.enabled_products) logger.error(msg) raise SetupError(errno.EINVAL, msg) # Validate setup support if self.setup not in consts.setups: msg = "Setup '%s' is not in sspl supported setup list: %s" % ( self.setup, consts.setups) logger.error(msg) raise SetupError(errno.EINVAL, msg) # Validate required pip3s and rpms are installed self.validate_dependencies(self.setup) # Validate BMC & Storage controller IP reachability if node_type.lower() not in ["vm", "virtual"]: # cluster_id required for decrypting the secret is only available from # the prepare stage. However accessibility validation will be done in # prepare stage. So at this time, validating ip reachability is fine. NetworkV().validate("connectivity", [bmc_ip, primary_ip, secondary_ip])
def create_user(self): """Add sspl-ll user and validate user creation.""" os.system("/usr/sbin/useradd -r %s -s /sbin/nologin \ -c 'User account to run the %s service'" % (consts.USER, consts.USER)) usernames = [x[0] for x in pwd.getpwall()] if consts.USER not in usernames: raise SetupError(errno.EINVAL, "User %s doesn't exit. Please add user." % consts.USER) # Add sspl-ll user to required groups and sudoers file etc. sspl_reinit = "%s/low-level/framework/sspl_reinit" % consts.SSPL_BASE_DIR _ , error, rc = SimpleProcess(sspl_reinit).run() if rc: raise SetupError(rc, "%s failed for with error : %e", sspl_reinit, error)
def validate(self): """Validate test command arguments.""" if not self.args.config: raise SetupError(errno.EINVAL, "%s - Argument validation failure. %s", self.name, "Global config is required.") if not self.args.plan: raise SetupError( errno.EINVAL, "%s - Argument validation failure. Test plan is needed", self.name) result = PkgV().validate("rpms", "sspl-test") if result == -1: raise SetupError(1, "'sspl-test' rpm pkg not found.")
def validate_nw_interfaces(self, interfaces): """Check network intefaces are up.""" if not isinstance(interfaces, list): raise SetupError( errno.EINVAL, "%s - validation failure. %s", self.name, "Expected list of interfaces. Received, %s." % interfaces) cmd = "ip --br a | awk '{print $1, $2}'" nws = [nw.strip() for nw in os.popen(cmd)] nw_status = {nw.split(" ")[0]: nw.split(" ")[1] for nw in nws} for interface, status in nw_status.items(): if interface in interfaces and status in ["down", "DOWN"]: raise SetupError(errno.EINVAL, "%s - validation failure. %s", self.name, "Network interface %s is down." % interface)
def validate(self): if not self.args.nodes: raise SetupError( 1, "Validation failure. %s", "join_cluster requires comma separated node names as argument." ) self.nodes = self.args.nodes[0]
def validate(self): """Validate init command arguments""" if not self.args.config: raise SetupError( errno.EINVAL, "%s - Argument validation failure. Global config is needed", self.name)
def enable_sspl_service(self): """Enable sspl-ll service.""" self.dbus_service.enable("sspl-ll.service") daemon_reload_cmd = "systemctl daemon-reload" output, error, rc = SimpleProcess(daemon_reload_cmd).run() if rc != 0: raise SetupError(rc, error, daemon_reload_cmd)
def process(self): args = ' '.join(self._args.args) sspl_bundle_generate = "%s/%s %s" % (self._script_dir, self.script, args) output, error, rc = SimpleProcess(sspl_bundle_generate).run( realtime_output=True) if rc != 0: raise SetupError(rc, "%s - validation failure. %s", self.name, error)
def validate(self): """Validate init command arguments.""" if not self.args.config: raise SetupError(errno.EINVAL, "%s - Argument validation failure. %s", self.name, "Global config is required.") # Validate config inputs Conf.load(PRVSNR_CONFIG_INDEX, self.args.config[0]) self.sspl_init.validate()
def validate(self): """Validate prepare install command arguments and given input.""" if not self.args.config: raise SetupError(errno.EINVAL, "%s - Argument validation failure. %s", self.name, "Global config URL is required.") # Validate config inputs Conf.load(PRVSNR_CONFIG_INDEX, self.args.config[0]) self.prepare.validate()
def process(self): args = ' '.join(self._args.args) manifest_support_bundle = "%s/%s %s" % (self._script_dir, self.script, args) output, error, returncode = SimpleProcess(manifest_support_bundle).run( realtime_output=True) if returncode != 0: raise SetupError(returncode, "%s - validation failure. %s", self.name, error)
def validate_nw_cable_connection(self, interfaces): """Check network interface links are up. 0 - Cable disconnected 1 - Cable connected """ if not isinstance(interfaces, list): raise SetupError( errno.EINVAL, "%s - validation failure. %s", self.name, "Expected list of interfaces. Received, %s." % interfaces) for interface in interfaces: cmd = "cat /sys/class/net/%s/carrier" % interface output, error, rc = SimpleProcess(cmd).run() output = output.decode().strip() if output == "0": raise SetupError( errno.EINVAL, "%s - validation failure. %s", self.name, "Network interface cable is disconnected - %s." % interface)
def process(self): # stop sspl service dbus_service = DbusServiceHandler() dbus_service.stop('sspl-ll.service') # Remove sspl_conf self.del_file(file_store_config_path) # Remove sspl-configured file self.del_file(SSPL_CONFIGURED) # Remove sspl data shutil.rmtree(DATA_PATH, ignore_errors=True) # Remove sspl-ll user if preset CMD = "id -u sspl-ll" output, error, returncode = SimpleProcess(CMD).run() if returncode != 0: raise SetupError(returncode, "ERROR: %s - CMD %s", error, CMD) else: self.user_present = True if self.user_present: CMD = "/usr/sbin/userdel sspl-ll" output, error, returncode = SimpleProcess(CMD).run() if returncode != 0: raise SetupError(returncode, "ERROR: %s - CMD %s", error, CMD) # Remove log directories shutil.rmtree(f"/var/log/{PRODUCT_FAMILY}/sspl", ignore_errors=True) shutil.rmtree(f"/var/log/{PRODUCT_FAMILY}/iem", ignore_errors=True) # Remove rsyslog config files self.del_file("/etc/rsyslog.d/0-iemfwd.conf") self.del_file("/etc/rsyslog.d/1-ssplfwd.conf") # Remove logrotate config files self.del_file("/etc/logrotate.d/iem_messages") self.del_file("/etc/logrotate.d/sspl_logs") # Remove SSPL configuration files shutil.rmtree("/etc/sspl-ll", ignore_errors=True) self.del_file("/etc/sspl.conf.bak")
def process(self): args = ' '.join(self._args.args) manifest_support_bundle = "%s/%s %s" % (self._script_dir, self.script, args) _, error, rc = SimpleProcess(manifest_support_bundle).run( realtime_output=True) if rc != 0: msg = "%s - validation failure. %s" % (self.name, error) logger.error(msg) raise SetupError(rc, msg) logger.info("%s - Process done" % self.name)
def create_user(self): """Add sspl-ll user and validate user creation.""" command = f"/usr/sbin/useradd -r {consts.USER} -s /sbin/nologin \ -c 'User account to run the {consts.USER} service'" _, error, rc = SimpleProcess(command).run() # rc 9 means user already exists if rc != 0 and rc != 9: logger.error(f"Failed to create sspl user. ERROR: {error}") raise SetupError(rc, error, command) self.validate_user_existence() self.validate_group_existence() # Add sspl-ll user to required groups and sudoers file etc. sspl_reinit = "%s/low-level/framework/sspl_reinit" % consts.SSPL_BASE_DIR _, error, rc = SimpleProcess(sspl_reinit).run() if rc: msg = "%s failed for with error : %e" % (sspl_reinit, error) logger.error(msg) raise SetupError(rc, msg)
def validate(self): """Validate init command arguments.""" if not self.args.config: msg = "%s - Argument validation failure. %s" % ( self.name, "Global config is required.") logger.error(msg) raise SetupError(errno.EINVAL, msg) # Validate config inputs Conf.load(PRVSNR_CONFIG_INDEX, self.args.config[0]) self.sspl_init.validate() logger.info("%s - validation done" % self.name)
def create_directories_and_ownership(self): """Create ras persistent cache directory and state file. Assign ownership recursively on the configured directory. The created state file will be used later by SSPL resourse agent(HA). """ # Extract the data path sspldp = Utility.get_config_value(consts.SSPL_CONFIG_INDEX, "SYSTEM_INFORMATION>data_path") if not sspldp: raise SetupError(errno.EINVAL, "Data path not set in sspl.conf") sspl_uid = Utility.get_uid(consts.USER) sspl_gid = Utility.get_gid(consts.USER) if sspl_uid == -1 or sspl_gid == -1: msg = "No user found with name : %s" % (consts.USER) logger.error(msg) raise SetupError(errno.EINVAL, msg) # Create sspl data directory if not exists os.makedirs(sspldp, exist_ok=True) # Create state file under sspl data directory if not os.path.exists(self.state_file): file = open(self.state_file, "w") file.close() # Create SSPL log and bundle directories os.makedirs(consts.SSPL_LOG_PATH, exist_ok=True) os.makedirs(consts.SSPL_BUNDLE_PATH, exist_ok=True) # set ownership for SSPL dirs list_root_dir = [consts.SSPL_CONFIGURED_DIR, consts.SSPL_LOG_PATH] Utility.set_ownership_recursively(list_root_dir, sspl_uid, sspl_gid) # Create /tmp/dcs/hpi if required. Not required for '<product>' role if self.setup != "cortx": os.makedirs(consts.HPI_PATH, mode=0o777, exist_ok=True) zabbix_uid = Utility.get_uid("zabbix") if zabbix_uid != -1: os.chown(consts.HPI_PATH, zabbix_uid, -1) # Create mdadm.conf to set ACL on it. with open(consts.MDADM_PATH, 'a'): os.utime(consts.MDADM_PATH) os.chmod(consts.MDADM_PATH, mode=0o666) os.chown(consts.MDADM_PATH, sspl_uid, -1)
def validate_group_existence(self): max_retry = 3 for i in range(max_retry): sspl_gid = Utility.get_gid(consts.USER) if sspl_gid != -1: break else: if i == (max_retry - 1): msg = "No group found with name : %s" % (consts.USER) logger.error(msg) raise SetupError(errno.EINVAL, msg) time.sleep(1)
def validate(self): if not self.args.config: raise SetupError( errno.EINVAL, "%s - Argument validation failure. Global config is required.", self.name) if not self.args.type: raise SetupError( errno.EINVAL, "%s - Argument validation failure. Reset type is required.", self.name) reset_type = self.args.type[0] if reset_type == "hard": self.process_class = "HardReset" elif reset_type == "soft": self.process_class = "SoftReset" else: raise SetupError( 1, "Invalid reset type specified. Please check usage.")
def validate(self): # Validate config inputs from framework.utils.utility import Utility Conf.load(GLOBAL_CONFIG_INDEX, global_config_path) self.product = Utility.get_config_value(GLOBAL_CONFIG_INDEX, "cortx>release>product") if self.product is None: msg = "%s - validation failure. %s" % ( self.name, "'Product' name is required to restore suitable configs.") logger.error(msg) raise SetupError(errno.EINVAL, msg) logger.info("%s - Validation done" % self.name)
def _send_command(self, command, fail_on_error=True): """ Execute command and retrun response Parameters: command: shell command to execute fail_on_error: Set to False will ignore command failure """ print(f"Executing: {command}") output, error, returncode = SimpleProcess(command).run() if fail_on_error and returncode != 0: raise SetupError(returncode, "ERROR: Command '%s' failed with error\n %s", command, error) return output.decode('utf-8')
def process(self): """Configure sensor monitoring and log level setting.""" # Update sspl.conf with provisioner supplied input config copy Conf.set(consts.SSPL_CONFIG_INDEX, "SYSTEM_INFORMATION>global_config_copy_url", consts.global_config_path) Conf.save(consts.SSPL_CONFIG_INDEX) if os.path.isfile(consts.SSPL_CONFIGURED): os.remove(consts.SSPL_CONFIGURED) os.makedirs(consts.SSPL_CONFIGURED_DIR, exist_ok=True) with open(consts.SSPL_CONFIGURED, 'a'): os.utime(consts.SSPL_CONFIGURED) sspl_uid = Utility.get_uid(consts.USER) sspl_gid = Utility.get_gid(consts.USER) Utility.set_ownership_recursively([consts.SSPL_CONFIGURED], sspl_uid, sspl_gid) # Get the types of server and storage we are currently running on and # enable/disable sensor groups in the conf file accordingly. update_sensor_info(consts.SSPL_CONFIG_INDEX, self.node_type, self.enclosure_type) # Message bus topic creation self.create_message_types() # Skip this step if sspl is being configured for node replacement # scenario as consul data is already # available on healthy node # Updating build requested log level if not os.path.exists(consts.REPLACEMENT_NODE_ENV_VAR_FILE): with open(f"{consts.SSPL_BASE_DIR}/low-level/files/opt/seagate" + \ "/sspl/conf/build-requested-loglevel") as f: log_level = f.read().strip() if not log_level: log_level = "INFO" if log_level in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]: Conf.set(consts.SSPL_CONFIG_INDEX, "SYSTEM_INFORMATION>log_level", log_level) Conf.save(consts.SSPL_CONFIG_INDEX) else: msg = "Unexpected log level is requested, '%s'" % (log_level) logger.error(msg) raise SetupError(errno.EINVAL, msg)
def validate(self): # Common validator classes to check Cortx/system wide validator if not os.path.exists(self.SSPL_CONFIGURED): error = "SSPL is not configured. Run provisioner scripts in %s" % ( self._script_dir) syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_LOCAL3) syslog.syslog(syslog.LOG_ERR, error) raise SetupError(1, "%s - validation failure. %s", self.name, error) # Validate required services are running retry = 3 while retry > 0: try: ServiceV().validate('isrunning', self.services) except VError: retry -= 1 time.sleep(5) else: break ServiceV().validate('isrunning', self.services)
def create_message_types(self): # Skip this step if sspl is being configured for node # replacement scenario as cluster is # already configured on the healthy node # Configure message bus if not os.path.exists(consts.REPLACEMENT_NODE_ENV_VAR_FILE): message_types = [ Conf.get(consts.SSPL_CONFIG_INDEX, "INGRESSPROCESSOR" ">message_type"), Conf.get(consts.SSPL_CONFIG_INDEX, "EGRESSPROCESSOR" ">message_type") ] mbadmin = MessageBusAdmin(admin_id="admin") try: mbadmin.register_message_type(message_types=message_types, partitions=1) except MessageBusError as e: if self.topic_already_exists not in e.desc: # if topic not already exists, raise exception msg = f"MessageBusError:{e}" logger.exception(msg) raise SetupError(1, msg)
def validate(self): """Check for below requirement. 1. Validate if sspl-ll user exists 2. Validate input keys """ # Check sspl-ll user exists sspl_uid = Utility.get_uid(self.user) if sspl_uid == -1: msg = "User %s doesn't exist. Please add user." % self.user logger.error(msg) raise SetupError(errno.EINVAL, msg) # Check input/provisioner configs machine_id = Utility.get_machine_id() cluster_id = Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "server_node>%s>cluster_id" % machine_id) Utility.get_config_value(consts.PRVSNR_CONFIG_INDEX, "cluster>%s>name" % cluster_id) Utility.get_config_value(consts.PRVSNR_CONFIG_INDEX, "cluster>%s>site_count" % cluster_id) storage_set_count = int( Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "cluster>%s>site>storage_set_count" % cluster_id)) for i in range(storage_set_count): Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "cluster>%s>storage_set[%s]>name" % (cluster_id, i)) Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "cluster>%s>storage_set[%s]>server_nodes" % (cluster_id, i)) Utility.get_config_value( consts.PRVSNR_CONFIG_INDEX, "cluster>%s>storage_set[%s]>storage_enclosures" % (cluster_id, i))
def validate(self): """Validate config command arguments""" if not self.args.config: raise SetupError(1, "%s - Argument validation failure. %s", self.name, "Global config is required.")
def validate(self): if not self.args.config: msg = "%s - Argument validation failure. %s" % ( self.name, "Global config is required.") logger.error(msg) raise SetupError(errno.EINVAL, msg)