Ejemplo n.º 1
0
def update_reservation_request(id):
    """
    Updates the reservation request of a recipe. The request must be 
    :mimetype:`application/json`.

    :param id: Recipe's id.
    :jsonparam boolean reserve: Whether the system will be reserved at the end
      of the recipe. If true, the system will be reserved. If false, the system
      will not be reserved.
    :jsonparam int duration: Number of seconds to reserve the system.
    :jsonparam string when: Circumstances under which the system will be 
      reserved. Valid values are:

      onabort
        If the recipe status is Aborted.
      onfail
        If the recipe status is Aborted, or the result is Fail.
      onwarn
        If the recipe status is Aborted, or the result is Fail or Warn.
      always
        Unconditionally.
    """

    recipe = _get_recipe_by_id(id)
    if not recipe.can_update_reservation_request(identity.current.user):
        raise Forbidden403('Cannot update the reservation request of recipe %s'
                % recipe.id)
    data = read_json_request(request)
    if 'reserve' not in data:
        raise BadRequest400('No reserve specified')
    with convert_internal_errors():
        if data['reserve']:
            if not recipe.reservation_request:
                recipe.reservation_request = RecipeReservationRequest()
            if 'duration' in data:
                duration = int(data['duration'])
                if duration > MAX_SECONDS_PROVISION:
                    raise BadRequest400('Reservation time exceeds maximum time of %s hours'
                            % MAX_HOURS_PROVISION)
                old_duration = recipe.reservation_request.duration
                recipe.reservation_request.duration = duration
                _record_activity(recipe, u'Reservation Request', old_duration,
                        duration)
            if 'when' in data:
                old_condition = recipe.reservation_request.when
                new_condition = RecipeReservationCondition.from_string(data['when'])
                recipe.reservation_request.when = new_condition
                _record_activity(recipe, u'Reservation Condition',
                        old_condition, new_condition)
            session.flush() # to ensure the id is populated
            return jsonify(recipe.reservation_request.__json__())
        else:
            if recipe.reservation_request:
                session.delete(recipe.reservation_request)
                _record_activity(recipe, u'Reservation Request',
                        recipe.reservation_request.duration, None)
            return jsonify(RecipeReservationRequest.empty_json())
Ejemplo n.º 2
0
def update_group(group_name):
    """
    Updates attributes of an existing group. The request body must be a JSON
    object containing one or more of the following keys.

    :jsonparam string group_name: New name for the group.
    :jsonparam string display_name: Display name of the group.
    :jsonparam string description: Description of the group.
    :jsonparam string root_password: Optional password. Can be an empty string.
      If empty, group jobs will use the root password preferences of the job submitter.
    :jsonparam string membership_type: New membership type for the group.
      See `POST /groups/` for more information.

    :status 200: Group was updated.
    :status 400: Invalid data was given.
    """
    group = _get_group_by_name(group_name)
    if not group.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit group')
    data = read_json_request(request)
    with convert_internal_errors():
        user = identity.current.user
        renamed = False
        if 'group_name' in data:
            new_name = data['group_name']
            if new_name != group.group_name:
                if Group.query.filter(Group.group_name == new_name).count():
                    raise Conflict409('Group %s already exists' % new_name)
                group.set_name(user, u'HTTP', new_name)
                renamed = True
        if 'display_name' in data:
            new_display_name = data['display_name']
            if new_display_name != group.display_name:
                group.set_display_name(user, u'HTTP', new_display_name)
        if 'description' in data:
            new_description = data['description']
            if new_description != group.description:
                group.set_description(user, u'HTTP', new_description)
        if 'root_password' in data:
            new_root_password = data['root_password']
            if new_root_password != group.root_password:
                group.set_root_password(user, u'HTTP', new_root_password)
        # for backwards compatibility
        if data.pop('ldap', False):
            data['membership_type'] = 'ldap'
        if 'membership_type' in data:
            new_type = GroupMembershipType.from_string(
                    data['membership_type'])
            if (new_type == GroupMembershipType.ldap and not
                group.can_edit_ldap(user)):
                raise BadRequest400('Cannot edit LDAP group %s' % group)
            if new_type != group.membership_type:
                group.membership_type = new_type
    response = jsonify(group.to_json())
    if renamed:
        response.headers.add('Location', absolute_url(group.href))
    return response
Ejemplo n.º 3
0
def update_pool(pool_name):
    """
    Updates attributes of an existing system pool. The request body must be a JSON 
    object containing one or more of the following keys.

    :param pool_name: System pool's name.
    :jsonparam string name: New name for the system pool.
    :jsonparam string description: Description of the system pool.
    :jsonparam object owner: JSON object containing a ``user_name`` key or
      ``group_name`` key identifying the new owner for the system pool.
    :status 200: System pool was updated.
    :status 400: Invalid data was given.
    """
    pool = _get_pool_by_name(pool_name)
    if not pool.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit system pool')
    data = read_json_request(request)

    # helper for recording activity below
    def record_activity(field, old, new, action=u'Changed'):
        pool.record_activity(user=identity.current.user,
                             service=u'HTTP',
                             action=action,
                             field=field,
                             old=old,
                             new=new)

    with convert_internal_errors():
        renamed = False
        if 'name' in data:
            new_name = data['name']
            if new_name != pool.name:
                if SystemPool.query.filter(
                        SystemPool.name == new_name).count():
                    raise Conflict409('System pool %s already exists' %
                                      new_name)
                record_activity(u'Name', pool.name, new_name)
                pool.name = new_name
                renamed = True
        if 'description' in data:
            new_description = data['description']
            if new_description != pool.description:
                record_activity(u'Description', pool.description,
                                new_description)
                pool.description = new_description
        if 'owner' in data:
            new_owner, owner_type = _get_owner(data['owner'])
            if owner_type == 'user':
                pool.change_owner(user=new_owner)
            else:
                pool.change_owner(group=new_owner)

    response = jsonify(pool.__json__())
    if renamed:
        response.headers.add('Location', absolute_url(pool.href))
    return response
