Skip to content

Commit

Permalink
Users Management: Add support to profile and i18n translation
Browse files Browse the repository at this point in the history
This patch implements the support to three pre-defined user profiles:
'kimchiuser', which does not have any host access; 'virtuser', which
has host access and virtualization rights (belongs to KVM group); and
'admin', which is a user with sudo rights.

This patch also fixes the Exceptions messages, in order to use i18n,
like Kimchi.

Change-Id: I5f9da6320f387179b31406524379dad8dd84bf57
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com>
Reviewed-on: http://9.181.129.215/56
Reviewed-by: Mark Wu <wudxw@linux.vnet.ibm.com>
  • Loading branch information
Truja authored and edwardbadboy committed Jun 27, 2014
1 parent 321e5f5 commit 582742b
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 33 deletions.
19 changes: 15 additions & 4 deletions API.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,38 @@
"active": {
"description": "State of the profile",
"type": "boolean",
"required" : true
"required": true
}
}
},
"users_create": {
"type": "object",
"error": "GINUSER0001E",
"properties": {
"name": {
"description": "The login name of the new user",
"type": "string",
"required": true
"required": true,
"error": "GINUSER0002E"
},
"password": {
"description": "The new user password",
"type": "string",
"required": true
"required": true,
"error": "GINUSER0003E"
},
"group": {
"description": "The group name of the new user",
"type": "string",
"required": true
"required": true,
"error": "GINUSER0004E"
},
"profile": {
"description": "The profile of the new user",
"type": "string",
"pattern": "^kimchiuser|virtuser|admin$",
"required": true,
"error": "GINUSER0005E"
}
}
},
Expand Down
18 changes: 17 additions & 1 deletion i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@
"GINNET0005E": _("Invalid parameter for DNS servers"),
"GINNET0006E": _("Invalid parameter for interface ip address"),
"GINNET0007E": _("Invalid parameter for interface netmask"),
"GINNET0008E": _("Invalid parameter for network gateway")
"GINNET0008E": _("Invalid parameter for network gateway"),

"GINUSER0001E": _("Specify name, password, group and profile for the new "
"user."),
"GINUSER0002E": _("User name is a required string."),
"GINUSER0003E": _("User password is a required string."),
"GINUSER0004E": _("User group is a required string."),
"GINUSER0005E": _("User profile is required and should be one among "
"kimchiuser, virtuser or admin."),
"GINUSER0006E": _("Could not add user '%(user)s' to kvm group."),
"GINUSER0007E": _("Could not add user '%(user)s' to sudoers list."),
"GINUSER0008E": _("The user name '%(user)s' is already in use'."),
"GINUSER0009E": _("Could not create user '%(user)s'."),
"GINUSER0010E": _("Could not delete user '%(user)s'."),
"GINUSER0011E": _("User '%(user)s' does not exist."),
"GINUSER0012E": _("Could not delete group '%(group)s'"),
"GINUSER0013E": _("Group for user '%(user)s' does not exist for removal.")
}
messages.update(kmessages)
132 changes: 104 additions & 28 deletions models/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,31 @@
from kimchi.utils import kimchi_log


SUDOERS_FILE = '/etc/sudoers.d/%s_conf'
SUDOERS_LINE = '%s\tALL=(ALL)\tALL\n'


class UsersModel():
"""
The model class for basic management of users in the host system
"""

def create(self, params):
adm = libuser.admin()
profile = params['profile']
# Login/Group already in use ?
user = adm.lookupUserByName(params['name'])
group = adm.lookupGroupByName(params['group'])
if user:
msg = 'User/Login "%s" already in use' % params['name']
kimchi_log.error(msg)
raise OperationFailed(msg)
raise OperationFailed('GINUSER0008E', {'user': params['name']})
# Adding user/group
try:
new_user = adm.initUser(params['name'])
new_user[libuser.LOGINSHELL] = '/sbin/nologin'
# Handling user shell according to profile, else, use default shell
if profile == "kimchiuser":
new_user[libuser.LOGINSHELL] = '/sbin/nologin'
# Creating group or adding user to existing group
if group is None:
new_group = adm.initGroup(params['group'])
Expand All @@ -60,11 +67,42 @@ def create(self, params):
adm.addUser(new_user)
# Password should come encrypted
adm.setpassUser(new_user, params['password'], True)
except:
kimchi_log.error('Could not add user %s', params['name'])
raise OperationFailed('Could not add user %s' % params['name'])
except Exception as e:
kimchi_log.error('Could not create user %s', params['name'], e)
raise OperationFailed('GINUSER0009E', {'user': params['name']})

# Handle profiles
if profile in ["virtuser", "admin"]:
self._add_user_to_kvm_group(adm, params['name'])
if profile == "admin":
self._add_user_to_sudoers(params['name'])

