Source code for provy.more.debian.users.user

#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''Roles in this namespace are meant to provide user management operations for Debian distributions.'''


import StringIO

from provy.core import Role


[docs]class UserRole(Role): ''' This role provides many utility methods for user management operations within Debian distributions. Example: :: from provy.core import Role from provy.more.debian import UserRole class MySampleRole(Role): def provision(self): with self.using(UserRole) as role: role.ensure_user('myuser', identified_by='mypass', is_admin=True) '''
[docs] def group_exists(self, group_name): ''' Returns :data:`True` if the given group exist, :data:`False` otherwise. :param group_name: Name of the group to verify. :type group_name: :class:`str` :return: Whether the group exists or not. :rtype: :class:`bool` Example: :: class MySampleRole(Role): def provision(self): with self.using(UserRole) as role: if role.group_exists('usersgroup'): pass ''' values = self.__first_values_from('group') return group_name in values
def __first_values_from(self, basename): values = self.execute("cat /etc/%s | cut -d ':' -f 1" % basename, stdout=False, sudo=True) values = values.strip().split() return values
[docs] def user_exists(self, username): ''' Returns :data:`True` if the given user exist, :data:`False` otherwise. :param username: Name of the user to verify. :type username: :class:`str` :return: Whether the user exists or not. :rtype: :class:`bool` Example: :: class MySampleRole(Role): def provision(self): with self.using(UserRole) as role: if role.user_exists('myuser'): pass ''' values = self.__first_values_from('passwd') return username in values
[docs] def user_in_group(self, username, group_name): ''' Returns :data:`True` if the given user is in the given group, :data:`False` otherwise. :param username: Name of the user to verify. :type username: :class:`str` :param group_name: Name of the group to verify. :type group_name: :class:`str` :return: Whether the user pertains to the group or not. :rtype: :class:`bool` Example: :: from provy.core import Role from provy.more.debian import UserRole class MySampleRole(Role): def provision(self): with self.using(UserRole) as role: if role.user_in_group('myuser', 'mygroup'): pass ''' raw_groups = self.execute('groups %s' % username, sudo=True, stdout=False).strip() if not raw_groups.startswith(username): raise ValueError("User '%s' doesn't exist" % username) groups_string = raw_groups.replace('%s : ' % username, '') groups = groups_string.split() return group_name in groups
[docs] def ensure_group(self, group_name, group_id=None): ''' Ensures that a given user group is present in the remote server. :param group_name: Name of the group to create. :type group_name: :class:`str` :param group_id: GID of the group. Defaults to :data:`None`, which assigns the next available GID. :type group_id: :class:`int` Example: :: from provy.core import Role from provy.more.debian import UserRole class MySampleRole(Role): def provision(self): with self.using(UserRole) as role: role.ensure_group('users-group') ''' if not self.group_exists(group_name): self.log("Group %s not found! Creating..." % group_name) if not group_id: self.execute('groupadd %s' % group_name, stdout=False, sudo=True) else: self.execute('groupadd --gid %s %s' % (group_id, group_name), stdout=False, sudo=True) self.log("Group %s created!" % group_name)
[docs] def ensure_user_groups(self, username, groups=[]): for user_group in groups: if not self.user_in_group(username, user_group): self.log("User %s should be in group %s! Rectifying that..." % (username, user_group)) self.execute('usermod -G %s %s' % (user_group, username), stdout=False, sudo=True) self.log("User %s is in group %s now!" % (username, user_group))
[docs] def ensure_user(self, username, identified_by=None, home_folder=None, default_script="/bin/bash", groups=[], is_admin=False, password_encrypted=False): ''' Ensures that a given user is present in the remote server. :param username: Name of the user. :type username: :class:`str` :param identified_by: Password that the user will use to login to the remote server. If set to :data:`None`, the user will not have a password. :type identified_by: :class:`str` :param home_folder: Specifies the user's home folder. Defaults to `/home/<username>`. :type home_folder: :class:`str` :param default_script: Sets the user's default script, the one that will execute commands per default when logging in. Defaults to `/bin/sh`. :type default_script: :class:`str` :param groups: Groups that this user belongs to. If the groups do not exist they are created prior to user creation. Defaults to the name of the user. :type groups: :class:`iterable` :param is_admin: If set to :data:`True` the user is added to the 'admin' (or 'sudo' if provisioning to Ubuntu) user group as well. Defaults to :data:`False`. :type is_admin: :class:`bool` :param password_encrypted: If set to :data:`True` password is considered to be in ecrypted form (as found in /etc/shadow). To generate encrypted form of password you may use :func:`provy.more.debian.users.passwd_utils.hash_password_function`. defaults to :data:`False` :type password_encrypted: :class:`bool` Example: :: from provy.core import Role from provy.more.debian import UserRole class MySampleRole(Role): def provision(self): with self.using(UserRole) as role: role.ensure_user('myuser', identified_by='mypass', is_admin=True) ''' admin_group = self.__get_admin_group() self.__ensure_initial_groups(groups, username) if not self.user_exists(username): self.__create_new_user(username, home_folder, groups, default_script, is_admin) elif is_admin and not self.user_in_group(username, admin_group): self.__set_user_as_admin(username, admin_group) self.ensure_user_groups(username, groups) self.set_user_password(username, identified_by, password_encrypted) self.context['owner'] = username
def __set_user_as_admin(self, username, admin_group): self.log("User %s should be administrator! Rectifying that..." % username) self.execute('usermod -G %s %s' % (admin_group, username), stdout=False, sudo=True) self.log("User %s is administrator now!" % username) def __create_new_user(self, username, home_folder, groups, default_script, is_admin): is_admin_command = " -G {}".format(self.__get_admin_group()) command = "useradd -g %(group)s%(is_admin_command)s -s %(default_script)s -d %(home_folder)s -m %(username)s" home_folder = home_folder or '/home/%s' % username group = groups and groups[0] or username self.log("User %s not found! Creating..." % username) self.execute(command % { 'group': group or username, 'is_admin_command': is_admin and is_admin_command or '', 'home_folder': home_folder, 'default_script': default_script, 'username': username }, stdout=False, sudo=True) self.log("User %s created!" % username) def __ensure_initial_groups(self, groups, username): for user_group in groups: self.ensure_group(user_group) if not groups: self.ensure_group(username) def __get_admin_group(self): distro_info = self.get_distro_info() if distro_info.distributor_id == 'Ubuntu': admin_group = 'sudo' else: admin_group = 'admin' return admin_group
[docs] def set_user_password(self, username, password, encrypted=False): """ Sets user password. :param username: Name of user for which to update password :type username: :class:`str` :param password: Password to set :type password: :class:`str` :param encrypted: If :data:`True` it meas that `password` is encrypted, (that is in hashed format), else it means password is in plaintext. :type encrypted: :class:`bool` """ tmp_file = self.create_remote_temp_file() password_line = "{username}:{password}".format( username=username, password=password ) self.put_file(StringIO.StringIO(password_line), tmp_file, sudo=True, stdout=False) command = 'cat "{tmp_file}" | chpasswd {encrypted}'.format( encrypted="-e" if encrypted else "", tmp_file=tmp_file ) self.execute(command, stdout=False, sudo=True) self.remove_file(tmp_file, sudo=True)