Ejemplo n.º 4
0
def _update_recipeset(recipeset, data=None):
    if not data:
        data = {}

    def record_activity(field, old=None, new=None, action=u'Changed'):
        recipeset.record_activity(user=identity.current.user,
                                  service=u'HTTP',
                                  action=action,
                                  field=field,
                                  old=old,
                                  new=new)

    with convert_internal_errors():
        if 'priority' in data:
            priority = TaskPriority.from_string(data['priority'])
            if priority != recipeset.priority:
                if not recipeset.can_change_priority(identity.current.user):
                    raise Forbidden403('Cannot change recipe set %s priority' %
                                       recipeset.id)
                allowed = recipeset.allowed_priorities(identity.current.user)
                if priority not in allowed:
                    raise Forbidden403(
                        'Cannot set recipe set %s priority to %s, '
                        'permitted priorities are: %s' %
                        (recipeset.id, priority, ' '.join(
                            unicode(pri) for pri in allowed)))
                record_activity(u'Priority',
                                old=recipeset.priority.value,
                                new=priority.value)
                recipeset.priority = priority
        if 'waived' in data:
            if not isinstance(data['waived'], bool):
                raise ValueError('waived key must be true or false')
            waived = data['waived']
            if waived != recipeset.waived:
                if not recipeset.can_waive(identity.current.user):
                    raise Forbidden403('Cannot waive recipe set %s' %
                                       recipeset.id)
                record_activity(u'Waived',
                                old=unicode(recipeset.waived),
                                new=unicode(waived))
                recipeset.waived = waived
Ejemplo n.º 5
0
def add_system_to_pool(pool_name):
    """
    Add a system to a system pool

    :param pool_name: System pool's name.
    :jsonparam fqdn: System's fully-qualified domain name.

    """
    u = identity.current.user
    data = read_json_request(request)
    pool = _get_pool_by_name(pool_name, lockmode='update')
    if 'fqdn' not in data:
        raise BadRequest400('System FQDN not specified')
    try:
        system = System.by_fqdn(data['fqdn'], u)
    except NoResultFound:
        raise BadRequest400("System '%s' does not exist" % data['fqdn'])
    if not pool in system.pools:
        if pool.can_edit(u) and system.can_edit(u):
            system.record_activity(user=u,
                                   service=u'HTTP',
                                   action=u'Added',
                                   field=u'Pool',
                                   old=None,
                                   new=unicode(pool))
            system.pools.append(pool)
            system.date_modified = datetime.datetime.utcnow()
            pool.record_activity(user=u,
                                 service=u'HTTP',
                                 action=u'Added',
                                 field=u'System',
                                 old=None,
                                 new=unicode(system))
        else:
            if not pool.can_edit(u):
                raise Forbidden403('You do not have permission to '
                                   'add systems to pool %s' % pool.name)
            if not system.can_edit(u):
                raise Forbidden403('You do not have permission to '
                                   'modify system %s' % system.fqdn)

    return '', 204
Ejemplo n.º 6
0
def remove_cc(fqdn, email):
    system = _get_system_by_FQDN(fqdn)
    if not system.can_edit(identity.current.user):
        raise Forbidden403('Cannot change notify cc')
    if email in system.cc:
        system.cc.remove(email)
        system.record_activity(user=identity.current.user,
                               service=u'HTTP',
                               action=u'Removed',
                               field=u'Cc',
                               old=email,
                               new=None)
        system.date_modified = datetime.datetime.utcnow()
    return jsonify({'notify_cc': list(system.cc)})
Ejemplo n.º 7
0
def save_access_policy(pool_name):
    """
    Updates the access policy for a system pool.

    :param pool_name: System pool's name.
    :jsonparam array rules: List of rules to include in the new policy. This 
      replaces all existing rules in the policy. Each rule is a JSON object 
      with ``user``, ``group``, and ``everybody`` keys.
    """
    pool = _get_pool_by_name(pool_name)
    if not pool.can_edit_policy(identity.current.user):
        raise Forbidden403('Cannot edit system pool policy')
    data = read_json_request(request)
    _edit_access_policy_rules(pool, pool.access_policy, data['rules'])
    return jsonify(pool.access_policy.__json__())
Ejemplo n.º 8
0
def delete_ssh_public_key(username, id):
    """
    Deletes a public SSH public key belonging to the given user account.

    :param username: The user's username.
    :param id: Database id of the SSH public key to be deleted.
    """
    user = _get_user(username)
    if not user.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit user %s' % user)
    matching_keys = [k for k in user.sshpubkeys if k.id == id]
    if not matching_keys:
        raise NotFound404('SSH public key id %s does not belong to user %s' % (id, user))
    key = matching_keys[0]
    session.delete(key)
    return '', 204
Ejemplo n.º 9
0
def save_system_access_policy(fqdn):
    system = _get_system_by_FQDN(fqdn)
    if not system.can_edit_policy(identity.current.user):
        raise Forbidden403('Cannot edit system policy')
    if system.custom_access_policy:
        policy = system.custom_access_policy
    else:
        policy = system.custom_access_policy = SystemAccessPolicy()
    data = read_json_request(request)
    # Figure out what is added, what is removed.
    # Rules are immutable, so if it has an id it is unchanged,
    # if it has no id it is new.
    kept_rule_ids = frozenset(r['id'] for r in data['rules'] if 'id' in r)
    removed = []
    for old_rule in policy.rules:
        if old_rule.id not in kept_rule_ids:
            removed.append(old_rule)
    for old_rule in removed:
        system.record_activity(user=identity.current.user,
                               service=u'HTTP',
                               field=u'Access Policy Rule',
                               action=u'Removed',
                               old=repr(old_rule))
        policy.rules.remove(old_rule)
    for rule in data['rules']:
        if 'id' not in rule:
            if rule['user']:
                user = User.by_user_name(rule['user'])
                if user is None:
                    raise BadRequest400('No such user %r' % rule['user'])
            else:
                user = None
            try:
                group = Group.by_name(rule['group']) if rule['group'] else None
            except NoResultFound:
                raise BadRequest400('No such group %r' % rule['group'])
            permission = SystemPermission.from_string(rule['permission'])
            new_rule = policy.add_rule(user=user,
                                       group=group,
                                       everybody=rule['everybody'],
                                       permission=permission)
            system.record_activity(user=identity.current.user,
                                   service=u'HTTP',
                                   field=u'Access Policy Rule',
                                   action=u'Added',
                                   new=repr(new_rule))
    return jsonify(policy.__json__())
