def unlock(cm_id, caller_id, cluster_id): """ Unlocks specified Cluster. Now VMs can be run on that Cluster. @clmview_admin_clm @param_post{cluster_id,int} id of the CM to unlock """ try: cluster = Cluster.objects.get(pk=cluster_id) except: raise CLMException('cluster_get') cluster.state = cluster_states['ok'] try: cluster.save() except: raise CLMException('cluster_unlock') users = list( User.objects.filter( is_active__exact=user_active_states['ok']).values_list('id', flat=True)) status = None try: status = CM(cluster.id).send_request("user/user/add_missing/", caller_id=caller_id, remote=users)['status'] except Exception, e: log.exception(caller_id, "Adding users: %s" % str(e)) status = False
def check_password(login, password): """ Checks User password's correctness. @clmview_guest @param_post{login} user's login @param_post{password} password to check @response{bool} False if password isn't correct @response{dict} User.dict() property if password is correct """ try: user = User.objects.get(login=login) except User.DoesNotExist: raise CLMException('user_get') if user.is_active == user_active_states['ok']: try: user.last_login_date = datetime.now() user.save() except: raise CLMException('user_edit') else: return False if user.password == password: return user.dict else: return False
def delete_user(cm_id, caller_id, user_id, group_id): """ Method deletes membership of a user from a specified group. Only group leader and user-to-delete may call this. @clmview_user @param_post{user_id,int} id of the user to delete from group @param_post{group_id,int} id of the managed group """ if caller_id != user_id: User.is_leader(caller_id, group_id) try: mem = UserGroup.objects.filter(group_id__exact=group_id).filter( user_id__exact=user_id)[0] except: raise CLMException('user2group_get') for m in Message.objects.filter(user_id__exact=caller_id).filter( code__exact='group_request'): log.debug(caller_id, 'message params %s' % m.params) if json.loads(m.params).get('group_id', None) == id: log.debug(caller_id, 'delete message for group %s' % id) m.delete() try: mem.delete() except: raise CLMException('group_delete_user')
def set_password_token(user_id, token, new_password): """ Sets new password provided reset-password token is correct. @clmview_guest @param_post{user_id} id of the User whose password should be set @param_post{token} token to set password @param_post{new_password,string} new password @response{dict} User's new data (if succeeded) """ try: user = User.objects.get(id=user_id) except Exception: raise CLMException('user_get') if token_generator.check_token(user, int_to_base36(user_id) + u'-' + token): user.password = new_password try: user.save() except Exception: raise CLMException('user_set_password') else: raise CLMException('user_bad_token') return user.dict
def activate_user(cm_id, caller_id, user_id, group_id): """ Method activates @prm{user_id} user in group @prm{group_id}. Activated user gains access to IsoImage-s shared by that group. @clmview_user @param_post{user_id,int} id of the user to activate @param_post{group_id,int} id of the group in which user must be activated """ # check that the caller is leader User.is_leader(caller_id, group_id) try: mem = UserGroup.objects.filter(group_id__exact=group_id).filter( user_id__exact=user_id).filter( status__exact=group_states['waiting'])[0] except: raise CLMException('user2group_get') mem.status = group_states['ok'] for m in Message.objects.filter(user_id__exact=caller_id).filter( code__exact='group_request'): if json.loads(m.params).get('group_id', None) == id: m.delete() try: mem.save() except: raise CLMException('user_activate')
def auth(is_user, is_clm_superuser, data): if is_user: login = data.pop('login') password = data.get('password') if password: del data['password'] try: user = User.objects.get(login=login) except User.DoesNotExist: raise CLMException('user_get') if 'Signature' in data.keys(): if not Signature.checkSignature(user.password, data.pop('Signature'), data['parameters']): raise CLMException('user_get') del data['parameters'] elif user.password != password: raise CLMException('user_get') data['caller_id'] = user.id if user.is_active != user_active_states['ok']: raise CLMException('user_inactive') if is_clm_superuser and not user.is_superuser: raise CLMException('user_permission') data['cm_id'] = data.pop('cm_id', None) if not data['cm_id']: if user.default_cluster_id is not None: data['cm_id'] = user.default_cluster_id return user.id else: return 0
def add(cm_id, caller_id, key, name): """ Adds given Key named @prm{name} with content @prm{key} to caller's keys list. @clmview_user @param_post{key,string} key's content @param_post{name,string} key's name @response{None} """ if len(Key.objects.filter( user_id__exact=caller_id)) > 5: # magic value, keys limit raise CLMException('ssh_key_limit') k = Key() k.user_id = caller_id k.data = key k.name = name r = re.search('ssh-rsa (.*) (.*)', key) if not r: raise CLMException('ssh_key_format') s = hashlib.md5(base64.b64decode(r.groups()[0])).hexdigest() k.fingerprint = ':'.join([s[i:i + 2] for i in xrange(0, 30, 2)]) try: k.save() except: raise CLMException('ssh_key_add')
def get_list(cm_id, caller_id, **data): """ @clmview_admin_cm @param_post{access,int} number representing image access, @seealso{src.common.states.image_access} @param_post{group_id,int} required for group access @param_post{user_id,int} """ if data['access'] == image_access['group']: groups = Group.objects.all() if data.get('group_id', None): groups = groups.objects.filter(id__exact=data['group_id']) if data.get('group_id', None): groups = groups.filter( usergroup__user_id__exact=data['user_id']).filter( usergroup__status__exact=group_states['ok']) data['group_id'] = [] r = {} for g in groups: data['group_id'].append(int(g.id)) r[g.id] = {'name': g.name, 'images': []} resp = CM(cm_id).send_request("admin_cm/system_image/get_list/", caller_id=caller_id, **data) d = {} for img in resp['data']: if str(img['user_id']) not in d: try: u = User.objects.get(pk=img['user_id']) d[str(img['user_id'])] = u.first + " " + u.last except: raise CLMException('user_get') img['owner'] = d[str(img['user_id'])] if data['access'] == image_access['group']: d = {} for img in resp['data']: r[img['group_id']]['images'].append(img) if img['user_id'] not in d: try: u = User.objects.get(pk=img['user_id']) d[img['user_id']] = u.first + " " + u.last except: raise CLMException('user_get') img['owner'] = d[img['user_id']] r = [{ 'group_id': k, 'name': v['name'], 'images': v['images'] } for k, v in r.iteritems()] return r return resp['data']
def get(cluster_id): """ @parameter{cluster_id,int} id of the requested Cluster @returns{Cluster} instance of the requested Cluster @raises{cluster_get,CLMException} no such Cluster @raises{cluster_locked,CLMException} Cluster is locked """ try: cluster = Cluster.objects.get(pk=cluster_id) except Cluster.DoesNotExist: raise CLMException('cluster_get') if cluster.state == cluster_states['locked']: raise CLMException('cluster_locked') return cluster
def edit( cm_id, caller_id, cluster_id, name=None, address=None, port=None, ): """ Updates Cluster's attributes. @clmview_admin_clm @param_post{cluster_id,int} id of the CM to edit @param_post{name,string} new name for edited CM @param_post{address,string} new adress of the edited CM @param_post{port,int} new port on which edited CM is to be running """ try: cluster = Cluster.objects.get(pk=cluster_id) if name: cluster.name = name if address: cluster.address = address if port: cluster.port = port cluster.save() except: raise CLMException('cluster_edit')
def join_request(cm_id, caller_id, group_id): """ Sends request for acceptation in specified Groupfor caller. Adds caller to members with 'waiting' state. @clmview_user @param_post{group_id,int} id of the Group, which caller wants to become member of """ group = Group.get(group_id) user = User.get(caller_id) mem = UserGroup() mem.user = user mem.group = group mem.status = group_states['waiting'] message.info(group.leader_id, 'group_request', params={ 'first_name': user.first, 'last_name': user.last, 'group_name': group.name, 'group_id': group.id }) try: mem.save() except: raise CLMException('group_request')
def create(cm_id, caller_id, name, description): """ Creates new Group of Users. Caller becomes its leader. He also becomes a member of that Group with @val{ok} state. @clmview_user @param_post{name,string} @param_post{description,string} """ user = User.get(caller_id) # create group group = Group() group.leader = user group.name = name group.desc = description group.save() # create first membership mem = UserGroup() mem.user = user mem.group = group mem.status = group_states['ok'] try: mem.save() except: raise CLMException('group_create')
def get_list(cm_id, caller_id, cm_password): """ Method returns list of Users of the managed cluster @cm_request{storage_image.get_list()} @clmview_admin_cm @param_post{short,bool} caller's CM admin password @response{list(dict)} dicts property for each requested cluster's User """ r = CM(cm_id).send_request("admin_cm/user/get_list/", cm_password=cm_password, caller_id=caller_id) if r['status'] != 'ok': raise CLMException(r['status']) # build dictionary 'id':'dict from cm' d = {} ret = {} for i in r['data']: d[i['user_id']] = i for user in User.objects.filter(id__in=d.keys()): ret[user.id] = d[user.id] ret[user.id].update(user.dict) return ret.values()
def activate(cm_id, caller_id, user_id, wi_data): """ Activates specified User. Activation may require several actions, depending on instructions provided in CLM's config.py file. @clmview_admin_clm @param_post{user_id,int} id of the User to activate @param_post{wi_data,dict} data for confirmation email @response{list(dict)} unlocked CMs available for user """ user = User.get(user_id) cms = [] for cluster in Cluster.objects.filter(state__exact=0): resp = CM(cluster.id).send_request("guest/user/add/", new_user_id=user.id) if resp['status'] == 'ok': cms.append(cluster.id) user.is_active = user_active_states['ok'] # don't overwrite activation_date if not user.activation_date: user.activation_date = datetime.now() try: user.save() except: raise CLMException('user_activate') if settings.MAILER_ACTIVE: mail.send_activation_confirmation_email(user, wi_data) return cms
def edit(cm_id, caller_id, user_id, first=None, last=None, organization=None, email=None): """ @clmview_admin_clm @param_post{user_id,int} id of the user to edit @param_post{first,string} new firstname @param_post{last,string} new lastname @param_post{organization,string} new organization user belong to @param_post{email,string} new user's email @response{dict} edited User data after update, (User.dict() property) """ user = User.get(user_id) if first: user.first = first if last: user.last = last if organization: user.organization = organization if email: user.email = email try: user.save() except: raise CLMException('user_edit') return user.dict
def check_token(user_id, token): """ Check password-reset token correctness for User. @clmview_guest @param_post{user_id} User whose token should be checked @param_post{token} token to check @response None """ try: user = User.objects.get(id=user_id) except Exception: raise CLMException('user_get') if token_generator.check_token(user, int_to_base36(user_id) + u'-' + token): return raise CLMException('user_bad_token')
def delete(cm_id, caller_id, user_id): """ Deletes User. For technical and legal reasons only inactive User may be deleted. Other users may only be blocked. @clmview_admin_clm @param_post{user_id,int} id of the User to delete """ user = User.get(user_id) if user.last_login_date or user.is_active == user_active_states['ok']: raise CLMException('user_active') try: user.delete() except Exception: raise CLMException('user_delete') return user.dict
def get_list(cm_response, **data): """ @clmview_admin_cm @cm_request_transparent{farm.get_list()} """ if cm_response['status'] != 'ok': raise CLMException('cm_error') names = {} for farm in cm_response["data"]: if str(farm['user_id']) not in names: try: user = User.objects.get(pk=farm['user_id']) names[str(farm['user_id'])] = "%s %s" % (user.first, user.last) except: raise CLMException('user_get') farm["owner"] = names[str(farm["user_id"])] return cm_response["data"]
def activate(act_key, wi_data): """ Method activates User with activation key @prm{act_key}. @clmview_guest @param_post{act_key,string} @param_post{wi_data,string} data for email @response{dict} user's data, fields: @dictkey{user,dict} @dictkey{registration_state,dict} """ try: user = User.objects.get(act_key=act_key) except: raise CLMException('user_get') user.is_active = user_active_states['email_confirmed'] reg_state = registration_states['admin_confirmation'] if settings.AUTOACTIVATION: # add user to all unlocked CMs while activating for cluster in Cluster.objects.filter(state__exact=0): # TODO: func user/user is not in cm! so i use guest/user resp = CM(cluster.id).send_request("guest/user/add/", new_user_id=user.id) if resp['status'] != 'ok': raise CLMException('cm_get') user.is_active = user_active_states['ok'] reg_state = registration_states['completed'] user.activation_date = datetime.now() user.act_key = '' try: user.save() except: raise CLMException('user_activate') if settings.MAILER_ACTIVE and reg_state == registration_states['admin_confirmation']: try: mail.send_admin_registration_notification(user, wi_data) except SMTPRecipientsRefused: pass return {'user': user.dict, 'registration_state': reg_state}
def reset_password_mail(email, wi_data): """ Sends mail for reseting password @clmview_guest @param_post{email,string} whom send "reset password" mail to @param_post{wi_data,dict} fields: @dictkey{site_domain} @dictkey{site_name} """ if settings.MAILER_ACTIVE: user = User.objects.get(email=email) token = token_generator.make_token(user) try: mail.send_reset_password_mail(user, token, wi_data) return except SMTPRecipientsRefused: raise CLMException('reset_password_smtp_error') raise CLMException('reset_password_error')
def generate(cm_id, caller_id, name): """ Generates Key pair named @prm{name} for caller. Public part of that Key is stored in database with specified name, whereas content of the private Key part is returned. Neither public, nor private part of the key is saved to file. Private part of the key is never stored - it's only returned once. @clmview_user @param_post{name,string} Key's name @response{string} content of private Key's file """ if len(Key.objects.filter( user_id__exact=caller_id)) > 5: # magic value, keys limit raise CLMException('ssh_key_limit') if Key.objects.filter(user_id__exact=caller_id).filter( name__exact=name).exists(): raise CLMException('ssh_key_already_exist') if subprocess.call([ 'ssh-keygen', '-q', '-f', '/tmp/' + str(caller_id) + '_' + name, '-N', '' ]) != 0: raise CLMException('ssh_key_generate') f = open('/tmp/' + str(caller_id) + '_' + name, 'r') f2 = open('/tmp/' + str(caller_id) + '_' + name + '.pub', 'r') k = Key() k.user_id = caller_id k.data = f2.read() k.name = name s = hashlib.md5(base64.b64decode(k.data.split()[1])).hexdigest() k.fingerprint = ':'.join([s[i:i + 2] for i in xrange(0, 30, 2)]) try: k.save() except: raise CLMException('ssh_key_generate') finally: private = f.read() os.remove('/tmp/' + str(caller_id) + '_' + name) os.remove('/tmp/' + str(caller_id) + '_' + name + '.pub') return private
def send_request(self, *args, **kw): """ Make request to particular CM. """ resp = self.server.send_request(*args, **kw) if resp['status'] != 'ok': raise CLMException(resp['status']) if 'messages' in resp: for user_id, msgs in resp['messages'].iteritems(): for msg in msgs: message.add(user_id, msg) return resp
def send_issue(cm_id, caller_id, topic, issue): """ Send issue email @clmview_user @param_post{topic,string} topic of the issue email @param_post{issue,string} content of the issue email """ try: mail.send(settings.ISSUE_EMAIL, issue, topic) except Exception: raise CLMException('send_issue_error')
def delete(cm_id, caller_id, message_id): """ Deletes specified Message. @clmview_user @param_post{message_id,int} id of the message to delete """ m = Message.get(message_id) try: m.delete() except: raise CLMException('message_delete')
def get(user_id): """ @parameter{user_id,int} primary index of the User @returns{User} instance of requested User @raises{user_get,CLMException} """ try: u = User.objects.get(pk=user_id) except: raise CLMException('user_get') return u
def superuser(user_id): """ @parameter{user_id,int} User's id @returns{bool} @avail{True} - User is superuser @raises{user_permission,CLMException} User isn't superuser """ user = User.get(user_id) if not user.is_superuser: raise CLMException('user_permission') return True
def delete(cm_id, caller_id, name): """ Method deletes specified key named @prm{name}. @clmview_user @param_post{name,string} name of the Key to delete @response{None} """ try: Key.objects.filter(user_id__exact=caller_id).filter( name__exact=name).delete() except: raise CLMException('ssh_key_delete')
def get_list(cm_id, caller_id, **data): """ Method returns list of images. @clmview_user @param_post{data,dict} @returns{list(dict)} images: <code>{gid, name, [images]}</code> """ group_dict = {} # creation of information in data['gid']: group ids the caller belongs to if data['access'] == image_access['group']: groups = User.get(caller_id).group_set.filter( usergroup__status__exact=group_states['ok']) data['group_id'] = [] for g in groups: # append info in data['gid'] to send with the request to CM data['group_id'].append(int(g.id)) group_dict[g.id] = {'name': g.name, 'images': []} resp = CM(cm_id).send_request("user/system_image/get_list/", caller_id=caller_id, **data) if resp['status'] != 'ok': return resp images = resp['data'] # uzupełnianie zapytania o ownera i grupowanie w słownik {gid, name, [images]} # adds information on the owner of the images with group access {gid, name, [images]} if data['access'] == image_access['group']: d = {} for img in images: group_dict[img['group_id']]['images'].append(img) if img['user_id'] not in d: try: u = User.objects.get(pk=img['user_id']) d[img['user_id']] = u.first + " " + u.last except: raise CLMException('user_get') img['owner'] = d[img['user_id']] resp = [{ 'group_id': k, 'name': v['name'], 'images': v['images'] } for k, v in group_dict.iteritems()] return resp return images
def get(news_id): """ @parameter{news_id,int} id of the requested News @returns{News} instance of the requested News @raises{news_get,CLMException} no such News found """ try: news = News.objects.get(pk=news_id) except: raise CLMException('news_get') return news
def get(msg_id): """ @parameter{msg_id,int} id of the requested Message @returns{Message} instance of the requested Message @raises{message_get,CLMException} no such Message """ try: m = Message.objects.get(pk=msg_id) except: raise CLMException('message_get') return m