return params['name']

def _add_user_to_sudoers(self, user):
try:
# Creates the file in /etc/sudoers.d with proper user permission
with open(SUDOERS_FILE % user, 'w') as f:
f.write(SUDOERS_LINE % user)
os.chmod(SUDOERS_FILE % user, 0440)
except Exception as e:
UserModel().delete(user)
kimchi_log.error('Could not add user %s to sudoers: %s',
user, e.message)
raise OperationFailed('GINUSER0007E', {'user': user})

def _add_user_to_kvm_group(self, adm, user):
# Add new user to KVM group
kvmgrp = adm.lookupGroupByName('kvm')
kvmgrp.add('gr_mem', user)
ret = adm.modifyGroup(kvmgrp)
if ret != 1:
UserModel().delete(user)
msg = ('Could not add user %s to kvm group. Operation failed.'
% user)
kimchi_log.error(msg)
raise OperationFailed('GINUSER0006E', {'user': user})

def get_list(self):
# Get list of users in the host excluding system users
return [user.pw_name for user in pwd.getpwall() if user.pw_uid >= 1000]
Expand All @@ -74,36 +112,74 @@ class UserModel():
def delete(self, user):
adm = libuser.admin()
user_obj = adm.lookupUserByName(user)
group_obj = adm.lookupGroupById(int(user_obj.get('pw_gid')[0]))
if user_obj:
# Delete home and mails too
try:
adm.deleteUser(user_obj, True, True)
except:
kimchi_log.error('Could not delete user %s', user)
raise OperationFailed('Could not delete user %s' % user)
else:
# Check if user exist
if user_obj is None:
kimchi_log.error('User "%s" does not exist', user)
raise OperationFailed('User "%s" does not exist' % user)
# Delete group if no user are assigned to it
raise OperationFailed('GINUSER0011E', {'user': user})
group_obj = adm.lookupGroupById(int(user_obj.get('pw_gid')[0]))
# Delete user with its home and mails too
try:
adm.deleteUser(user_obj, True, True)
except Exception as e:
kimchi_log.error('Could not delete user %s: %s', user, e)
raise OperationFailed('GINUSER0010E', {'user': user})

# Handle user according to its profile
self._delete_profile_settings(user)

# Delete group if no users are assigned to it
# It is not possible to delete user/group at same time
if group_obj:
group = group_obj.get('gr_name')[0]
if not adm.enumerateUsersByGroup(group):
try:
adm.deleteGroup(group_obj)
except:
kimchi_log.error('Could not delete group "%s"', group)
raise OperationFailed('Could not delete group "%s"'
% group)
else:
if group_obj is None:
msg = 'Group for user "%s" does not exist for removal' % user
kimchi_log.warn(msg)
raise OperationFailed(msg)
raise OperationFailed('GINUSER0013E', {'user': user})
group = group_obj.get('gr_name')[0]
if not adm.enumerateUsersByGroup(group):
try:
adm.deleteGroup(group_obj)
except Exception as e:
kimchi_log.error('Could not delete group "%s": %s', group, e)
raise OperationFailed('GINUSER0012E', {'group': group})

def lookup(self, user):
user_info = pwd.getpwnam(user)
return {"name": user,
"uid": user_info.pw_uid,
"gid": user_info.pw_gid,
"group": grp.getgrgid(user_info.pw_gid).gr_name}
"group": grp.getgrgid(user_info.pw_gid).gr_name,
"profile": self._get_user_profile(user)}

def _get_user_profile(self, user):
# ADMIN: Check /etc/sudoers.d
if os.path.isfile(SUDOERS_FILE % user):
return 'admin'
# VIRTUSER: Check kvm group
adm = libuser.admin()
kvmgrp = adm.lookupGroupByName('kvm')
if user in kvmgrp.get('gr_mem'):
return 'virtuser'
# KIMCHIUSER: If not any before
return 'kimchiuser'

def _delete_profile_settings(self, user):
profile = self._get_user_profile(user)
if profile == 'kimchiuser':
return
# Removing from sudoers
elif profile == 'admin':
f = SUDOERS_FILE % user
try:
os.unlink(f)
except Exception as e:
kimchi_log.error('Error removing file "%s": %s', f, e)

# Finally remove from kvm group
try:
adm = libuser.admin()
kvmgrp = adm.lookupGroupByName('kvm')
# Remove all ocurrences
members = set(kvmgrp.get('gr_mem')) - set([user])
kvmgrp.set('gr_mem', list(members))
adm.modifyGroup(kvmgrp)
except Exception as e:
kimchi_log.error('Error while removing user from kvm group: %s', e)

0 comments on commit 582742b

Please sign in to comment.