Ejemplo n.º 10
0
def remove_system_from_pool(pool_name):
    """
    Remove a system from a system pool

    :param pool_name: System pool's name.
    :queryparam fqdn: System's fully-qualified domain name

    """
    if 'fqdn' not in request.args:
        raise MethodNotAllowed405
    fqdn = request.args['fqdn']
    system = _get_system_by_FQDN(fqdn)
    u = identity.current.user
    pool = _get_pool_by_name(pool_name, lockmode='update')
    if pool in system.pools:
        if pool.can_edit(u) or system.can_edit(u):
            if system.active_access_policy == pool.access_policy:
                system.active_access_policy = system.custom_access_policy
                system.record_activity(user=u,
                                       service=u'HTTP',
                                       field=u'Active Access Policy',
                                       action=u'Changed',
                                       old='Pool policy: %s' % pool_name,
                                       new='Custom access policy')
            system.pools.remove(pool)
            system.record_activity(user=u,
                                   service=u'HTTP',
                                   action=u'Removed',
                                   field=u'Pool',
                                   old=unicode(pool),
                                   new=None)
            system.date_modified = datetime.datetime.utcnow()
            pool.record_activity(user=u,
                                 service=u'HTTP',
                                 action=u'Removed',
                                 field=u'System',
                                 old=unicode(system),
                                 new=None)
        else:
            raise Forbidden403('You do not have permission to modify system %s'
                               'or remove systems from pool %s' %
                               (system.fqdn, pool.name))
    else:
        raise BadRequest400('System %s is not in pool %s' %
                            (system.fqdn, pool.name))
    return '', 204
Ejemplo n.º 11
0
def update_reservation_request(id):
    """
    Updates the reservation request of a recipe. The request must be 
    :mimetype:`application/json`.

    :param id: Recipe's id.
    :jsonparam boolean reserve: Whether the system will be reserved at the end
      of the recipe. If true, the system will be reserved. If false, the system
      will not be reserved.
    :jsonparam int duration: Number of seconds to rerserve the system.
    """

    recipe = _get_recipe_by_id(id)
    if not recipe.can_update_reservation_request(identity.current.user):
        raise Forbidden403('Cannot update the reservation request of recipe %s'
                % recipe.id)
    data = read_json_request(request)
    if 'reserve' not in data:
        raise BadRequest400('No reserve specified')
    with convert_internal_errors():
        if data['reserve']:
            if 'duration' not in data:
                raise BadRequest400('No duration specified')
            duration = data['duration']
            if duration > MAX_SECONDS_PROVISION:
                raise BadRequest400('Reservation time exceeds maximum time of %s hours' % MAX_HOURS_PROVISION)
            if recipe.reservation_request:
                old_duration = recipe.reservation_request.duration
                recipe.reservation_request.duration = data['duration']
                _record_activity(recipe, u'Reservation Request', old_duration,
                        data['duration'])
            else:
                reservation_request = RecipeReservationRequest(data['duration'])
                recipe.reservation_request = reservation_request
                _record_activity(recipe, u'Reservation Request', None,
                        reservation_request.duration, 'Changed')
            return jsonify(recipe.reservation_request.__json__())
        else:
            if recipe.reservation_request:
                session.delete(recipe.reservation_request)
                _record_activity(recipe, u'Reservation Request',
                        recipe.reservation_request.duration, None)
            return jsonify(RecipeReservationRequest.empty_json())
Ejemplo n.º 12
0
def add_access_policy_rule(pool_name):
    """
    Adds a new rule to the access policy for a system pool. Each rule in the policy
    grants a permission to a single user, a group of users, or to everybody.

    See :ref:`system-access-policies-api` for a description of the expected JSON parameters.

    :param pool_name: System pool's name.
    """
    pool = _get_pool_by_name(pool_name)
    if not pool.can_edit_policy(identity.current.user):
        raise Forbidden403('Cannot edit system pool policy')
    policy = pool.access_policy
    rule = read_json_request(request)
    if rule.get('user', None):
        user = User.by_user_name(rule['user'])
        if not user:
            raise BadRequest400("User '%s' does not exist" % rule['user'])
    else:
        user = None

    if rule.get('group', None):
        try:
            group = Group.by_name(rule['group'])
        except NoResultFound:
            raise BadRequest400("Group '%s' does not exist" % rule['group'])
    else:
        group = None

    try:
        permission = SystemPermission.from_string(rule['permission'])
    except ValueError:
        raise BadRequest400('Invalid permission')
    new_rule = policy.add_rule(user=user,
                               group=group,
                               everybody=rule['everybody'],
                               permission=permission)
    pool.record_activity(user=identity.current.user,
                         service=u'HTTP',
                         field=u'Access Policy Rule',
                         action=u'Added',
                         new=repr(new_rule))
    return '', 204
Ejemplo n.º 13
0
def _get_owner(data):
    if data is None:
        data = {}
    user_name = data.get('user_name')
    group_name = data.get('group_name')
    if user_name and group_name:
        raise Forbidden403('System pool can have either an user or a group as owner')
    if user_name:
        owner = User.by_user_name(user_name)
        if owner is None:
            raise BadRequest400('No such user %s' % user_name)
        owner_type = 'user'
    if group_name:
        try:
            owner = Group.by_name(group_name)
        except NoResultFound:
            raise BadRequest400('No such group %r' % group_name)
        owner_type = 'group'
    return owner, owner_type
