def extended_info(device, custom_options='', test_mode=TESTMODE): """Retrieves a list of SMART attributes found from parsing smartctl -a output Mostly ATA / SATA as SCSI uses a free form syntax for this. Extracts all lines starting with ID# ATTRIBUTE_NAME and creates a dictionary of lists containing each lines column entries indexed in the dictionary via the Attribute name. :param device: disk device name :param testmode: Not True causes cat from file rather than smartctl command :return: dictionary of smart attributes extracted from device or test file """ if not test_mode: o, e, rc = run_command([SMART, '-a'] + get_dev_options(device, custom_options), throw=False) else: # we are testing so use a smartctl -a file dump instead o, e, rc = run_command([CAT, '/root/smartdumps/smart-a.out']) attributes = {} for i in range(len(o)): if (re.match('Vendor Specific SMART Attributes with Thresholds:', o[i]) is not None): if (len(o) > i + 1): if (re.match('ID# ATTRIBUTE_NAME', o[i + 1]) is not None): for j in range(i + 2, len(o)): if (o[j] == ''): break fields = o[j].strip().split() if (len(fields) > 10): fields[9] = ' '.join(fields[9:]) attributes[fields[1]] = fields[0:10] return attributes
def test_logs(device, test_mode=TESTMODE): """ Retrieves information from SMART Self-Test logs held by the drive. Creates a dictionary of previous test info, indexed by test number and a list containing the remaining log info, each line is an item in the list. :param device: disk device name :param test_mode: Not True causes cat from file rather than smartctl command :return: test_d as a dictionary of summarized test """ if not test_mode: o, e, rc = run_command( [SMART, '-l', 'selftest', '-l', 'selective', '/dev/%s' % device]) else: o, e, rc = run_command( [CAT, '/root/smartdumps/smart-l-selftest-l-selective.out']) test_d = {} log_l = [] for i in range(len(o)): if (re.match('SMART Self-test log structure revision number', o[i]) is not None): log_l.append(o[i]) if (len(o) > (i + 1)): if (re.match('Num Test_Description Status', o[i + 1]) is not None): for j in range(i + 2, len(o)): if (re.match('# ', o[j]) is not None): fields = re.split(r'\s\s+', o[j].strip()[2:]) fields[3] = 100 - int(fields[3][:-1]) test_d[fields[0]] = fields[1:] else: log_l.append(o[j]) return (test_d, log_l)
def update_check(): pkg = 'rockstor' version, date = rpm_build_info(pkg) o, e, rc = run_command([YUM, 'changelog', date, pkg]) log = False available = False new_version = None updates = [] for l in o: if (re.search('Available Packages', l) is not None): available = True if (not available): continue if (new_version is None and (re.match('rockstor-', l) is not None)): new_version = l.split()[0].split('rockstor-')[1].split('.x86_64')[0] if (log is True): updates.append(l) if (len(l.strip()) == 0): log = False if (re.match('\* ', l) is not None): log = True if (new_version is None): new_version = version #do a second check which is valid for updates without changelog #updates. eg: same day updates, testing updates. o, e, rc = run_command([YUM, 'update', pkg, '--assumeno'], throw=False) if (rc == 1): for l in o: if (re.search('will be an update', l) is not None): if (re.search('rockstor.x86_64', l) is not None): new_version = l.strip().split()[3].split(':')[1] return (version, new_version, updates)
def service_status(service_name, config=None): """ Service status of either systemd or supervisord managed services. Hardwired to identify controlling system by service name and uses one of systemctrl, init_service_op, or superctl to assess status accordingly. Note some sanity checks for some services. :param service_name: :return: """ if (service_name == 'nis' or service_name == 'nfs'): out, err, rc = init_service_op('rpcbind', 'status', throw=False) if (rc != 0): return out, err, rc if (service_name == 'nis'): return init_service_op('ypbind', 'status', throw=False) else: return init_service_op('nfs', 'status', throw=False) elif (service_name == 'ldap'): return init_service_op('nslcd', 'status', throw=False) elif (service_name == 'sftp'): out, err, rc = init_service_op('sshd', 'status', throw=False) # initial check on sshd status: 0 = OK 3 = stopped if (rc != 0): return out, err, rc # sshd has sftp subsystem so we check for it's config line which is # inserted or deleted to enable or disable the sftp service. with open(SSHD_CONFIG) as sfo: for line in sfo.readlines(): if (re.match("Subsystem\s+sftp", line) is not None): return out, err, rc # -1 not appropriate as inconsistent with bash return codes # Returning 1 as Catchall for general errors. # the calling system interprets -1 as enabled, 1 works for disabled. return out, err, 1 elif (service_name in ('replication', 'data-collector', 'ztask-daemon')): return superctl(service_name, 'status') elif (service_name == 'smb'): out, err, rc = run_command([SYSTEMCTL_BIN, 'status', 'smb'], throw=False) if (rc != 0): return out, err, rc return run_command([SYSTEMCTL_BIN, 'status', 'nmb'], throw=False) elif (service_name == 'nut'): # Establish if nut is running by lowest common denominator nut-monitor # In netclient mode it is all that is required, however we don't then # reflect the state of the other services of nut-server and nut-driver. return run_command([SYSTEMCTL_BIN, 'status', 'nut-monitor'], throw=False) elif (service_name == 'active-directory'): if (config is not None): REALM = '/usr/sbin/realm' o, e, rc = run_command([REALM, 'list', '--name-only']) for l in o: if (l == config['domain']): return '', '', 0 # bootstrap switch subsystem interprets -1 as ON so returning 1 instead return '', '', 1 return init_service_op(service_name, 'status', throw=False)
def update_run(subscription=None, yum_update=False): # update_run modified to handle yum updates too # and avoid an ad hoc yum update function # If we have a yum update we don't stop/start Rockstor and # don't delete *.pyc files if (subscription is not None): switch_repo(subscription) run_command([SYSTEMCTL, 'start', 'atd']) fh, npath = mkstemp() with open(npath, 'w') as atfo: if not yum_update: atfo.write('%s stop rockstor\n' % SYSTEMCTL) # rockstor-pre stop ensures initrock re-run on next rockstor start atfo.write('%s stop rockstor-pre\n' % SYSTEMCTL) atfo.write('/usr/bin/find %s -name "*.pyc" -type f -delete\n' % settings.ROOT_DIR) atfo.write('%s --setopt=timeout=600 -y update\n' % YUM) # account for moving from dev/source to package install: atfo.write('%s --setopt=timeout=600 -y install rockstor\n' % YUM) # the following rockstor start invokes rockstor-pre (initrock) also atfo.write('%s start rockstor\n' % SYSTEMCTL) else: atfo.write('%s --setopt=timeout=600 -y -x rock* update\n' % YUM) atfo.write('/bin/rm -f %s\n' % npath) out, err, rc = run_command([AT, '-f', npath, 'now + 1 minutes']) time.sleep(120) return out, err, rc
def new_team_connection(name, config, members, ipaddr=None, gateway=None, dns_servers=None, search_domains=None): run_command([NMCLI, 'c', 'add', 'type', 'team', 'con-name', name, 'ifname', name, 'config', config]) new_connection_helper(name, ipaddr, gateway, dns_servers, search_domains) new_member_helper(name, members, 'team-slave') reload_connection(name)
def new_ethernet_connection(name, ifname, ipaddr=None, gateway=None, dns_servers=None, search_domains=None): run_command([NMCLI, 'c', 'add', 'type', 'ethernet', 'con-name', name, 'ifname', ifname]) new_connection_helper(name, ipaddr, gateway, dns_servers, search_domains) #@todo: probably better to get the uuid and reload with it instead of name. reload_connection(name)
def service_status(service_name): if (service_name == 'nis' or service_name == 'nfs'): out, err, rc = init_service_op('rpcbind', 'status', throw=False) if (rc != 0): return out, err, rc if (service_name == 'nis'): return init_service_op('ypbind', 'status', throw=False) else: return init_service_op('nfs', 'status', throw=False) elif (service_name == 'ldap'): return init_service_op('nslcd', 'status', throw=False) elif (service_name == 'sftp'): out, err, rc = init_service_op('sshd', 'status', throw=False) if (rc != 0): return out, err, rc with open(SSHD_CONFIG) as sfo: for line in sfo.readlines(): if (re.match("Subsystem\tsftp\tinternal-sftp", line) is not None): return out, err, rc return out, err, -1 elif (service_name == 'replication' or service_name == 'task-scheduler' or service_name == 'data-collector' or service_name == 'service-monitor'): return superctl(service_name, 'status') elif (service_name == 'smb'): out, err, rc = run_command([SYSTEMCTL_BIN, 'status', 'smb'], throw=False) if (rc != 0): return out, err, rc return run_command([SYSTEMCTL_BIN, 'status', 'nmb'], throw=False) return init_service_op(service_name, 'status', throw=False)
def devices(): dmap = {} o, e, rc = run_command([NMCLI, '-t', '-f', 'device', 'device']) for dev in o: if (len(dev.strip()) == 0): continue tmap = { 'dtype': None, 'mac': None, 'mtu': None, 'state': None, } o2, e2, r2 = run_command([NMCLI, 'd', 'show', dev]) for l in o2: if (re.match('GENERAL.TYPE:', l) is not None): tmap['dtype'] = val(l) elif (re.match('GENERAL.HWADDR:', l) is not None): tmap['mac'] = val(l) elif (re.match('GENERAL.MTU:', l) is not None): tmap['mtu'] = val(l) elif (re.match('GENERAL.STATE:', l) is not None): tmap['state'] = val(l) elif (re.match('GENERAL.CONNECTION:', l) is not None): connection = val(l) if (connection is not None): tmap['connection'] = connection dmap[dev] = tmap return dmap
def add_ssh_key(username, key, old_key=None): groupname = grp.getgrgid(pwd.getpwnam(username).pw_gid).gr_name SSH_DIR = '/home/%s/.ssh' % username AUTH_KEYS = '%s/authorized_keys' % SSH_DIR openmode = 'r' if (not os.path.isfile(AUTH_KEYS)): openmode = 'a+' if (not os.path.isdir(SSH_DIR)): os.mkdir(SSH_DIR) run_command([CHOWN, '-R', '%s:%s' % (username, groupname), SSH_DIR]) os.chmod(SSH_DIR, 0700) fo, npath = mkstemp() exists = False with open(AUTH_KEYS, openmode) as afo, open(npath, 'w') as tfo: for line in afo.readlines(): if (line.strip('\n') == key): exists = True if (line.strip('\n') == old_key): continue tfo.write(line) if (not exists and key is not None): tfo.write('%s\n' % key) if (exists): return os.remove(npath) move(npath, AUTH_KEYS) os.chmod(AUTH_KEYS, 0600) run_command([CHOWN, '%s:%s' % (username, groupname), AUTH_KEYS])
def get_base_device(device, test_mode=TESTMODE): """ Helper function that returns the full path of the base device of a partition or if given a base device then will return it's full path, ie input sda3 output /dev/sda input sda output /dev/sda Works as a function of lsblk list order ie base devices first. So we return the first start of line match to our supplied device name with the pattern as the first element in lsblk's output and the match target as our device. :param device: device name as per db entry, ie as returned from scan_disks :param test_mode: Not True causes cat from file rather than smartctl command :return: base_dev: single item list containing the root device's full path ie device = sda3 the base_dev = /dev/sda or [''] if no lsblk entry was found to match. """ base_dev = [ '', ] if not test_mode: out, e, rc = run_command([LSBLK]) else: out, e, rc = run_command([CAT, '/root/smartdumps/lsblk.out']) # now examine the output from lsblk line by line for line in out: line_fields = line.split() if len(line_fields) < 1: # skip empty lines continue if re.match(line_fields[0], device): # We have found a device string match to our device so record it. base_dev[0] = '/dev/' + line_fields[0] break # Return base_dev ie [''] or first character matches to line start in lsblk. return base_dev
def new_bond_connection(name, mode, members, ipaddr=None, gateway=None, dns_servers=None, search_domains=None): run_command([NMCLI, 'c', 'add', 'type', 'bond', 'con-name', name, 'ifname', name, 'mode', mode]) new_connection_helper(name, ipaddr, gateway, dns_servers, search_domains) new_member_helper(name, members, 'bond-slave') reload_connection(name)
def extended_info(device, custom_options='', test_mode=TESTMODE): """ Retrieves a list of SMART attributes found from parsing smartctl -a output Mostly ATA / SATA as SCSI uses a free form syntax for this. Extracts all lines starting with ID# ATTRIBUTE_NAME and creates a dictionary of lists containing each lines column entries indexed in the dictionary via the Attribute name. :param device: disk device name :param testmode: Not True causes cat from file rather than smartctl command :return: dictionary of smart attributes extracted from device or test file """ if not test_mode: o, e, rc = run_command( [SMART, '-a'] + get_dev_options(device, custom_options), throw=False) else: # we are testing so use a smartctl -a file dump instead o, e, rc = run_command([CAT, '/root/smartdumps/smart-a.out']) attributes = {} for i in range(len(o)): if (re.match('Vendor Specific SMART Attributes with Thresholds:', o[i]) is not None): if (len(o) > i + 1): if (re.match('ID# ATTRIBUTE_NAME', o[i + 1]) is not None): for j in range(i + 2, len(o)): if (o[j] == ''): break fields = o[j].strip().split() if (len(fields) > 10): fields[9] = ' '.join(fields[9:]) attributes[fields[1]] = fields[0:10] return attributes
def add_ssh_key(username, key, old_key=None): groupname = grp.getgrgid(pwd.getpwnam(username).pw_gid).gr_name SSH_DIR = "/home/%s/.ssh" % username AUTH_KEYS = "%s/authorized_keys" % SSH_DIR openmode = "r" if not os.path.isfile(AUTH_KEYS): openmode = "a+" if not os.path.isdir(SSH_DIR): os.mkdir(SSH_DIR) run_command([CHOWN, "-R", "%s:%s" % (username, groupname), SSH_DIR]) # Set directory to rwx --- --- (700) via stat constants. os.chmod(SSH_DIR, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) fo, npath = mkstemp() exists = False with open(AUTH_KEYS, openmode) as afo, open(npath, "w") as tfo: for line in afo.readlines(): if line.strip("\n") == key: exists = True if line.strip("\n") == old_key: continue tfo.write(line) if not exists and key is not None: tfo.write("%s\n" % key) if exists: return os.remove(npath) move(npath, AUTH_KEYS) # Set file to rw- --- --- (600) via stat constants. os.chmod(AUTH_KEYS, stat.S_IRUSR | stat.S_IWUSR) run_command([CHOWN, "%s:%s" % (username, groupname), AUTH_KEYS])
def update_run(subscription=None, update_all_other=False): # update_run modified to handle yum updates too # and avoid an ad hoc yum update function # If we have a yum update we don't stop/start Rockstor and # don't delete *.pyc files if subscription is not None: switch_repo(subscription) run_command([SYSTEMCTL, "start", "atd"]) fh, npath = mkstemp() # Set system wide package manager refresh command according to distro. distro_id = distro.id() pkg_refresh_cmd = "{} --non-interactive refresh\n".format(ZYPPER) if distro_id == "rockstor": # CentOS based Rockstor conditional pkg_refresh_cmd = "{} --setopt=timeout=600 -y update\n".format(YUM) # Set package manager rockstor install/update command according to distro. pkg_in_up_rockstor = "{} --non-interactive install rockstor\n".format( ZYPPER) if distro_id == "rockstor": # CentOS based Rockstor conditional pkg_in_up_rockstor = "{} --setopt=timeout=600 -y install rockstor\n".format( YUM) pkg_update_all = "" if distro_id == "opensuse-leap": pkg_update_all = "{} --non-interactive update --no-recommends\n".format( ZYPPER) if distro_id == "opensuse-tumbleweed": pkg_update_all = "{} --non-interactive dist-upgrade --no-recommends\n".format( ZYPPER) with open(npath, "w") as atfo: if not update_all_other: atfo.write("sleep 10\n") atfo.write("{} stop rockstor\n".format(SYSTEMCTL)) # rockstor-pre stop ensures initrock re-run on next rockstor start atfo.write("{} stop rockstor-pre\n".format(SYSTEMCTL)) # Exclude eggs subdir, as these are in rpm so will be deleted # as otherwise floods YUM log with "No such file or directory" atfo.write( '/usr/bin/find {} -name "*.pyc" -not -path "*/eggs/*" -type f -delete\n' .format(settings.ROOT_DIR)) atfo.write(pkg_refresh_cmd) # account for moving from dev/source to package install: atfo.write(pkg_in_up_rockstor) # the following rockstor start invokes rockstor-pre (initrock) also atfo.write("{} start rockstor\n".format(SYSTEMCTL)) else: # update_all_other True so update all bar the rockstor package. logger.info( "Updating all but rockstor package for distro {}".format( distro_id)) if distro_id == "rockstor": atfo.write( "{} --setopt=timeout=600 -y -x rock* update\n".format(YUM)) else: atfo.write("{} addlock rockstor\n".format(ZYPPER)) atfo.write(pkg_update_all) atfo.write("{} removelock rockstor\n".format(ZYPPER)) atfo.write("/bin/rm -f {}\n".format(npath)) # out, err, rc = run_command([AT, '-f', npath, 'now + 1 minutes']) out, err, rc = run_command([AT, "-f", npath, "now"]) time.sleep(120) return out, err, rc
def new_member_helper(name, members, mtype): for i in range(len(members)): mname = '%s-slave-%d' % (name, i) run_command([NMCLI, 'c', 'add', 'type', mtype, 'con-name', mname, 'ifname', members[i], 'master', name]) for i in range(len(members)): mname = '%s-slave-%d' % (name, i) run_command([NMCLI, 'c', 'up', mname])
def restart_samba(hard=False): """ call whenever config is updated """ mode = 'reload' if (hard): mode = 'restart' run_command([SYSTEMCTL, mode, 'smb']) return run_command([SYSTEMCTL, mode, 'nmb'])
def restart_samba(hard=False): """ call whenever config is updated """ mode = "reload" if hard: mode = "restart" run_command([SYSTEMCTL, mode, "smb"]) return run_command([SYSTEMCTL, mode, "nmb"])
def update_samba_discovery(ipaddr, clean_config): fo, npath = mkstemp() dest_file = '/etc/avahi/services/smb.service' regex = (' <name replace-wildcards="yes">') nl = (' <name replace-wildcards="yes">RockStor@%s</name>\n' % ipaddr,) inplace_replace(clean_config, npath, (regex,), nl) shutil.move(npath, dest_file) run_command([CHMOD, '755', dest_file]) return run_command([SYSTEMCTL, 'restart', 'avahi-daemon', ])
def add_ssh_key(username, key): SSH_DIR = "/home/%s/.ssh" % username AUTH_KEYS = "%s/authorized_keys" % SSH_DIR if not os.path.isdir(SSH_DIR): os.mkdir(SSH_DIR) with open(AUTH_KEYS, "w") as afo: afo.write("%s\n" % key) os.chmod(AUTH_KEYS, 0600) run_command([CHOWN, "%s:%s" % (username, username), AUTH_KEYS])
def add_ssh_key(username, key): SSH_DIR = '/home/%s/.ssh' % username AUTH_KEYS = '%s/authorized_keys' % SSH_DIR if (not os.path.isdir(SSH_DIR)): os.mkdir(SSH_DIR) with open(AUTH_KEYS, 'w') as afo: afo.write('%s\n' % key) os.chmod(AUTH_KEYS, 0600) run_command([CHOWN, '%s:%s' % (username, username), AUTH_KEYS])
def restart_samba(hard=False): """ call whenever config is updated """ mode = "reload" if hard: mode = "restart" run_command([SYSTEMCTL, mode, "smb"], log=True) return run_command([SYSTEMCTL, mode, "nmb"], log=True)
def userdel(uname): try: pwd.getpwnam(uname) except KeyError: # user doesn't exist return #Ensure user get deleted from samba pass db run_command([SMBPASSWD, '-x', uname]) return run_command([USERDEL, '-r', uname])
def userdel(uname): try: pwd.getpwnam(uname) except KeyError: # user doesn't exist return # Ensure user get deleted from samba pass db run_command([SMBPASSWD, "-x", uname]) return run_command([USERDEL, "-r", uname])
def update_check(subscription=None): if (subscription is not None): switch_repo(subscription) pkg = 'rockstor' version, date = rpm_build_info(pkg) if date is None: # None date signifies no rpm installed so list all changelog entries. date = 'all' log = False available = False new_version = None updates = [] try: o, e, rc = run_command([YUM, 'changelog', date, pkg]) except CommandException as e: # Catch as yet unconfigured repos ie Leap 15.1: error log accordingly. # Avoids breaking current version display and update channel selection. emsg = 'Error\\: Cannot retrieve repository metadata \\(repomd.xml\\)' if re.match(emsg, e.err[-2]) is not None: logger.error( 'Rockstor repo for distro.id ({}) version ({}) may ' 'not exist: pending or deprecated.\nReceived: ({}).'.format( distro.id(), distro.version(), e.err)) new_version = version # Explicitly set (flag) for code clarity. return version, new_version, updates # otherwise we raise an exception as normal. raise e for l in o: if (re.search('Available Packages', l) is not None): available = True if (not available): continue if (new_version is None and (re.match('rockstor-', l) is not None)): new_version = l.split()[0].split('rockstor-')[1].split( '.x86_64')[0] if (log is True): updates.append(l) if (len(l.strip()) == 0): log = False if (re.match('\* ', l) is not None): updates.append(l) log = True if (new_version is None): new_version = version # do a second check which is valid for updates without changelog # updates. eg: same day updates, testing updates. o, e, rc = run_command([YUM, 'update', pkg, '--assumeno'], throw=False) if (rc == 1): for l in o: if (re.search('will be an update', l) is not None): if (re.search('rockstor.x86_64', l) is not None): new_version = l.strip().split()[3].split(':')[1] return version, new_version, updates
def update_run(): fh, npath = mkstemp() with open(npath, 'w') as atfo: atfo.write('%s stop rockstor\n' % SYSTEMCTL) atfo.write('%s --setopt=timeout=600 -y update\n' % YUM) atfo.write('%s start rockstor\n' % SYSTEMCTL) atfo.write('/bin/rm -f %s\n' % npath) run_command([SYSTEMCTL, 'start', 'atd']) out, err, rc = run_command([AT, '-f', npath, 'now + 1 minutes']) time.sleep(120) return out, err, rc
def service_status(service_name, config=None): """ Service status of either systemd or supervisord managed services. Hardwired to identify controlling system by service name and uses one of systemctrl, init_service_op, or superctl to assess status accordingly. Note some sanity checks for some services. :param service_name: :return: """ if (service_name == 'nis' or service_name == 'nfs'): out, err, rc = init_service_op('rpcbind', 'status', throw=False) if (rc != 0): return out, err, rc if (service_name == 'nis'): return init_service_op('ypbind', 'status', throw=False) else: return init_service_op('nfs', 'status', throw=False) elif (service_name == 'ldap'): return init_service_op('nslcd', 'status', throw=False) elif (service_name == 'sftp'): out, err, rc = init_service_op('sshd', 'status', throw=False) if (rc != 0): return out, err, rc with open(SSHD_CONFIG) as sfo: for line in sfo.readlines(): if (re.match("Subsystem\tsftp\tinternal-sftp", line) is not None): return out, err, rc return out, err, -1 elif (service_name == 'replication' or service_name == 'data-collector'): return superctl(service_name, 'status') elif (service_name == 'smb'): out, err, rc = run_command([SYSTEMCTL_BIN, 'status', 'smb'], throw=False) if (rc != 0): return out, err, rc return run_command([SYSTEMCTL_BIN, 'status', 'nmb'], throw=False) elif (service_name == 'nut'): # Establish if nut is running by lowest common denominator nut-monitor # In netclient mode it is all that is required, however we don't then # reflect the state of the other services of nut-server and nut-driver. return run_command([SYSTEMCTL_BIN, 'status', 'nut-monitor'], throw=False) elif (service_name == 'active-directory'): if (config is not None): REALM = '/usr/sbin/realm' o, e, rc = run_command([REALM, 'list', '--name-only']) for l in o: if (l == config['domain']): return '', '', 0 return '', '', -1 return init_service_op(service_name, 'status', throw=False)
def update_check(subscription=None): if (subscription is not None): switch_repo(subscription) pkg = 'rockstor' version, date = rpm_build_info(pkg) if date is None: # None date signifies no rpm installed so list all changelog entries. date = 'all' log = False available = False new_version = None updates = [] try: o, e, rc = run_command([YUM, 'changelog', date, pkg]) except CommandException as e: # Catch as yet unconfigured repos ie Leap 15.1: error log accordingly. # Avoids breaking current version display and update channel selection. emsg = 'Error\\: Cannot retrieve repository metadata \\(repomd.xml\\)' if re.match(emsg, e.err[-2]) is not None: logger.error('Rockstor repo for distro.id ({}) version ({}) may ' 'not exist: pending or deprecated.\nReceived: ({}).' .format(distro.id(), distro.version(), e.err)) new_version = version # Explicitly set (flag) for code clarity. return version, new_version, updates # otherwise we raise an exception as normal. raise e for l in o: if (re.search('Available Packages', l) is not None): available = True if (not available): continue if (new_version is None and (re.match('rockstor-', l) is not None)): new_version = l.split()[0].split( 'rockstor-')[1].split('.x86_64')[0] if (log is True): updates.append(l) if (len(l.strip()) == 0): log = False if (re.match('\* ', l) is not None): log = True if (new_version is None): new_version = version # do a second check which is valid for updates without changelog # updates. eg: same day updates, testing updates. o, e, rc = run_command([YUM, 'update', pkg, '--assumeno'], throw=False) if (rc == 1): for l in o: if (re.search('will be an update', l) is not None): if (re.search('rockstor.x86_64', l) is not None): new_version = l.strip().split()[3].split(':')[1] return version, new_version, updates
def info(device, custom_options='', test_mode=TESTMODE): """ Retrieve matching properties found in smartctl -H --info output. Used to populate the Identity / general info tab by views/disk_smart.py :param device: disk device name :param test_mode: False causes cat from file rather than smartctl command :return: list of smart parameters extracted from device or test file """ if not test_mode: o, e, rc = run_command([SMART, '-H', '--info'] + get_dev_options(device, custom_options), throw=False) else: # we are testing so use a smartctl -H --info file dump instead o, e, rc = run_command([CAT, '/root/smartdumps/smart-H--info.out']) # List of string matches to look for in smartctrl -H --info output. # Note the "|" char allows for defining alternative matches ie A or B matches = ( 'Model Family:|Vendor:', 'Device Model:|Product:', 'Serial Number:|Serial number:', 'LU WWN Device Id:|Logical Unit id:', 'Firmware Version:|Revision', 'User Capacity:', 'Sector Sizes?:|Logical block size:', 'Rotation Rate:', 'Device is:', 'ATA Version is:', 'SATA Version is:', 'Local Time is:', 'SMART support is:.* Available', 'SMART support is:.* Enabled', 'SMART overall-health self-assessment|SMART Health Status:', ) # create a list of empty strings ready to store our smart results / values res = [ '', ] * len(matches) version = '' for line in o: if (re.match('smartctl ', line) is not None): version = ' '.join(line.split()[1:4]) for i in range(len(matches)): if (re.match(matches[i], line) is not None): # find location of first colon first_colon = re.search(':', line).start() # Assume all characters after colon are the result / value and # strip off begin and end spaces. Limit to 64 chars for db. res[i] = line[first_colon + 1:].strip()[:64] # smartctl version is expected at index 14 (15th item) res.insert(14, version) return res
def new_connection_helper(name, ipaddr, gateway, dns_servers, search_domains): manual = False if (ipaddr is not None and len(ipaddr.strip()) > 0): manual = True run_command([NMCLI, 'c', 'mod', name, 'ipv4.addresses', ipaddr]) if (gateway is not None and len(gateway.strip()) > 0): run_command([NMCLI, 'c', 'mod', name, 'ipv4.gateway', gateway]) if (manual): run_command([NMCLI, 'c', 'mod', name, 'ipv4.method', 'manual']) if (dns_servers is not None and len(dns_servers.strip()) > 0): run_command([NMCLI, 'c', 'mod', name, 'ipv4.dns', dns_servers]) if (search_domains is not None and len(search_domains.strip()) > 0): run_command([NMCLI, 'c', 'mod', name, 'ipv4.dns-search', search_domains])
def toggle_auth_service(service, command, config=None): ac_cmd = [AUTHCONFIG, '--update', ] if (service == 'ldap'): ac_cmd.extend(ldap_input(config, command)) else: return None return run_command(ac_cmd)
def superctl(service, switch): out, err, rc = run_command([SUPERCTL_BIN, switch, service]) if (switch == 'status'): status = out[0].split()[1] if (status != 'RUNNING'): rc = 1 return out, err, rc
def useradd(username, shell, uid=None, gid=None): pw_entry = None try: pw_entry = pwd.getpwnam(username) except: pass if (pw_entry is not None): if (uid is not None and uid != pw_entry.pw_uid): raise Exception('User(%s) already exists, but her uid(%d) is different from the input(%d).' % (username, pw_entry.pw_uid, uid)) if (gid is not None and gid != pw_entry.pw_gid): raise Exception('User(%s) already exists, but her gid(%d) is different from the input(%d).' % (username, pw_entry.pw_gid, gid)) if (shell != pw_entry.pw_shell): raise Exception('User(%s) already exists, but her shell(%s) is different from the input(%s).' % (username, pw_entry.shell, shell)) return ([''], [''], 0) cmd = [USERADD, '-s', shell, '-m', username] if (uid is not None): cmd.insert(-1, '-u') cmd.insert(-1, str(uid)) if (gid is not None): cmd.insert(-1, '-g') cmd.insert(-1, str(gid)) return run_command(cmd)
def capabilities(device): o, e, rc = run_command([SMART, '-c', '/dev/%s' % device]) cap_d = {} for i in range(len(o)): if (re.match('=== START OF READ SMART DATA SECTION ===', o[i]) is not None): prev_line = None cur_cap = None cur_val = None for j in range(i+2, len(o)): if (re.match('.*:\s+\(.*\)', o[j]) is not None): cap = o[j][:o[j].index(':')] flag = o[j][(o[j].index('(') + 1):o[j].index(')')].strip() val = o[j][(o[j].index(')') + 1):].strip() if (val == 'seconds.' or val == 'minutes.'): val = '%s %s' % (flag, val) flag = '' if (prev_line is not None): cap = '%s %s' % (prev_line, cap) prev_line = None cur_cap = cap cap_d[cur_cap] = [flag, val] elif (re.match('\s', o[j]) is not None): cap_d[cur_cap][1] += '\n' cap_d[cur_cap][1] += o[j].strip() else: prev_line = o[j].strip() break return cap_d
def init_service_op(service_name, command, throw=True): supported_services = ('nfs', 'smb', 'sshd', 'ypbind', 'rpcbind', 'ntpd', 'winbind', 'nslcd',) if (service_name not in supported_services): raise Exception('unknown service: %s' % service_name) return run_command([SYSTEMCTL_BIN, command, service_name], throw=throw)
def info(device): #get smart info of the device, such as availability o, e, rc = run_command( [SMART, '-H', '--info', '/dev/%s' % device], throw=False) res = {} matches = ( 'Model Family:', 'Device Model:', 'Serial Number:', 'LU WWN Device Id:', 'Firmware Version:', 'User Capacity:', 'Sector Size:', 'Rotation Rate:', 'Device is:', 'ATA Version is:', 'SATA Version is:', 'Local Time is:', 'SMART support is: Available', 'SMART support is: Enabled', 'SMART overall-health self-assessment', ) res = [ '', ] * len(matches) version = '' for l in o: if (re.match('smartctl ', l) is not None): version = ' '.join(l.split()[1:4]) for i in range(len(matches)): if (re.match(matches[i], l) is not None): res[i] = l.split(': ')[1].strip() res.insert(14, version) return res
def ip_restrict(tid): """ no restrictions at all """ cmd = [TGTADM_BIN, '--lld', 'iscsi', '--mode', 'target', '--op', 'bind', '--tid', tid, '-I', 'ALL'] return run_command(cmd)
def useradd(username, shell, uid=None, gid=None): pw_entry = None try: # Use unix password db to assess prior user status by name pw_entry = pwd.getpwnam(username) except: pass if pw_entry is not None: # If we have a prior user by name assess uid gid mismatches. if uid is not None and uid != pw_entry.pw_uid: raise Exception( "User({0}) already exists, but her uid({1}) is " "different from the input({2}).".format(username, pw_entry.pw_uid, uid) ) if gid is not None and gid != pw_entry.pw_gid: raise Exception( "User({0}) already exists, but her gid({1}) is " "different from the input({2}).".format(username, pw_entry.pw_gid, gid) ) if shell != pw_entry.pw_shell: raise Exception( "User({0}) already exists, but her shell({1}) is " "different from the input({2}).".format(username, pw_entry.shell, shell) ) return ([""], [""], 0) cmd = [USERADD, "-s", shell, "-m", username] if uid is not None: cmd.insert(-1, "-u") cmd.insert(-1, str(uid)) if gid is not None: cmd.insert(-1, "-g") cmd.insert(-1, str(gid)) return run_command(cmd)
def capabilities(device): o, e, rc = run_command([SMART, '-c', '/dev/%s' % device]) cap_d = {} for i in range(len(o)): if (re.match('=== START OF READ SMART DATA SECTION ===', o[i]) is not None): prev_line = None cur_cap = None cur_val = None for j in range(i + 2, len(o)): if (re.match('.*:\s+\(.*\)', o[j]) is not None): cap = o[j][:o[j].index(':')] flag = o[j][(o[j].index('(') + 1):o[j].index(')')].strip() val = o[j][(o[j].index(')') + 1):].strip() if (val == 'seconds.' or val == 'minutes.'): val = '%s %s' % (flag, val) flag = '' if (prev_line is not None): cap = '%s %s' % (prev_line, cap) prev_line = None cur_cap = cap cap_d[cur_cap] = [flag, val] elif (re.match('\s', o[j]) is not None): cap_d[cur_cap][1] += '\n' cap_d[cur_cap][1] += o[j].strip() else: prev_line = o[j].strip() break return cap_d
def test_parm(config="/etc/samba/smb.conf"): cmd = [TESTPARM, "-s", config] o, e, rc = run_command(cmd, throw=False) if rc != 0: raise Exception( "Syntax error while checking the temporary samba config file") return True
def useradd(username, shell, uid=None, gid=None): pw_entry = None try: # Use unix password db to assess prior user status by name pw_entry = pwd.getpwnam(username) except: pass if (pw_entry is not None): # If we have a prior user by name assess uid gid mismatches. if (uid is not None and uid != pw_entry.pw_uid): raise Exception('User({0}) already exists, but her uid({1}) is ' 'different from the input({2}).'.format( username, pw_entry.pw_uid, uid)) if (gid is not None and gid != pw_entry.pw_gid): raise Exception('User({0}) already exists, but her gid({1}) is ' 'different from the input({2}).'.format( username, pw_entry.pw_gid, gid)) if (shell != pw_entry.pw_shell): raise Exception('User({0}) already exists, but her shell({1}) is ' 'different from the input({2}).'.format( username, pw_entry.shell, shell)) return ([''], [''], 0) cmd = [USERADD, '-s', shell, '-m', username] if (uid is not None): cmd.insert(-1, '-u') cmd.insert(-1, str(uid)) if (gid is not None): cmd.insert(-1, '-g') cmd.insert(-1, str(gid)) return run_command(cmd)
def validate_tls_cert(server, cert): """ Run openssl s_client -connect server:389 -CAfile path-to-cert to verify the provided TLS certificate against the LDAP server. :param server: String - FQDN of the LDAP server :param cert: String - Absolute path to the TLS certificate :return: """ cmd = [ OPENSSL, "s_client", "-connect", "{}:389".format(server), "-CAfile", cert, ] o, e, rc = run_command(cmd, throw=False) if "Verification: OK" not in o: err_msg = ( "Failed to validate the TLS certificate ({}).\n" "out: {} err: {} rc: {}".format(cert, o, e, rc) ) if any("fopen:No such file or directory" in err for err in e): err_msg = ( "The TLS certificate file could not be found at {}.\n" "out: {} err: {} rc: {}".format(cert, o, e, rc) ) raise Exception(err_msg)
def pkg_latest_available(pkg_name, arch, distro_id): """ Simple wrapper around "yum update pkg_name --assumeno" to retrieve latest version available from "Version" column :return: """ new_version = None # TODO: We might use "zypper se -s --match-exact rockstor" and parse first # line with rockstor in second column but unit test will be defunct. # Advantage: works with no rockstor version installed, no so dnf-yum o, e, rc = run_command([YUM, "update", pkg_name, "--assumeno"], throw=False) if rc == 1: for l in o: if distro_id == "rockstor": # Legacy Yum appropriate parsing, all info on one line. # "Package rockstor.x86_64 0:3.9.2-51.2089 will be an update" if re.search("will be an update", l) is not None: if re.search("rockstor.{}".format(arch), l) is not None: new_version = l.strip().split()[3].split(":")[1] else: # We are assuming openSUSE with dnf-yum output format # dnf-yum output line of interest; when presented: # " rockstor x86_64 3.9.2-51.2089 localrepo 15 M" if re.match(" rockstor", l) is not None: new_version = l.strip().split()[2] return new_version
def test_parm(config='/etc/samba/smb.conf'): cmd = [TESTPARM, '-s', config] o, e, rc = run_command(cmd, throw=False) if (rc != 0): raise Exception('Syntax error while checking the temporary ' 'samba config file') return True