def chgid(name, gid): ''' Change the default group of the user CLI Example: .. code-block:: bash salt '*' user.chgid foo 4376 ''' if not isinstance(gid, int): raise SaltInvocationError('gid must be an integer') pre_info = info(name) if not pre_info: raise CommandExecutionError('User {0!r} does not exist'.format(name)) if gid == pre_info['gid']: return True _dscl( '/Users/{0} PrimaryGroupID {1!r} {2!r}'.format( _cmd_quote(name), _cmd_quote(pre_info['gid']), _cmd_quote(gid)), ctype='change' ) # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) return info(name).get('gid') == gid
def chgroups(name, groups, append=True): ''' Change the groups this user belongs to, add append=False to make the user a member of only the specified groups Args: name (str): The user name for which to change groups groups (str, list): A single group or a list of groups to assign to the user. For multiple groups this can be a comma delimited string or a list. append (bool, optional): True adds the passed groups to the user's current groups. False sets the user's groups to the passed groups only. Default is True. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' user.chgroups jsnuffy Administrators,Users True ''' if six.PY2: name = _to_unicode(name) if isinstance(groups, string_types): groups = groups.split(',') groups = [x.strip(' *') for x in groups] if six.PY2: groups = [_to_unicode(x) for x in groups] ugrps = set(list_groups(name)) if ugrps == set(groups): return True name = _cmd_quote(name) if not append: for group in ugrps: group = _cmd_quote(group).lstrip('\'').rstrip('\'') if group not in groups: cmd = 'net localgroup "{0}" {1} /delete'.format(group, name) __salt__['cmd.run_all'](cmd, python_shell=True) for group in groups: if group in ugrps: continue group = _cmd_quote(group).lstrip('\'').rstrip('\'') cmd = 'net localgroup "{0}" {1} /add'.format(group, name) out = __salt__['cmd.run_all'](cmd, python_shell=True) if out['retcode'] != 0: log.error(out['stdout']) return False agrps = set(list_groups(name)) return len(ugrps - agrps) == 0
def _rbenv_exec(command, args='', env=None, runas=None, ret=None): if not is_installed(runas): return False binary = _rbenv_bin(runas) path = _rbenv_path(runas) environ = {} for token in _cmd_split(env): try: var, val = token.split('=') environ[var] = val except Exception: pass # if token != var=val, it's not a proper env anyway environ['RBENV_ROOT'] = path args = ' '.join([_cmd_quote(arg) for arg in _cmd_split(args)]) result = __salt__['cmd.run_all']( '{0} {1} {2}'.format(binary, _cmd_quote(command), args), runas=runas, env=environ ) if isinstance(ret, dict): ret.update(result) return ret if result['retcode'] == 0: return result['stdout'] else: return False
def chfullname(name, fullname): ''' Change the full name of the user CLI Example: .. code-block:: bash salt '*' user.chfullname user 'First Last' ''' pre_info = info(name) if not pre_info: return False name = _cmd_quote(name) fullname_qts = _cmd_quote(fullname).replace("'", "\"") if fullname == pre_info['fullname']: return True if __salt__['cmd.retcode']('net user {0} /fullname:{1}'.format( name, fullname_qts), python_shell=True) != 0: return False post_info = info(name) if post_info['fullname'] != pre_info['fullname']: return post_info['fullname'] == fullname return False
def _bootstrap_yum( root, pkg_confs='/etc/yum*', pkgs=None, exclude_pkgs=None, epel_url=EPEL_URL, ): ''' Bootstrap an image using the yum tools root The root of the image to install to. Will be created as a directory if if does not exist. (e.x.: /root/arch) pkg_confs The location of the conf files to copy into the image, to point yum to the right repos and configuration. pkgs A list of packages to be installed on this image. For RedHat, this will include ``yum``, ``centos-release`` and ``iputils`` by default. exclude_pkgs A list of packages to be excluded. If you do not want to install the defaults, you need to include them in this list. epel_url The URL to download the EPEL release package from. TODO: Set up a pre-install overlay, to copy files into /etc/ and so on, which are required for the install to work. ''' if pkgs is None: pkgs = [] default_pkgs = ('yum', 'centos-release', 'iputils') for pkg in default_pkgs: if pkg not in pkgs: pkgs.append(pkg) if exclude_pkgs is None: exclude_pkgs = [] for pkg in exclude_pkgs: pkgs.remove(pkg) _make_nodes(root) release_files = [rf for rf in os.listdir('/etc') if rf.endswith('release')] __salt__['cmd.run']('cp /etc/resolv/conf {rfs} {root}/etc'.format(root=_cmd_quote(root), rfs=' '.join(release_files))) __salt__['cmd.run']('cp -r {rfs} {root}/etc'.format(root=_cmd_quote(root), rfs=' '.join(release_files))) __salt__['cmd.run']('cp -r {confs} {root}/etc'.format(root=_cmd_quote(root), confs=_cmd_quote(pkg_confs))) yum_args = ['yum', 'install', '--installroot={0}'.format(_cmd_quote(root)), '-y'] + pkgs __salt__['cmd.run'](yum_args, python_shell=False) if 'epel-release' not in exclude_pkgs: __salt__['cmd.run']( ('rpm', '--root={0}'.format(_cmd_quote(root)), '-Uvh', epel_url), python_shell=False )
def chfullname(name, fullname): ''' Change the user's Full Name CLI Example: .. code-block:: bash salt '*' user.chfullname foo 'Foo Bar' ''' fullname = str(fullname) pre_info = info(name) if not pre_info: raise CommandExecutionError('User {0!r} does not exist'.format(name)) if fullname == pre_info['fullname']: return True _dscl( '/Users/{0} RealName {1!r}'.format(_cmd_quote(name), _cmd_quote(fullname)), # use a "create" command, because a "change" command would fail if # current fullname is an empty string. The "create" will just overwrite # this field. ctype='create' ) # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) return info(name).get('fullname') == fullname
def pair(address, key): ''' Pair the bluetooth adapter with a device CLI Example: .. code-block:: bash salt '*' bluetooth.pair DE:AD:BE:EF:CA:FE 1234 Where DE:AD:BE:EF:CA:FE is the address of the device to pair with, and 1234 is the passphrase. TODO: This function is currently broken, as the bluez-simple-agent program no longer ships with BlueZ >= 5.0. It needs to be refactored. ''' if not salt.utils.validate.net.mac(address): raise CommandExecutionError( 'Invalid BD address passed to bluetooth.pair') try: int(key) except Exception: raise CommandExecutionError( 'bluetooth.pair requires a numerical key to be used') addy = address_() cmd = 'echo {0} | bluez-simple-agent {1} {2}'.format( _cmd_quote(addy['device']), _cmd_quote(address), _cmd_quote(key)) out = __salt__['cmd.run'](cmd, python_shell=True).splitlines() return out
def chhome(name, home): ''' Change the home directory of the user CLI Example: .. code-block:: bash salt '*' user.chhome foo /Users/foo ''' pre_info = info(name) if not pre_info: raise CommandExecutionError('User {0!r} does not exist'.format(name)) if home == pre_info['home']: return True _dscl( '/Users/{0} NFSHomeDirectory {1!r} {2!r}'.format( _cmd_quote(name), _cmd_quote(pre_info['home']), _cmd_quote(home)), ctype='change' ) # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) return info(name).get('home') == home
def chshell(name, shell): ''' Change the default shell of the user CLI Example: .. code-block:: bash salt '*' user.chshell foo /bin/zsh ''' pre_info = info(name) if not pre_info: raise CommandExecutionError('User {0!r} does not exist'.format(name)) if shell == pre_info['shell']: return True _dscl( '/Users/{0} UserShell {1!r} {2!r}'.format( _cmd_quote(name), _cmd_quote(pre_info['shell']), _cmd_quote(shell)), ctype='change' ) # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) return info(name).get('shell') == shell
def addgroup(name, group): ''' Add user to a group Args: name (str): The user name to add to the group group (str): The name of the group to which to add the user Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' user.addgroup jsnuffy 'Power Users' ''' if six.PY2: name = _to_unicode(name) group = _to_unicode(group) name = _cmd_quote(name) group = _cmd_quote(group).lstrip('\'').rstrip('\'') user = info(name) if not user: return False if group in user['groups']: return True cmd = 'net localgroup "{0}" {1} /add'.format(group, name) ret = __salt__['cmd.run_all'](cmd, python_shell=True) return ret['retcode'] == 0
def _rbenv_exec(command, args='', env=None, runas=None, ret=None): if not is_installed(runas): return False binary = _rbenv_bin(runas) path = _rbenv_path(runas) environ = _parse_env(env) environ['RBENV_ROOT'] = path args = ' '.join([_cmd_quote(arg) for arg in _shlex_split(args)]) result = __salt__['cmd.run_all']( '{0} {1} {2}'.format(binary, _cmd_quote(command), args), runas=runas, env=environ ) if isinstance(ret, dict): ret.update(result) return ret if result['retcode'] == 0: return result['stdout'] else: return False
def _bootstrap_pacman(root, pkg_confs='/etc/pacman*', img_format='dir'): ''' Bootstrap an image using the pacman tools root The root of the image to install to. Will be created as a directory if if does not exist. (e.x.: /root/arch) pkg_confs The location of the conf files to copy into the image, to point pacman to the right repos and configuration. img_format The image format to be used. The ``dir`` type needs no special treatment, but others need special treatement. ''' _make_nodes(root) if img_format != 'dir': __salt__['mount.mount']('{0}/proc'.format(root), '/proc', fstype='', opts='bind') __salt__['mount.mount']('{0}/dev'.format(root), '/dev', fstype='', opts='bind') __salt__['file.mkdir']( '{0}/var/lib/pacman/local'.format(root), 'root', 'root', '755' ) pac_files = [rf for rf in os.listdir('/etc') if rf.startswith('pacman.')] for pac_file in pac_files: __salt__['cmd.run']('cp -r /etc/{0} {1}/etc'.format(pac_file, _cmd_quote(root))) __salt__['file.copy']('/var/lib/pacman/sync', '{0}/var/lib/pacman/sync'.format(root), recurse=True) __salt__['cmd.run']('pacman --noconfirm -r {0} -S pacman linux'.format(_cmd_quote(root))) if img_format != 'dir': __salt__['mount.umount']('{0}/proc'.format(root)) __salt__['mount.umount']('{0}/dev'.format(root))
def version_cmp(pkg1, pkg2): ''' Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem making the comparison. CLI Example: .. code-block:: bash salt '*' pkg.version_cmp '0.2.4-0' '0.2.4.1-0' ''' cmd_compare = ['opkg-compare-versions'] for oper, ret in (("<<", -1), ("=", 0), (">>", 1)): cmd = cmd_compare[:] cmd.append(_cmd_quote(pkg1)) cmd.append(oper) cmd.append(_cmd_quote(pkg2)) retcode = __salt__['cmd.retcode'](cmd, output_loglevel='trace', ignore_retcode=True, python_shell=False) if retcode == 0: return ret return None
def _rbenv_exec(command, args='', env=None, runas=None, ret=None): if not is_installed(runas): return False binary = _rbenv_bin(runas) path = _rbenv_path(runas) environ = _parse_env(env) environ['RBENV_ROOT'] = path args = ' '.join([_cmd_quote(arg) for arg in _shlex_split(args)]) result = __salt__['cmd.run_all']('{0} {1} {2}'.format( binary, _cmd_quote(command), args), runas=runas, env=environ) if isinstance(ret, dict): ret.update(result) return ret if result['retcode'] == 0: return result['stdout'] else: return False
def removegroup(name, group): """ Remove user from a group Args: name (str): The user name to remove from the group group (str): The name of the group from which to remove the user Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' user.removegroup jsnuffy 'Power Users' """ name = _cmd_quote(name) group = _cmd_quote(group).lstrip("'").rstrip("'") user = info(name) if not user: return False if group not in user["groups"]: return True cmd = 'net localgroup "{}" {} /delete'.format(group, name) ret = __salt__["cmd.run_all"](cmd, python_shell=True) return ret["retcode"] == 0
def do(cmdline=None, runas=None): ''' Execute a python command with pyenv's shims from the user or the system. CLI Example: .. code-block:: bash salt '*' pyenv.do 'gem list bundler' salt '*' pyenv.do 'gem list bundler' deploy ''' path = _pyenv_path(runas) cmd_split = cmdline.split() quoted_line = '' for cmd in cmd_split: quoted_line = quoted_line + ' ' + _cmd_quote(cmd) result = __salt__['cmd.run_all']( 'env PATH={0}/shims:$PATH {1}'.format(_cmd_quote(path), quoted_line), runas=runas, python_shell=True ) if result['retcode'] == 0: rehash(runas=runas) return result['stdout'] else: return False
def chhome(name, home, **kwargs): ''' Change the home directory of the user CLI Example: .. code-block:: bash salt '*' user.chhome foo /Users/foo ''' kwargs = salt.utils.clean_kwargs(**kwargs) persist = kwargs.pop('persist', False) if kwargs: salt.utils.invalid_kwargs(kwargs) if persist: log.info('Ignoring unsupported \'persist\' argument to user.chhome') pre_info = info(name) if not pre_info: raise CommandExecutionError('User {0!r} does not exist'.format(name)) if home == pre_info['home']: return True _dscl('/Users/{0} NFSHomeDirectory {1!r} {2!r}'.format( _cmd_quote(name), _cmd_quote(pre_info['home']), _cmd_quote(home)), ctype='change') # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) return info(name).get('home') == home
def removegroup(name, group): ''' Remove user from a group CLI Example: .. code-block:: bash salt '*' user.removegroup username groupname ''' name = _cmd_quote(name) group = _cmd_quote(group).lstrip('\'').rstrip('\'') user = info(name) if not user: return False if group not in user['groups']: return True cmd = 'net localgroup "{0}" {1} /delete'.format(group, name) ret = __salt__['cmd.run_all'](cmd, python_shell=True) return ret['retcode'] == 0
def chuid(name, uid): ''' Change the uid for a named user CLI Example: .. code-block:: bash salt '*' user.chuid foo 4376 ''' if not isinstance(uid, int): raise SaltInvocationError('uid must be an integer') pre_info = info(name) if not pre_info: raise CommandExecutionError('User {0!r} does not exist'.format(name)) if uid == pre_info['uid']: return True _dscl('/Users/{0} UniqueID {1!r} {2!r}'.format(_cmd_quote(name), _cmd_quote(pre_info['uid']), uid), ctype='change') # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) return info(name).get('uid') == uid
def chfullname(name, fullname): ''' Change the user's Full Name CLI Example: .. code-block:: bash salt '*' user.chfullname foo 'Foo Bar' ''' fullname = str(fullname) pre_info = info(name) if not pre_info: raise CommandExecutionError('User {0!r} does not exist'.format(name)) if fullname == pre_info['fullname']: return True _dscl( '/Users/{0} RealName {1!r}'.format(_cmd_quote(name), _cmd_quote(fullname)), # use a "create" command, because a "change" command would fail if # current fullname is an empty string. The "create" will just overwrite # this field. ctype='create') # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) return info(name).get('fullname') == fullname
def do(cmdline=None, runas=None): """ Execute a python command with pyenv's shims from the user or the system. CLI Example: .. code-block:: bash salt '*' pyenv.do 'gem list bundler' salt '*' pyenv.do 'gem list bundler' deploy """ path = _pyenv_path(runas) cmd_split = cmdline.split() quoted_line = "" for cmd in cmd_split: quoted_line = quoted_line + " " + _cmd_quote(cmd) result = __salt__["cmd.run_all"]( "env PATH={0}/shims:$PATH {1}".format(_cmd_quote(path), quoted_line), runas=runas, python_shell=True, ) if result["retcode"] == 0: rehash(runas=runas) return result["stdout"] else: return False
def removegroup(name, group): ''' Remove user from a group :param str name: user name to remove from the group :param str group: name of the group from which to remove the user :return: True if successful. False is unsuccessful. :rtype: bool CLI Example: .. code-block:: bash salt '*' user.removegroup jsnuffy 'Power Users' ''' name = _cmd_quote(name) group = _cmd_quote(group).lstrip('\'').rstrip('\'') user = info(name) if not user: return False if group not in user['groups']: return True cmd = 'net localgroup "{0}" {1} /delete'.format(group, name) ret = __salt__['cmd.run_all'](cmd, python_shell=True) return ret['retcode'] == 0
def pair(address, key): ''' Pair the bluetooth adapter with a device CLI Example: .. code-block:: bash salt '*' bluetooth.pair DE:AD:BE:EF:CA:FE 1234 Where DE:AD:BE:EF:CA:FE is the address of the device to pair with, and 1234 is the passphrase. TODO: This function is currently broken, as the bluez-simple-agent program no longer ships with BlueZ >= 5.0. It needs to be refactored. ''' if not salt.utils.validate.net.mac(address): raise CommandExecutionError( 'Invalid BD address passed to bluetooth.pair' ) try: int(key) except Exception: raise CommandExecutionError( 'bluetooth.pair requires a numerical key to be used' ) addy = address_() cmd = 'echo {0} | bluez-simple-agent {1} {2}'.format( _cmd_quote(addy['device']), _cmd_quote(address), _cmd_quote(key) ) out = __salt__['cmd.run'](cmd, python_shell=True).splitlines() return out
def sources_list(ruby=None, runas=None, gem_bin=None): ''' List the configured gem sources. :param gem_bin: string : None Full path to ``gem`` binary to use. :param ruby: string : None If RVM or rbenv are installed, the ruby version and gemset to use. Ignored if ``gem_bin`` is specified. :param runas: string : None The user to run gem as. CLI Example: .. code-block:: bash salt '*' gem.sources_list ''' # Check for injection if ruby: ruby = _cmd_quote(ruby) if gem_bin: gem_bin = _cmd_quote(gem_bin) ret = _gem('sources', ruby, gem_bin=gem_bin, runas=runas) return [] if ret is False else ret.splitlines()[2:]
def do(cmdline=None, runas=None): ''' Execute a python command with pyenv's shims from the user or the system. CLI Example: .. code-block:: bash salt '*' pyenv.do 'gem list bundler' salt '*' pyenv.do 'gem list bundler' deploy ''' path = _pyenv_path(runas) cmd_split = cmdline.split() quoted_line = '' for cmd in cmd_split: quoted_line = quoted_line + ' ' + _cmd_quote(cmd) result = __salt__['cmd.run_all']('env PATH={0}/shims:$PATH {1}'.format( _cmd_quote(path), quoted_line), runas=runas, python_shell=True) if result['retcode'] == 0: rehash(runas=runas) return result['stdout'] else: return False
def update_system(version='', ruby=None, runas=None, gem_bin=None): ''' Update rubygems. :param version: string : (newest) The version of rubygems to install. :param gem_bin: string : None Full path to ``gem`` binary to use. :param ruby: string : None If RVM or rbenv are installed, the ruby version and gemset to use. Ignored if ``gem_bin`` is specified. :param runas: string : None The user to run gem as. CLI Example: .. code-block:: bash salt '*' gem.update_system ''' # Check for injection if version: version = _cmd_quote(version) if ruby: ruby = _cmd_quote(ruby) if gem_bin: gem_bin = _cmd_quote(gem_bin) return _gem('update --system {version}'.format(version=version), ruby, gem_bin=gem_bin, runas=runas)
def sources_remove(source_uri, ruby=None, runas=None, gem_bin=None): ''' Remove a gem source. :param source_uri: string The source URI to remove. :param gem_bin: string : None Full path to ``gem`` binary to use. :param ruby: string : None If RVM or rbenv are installed, the ruby version and gemset to use. Ignored if ``gem_bin`` is specified. :param runas: string : None The user to run gem as. CLI Example: .. code-block:: bash salt '*' gem.sources_remove http://rubygems.org/ ''' # Check for injection if source_uri: source_uri = _cmd_quote(source_uri) if ruby: ruby = _cmd_quote(ruby) if gem_bin: gem_bin = _cmd_quote(gem_bin) return _gem('sources --remove {source_uri}'.format(source_uri=source_uri), ruby, gem_bin=gem_bin, runas=runas)
def update(gems, ruby=None, runas=None, gem_bin=None): ''' Update one or several gems. :param gems: string The gems to update. :param gem_bin: string : None Full path to ``gem`` binary to use. :param ruby: string : None If RVM or rbenv are installed, the ruby version and gemset to use. Ignored if ``gem_bin`` is specified. :param runas: string : None The user to run gem as. CLI Example: .. code-block:: bash salt '*' gem.update vagrant ''' # Check for injection if gems: gems = ' '.join([_cmd_quote(gem) for gem in gems.split()]) if ruby: ruby = _cmd_quote(ruby) if gem_bin: gem_bin = _cmd_quote(gem_bin) return _gem('update {gems}'.format(gems=gems), ruby, gem_bin=gem_bin, runas=runas)
def version_cmp(pkg1, pkg2, ignore_epoch=False): ''' Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem making the comparison. ignore_epoch : False Set to ``True`` to ignore the epoch when comparing versions .. versionadded:: 2016.3.4 CLI Example: .. code-block:: bash salt '*' pkg.version_cmp '0.2.4-0' '0.2.4.1-0' ''' normalize = lambda x: str(x).split(':', 1)[-1] if ignore_epoch else str(x) pkg1 = normalize(pkg1) pkg2 = normalize(pkg2) cmd_compare = ['opkg-compare-versions'] for oper, ret in (("<<", -1), ("=", 0), (">>", 1)): cmd = cmd_compare[:] cmd.append(_cmd_quote(pkg1)) cmd.append(oper) cmd.append(_cmd_quote(pkg2)) retcode = __salt__['cmd.retcode'](cmd, output_loglevel='trace', ignore_retcode=True, python_shell=False) if retcode == 0: return ret return None
def _rbenv_exec(command, args='', env=None, runas=None, ret=None): if not is_installed(runas): return False binary = _rbenv_bin(runas) path = _rbenv_path(runas) environ = {} for token in _cmd_split(env): try: var, val = token.split('=') environ[var] = val except Exception: pass # if token != var=val, it's not a proper env anyway environ['RBENV_ROOT'] = path args = ' '.join([_cmd_quote(arg) for arg in _cmd_split(args)]) result = __salt__['cmd.run_all']('{0} {1} {2}'.format( binary, _cmd_quote(command), args), runas=runas, env=environ) if isinstance(ret, dict): ret.update(result) return ret if result['retcode'] == 0: return result['stdout'] else: return False
def _bootstrap_pacman(root, pkg_confs="/etc/pacman*", img_format="dir", pkgs=None, exclude_pkgs=None): """ Bootstrap an image using the pacman tools root The root of the image to install to. Will be created as a directory if if does not exist. (e.x.: /root/arch) pkg_confs The location of the conf files to copy into the image, to point pacman to the right repos and configuration. img_format The image format to be used. The ``dir`` type needs no special treatment, but others need special treatement. pkgs A list of packages to be installed on this image. For Arch Linux, this will include ``pacman``, ``linux``, ``grub``, and ``systemd-sysvcompat`` by default. exclude_pkgs A list of packages to be excluded. If you do not want to install the defaults, you need to include them in this list. """ _make_nodes(root) if pkgs is None: pkgs = [] default_pkgs = ("pacman", "linux", "systemd-sysvcompat", "grub") for pkg in default_pkgs: if pkg not in pkgs: pkgs.append(pkg) if exclude_pkgs is None: exclude_pkgs = [] for pkg in exclude_pkgs: pkgs.remove(pkg) if img_format != "dir": __salt__["mount.mount"]("{0}/proc".format(root), "/proc", fstype="", opts="bind") __salt__["mount.mount"]("{0}/dev".format(root), "/dev", fstype="", opts="bind") __salt__["file.mkdir"]("{0}/var/lib/pacman/local".format(root), "root", "root", "755") pac_files = [rf for rf in os.listdir("/etc") if rf.startswith("pacman.")] for pac_file in pac_files: __salt__["cmd.run"]("cp -r /etc/{0} {1}/etc".format(pac_file, _cmd_quote(root))) __salt__["file.copy"]("/var/lib/pacman/sync", "{0}/var/lib/pacman/sync".format(root), recurse=True) pacman_args = ["pacman", "--noconfirm", "-r", _cmd_quote(root), "-S"] + pkgs __salt__["cmd.run"](pacman_args, python_shell=False) if img_format != "dir": __salt__["mount.umount"]("{0}/proc".format(root)) __salt__["mount.umount"]("{0}/dev".format(root))
def chgroups(name, groups, append=False): ''' Change the groups to which the user belongs. Note that the user's primary group does not have to be one of the groups passed, membership in the user's primary group is automatically assumed. groups Groups to which the user should belong, can be passed either as a python list or a comma-separated string append Instead of removing user from groups not included in the ``groups`` parameter, just add user to any groups for which they are not members CLI Example: .. code-block:: bash salt '*' user.chgroups foo wheel,root ''' ### NOTE: **args isn't used here but needs to be included in this ### function for compatibility with the user.present state uinfo = info(name) if not uinfo: raise CommandExecutionError('User {0!r} does not exist'.format(name)) if isinstance(groups, string_types): groups = groups.split(',') bad_groups = [x for x in groups if salt.utils.contains_whitespace(x)] if bad_groups: raise SaltInvocationError( 'Invalid group name(s): {0}'.format(', '.join(bad_groups)) ) ugrps = set(list_groups(name)) desired = set(str(x) for x in groups if bool(str(x))) primary_group = __salt__['file.gid_to_group'](uinfo['gid']) if primary_group: desired.add(primary_group) if ugrps == desired: return True # Add groups from which user is missing for group in desired - ugrps: _dscl( '/Groups/{0} GroupMembership {1}'.format(_cmd_quote(group), _cmd_quote(name)), ctype='append' ) if not append: # Remove from extra groups for group in ugrps - desired: _dscl( '/Groups/{0} GroupMembership {1}'.format(_cmd_quote(group), _cmd_quote(name)), ctype='delete' ) time.sleep(1) return set(list_groups(name)) == desired
def install(pecls, defaults=False, force=False, preferred_state="stable"): """ .. versionadded:: 0.17.0 Installs one or several pecl extensions. pecls The pecl extensions to install. defaults Use default answers for extensions such as pecl_http which ask questions before installation. Without this option, the pecl.installed state will hang indefinitely when trying to install these extensions. force Whether to force the installed version or not CLI Example: .. code-block:: bash salt '*' pecl.install fuse """ if isinstance(pecls, six.string_types): pecls = [pecls] preferred_state = "-d preferred_state={0}".format( _cmd_quote(preferred_state)) if force: return _pecl( "{0} install -f {1}".format(preferred_state, _cmd_quote(" ".join(pecls))), defaults=defaults, ) else: _pecl( "{0} install {1}".format(preferred_state, _cmd_quote(" ".join(pecls))), defaults=defaults, ) if not isinstance(pecls, list): pecls = [pecls] for pecl in pecls: found = False if "/" in pecl: channel, pecl = pecl.split("/") else: channel = None installed_pecls = list_(channel) for pecl in installed_pecls: installed_pecl_with_version = "{0}-{1}".format( pecl, installed_pecls.get(pecl)[0]) if pecl in installed_pecl_with_version: found = True if not found: return False return True
def chgroups(name, groups, append=True): ''' Change the groups this user belongs to, add append=False to make the user a member of only the specified groups :param str name: user name for which to change groups :param groups: a single group or a list of groups to assign to the user :type groups: list, str :param bool append: True adds the passed groups to the user's current groups False sets the user's groups to the passed groups only :return: True if successful. False is unsuccessful. :rtype: bool CLI Example: .. code-block:: bash salt '*' user.chgroups jsnuffy Administrators,Users True ''' if isinstance(groups, string_types): groups = groups.split(',') groups = [x.strip(' *') for x in groups] ugrps = set(list_groups(name)) if ugrps == set(groups): return True name = _cmd_quote(name) if not append: for group in ugrps: group = _cmd_quote(group).lstrip('\'').rstrip('\'') if group not in groups: cmd = 'net localgroup "{0}" {1} /delete'.format(group, name) __salt__['cmd.run_all'](cmd, python_shell=True) for group in groups: if group in ugrps: continue group = _cmd_quote(group).lstrip('\'').rstrip('\'') cmd = 'net localgroup "{0}" {1} /add'.format(group, name) out = __salt__['cmd.run_all'](cmd, python_shell=True) if out['retcode'] != 0: log.error(out['stdout']) return False agrps = set(list_groups(name)) return len(ugrps - agrps) == 0
def execute(opts, data, func, args, kwargs): ''' Allow for the calling of execution modules via sudo. This module is invoked by the minion if the ``sudo_user`` minion config is present. Example minion config: .. code-block:: yaml sudo_user: saltdev Once this setting is made, any execution module call done by the minion will be run under ``sudo -u <sudo_user> salt-call``. For example, with the above minion config, .. code-block:: bash salt sudo_minion cmd.run 'cat /etc/sudoers' is equivalent to .. code-block:: bash sudo -u saltdev salt-call cmd.run 'cat /etc/sudoers' being run on ``sudo_minion``. ''' cmd = ['sudo', '-u', opts.get('sudo_user'), 'salt-call', '--out', 'json', '--metadata', '-c', salt.syspaths.CONFIG_DIR, '--', data.get('fun')] if data['fun'] == 'state.sls': kwargs['concurrent'] = True for arg in args: cmd.append(_cmd_quote(str(arg))) for key in kwargs: cmd.append(_cmd_quote('{0}={1}'.format(key, kwargs[key]))) cmd_ret = __salt__['cmd.run_all'](cmd, use_vt=True, python_shell=False) if cmd_ret['retcode'] == 0: cmd_meta = json.loads(cmd_ret['stdout'])['local'] ret = cmd_meta['return'] __context__['retcode'] = cmd_meta.get('retcode', 0) else: ret = cmd_ret['stderr'] __context__['retcode'] = cmd_ret['retcode'] return ret
def _bootstrap_yum(root, pkg_confs="/etc/yum*", pkgs=None, exclude_pkgs=None, epel_url=EPEL_URL): """ Bootstrap an image using the yum tools root The root of the image to install to. Will be created as a directory if if does not exist. (e.x.: /root/arch) pkg_confs The location of the conf files to copy into the image, to point yum to the right repos and configuration. pkgs A list of packages to be installed on this image. For RedHat, this will include ``yum``, ``centos-release`` and ``iputils`` by default. exclude_pkgs A list of packages to be excluded. If you do not want to install the defaults, you need to include them in this list. epel_url The URL to download the EPEL release package from. TODO: Set up a pre-install overlay, to copy files into /etc/ and so on, which are required for the install to work. """ if pkgs is None: pkgs = [] default_pkgs = ("yum", "centos-release", "iputils") for pkg in default_pkgs: if pkg not in pkgs: pkgs.append(pkg) if exclude_pkgs is None: exclude_pkgs = [] for pkg in exclude_pkgs: pkgs.remove(pkg) _make_nodes(root) release_files = [rf for rf in os.listdir("/etc") if rf.endswith("release")] __salt__["cmd.run"]( "cp /etc/resolv/conf {rfs} {root}/etc".format(root=_cmd_quote(root), rfs=" ".join(release_files)) ) __salt__["cmd.run"]("cp -r {rfs} {root}/etc".format(root=_cmd_quote(root), rfs=" ".join(release_files))) __salt__["cmd.run"]("cp -r {confs} {root}/etc".format(root=_cmd_quote(root), confs=_cmd_quote(pkg_confs))) yum_args = ["yum", "install", "--installroot={0}".format(_cmd_quote(root)), "-y"] + pkgs __salt__["cmd.run"](yum_args, python_shell=False) if "epel-release" not in exclude_pkgs: __salt__["cmd.run"](("rpm", "--root={0}".format(_cmd_quote(root)), "-Uvh", epel_url), python_shell=False)
def install(pecls, defaults=False, force=False, preferred_state='stable'): ''' .. versionadded:: 0.17.0 Installs one or several pecl extensions. pecls The pecl extensions to install. defaults Use default answers for extensions such as pecl_http which ask questions before installation. Without this option, the pecl.installed state will hang indefinitely when trying to install these extensions. force Whether to force the installed version or not CLI Example: .. code-block:: bash salt '*' pecl.install fuse ''' if isinstance(pecls, six.string_types): pecls = [pecls] preferred_state = '-d preferred_state={0}'.format(_cmd_quote(preferred_state)) if force: return _pecl('{0} install -f {1}'.format(preferred_state, _cmd_quote(' '.join(pecls))), defaults=defaults) else: _pecl('{0} install {1}'.format(preferred_state, _cmd_quote(' '.join(pecls))), defaults=defaults) if not isinstance(pecls, list): pecls = [pecls] for pecl in pecls: found = False if '/' in pecl: channel, pecl = pecl.split('/') else: channel = None installed_pecls = list_(channel) for pecl in installed_pecls: installed_pecl_with_version = '{0}-{1}'.format( pecl, installed_pecls.get(pecl)[0] ) if pecl in installed_pecl_with_version: found = True if not found: return False return True
def version_cmp(pkg1, pkg2, ignore_epoch=False): ''' Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem making the comparison. ignore_epoch : False Set to ``True`` to ignore the epoch when comparing versions .. versionadded:: 2016.3.4 CLI Example: .. code-block:: bash salt '*' pkg.version_cmp '0.2.4-0' '0.2.4.1-0' ''' normalize = lambda x: str(x).split(':', 1)[-1] if ignore_epoch else str(x) pkg1 = normalize(pkg1) pkg2 = normalize(pkg2) output = __salt__['cmd.run_stdout'](['opkg', '--version'], output_loglevel='trace', python_shell=False) opkg_version = output.split(' ')[2].strip() if distutils.version.LooseVersion( opkg_version) >= distutils.version.LooseVersion('0.3.4'): cmd_compare = ['opkg', 'compare-versions'] elif salt.utils.which('opkg-compare-versions'): cmd_compare = ['opkg-compare-versions'] else: log.warning( 'Unable to find a compare-versions utility installed. Either upgrade opkg to ' 'version > 0.3.4 (preferred) or install the older opkg-compare-versions script.' ) return None for oper, ret in (("<<", -1), ("=", 0), (">>", 1)): cmd = cmd_compare[:] cmd.append(_cmd_quote(pkg1)) cmd.append(oper) cmd.append(_cmd_quote(pkg2)) retcode = __salt__['cmd.retcode'](cmd, output_loglevel='trace', ignore_retcode=True, python_shell=False) if retcode == 0: return ret return None
def _rvm(command, arguments=None, runas=None, cwd=None): if runas is None: runas = __salt__['config.option']('rvm.runas') if not is_installed(runas): return False cmd = [_get_rvm_location(runas), _cmd_quote(command)] if arguments: cmd.extend([_cmd_quote(arg) for arg in arguments.split()]) ret = __salt__['cmd.run_all'](' '.join(cmd), runas=runas, cwd=cwd) if ret['retcode'] == 0: return ret['stdout'] return False
def delete(target, stop=True): ''' Deletes a gluster volume target Volume to delete stop Stop volume before delete if it is started, True by default ''' if target not in list_volumes(): return 'Volume does not exist' cmd = 'yes | gluster volume delete {0}'.format(_cmd_quote(target)) # Stop volume if requested to and it is running if stop is True and isinstance(status(target), dict): stop_volume(target) stopped = True else: stopped = False # Warn volume is running if stop not requested if isinstance(status(target), dict): return 'Error: Volume must be stopped before deletion' result = __salt__['cmd.run'](cmd, python_shell=True) if result.splitlines()[0].endswith('success'): if stopped: return 'Volume {0} stopped and deleted'.format(target) else: return 'Volume {0} deleted'.format(target) else: return result
def _update_python_build(path, runas=None): path = '{0}/plugins/python-build'.format(path) if not os.path.isdir(path): return False return 0 == __salt__['cmd.retcode']( 'cd {0} && git pull'.format(_cmd_quote(path)), runas=runas)
def list_(pkg=None, dir=None, runas=None, env=None): ''' List installed NPM packages. If no directory is specified, this will return the list of globally- installed packages. pkg Limit package listing by name dir The directory whose packages will be listed, or None for global installation runas The user to run NPM with .. versionadded:: 2014.7.0 env Environment variables to set when invoking npm. Uses the same ``env`` format as the :py:func:`cmd.run <salt.modules.cmdmod.run>` execution function. .. versionadded:: 2014.7.0 CLI Example: .. code-block:: bash salt '*' npm.list ''' env = env or {} if runas: uid = salt.utils.get_uid(runas) if uid: env.update({'SUDO_UID': b'{0}'.format(uid), 'SUDO_USER': b''}) cmd = ['npm', 'list', '--json', '--silent'] if not dir: cmd.append('--global') if pkg: # Protect against injection pkg = _cmd_quote(pkg) cmd.append('"{0}"'.format(pkg)) cmd = ' '.join(cmd) result = __salt__['cmd.run_all']( cmd, cwd=dir, runas=runas, env=env, python_shell=True, ignore_retcode=True) # npm will return error code 1 for both no packages found and an actual # error. The only difference between the two cases are if stderr is empty if result['retcode'] != 0 and result['stderr']: raise CommandExecutionError(result['stderr']) return json.loads(result['stdout']).get('dependencies', {})
def list_(channel=None): ''' List installed pecl extensions. CLI Example: .. code-block:: bash salt '*' pecl.list ''' pecls = {} command = 'list' if channel: command = '{0} -c {1}'.format(command, _cmd_quote(channel)) lines = _pecl(command).splitlines() lines.pop(0) # Only one line if no package installed: # (no packages installed from channel pecl.php.net) if not lines: return pecls lines.pop(0) lines.pop(0) for line in lines: match = re.match('^([^ ]+)[ ]+([^ ]+)[ ]+([^ ]+)', line) if match: pecls[match.group(1)] = [match.group(2), match.group(3)] return pecls
def info(name): ''' Return information for the specified user CLI Example: .. code-block:: bash salt '*' shadow.info someuser ''' try: data = pwd.getpwnam(name) ret = { 'name': data.pw_name, 'passwd': data.pw_passwd} except KeyError: return { 'name': '', 'passwd': ''} # Get password aging info on FreeBSD # TODO: Implement this for NetBSD, OpenBSD if __salt__['cmd.has_exec']('pw'): cmd = 'pw user show {0} | cut -f6,7 -d:'.format(_cmd_quote(name)) try: change, expire = __salt__['cmd.run_all'](cmd, python_shell=True)['stdout'].split(':') except ValueError: pass else: ret['change'] = change ret['expire'] = expire return ret
def _install_rbenv(path, runas=None): if os.path.isdir(path): return True return 0 == __salt__['cmd.retcode']( 'git clone https://github.com/sstephenson/rbenv.git {0}' .format(_cmd_quote(path)), runas=runas)
def do(cmdline=None, runas=None): ''' Execute a ruby command with rbenv's shims from the user or the system. CLI Example: .. code-block:: bash salt '*' rbenv.do 'gem list bundler' salt '*' rbenv.do 'gem list bundler' deploy ''' path = _rbenv_path(runas) environ = {'PATH': '{0}/shims:{1}'.format(path, os.environ['PATH'])} cmdline = ' '.join([_cmd_quote(cmd) for cmd in _shlex_split(cmdline)]) result = __salt__['cmd.run_all']( cmdline, runas=runas, env=environ ) if result['retcode'] == 0: rehash(runas=runas) return result['stdout'] else: return False