Ejemplo n.º 14
0
def post_recipeset_comment(id):
    """
    Adds a new comment to a recipe set. The request must be :mimetype:`application/json`.

    :param id: ID of the recipe set.
    :jsonparam string comment: Comment text.
    """
    recipeset = _get_rs_by_id(id)
    if not recipeset.can_comment(identity.current.user):
        raise Forbidden403('Cannot post recipe set comment')
    data = read_json_request(request)
    if 'comment' not in data:
        raise BadRequest400('Missing "comment" key')
    with convert_internal_errors():
        comment = RecipeSetComment(user=identity.current.user,
                                   comment=data['comment'])
        recipeset.comments.append(comment)
    session.flush()  # to populate the id
    return jsonify(comment.__json__())
Ejemplo n.º 15
0
def delete_submission_delegate(username):
    """
    Deletes a submission delegate for a user account.

    :param username: The user's username.
    :query string user_name: The submission delegate's username.
    """
    user = _get_user(username)
    if not user.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit user %s' % user)
    if 'user_name' not in request.args:
        raise MethodNotAllowed405
    submission_delegate = User.by_user_name(request.args['user_name'])
    if submission_delegate is None:
        raise NotFound404('Submission delegate %s does not exist' % request.args['user_name'])
    if not submission_delegate.is_delegate_for(user):
        raise Conflict409('User %s is not a submission delegate for %s'
                % (submission_delegate, user))
    user.remove_submission_delegate(submission_delegate)
    return '', 204
Ejemplo n.º 16
0
def _create_keystone_trust(user):
    if not config.get('openstack.identity_api_url'):
        raise BadRequest400("OpenStack Integration is not enabled")
    if not user.can_edit_keystone_trust(identity.current.user):
        raise Forbidden403('Cannot edit Keystone trust of user %s' % user.username)
    data = read_json_request(request)
    if 'openstack_username' not in data:
        raise BadRequest400('No OpenStack username specified')
    if 'openstack_password' not in data:
        raise BadRequest400('No OpenStack password specified')
    if 'openstack_project_name' not in data:
        raise BadRequest400('No OpenStack project name specified')
    try:
        trust_id = dynamic_virt.create_keystone_trust(data['openstack_username'],
                data['openstack_password'], data['openstack_project_name'])
    except ValueError as err:
        raise BadRequest400(u'Could not authenticate with OpenStack using your credentials: %s' % unicode(err))
    user.openstack_trust_id = trust_id
    user.record_activity(user=identity.current.user, service=u'HTTP',
            field=u'OpenStack Trust ID', action=u'Changed')
    return jsonify({'openstack_trust_id': trust_id})
Ejemplo n.º 17
0
def delete_keystone_trust(username):
    """
    Deletes the Keystone trust for a user account.

    :param username: The user's username.
    """
    user = _get_user(username)
    if not config.get('openstack.identity_api_url'):
        raise BadRequest400("OpenStack Integration is not enabled")
    if not user.can_edit_keystone_trust(identity.current.user):
        raise Forbidden403('Cannot edit Keystone trust of user %s' % username)
    if not user.openstack_trust_id:
        raise BadRequest400('No Keystone trust created by %s' % user)
    manager = dynamic_virt.VirtManager(user)
    manager.delete_keystone_trust()
    old_trust_id = user.openstack_trust_id
    user.openstack_trust_id = None
    user.record_activity(user=identity.current.user, service=u'HTTP',
            field=u'OpenStack Trust ID', action=u'Deleted',
            old=old_trust_id)
    return '', 204
Ejemplo n.º 18
0
def add_submission_delegate(username):
    """
    Adds a submission delegate for a user account. Submission delegates are 
    other users who are allowed to submit jobs on behalf of this user.

    :param username: The user's username.
    :jsonparam string user_name: The submission delegate's username.
    """
    user = _get_user(username)
    if not user.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit user %s' % user)
    data = read_json_request(request)
    if 'user_name' not in data:
        raise BadRequest400('Missing "user_name" key to specify submission delegate')
    submission_delegate = User.by_user_name(data['user_name'])
    if submission_delegate is None:
        raise BadRequest400('Submission delegate %s does not exist' % data['user_name'])
    try:
        user.add_submission_delegate(submission_delegate, service=u'HTTP')
    except NoChangeException as e:
        raise Conflict409(unicode(e))
    return 'Added', 201
Ejemplo n.º 19
0
def add_system_access_policy_rule(fqdn):
    system = _get_system_by_FQDN(fqdn)
    if not system.can_edit_policy(identity.current.user):
        raise Forbidden403('Cannot edit system policy')
    if system.custom_access_policy:
        policy = system.custom_access_policy
    else:
        policy = system.custom_access_policy = SystemAccessPolicy()
    rule = read_json_request(request)

    if rule['user']:
        user = User.by_user_name(rule['user'])
        if not user:
            raise BadRequest400("User '%s' does not exist" % rule['user'])
    else:
        user = None

    if rule['group']:
        try:
            group = Group.by_name(rule['group'])
        except NoResultFound:
            raise BadRequest400("Group '%s' does not exist" % rule['group'])
    else:
        group = None

    try:
        permission = SystemPermission.from_string(rule['permission'])
    except ValueError:
        raise BadRequest400
    new_rule = policy.add_rule(user=user,
                               group=group,
                               everybody=rule['everybody'],
                               permission=permission)
    system.record_activity(user=identity.current.user,
                           service=u'HTTP',
                           field=u'Access Policy Rule',
                           action=u'Added',
                           new=repr(new_rule))
    return '', 204
Ejemplo n.º 20
0
def readd_user(group_name):
    """
    Re-add a user who has been excluded from the group.

    :param group_name: Group's name.
    :queryparam string user_name: User's username.

    """
    u = identity.current.user
    group = _get_group_by_name(group_name, lockmode='update')
    if not group.can_modify_membership(identity.current.user):
        raise Forbidden403('Cannot edit membership of group %s' % group_name)
    if 'user_name' not in request.args:
        raise MethodNotAllowed405
    user = _get_user_by_username(request.args['user_name'])
    if user not in group.users:
        with convert_internal_errors():
            group.readd_user(user, agent=identity.current.user)
    else:
        raise Conflict409('User %s is not excluded from group %s' %
                          (user.user_name, group_name))
    return '', 204
Ejemplo n.º 21
0
def delete_pool(pool_name):
    """
    Deletes a system pool

    :param pool_name: System pool's name

    """
    pool = _get_pool_by_name(pool_name, lockmode='update')
    u = identity.current.user
    if not pool.can_edit(u):
        raise Forbidden403('Cannot delete pool %s' % pool_name)

    systems = System.query.filter(System.pools.contains(pool))
    System.record_bulk_activity(systems,
                                user=identity.current.user,
                                service=u'HTTP',
                                action=u'Removed',
                                field=u'Pool',
                                old=unicode(pool),
                                new=None)
    # Since we are deleting the pool, we will have to change the active
    # access policy for all systems using the pool's policy to their
    # custom policy
    systems = System.query.filter(
        System.active_access_policy == pool.access_policy)
    for system in systems:
        system.active_access_policy = system.custom_access_policy
    System.record_bulk_activity(systems,
                                user=identity.current.user,
                                service=u'HTTP',
                                field=u'Active Access Policy',
                                action=u'Changed',
                                old='Pool policy: %s' % pool_name,
                                new='Custom access policy')
    session.delete(pool)
    activity = Activity(u, u'HTTP', u'Deleted', u'Pool', pool_name)
    session.add(activity)
    return '', 204
Ejemplo n.º 22
0
def delete_submission_delegate(username):
    """
    Deletes a public SSH public key belonging to the given user account.

    :param username: The user's username.
    :param id: Database id of the SSH public key to be deleted.
    """
    user = User.by_user_name(username)  #XXX lockmode='update'
    if user is None:
        raise NotFound404('User %s does not exist' % username)
    if not user.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit user %s' % user)
    if 'user_name' not in request.args:
        raise MethodNotAllowed405
    submission_delegate = User.by_user_name(request.args['user_name'])
    if submission_delegate is None:
        raise NotFound404('Submission delegate %s does not exist' %
                          request.args['user_name'])
    if not submission_delegate.is_delegate_for(user):
        raise Conflict409('User %s is not a submission delegate for %s' %
                          (submission_delegate, user))
    user.remove_submission_delegate(submission_delegate)
    return '', 204
Ejemplo n.º 23
0
def grant_ownership(group_name):
    """
    Grant group ownership to a user. The user can either be the group member or
    not. If the user is not the group member, it will be added first.

    :param group_name: Group's name.
    :jsonparam string user_name: User's username.

    """
    u = identity.current.user
    data = read_json_request(request)
    group = _get_group_by_name(group_name, lockmode='update')
    if not group.can_modify_ownership(identity.current.user):
        raise Forbidden403('Cannot edit ownership of group %s' % group_name)
    if 'user_name' not in data:
        raise BadRequest400('User not specified')
    user_name = data['user_name']
    user = _get_user_by_username(user_name)
    if not group.has_owner(user):
        group.grant_ownership(user, agent=identity.current.user)
    else:
        raise Conflict409('User %s is already an owner of group %s' % (user.user_name, group_name))
    return '', 204
Ejemplo n.º 24
0
def delete_access_policy_rules(pool_name):
    """
    Deletes one or more matching rules from a system pool's access policy.

    See :ref:`system-access-policies-api` for description of the expected query parameters

    :param pool_name: System pool's name.

    """
    pool = _get_pool_by_name(pool_name)
    if not pool.can_edit_policy(identity.current.user):
        raise Forbidden403('Cannot edit system policy')

    policy = pool.access_policy
    query = SystemAccessPolicyRule.query.filter(
        SystemAccessPolicyRule.policy == policy)
    if 'permission' in request.args:
        query = query.filter(
            SystemAccessPolicyRule.permission.in_(
                request.args.getlist('permission',
                                     type=SystemPermission.from_string)))
    else:
        raise MethodNotAllowed405
    if 'user' in request.args:
        query = query.join(SystemAccessPolicyRule.user)\
                .filter(User.user_name.in_(request.args.getlist('user')))
    elif 'group' in request.args:
        query = query.join(SystemAccessPolicyRule.group)\
                .filter(Group.group_name.in_(request.args.getlist('group')))
    elif 'everybody' in request.args:
        query = query.filter(SystemAccessPolicyRule.everybody)
    else:
        raise MethodNotAllowed405
    for rule in query:
        rule.record_deletion(service=u'HTTP')
        session.delete(rule)
    return '', 204
Ejemplo n.º 25
0
def remove_permission(group_name):
    """
    Remove a permission from a group.

    :param group_name: Group's name.
    :queryparam permission_name: Permission's name.

    """
    u = identity.current.user
    group = _get_group_by_name(group_name, lockmode='update')
    if not group.can_edit(u):
        raise Forbidden403('Cannot edit group %s' % group_name)
    if 'permission_name' not in request.args:
        raise MethodNotAllowed405
    permission_name = request.args['permission_name']
    permission = _get_permission_by_name(permission_name)
    if permission in group.permissions:
        group.permissions.remove(permission)
        group.record_activity(user=u, service=u'HTTP',
                             action=u'Removed', field=u'Permission',
                             old=unicode(permission), new=None)
    else:
        raise Conflict409('Group %s does not have permission %s' % (group_name, permission_name))
    return '', 204
Ejemplo n.º 26
0
def provision_system(fqdn):
    system = _get_system_by_FQDN(fqdn)
    if not system.can_configure_netboot(identity.current.user):
        raise Forbidden403('Cannot provision system')
    data = read_json_request(request)
    with convert_internal_errors():
        if not data['distro_tree'] or 'id' not in data['distro_tree']:
            raise ValueError('No distro tree specified')
        distro_tree = DistroTree.by_id(data['distro_tree']['id'])
        user = identity.current.user
        if user.rootpw_expired:
            raise ValueError('Your root password has expired, you must '
                             'change or clear it in order to provision.')
            redirect(u"/view/%s" % system.fqdn)
        install_options = system.manual_provision_install_options(distro_tree)\
                .combined_with(InstallOptions.from_strings(data.get('ks_meta'),
                    data.get('koptions'), data.get('koptions_post')))
        if 'ks' not in install_options.kernel_options:
            kickstart = generate_kickstart(install_options,
                                           distro_tree=distro_tree,
                                           system=system,
                                           user=user)
            install_options.kernel_options['ks'] = kickstart.link
        system.configure_netboot(distro_tree,
                                 install_options.kernel_options_str,
                                 service=u'HTTP')
        system.record_activity(user=identity.current.user,
                               service=u'HTTP',
                               action=u'Provision',
                               field=u'Distro Tree',
                               new=unicode(distro_tree))
        if data.get('reboot'):
            system.action_power(action=u'reboot', service=u'HTTP')
    # in future "installations" will be a real thing in our model,
    # but for now we have nothing to return
    return 'Provisioned', 201
Ejemplo n.º 27
0
def update_user(username):
    """
    Updates a Beaker user account.

    :param username: The user's username.
    :jsonparam string user_name: New username. If the username is changed, the 
      response will include a Location header referring to the new URL for newly 
      renamed user resource.
    :jsonparam string display_name: New display name.
    :jsonparam string email_address: New email address.
    :jsonparam string password: New password. Only valid when Beaker is not 
      using external authentication for this account.
    :jsonparam string root_password: Root password to be set on systems 
      provisioned by Beaker.
    :jsonparam boolean use_old_job_page: True if the user has opted to use the
      old, deprecated pre-Beaker-23 job page.
    :jsonparam boolean notify_job_completion: True if the user receives
      notifications upon the completion of an owned job.
    :jsonparam boolean notify_broken_system: True if the user receives
      notifications upon a system being automatically marked broken.
    :jsonparam boolean notify_system_loan: True if the user receives
      notifications when their systems are loaned or loans are returned.
    :jsonparam boolean notify_group_membership: True if the user receives
      notifications of modifications to the groups the user belongs to.
    :jsonparam boolean notify_reservesys: True if the user receives
      notifications upon reservesys being ready.
    :jsonparam boolean disabled: Whether the user should be temporarily 
      disabled. Disabled users cannot log in or submit jobs, and any running jobs 
      are cancelled when their account is disabled.
    :jsonparam string removed: Pass the string 'now' to remove a user account. 
      Pass null to un-remove a removed user account.
    """
    user = _get_user(username)
    data = read_json_request(request)
    renamed = False
    if data.get('password') is not None:
        if not user.can_change_password(identity.current.user):
            raise Forbidden403('Cannot change password for user %s' % user)
        with convert_internal_errors():
            user.password = data.pop('password')
    if data:
        if not user.can_edit(identity.current.user):
            raise Forbidden403('Cannot edit user %s' % user)
        with convert_internal_errors():
            if 'user_name' in data:
                new_user_name = data['user_name'].strip()
                if user.user_name != new_user_name:
                    if not user.can_rename(identity.current.user):
                        raise Forbidden403('Cannot rename user %s to %s' %
                                           (user, new_user_name))
                    if User.by_user_name(new_user_name) is not None:
                        raise Conflict409('User %s already exists' %
                                          new_user_name)
                    user.user_name = new_user_name
                    renamed = True
            if 'display_name' in data:
                user.display_name = data['display_name'].strip()
            if 'email_address' in data:
                user.email_address = data['email_address'].strip()
            if 'root_password' in data:
                new_root_password = data['root_password']
                if user.root_password != new_root_password:
                    user.root_password = new_root_password
            if 'use_old_job_page' in data:
                user.use_old_job_page = data['use_old_job_page']
            if 'notify_job_completion' in data:
                user.notify_job_completion = data['notify_job_completion']
            if 'notify_broken_system' in data:
                user.notify_broken_system = data['notify_broken_system']
            if 'notify_system_loan' in data:
                user.notify_system_loan = data['notify_system_loan']
            if 'notify_group_membership' in data:
                user.notify_group_membership = data['notify_group_membership']
            if 'notify_reservesys' in data:
                user.notify_reservesys = data['notify_reservesys']
            if 'disabled' in data:
                user.disabled = data['disabled']
                if user.disabled:
                    _disable(user, method=u'HTTP')
            if 'removed' in data:
                if data['removed'] is None:
                    _unremove(user)
                elif data['removed'] == 'now':
                    _remove(user, method=u'HTTP')
                else:
                    raise ValueError('"removed" value must be "now" or null')
    session.flush()
    response = jsonify(user_full_json(user))
    if renamed:
        response.headers.add('Location', absolute_url(user.href))
    return response
Ejemplo n.º 28
0
def update_labcontroller(fqdn):
    """
    Updates attributes of the lab controller identified by it's FQDN. The
    request body must be a json object or only the FQDN if
    that is the only value to be updated.

    :param string fqdn: Lab controller's new fully-qualified domain name.
    :jsonparam string user_name: User name associated with the lab controller.
    :jsonparam string email_address: Email of the user account associated with the lab controller.
    :jsonparam string password: Optional password for the user account used to login.
    :jsonparam string removed: If True, detaches all systems, cancels all
        running recipes and removes associated distro trees. If False, restores
        the lab controller.
    :jsonparam bool disabled: Whether the lab controller should be disabled. New
        recipes are not scheduled on a lab controller while it is disabled.
    :status 200: LabController updated.
    :status 400: Invalid data was given.
    """
    labcontroller = find_labcontroller_or_raise404(fqdn)
    if not labcontroller.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit lab controller')
    data = read_json_request(request)
    with convert_internal_errors():
        # should the lab controller be removed?
        if data.get('removed', False) and not labcontroller.removed:
            remove_labcontroller(labcontroller)

        # should the controller be restored?
        if data.get('removed') is False and labcontroller.removed:
            restore_labcontroller(labcontroller)
        fqdn_changed = False
        new_fqdn = data.get('fqdn', fqdn)
        if labcontroller.fqdn != new_fqdn:
            lc = None
            try:
                lc = LabController.by_name(new_fqdn)
            except NoResultFound:
                pass
            if lc is not None:
                raise BadRequest400('FQDN %s already in use' % new_fqdn)

            labcontroller.record_activity(user=identity.current.user,
                                          service=u'HTTP',
                                          field=u'fqdn',
                                          action=u'Changed',
                                          old=labcontroller.fqdn,
                                          new=new_fqdn)
            labcontroller.fqdn = new_fqdn
            labcontroller.user.display_name = new_fqdn
            fqdn_changed = True
        if 'user_name' in data:
            user = find_user_or_create(data['user_name'])
            if labcontroller.user != user:
                user = update_user(user,
                                   display_name=new_fqdn,
                                   email_address=data.get(
                                       'email_address', user.email_address),
                                   password=data.get('password',
                                                     user.password))
                labcontroller.record_activity(user=identity.current.user,
                                              service=u'HTTP',
                                              field=u'User',
                                              action=u'Changed',
                                              old=labcontroller.user.user_name,
                                              new=user.user_name)
                labcontroller.user = user
        if 'email_address' in data:
            new_email_address = data.get('email_address')
            if labcontroller.user.email_address != new_email_address:
                labcontroller.user.email_address = new_email_address
        if data.get('password') is not None:
            labcontroller.user.password = data.get('password')
        if labcontroller.disabled != data.get('disabled',
                                              labcontroller.disabled):
            labcontroller.record_activity(user=identity.current.user,
                                          service=u'HTTP',
                                          field=u'disabled',
                                          action=u'Changed',
                                          old=unicode(labcontroller.disabled),
                                          new=data['disabled'])
            labcontroller.disabled = data['disabled']

    response = jsonify(labcontroller.__json__())
    if fqdn_changed:
        response.headers.add('Location', absolute_url(labcontroller.href))
    return response
Ejemplo n.º 29
0
def update_system(fqdn):
    system = _get_system_by_FQDN(fqdn)
    if not system.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit system')
    data = read_json_request(request)

    # helper for recording activity below
    def record_activity(field, old, new, action=u'Changed'):
        system.record_activity(user=identity.current.user,
                               service=u'HTTP',
                               action=action,
                               field=field,
                               old=old,
                               new=new)

    with convert_internal_errors():
        # XXX what a nightmare... need to use a validation/conversion library,
        # and maybe simplify/relocate the activity recording stuff somehow
        changed = False
        renamed = False
        if 'fqdn' in data:
            new_fqdn = data['fqdn'].lower()
            if new_fqdn != system.fqdn:
                if System.query.filter(System.fqdn == new_fqdn).count():
                    raise Conflict409('System %s already exists' % new_fqdn)
                record_activity(u'FQDN', system.fqdn, new_fqdn)
                system.fqdn = new_fqdn
                changed = True
                renamed = True
        if 'owner' in data and data['owner'].get(
                'user_name') != system.owner.user_name:
            if not system.can_change_owner(identity.current.user):
                raise Forbidden403('Cannot change owner')
            new_owner = User.by_user_name(data['owner'].get('user_name'))
            if new_owner is None:
                raise BadRequest400('No such user %s' %
                                    data['owner'].get('user_name'))
            record_activity(u'Owner', system.owner, new_owner)
            system.owner = new_owner
            changed = True
        if 'status' in data:
            new_status = SystemStatus.from_string(data['status'])
            if new_status != system.status:
                record_activity(u'Status', system.status, new_status)
                system.status = new_status
                if not new_status.bad and system.status_reason:
                    # clear the status reason for "good" statuses
                    record_activity(u'Status Reason', system.status_reason,
                                    None)
                    system.status_reason = None
                changed = True
        if 'status_reason' in data:
            new_reason = data['status_reason'] or None
            if new_reason and not system.status.bad:
                raise ValueError('Cannot set status reason when status is %s' %
                                 system.status)
            if new_reason != system.status_reason:
                record_activity(u'Status Reason', system.status_reason,
                                new_reason)
                system.status_reason = new_reason
                changed = True
        if 'type' in data:
            new_type = SystemType.from_string(data['type'])
            if new_type != system.type:
                record_activity(u'Type', system.type, new_type)
                system.type = new_type
                changed = True
        if 'arches' in data:
            new_arches = [Arch.by_name(a) for a in (data['arches'] or [])]
            added_arches = set(new_arches).difference(system.arch)
            removed_arches = set(system.arch).difference(new_arches)
            if added_arches or removed_arches:
                for added_arch in added_arches:
                    record_activity(u'Arch', None, added_arch, u'Added')
                for removed_arch in removed_arches:
                    record_activity(u'Arch', removed_arch, None, u'Removed')
                system.arch[:] = new_arches
                changed = True
        if 'lab_controller_id' in data:
            if data['lab_controller_id']:
                new_lc = LabController.by_id(data['lab_controller_id'])
            else:
                new_lc = None
            if new_lc != system.lab_controller:
                if system.open_reservation is not None:
                    raise Conflict409(
                        'Unable to change lab controller while system '
                        'is in use (return the system first)')
                record_activity(u'Lab Controller', system.lab_controller,
                                new_lc)
                system.lab_controller = new_lc
                changed = True
        # If we're given any power-related keys, need to ensure system.power exists
        if not system.power and set(['power_type', 'power_address', 'power_user',
                'power_password', 'power_id', 'power_quiescent_period'])\
                .intersection(data.keys()):
            system.power = Power()
        if 'power_type' in data:
            new_power_type = PowerType.by_name(data['power_type'])
            if new_power_type != system.power.power_type:
                if not system.power.power_type:
                    old_power_type = ''
                else:
                    old_power_type = system.power.power_type.name
                record_activity(u'power_type', old_power_type,
                                new_power_type.name)
                system.power.power_type = new_power_type
                changed = True
        if 'power_address' in data:
            new_power_address = data['power_address']
            if not new_power_address:
                raise ValueError('Power address is required')
            if new_power_address != system.power.power_address:
                record_activity(u'power_address', system.power.power_address,
                                data['power_address'])
                system.power.power_address = new_power_address
                changed = True
        if 'power_user' in data:
            new_power_user = data['power_user'] or u''
            if new_power_user != (system.power.power_user or u''):
                record_activity(u'power_user', u'********', u'********')
                system.power.power_user = new_power_user
                changed = True
        if 'power_password' in data:
            new_power_password = data['power_password'] or u''
            if new_power_password != (system.power.power_passwd or u''):
                record_activity(u'power_passwd', u'********', u'********')
                system.power.power_passwd = new_power_password
                changed = True
        if 'power_id' in data:
            new_power_id = data['power_id'] or u''
            if new_power_id != (system.power.power_id or u''):
                record_activity(u'power_id', system.power.power_id,
                                new_power_id)
                system.power.power_id = new_power_id
                changed = True
        if 'power_quiescent_period' in data:
            new_qp = int(data['power_quiescent_period'])
            if new_qp != system.power.power_quiescent_period:
                record_activity(u'power_quiescent_period',
                                system.power.power_quiescent_period, new_qp)
                system.power.power_quiescent_period = new_qp
                changed = True
        if 'release_action' in data:
            new_release_action = ReleaseAction.from_string(
                data['release_action'])
            if new_release_action != (system.release_action
                                      or ReleaseAction.power_off):
                record_activity(
                    u'release_action',
                    (system.release_action or ReleaseAction.power_off),
                    new_release_action)
                system.release_action = new_release_action
                changed = True
        if 'reprovision_distro_tree' in data:
            if (not data['reprovision_distro_tree']
                    or 'id' not in data['reprovision_distro_tree']):
                new_rpdt = None
            else:
                new_rpdt = DistroTree.by_id(
                    data['reprovision_distro_tree']['id'])
            if new_rpdt != system.reprovision_distro_tree:
                record_activity(u'reprovision_distro_tree',
                                unicode(system.reprovision_distro_tree),
                                unicode(new_rpdt))
                system.reprovision_distro_tree = new_rpdt
                changed = True
        if 'location' in data:
            new_location = data['location'] or None
            if new_location != system.location:
                record_activity(u'Location', system.location, new_location)
                system.location = new_location
                changed = True
        if 'lender' in data:
            new_lender = data['lender'] or None
            if new_lender != system.lender:
                record_activity(u'Lender', system.lender, new_lender)
                system.lender = new_lender
                changed = True
        if 'kernel_type' in data:
            new_kernel_type = KernelType.by_name(data['kernel_type'])
            if new_kernel_type != system.kernel_type:
                record_activity(u'Kernel Type', system.kernel_type,
                                new_kernel_type)
                system.kernel_type = new_kernel_type
                changed = True
        if 'hypervisor' in data:
            if data['hypervisor']:
                new_hypervisor = Hypervisor.by_name(data['hypervisor'])
            else:
                new_hypervisor = None
            if new_hypervisor != system.hypervisor:
                record_activity(u'Hypervisor', system.hypervisor,
                                new_hypervisor)
                system.hypervisor = new_hypervisor
                changed = True
        if 'vendor' in data:
            new_vendor = data['vendor'] or None
            if new_vendor != system.vendor:
                record_activity(u'Vendor', system.vendor, new_vendor)
                system.vendor = new_vendor
                changed = True
        if 'model' in data:
            new_model = data['model'] or None
            if new_model != system.model:
                record_activity(u'Model', system.model, new_model)
                system.model = new_model
                changed = True
        if 'serial_number' in data:
            new_serial_number = data['serial_number'] or None
            if new_serial_number != system.serial:
                record_activity(u'Serial Number', system.serial,
                                new_serial_number)
                system.serial = new_serial_number
                changed = True
        if 'mac_address' in data:
            new_mac_address = data['mac_address'] or None
            if new_mac_address != system.mac_address:
                record_activity(u'MAC Address', system.mac_address,
                                new_mac_address)
                system.mac_address = new_mac_address
                changed = True
        if 'memory' in data:
            new_memory = int(data['memory']) if data['memory'] else None
            if new_memory != system.memory:
                record_activity(u'Memory', system.memory, new_memory)
                system.memory = new_memory
                changed = True
        if 'numa_nodes' in data:
            new_numa_nodes = int(
                data['numa_nodes']) if data['numa_nodes'] else None
            if not system.numa:
                system.numa = Numa()
            if new_numa_nodes != system.numa.nodes:
                record_activity(u'NUMA/Nodes', system.numa.nodes,
                                new_numa_nodes)
                system.numa.nodes = new_numa_nodes
                changed = True
        if changed:
            # XXX clear checksum!?
            system.date_modified = datetime.datetime.utcnow()
    response = jsonify(system.__json__())
    if renamed:
        response.headers.add('Location', url('/view/%s' % system.fqdn))
    return response