예제 #1
0
def update_user_settings(request):
    """
    Tags: users
    ---
    User related actions
    Edit name, Update password
    """

    # SEC raise exception if not user
    user = user_from_request(request)

    auth_context = auth_context_from_request(request)

    params = params_from_request(request)

    action = params.get('action')
    actions = ['update_details', 'update_password']
    if action not in actions:
        log.error("Update_user_settings bad action='%s'", action)
        raise BadRequestError('action')

    if action == 'update_details':
        avatar = params.get('avatar')
        if avatar:
            try:
                Avatar.objects.get(id=avatar)
                user.avatar = avatar
            except DoesNotExist:
                raise BadRequestError('Avatar does not exist')
        if params.get('first_name') or params.get('last_name'):
            user.first_name = params.get('first_name')
            user.last_name = params.get('last_name')
        elif params.get('name'):
            name_array = params.get('name').split(' ')
            if len(name_array) > 1:
                user.last_name = name_array[-1]
            user.first_name = ' '.join(name_array[:-1])
        user.save()
        trigger_session_update(auth_context.owner, ['user'])
        return {}

    if action == 'update_password':
        current_password = params.get('current_password', '')
        password = params.get('password', '')
        # check if current_password provided
        if not current_password and (user.password and user.password != ''):
            raise RequiredParameterMissingError("Current password")
        # check if new password provided
        if not password:
            raise RequiredParameterMissingError("New password")

        # SEC check if current_password valid
        if not user.check_password(current_password):
            raise UnauthorizedError("Invalid current password")

        # set new password
        user.set_password(password)
        return {}
예제 #2
0
    def _create_volume__prepare_args(self, kwargs):
        for param in (
                'name',
                'size',
        ):
            if not kwargs.get(param):
                raise RequiredParameterMissingError(param)
        if not kwargs['dynamic']:
            if not kwargs.get('volume_params'):
                msg = """Parameter volume_params must be a populated
                dictionary/object with the coresponding
                parameter/value pairs depending on volume type.
                If you are not sure please enable dynamic creation."""
                raise RequiredParameterMissingError(msg)
            else:
                kwargs['ex_volume_params'] = kwargs.pop('volume_params')
            if not kwargs.get('volume_type'):
                msg = """A volume_type must be specified from the
                supported volume types by kubernetes.
                If you are not sure enable dynamic volume creation."""
                raise RequiredParameterMissingError(msg)

        else:
            for param in ('location', 'storage_class_name'):
                if not kwargs.get(param):
                    raise RequiredParameterMissingError(param)
            kwargs['ex_storage_class_name'] = kwargs.pop('storage_class_name')

        if 'volume_type' in kwargs:
            kwargs['ex_volume_type'] = kwargs.pop('volume_type')
        if 'volume_mode' in kwargs:
            if kwargs['volume_mode'] not in {'Filesystem', 'Block'}:
                raise ValueError("volume_mode can be either "
                                 "Filesysystem or Block.")
            kwargs['ex_volume_mode'] = kwargs.pop('volume_mode')
        if 'access_mode' in kwargs:
            kwargs['ex_access_mode'] = kwargs.pop('access_mode')
        if 'reclaim_policy' in kwargs:
            kwargs['ex_reclaim_policy'] = kwargs.pop('reclaim_policy')
        kwargs['ex_dynamic'] = kwargs.pop('dynamic')
        # FIXME circular imports
        from mist.api.clouds.models import CloudLocation
        if not kwargs.get('location'):
            raise RequiredParameterMissingError('location')
        try:
            location = CloudLocation.objects.get(id=kwargs['location'],
                                                 missing_since=None)
            kwargs['location'] = location
        except CloudLocation.DoesNotExist:
            raise NotFoundError("Location with id '%s'." % kwargs['location'])
예제 #3
0
def suppressed_emails(request):

    params = dict(params_from_request(request).copy())

    try:
        mac_verify(params)
    except Exception as exc:
        raise BadRequestError(str(exc))

    try:
        decrypted_str = decrypt(params['token'])
        decrypted_json = json.loads(decrypted_str)
    except Exception as exc:
        log.exception(repr(exc))
        raise BadRequestError()

    if decrypted_json.get('key') != Portal.get_singleton().external_api_key:
        raise NotFoundError()

    action = decrypted_json.get('action')
    if not action:
        raise RequiredParameterMissingError('action')

    if action == 'delete':
        Notification.objects(suppressed=True).delete()
    elif action == 'unsuppress':
        Notification.objects.update(suppressed=False)
    else:
        raise BadRequestError('Action "%s" not supported' % action)

    return Response("OK", 200)
예제 #4
0
def delete_schedule(request):
    """
    Tags: schedules
    ---
    Deletes a schedule entry of a user.
    REMOVE permission required on schedule
    ---
    schedule_id:
      type: string
      required: true
    """
    schedule_id = request.matchdict['schedule_id']
    auth_context = auth_context_from_request(request)

    if not schedule_id:
        raise RequiredParameterMissingError('No schedule id provided')

    # Check if entry exists
    try:
        schedule = Schedule.objects.get(id=schedule_id, deleted=None)
    except me.DoesNotExist:
        raise ScheduleTaskNotFound()

    # SEC
    auth_context.check_perm('schedule', 'remove', schedule_id)

    # NOTE: Do not perform an atomic operation when marking a schedule as
    # deleted, since we do not wish to bypass pre-save validation/cleaning.
    schedule.deleted = datetime.utcnow()
    schedule.save()

    trigger_session_update(auth_context.owner, ['schedules'])
    return OK
예제 #5
0
def su(request):
    """
    Impersonate another user.

    This allows an admin to take the identity of any other user. It is meant to
    be used strictly for debugging. You can return to your regular user simply
    by logging out. This won't affect the last login time of the actual user.
    An email should be immediately sent out to the team, notifying of the 'su'
    action for security reasons.

    """
    # SEC raise exception if user not admin
    user = user_from_request(request, admin=True)

    session = request.environ['session']
    if isinstance(session, ApiToken):
        raise ForbiddenError('Cannot do su when authenticated with api token')
    real_email = user.email
    params = params_from_request(request)
    email = params.get('email')
    if not email:
        raise RequiredParameterMissingError('email')
    try:
        user = User.objects.get(email=email)
    except (UserNotFoundError, User.DoesNotExist):
        raise UserUnauthorizedError()
    reissue_cookie_session(request, real_email, su=user.id)

    # alert admins
    subject = "Some admin used su"
    body = "Admin: %s\nUser: %s\nServer: %s" % (real_email, user.email,
                                                config.CORE_URI)
    send_email(subject, body, config.NOTIFICATION_EMAIL['ops'])
    return HTTPFound('/')
예제 #6
0
def transfer_ownership_to_user(request):
    """
    Tags: ownership

    ---

    Transfer ownership of a resource

    If a resource isn't owned by the requesting user, then an UnauthorizedError
    error will be thrown, unless the requesting user is a member of the Owners
    team.

    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)

    if not params.get('user_id'):
        raise RequiredParameterMissingError('user_id')
    try:
        new_owner = User.objects.get(id=params['user_id'])
    except User.DoesNotExist:
        raise NotFoundError('User with id %s' % params['user_id'])

    for rtype, rids in params.get('resources', {}).iteritems():
        Model = get_resource_model(rtype)
        for rid in rids:
            try:
                resource = Model.objects.get(owner=auth_context.owner, id=rid)
                resource.transfer_ownership(auth_context, new_owner)
            except Model.DoesNotExist:
                raise NotFoundError('%s with id %s' % (rtype, rid))

    trigger_session_update(auth_context.owner)

    return Response('OK', 200)
예제 #7
0
파일: views.py 프로젝트: hb407033/mist.api
def get_private_key(request):
    """
    Gets private key from key name.
    It is used in single key view when the user clicks the display private key
    button.
    READ_PRIVATE permission required on key.
    ---
    key:
      description: The key id
      in: path
      required: true
      type: string
    """

    key_id = request.matchdict['key']
    if not key_id:
        raise RequiredParameterMissingError("key_id")

    auth_context = auth_context_from_request(request)
    try:
        key = SSHKey.objects.get(owner=auth_context.owner,
                                 id=key_id,
                                 deleted=None)
    except me.DoesNotExist:
        raise NotFoundError('Key id does not exist')

    auth_context.check_perm('key', 'read_private', key.id)
    return key.private
예제 #8
0
    def add(cls, owner, cloud, id='', **kwargs):
        """Add Zone

        This is a class method, meaning that it is meant to be called on the
        class itself and not on an instance of the class.

        You're not meant to be calling this directly, but on a cloud subclass
        instead like this:

            zone = Zone.add(owner=org, domain='domain.com.')

        Params:
        - owner and domain are common and required params
        - only provide a custom zone id if you're migrating something
        - kwargs will be passed to appropriate controller, in most cases these
          should match the extra fields of the particular zone type.

        """
        if not kwargs['domain']:
            raise RequiredParameterMissingError('domain')
        if not cloud or not isinstance(cloud, Cloud):
            raise BadRequestError('cloud')
        if not owner or not isinstance(owner, Organization):
            raise BadRequestError('owner')
        zone = cls(owner=owner, cloud=cloud, domain=kwargs['domain'])
        if id:
            zone.id = id
        return zone.ctl.create_zone(**kwargs)
예제 #9
0
파일: views.py 프로젝트: hb407033/mist.api
def get_public_key(request):
    """
    Get public key
    Gets public key from key name.
    READ permission required on key.
    ---
    key:
      description: The key id
      in: path
      required: true
      type: string
    """
    key_id = request.matchdict['key']
    if not key_id:
        raise RequiredParameterMissingError("key_id")

    auth_context = auth_context_from_request(request)
    try:
        key = SSHKey.objects.get(owner=auth_context.owner,
                                 id=key_id,
                                 deleted=None)
    except me.DoesNotExist:
        raise NotFoundError('Key id does not exist')

    auth_context.check_perm('key', 'read', key.id)
    return key.public
예제 #10
0
def revoke_session(request):
    """
    Tags: sessions
    ---
    Revoke an active session
    ---
    id:
      description: Session ID
    """

    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    auth_token_id = params.get("id")

    if not auth_token_id:
        raise RequiredParameterMissingError("No token id parameter provided")

    try:
        if auth_context.is_owner():
            auth_token = AuthToken.objects.get(org=auth_context.org,
                                               id=auth_token_id)
        else:
            auth_token = AuthToken.objects.get(
                user_id=auth_context.user.get_id(), id=auth_token_id)
        if auth_token.is_valid():
            auth_token.invalidate()
            auth_token.save()

    except me.DoesNotExist:
        raise NotFoundError('Session not found')

    return OK
예제 #11
0
파일: views.py 프로젝트: hb407033/mist.api
def rename_cloud(request):
    """
    Rename a cloud
    Renames cloud with given cloud_id.
    EDIT permission required on cloud.
    ---
    cloud:
      in: path
      required: true
      type: string
    new_name:
      description: ' New name for the key (will also serve as the key''s id)'
      type: string
    """
    auth_context = auth_context_from_request(request)
    cloud_id = request.matchdict['cloud']
    try:
        Cloud.objects.get(owner=auth_context.owner, id=cloud_id, deleted=None)
    except Cloud.DoesNotExist:
        raise NotFoundError('Cloud does not exist')

    params = params_from_request(request)
    new_name = params.get('new_name', '')
    if not new_name:
        raise RequiredParameterMissingError('new_name')
    auth_context.check_perm('cloud', 'edit', cloud_id)

    m_rename_cloud(auth_context.owner, cloud_id, new_name)
    return OK
예제 #12
0
def disassociate_metric(request):
    """
    Tags: monitoring
    ---
    Disassociate a metric from a machine.
    READ permission required on cloud.
    EDIT_GRAPHS permission required on machine
    ---
    machine:
      in: path
      type: string
      required: true
    metric_id:
      type: string
      required: true
    """
    auth_context = auth_context_from_request(request)
    machine = _machine_from_matchdict(request)

    # SEC require permission EDIT_GRAPHS on machine
    auth_context.check_perm("machine", "edit_graphs", machine.id)

    params = params_from_request(request)
    metric_id = params.get('metric_id')
    if not metric_id:
        raise RequiredParameterMissingError('metric_id')

    mist.api.monitoring.methods.disassociate_metric(machine, metric_id)
    return {}
예제 #13
0
def show_schedule_entry(request):
    """
    Tags: schedules
    ---
    Show details of schedule.
    READ permission required on schedule
    ---
    schedule_id:
      type: string
      required: true
    """
    schedule_id = request.matchdict['schedule_id']
    auth_context = auth_context_from_request(request)

    if not schedule_id:
        raise RequiredParameterMissingError('No schedule id provided')

    try:
        schedule = Schedule.objects.get(id=schedule_id, deleted=None,
                                        owner=auth_context.owner)
    except me.DoesNotExist:
        raise ScheduleTaskNotFound()

    # SEC require READ permission on schedule
    auth_context.check_perm('schedule', 'read', schedule_id)

    return schedule.as_dict()
예제 #14
0
    def __init__(self,
                 host,
                 username=None,
                 key=None,
                 password=None,
                 cert_file=None,
                 port=22):
        """Initialize a Shell instance

        Initializes a Shell instance for host. If username is provided, then
        it tries to actually initiate the connection, by calling connect().
        Check out the docstring of connect().

        """

        if not host:
            raise RequiredParameterMissingError('host not given')
        self.host = host
        self.sudo = False

        self.ssh = paramiko.SSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        # if username provided, try to connect
        if username:
            self.connect(username, key, password, cert_file, port)
예제 #15
0
def delete_script(request):
    """
    Delete script
    REMOVE permission required on script.
    ---
    script_id:
      in: path
      required: true
      type: string
    """
    script_id = request.matchdict['script_id']
    auth_context = auth_context_from_request(request)

    if not script_id:
        raise RequiredParameterMissingError('No script id provided')

    try:
        script = Script.objects.get(owner=auth_context.owner,
                                    id=script_id,
                                    deleted=None)

    except me.DoesNotExist:
        raise NotFoundError('Script id not found')

    # SEC require REMOVE permission on script
    auth_context.check_perm('script', 'remove', script_id)

    script.ctl.delete()
    return OK
예제 #16
0
    def add(cls, owner, title, id='', **kwargs):
        """Add cloud

        This is a class method, meaning that it is meant to be called on the
        class itself and not on an instance of the class.

        You're not meant to be calling this directly, but on a cloud subclass
        instead like this:

            cloud = AmazonCloud.add(owner=org, title='EC2',
                                    apikey=apikey, apisecret=apisecret)

        Params:
        - owner and title are common and required params
        - only provide a custom cloud id if you're migrating something
        - kwargs will be passed to appropriate controller, in most cases these
          should match the extra fields of the particular cloud type.

        """
        if not title:
            raise RequiredParameterMissingError('title')
        if not owner or not isinstance(owner, Organization):
            raise BadRequestError('owner')
        if Cloud.objects(owner=owner, title=title, deleted=None):
            raise CloudExistsError()
        cloud = cls(owner=owner, title=title)
        if id:
            cloud.id = id
        cloud.ctl.add(**kwargs)
        return cloud
예제 #17
0
def download_script(request):
    """
    Download script file or archive.
    READ permission required on script.
    ---
    script_id:
      type: string
      required: true
      in: path
    """
    script_id = request.matchdict['script_id']
    auth_context = auth_context_from_request(request)

    if not script_id:
        raise RequiredParameterMissingError('No script id provided')

    try:
        script = Script.objects.get(owner=auth_context.owner,
                                    id=script_id,
                                    deleted=None)
    except me.DoesNotExist:
        raise NotFoundError('Script id not found')

    # SEC require READ permission on SCRIPT
    auth_context.check_perm('script', 'read', script_id)
    try:
        return script.ctl.get_file()
    except BadRequestError():
        return Response("Unable to find: {}".format(request.path_info))
예제 #18
0
def show_script(request):
    """
    Show script details and job history.
    READ permission required on script.
    ---
    script_id:
      type: string
      required: true
      in: path
    """
    script_id = request.matchdict['script_id']
    auth_context = auth_context_from_request(request)

    if not script_id:
        raise RequiredParameterMissingError('No script id provided')

    try:
        script = Script.objects.get(owner=auth_context.owner,
                                    id=script_id,
                                    deleted=None)
    except me.DoesNotExist:
        raise NotFoundError('Script id not found')

    # SEC require READ permission on SCRIPT
    auth_context.check_perm('script', 'read', script_id)

    ret_dict = script.as_dict()
    jobs = get_stories('job', auth_context.owner.id, script_id=script_id)
    ret_dict['jobs'] = [job['job_id'] for job in jobs]
    return ret_dict
예제 #19
0
    def add(cls, network, cidr, name='', description='', id='', **kwargs):
        """Add a Subnet.

        This is a class method, meaning that it is meant to be called on the
        class itself and not on an instance of the class.

        You're not meant to be calling this directly, but on a network subclass
        instead like this:

            subnet = AmazonSubnet.add(network=network,
                                      name='Ec2Subnet',
                                      cidr='172.31.10.0/24')

        :param network: the Network nn which the subnet is going to be created.
        :param cidr: the CIDR to be assigned to the new subnet.
        :param name: the name to be assigned to the new subnet.
        :param description: an optional description.
        :param id: a custom object id, passed in case of a migration.
        :param kwargs: the kwargs to be passed to the corresponding controller.

        """
        assert isinstance(network, Network)
        if not cidr:
            raise RequiredParameterMissingError('cidr')
        subnet = cls(network=network,
                     cidr=cidr,
                     name=name,
                     description=description)
        if id:
            subnet.id = id
        subnet.ctl.create(**kwargs)
        return subnet
예제 #20
0
파일: shell.py 프로젝트: ghoul008/mist.api
    def connect(self, username, key=None, password=None, cert_file=None,
                port=22):
        """Initialize an SSH connection.

        Tries to connect and configure self. If only password is provided, it
        will be used for authentication. If key is provided, it is treated as
        and OpenSSH private RSA key and used for authentication. If both key
        and password are provided, password is used as a passphrase to unlock
        the private key.

        Raises MachineUnauthorizedError if it fails to connect.

        """

        if not key and not password:
            raise RequiredParameterMissingError("neither key nor password "
                                                "provided.")

        if key:
            private = key.private
            if isinstance(key, SignedSSHKey) and cert_file:
                # signed ssh key, use RSACert
                rsa_key = paramiko.RSACert(privkey_file_obj=StringIO(private),
                                           cert_file_obj=StringIO(cert_file))
            else:
                rsa_key = paramiko.RSAKey.from_private_key(StringIO(private))
        else:
            rsa_key = None

        attempts = 3
        while attempts:
            attempts -= 1
            try:
                self.ssh.connect(
                    self.host,
                    port=port,
                    username=username,
                    password=password,
                    pkey=rsa_key,
                    allow_agent=False,
                    look_for_keys=False,
                    timeout=10
                )
                break
            except paramiko.AuthenticationException as exc:
                log.error("ssh exception %r", exc)
                raise MachineUnauthorizedError("Couldn't connect to "
                                               "%s@%s:%s. %s"
                                               % (username, self.host,
                                                  port, exc))
            except socket.error as exc:
                log.error("Got ssh error: %r", exc)
                if not attempts:
                    raise ServiceUnavailableError("SSH timed-out repeatedly.")
            except Exception as exc:
                log.error("ssh exception %r", exc)
                # don't fail if SSHException or other paramiko exception,
                # eg related to network, but keep until all attempts are made
                if not attempts:
                    raise ServiceUnavailableError(repr(exc))
예제 #21
0
파일: views.py 프로젝트: hb407033/mist.api
def edit_key(request):
    """
    Edit a key
    Edits a given key's name  to new_name
    EDIT permission required on key.
    ---
    new_name:
      description: The new key name
      type: string
    key_id:
      description: The key id
      in: path
      required: true
      type: string
    """
    key_id = request.matchdict['key']
    params = params_from_request(request)
    new_name = params.get('new_name')
    if not new_name:
        raise RequiredParameterMissingError("new_name")

    auth_context = auth_context_from_request(request)
    try:
        key = Key.objects.get(owner=auth_context.owner,
                              id=key_id,
                              deleted=None)
    except me.DoesNotExist:
        raise NotFoundError('Key with that id does not exist')
    auth_context.check_perm('key', 'edit', key.id)
    key.ctl.rename(new_name)

    return {'new_name': new_name}
예제 #22
0
def delete_portforward(request):
    """
    Tags: networks
    ---
    Delete the portforward of a GigG8 network
    READ permission required on network
    EDIT permission required on network
    ---
    network:
      in: path
      required: true
      type: string
    public_port:
      required: true
      type: string
    protocol:
      required: true
      type: string
    """
    network_id = request.matchdict['network']
    auth_context = auth_context_from_request(request)

    params = params_from_request(request)

    if not params.get('public_port'):
        raise RequiredParameterMissingError('public_port')

    if not params.get('protocol'):
        raise RequiredParameterMissingError('protocol')

    # SEC
    auth_context.check_perm('network', 'read', network_id)
    auth_context.check_perm('network', 'edit', network_id)

    try:
        network = Network.objects.get(owner=auth_context.owner, id=network_id)
    except Network.DoesNotExist:
        raise NetworkNotFoundError()

    try:
        network.cloud.ctl.network.delete_portforward(network, **params)
    except NotImplementedError:
        raise MistNotImplementedError

    return OK
예제 #23
0
def create_network(request):
    """
    Create network on a cloud
    Creates a new network. If subnet dict is specified,
    after creating the network it will use the new
    network's id to create a subnet.
    CREATE_RESOURCES permission required on cloud.
    ---
    cloud_id:
      in: path
      required: true
      description: The Cloud ID
      type: string
    network:
      required: true
      type: dict
    subnet:
      type: dict
    """
    cloud_id = request.matchdict['cloud']

    params = params_from_request(request)
    network_params = params.get('network')
    subnet_params = params.get('subnet')

    auth_context = auth_context_from_request(request)

    if not network_params:
        raise RequiredParameterMissingError('network')

    # TODO
    if not auth_context.is_owner():
        raise PolicyUnauthorizedError()

    try:
        cloud = Cloud.objects.get(owner=auth_context.owner, id=cloud_id)
    except me.DoesNotExist:
        raise CloudNotFoundError

    network = methods.create_network(auth_context.owner, cloud, network_params)
    network_dict = network.as_dict()

    # Bundling Subnet creation in this call because it is required
    #  for backwards compatibility with the current UI
    if subnet_params:
        try:
            subnet = create_subnet(auth_context.owner, cloud,
                                   network, subnet_params)
        except Exception as exc:
            # Cleaning up the network object in case subnet creation
            #  fails for any reason
            network.ctl.delete()
            raise exc
        network_dict['subnet'] = subnet.as_dict()

    return network.as_dict()
예제 #24
0
 def _create_volume__prepare_args(self, kwargs):
     # FIXME Imported here due to circular dependency issues.
     from mist.api.clouds.models import CloudLocation
     if not kwargs.get('location'):
         raise RequiredParameterMissingError('location')
     try:
         location = CloudLocation.objects.get(id=kwargs['location'])
     except CloudLocation.DoesNotExist:
         raise NotFoundError("Location with id '%s'." % kwargs['location'])
     kwargs['location'] = location.name
예제 #25
0
def update_monitoring(request):
    """
    Tags: monitoring
    ---
    Enable or disable monitoring for a machine
    ---
    machine:
      in: path
      type: string
      required: true
    action:
      enum:
      - enable
      - disable
      type: string
      required: true
    no_ssh:
      type: boolean
      default: false
    dry:
      type: boolean
      default: false

    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    no_ssh = bool(params.get('no_ssh'))
    dry = bool(params.get('dry'))
    action = params.get('action')
    if not action:
        raise RequiredParameterMissingError('action')

    if action == 'enable':
        machine = _machine_from_matchdict(request)
    elif action == 'disable':
        machine = _machine_from_matchdict(request, deleted=True)
    else:
        raise BadRequestError('Action must be one of (enable, disable)')

    # SEC require permission EDIT on machine
    auth_context.check_perm("machine", "edit", machine.id)

    if action == 'enable':
        return mist.api.monitoring.methods.enable_monitoring(
            owner=auth_context.owner,
            cloud_id=machine.cloud.id,
            machine_id=machine.machine_id,
            no_ssh=no_ssh,
            dry=dry)
    elif action == 'disable':
        return mist.api.monitoring.methods.disable_monitoring(
            owner=auth_context.owner,
            cloud_id=machine.cloud.id,
            machine_id=machine.machine_id,
            no_ssh=no_ssh)
예제 #26
0
def add_key(request):
    """
    Tags: keys
    ---
    Adds key.
    ADD permission required on key.
    ---
    name:
      description: The key's name
      required: true
      type: string
    priv:
      description: The private key
      required: true
      type: string
    certificate:
      description: The signed public key, when using signed ssh keys
      type: string
    """
    params = params_from_request(request)
    key_name = params.pop('name', None)
    private_key = params.get('priv', None)
    certificate = params.get('certificate', None)
    auth_context = auth_context_from_request(request)
    key_tags = auth_context.check_perm("key", "add", None)

    if not key_name:
        raise BadRequestError("Key name is not provided")
    if not private_key:
        raise RequiredParameterMissingError("Private key is not provided")

    if certificate:
        key = SignedSSHKey.add(auth_context.owner, key_name, **params)
    else:
        key = SSHKey.add(auth_context.owner, key_name, **params)

    # Set ownership.
    key.assign_to(auth_context.user)

    if key_tags:
        add_tags_to_resource(auth_context.owner, key, key_tags.items())
    # since its a new key machines fields should be an empty list

    clouds = Cloud.objects(owner=auth_context.owner, deleted=None)
    machines = Machine.objects(cloud__in=clouds,
                               key_associations__keypair__exact=key)

    assoc_machines = transform_key_machine_associations(machines, key)

    return {
        'id': key.id,
        'name': key.name,
        'machines': assoc_machines,
        'isDefault': key.default
    }
예제 #27
0
def delete_keys(request):
    """
    Tags: keys
    ---
    Deletes multiple keys.
    Provide a list of key ids to be deleted. The method will try to delete
    all of them and then return a json that describes for each key id
    whether or not it was deleted or not_found if the key id could not
    be located. If no key id was found then a 404(Not Found) response will
    be returned.
    REMOVE permission required on each key.
    ---
    key_ids:
      required: true
      type: array
      items:
        type: string
    """
    auth_context = auth_context_from_request(request)

    params = params_from_request(request)
    key_ids = params.get('key_ids', [])
    if type(key_ids) != list or len(key_ids) == 0:
        raise RequiredParameterMissingError('No key ids provided')
    # remove duplicate ids if there are any
    key_ids = set(key_ids)

    report = {}
    for key_id in key_ids:
        try:
            key = Key.objects.get(owner=auth_context.owner,
                                  id=key_id,
                                  deleted=None)
        except me.DoesNotExist:
            report[key_id] = 'not_found'
            continue
        try:
            auth_context.check_perm('key', 'remove', key.id)
        except PolicyUnauthorizedError:
            report[key_id] = 'unauthorized'
        else:
            delete_key(auth_context.owner, key_id)
            report[key_id] = 'deleted'

    # if no key id was valid raise exception
    if len(filter(lambda key_id: report[key_id] == 'not_found',
                  report)) == len(key_ids):
        raise NotFoundError('No valid key id provided')
    # if user was unauthorized for all keys
    if len(filter(lambda key_id: report[key_id] == 'unauthorized',
                  report)) == len(key_ids):
        raise NotFoundError('Unauthorized to modify any of the keys')
    return report
예제 #28
0
    def _create_volume__prepare_args(self, kwargs):
        if not kwargs.get('resource_group'):
            raise RequiredParameterMissingError('resource_group')
        if not kwargs.get('location'):
            raise RequiredParameterMissingError('location')

        # FIXME Imported here due to circular dependency issues.
        from mist.api.clouds.models import CloudLocation
        try:
            location = CloudLocation.objects.get(id=kwargs['location'])
        except CloudLocation.DoesNotExist:
            raise NotFoundError("Location with id '%s'." % kwargs['location'])
        node_location = NodeLocation(id=location.external_id,
                                     name=location.name,
                                     country=location.country,
                                     driver=None)
        kwargs['location'] = node_location
        resource_group = kwargs.pop('resource_group')
        conn = self.cloud.ctl.compute.connection
        resource_groups = conn.ex_list_resource_groups()
        ex_resource_group = None
        for lib_resource_group in resource_groups:
            if lib_resource_group.id == resource_group:
                ex_resource_group = lib_resource_group.name
                break

        # if not found, create it
        if ex_resource_group is None:
            try:
                conn.ex_create_resource_group(resource_group, node_location)
                ex_resource_group = resource_group
                # add delay cause sometimes the group is not yet ready
                time.sleep(5)
            except Exception as exc:
                raise LibcloudError("Couldn't create resource group. \
                    %s" % exc)
        kwargs['ex_resource_group'] = ex_resource_group
        account_type = kwargs.pop('storage_account_type', 'Standard_LRS')
        kwargs['ex_storage_account_type'] = account_type
예제 #29
0
def toggle_cloud(request):
    """
    Tags: clouds
    ---
    Toggles cloud with given cloud id.
    EDIT permission required on cloud.
    ---
    cloud_id:
      in: path
      required: true
      type: string
    new_state:
      enum:
      - '0'
      - '1'
      required: true
      type: string
    """
    auth_context = auth_context_from_request(request)
    cloud_id = request.matchdict['cloud']
    try:
        cloud = Cloud.objects.get(owner=auth_context.owner,
                                  id=cloud_id,
                                  deleted=None)
    except Cloud.DoesNotExist:
        raise NotFoundError('Cloud does not exist')

    auth_context.check_perm('cloud', 'edit', cloud_id)

    new_state = params_from_request(request).get('new_state', None)
    dns_enabled = params_from_request(request).get('dns_enabled', None)

    if new_state == '1':
        cloud.ctl.enable()
    elif new_state == '0':
        cloud.ctl.disable()
    elif new_state:
        raise BadRequestError('Invalid cloud state')

    if dns_enabled == 1:
        cloud.ctl.dns_enable()
    elif dns_enabled == 0:
        cloud.ctl.dns_disable()
    elif dns_enabled:
        raise BadRequestError('Invalid DNS state')

    if new_state is None and dns_enabled is None:
        raise RequiredParameterMissingError('new_state or dns_enabled')

    trigger_session_update(auth_context.owner, ['clouds'])
    return OK
예제 #30
0
def add_cloud_v_2(owner, title, provider, params):
    """Add cloud to owner"""

    # FIXME: Some of these should be explicit arguments, others shouldn't exist
    fail_on_error = params.pop('fail_on_error',
                               params.pop('remove_on_error', True))
    monitoring = params.pop('monitoring', False)
    params.pop('title', None)
    params.pop('provider', None)
    # Find proper Cloud subclass.
    if not provider:
        raise RequiredParameterMissingError("provider")
    log.info("Adding new cloud in provider '%s'", provider)
    if provider not in cloud_models.CLOUDS:
        raise BadRequestError("Invalid provider '%s'." % provider)
    cloud_cls = cloud_models.CLOUDS[provider]  # Class of Cloud model.

    # Add the cloud.
    cloud = cloud_cls.add(owner,
                          title,
                          fail_on_error=fail_on_error,
                          fail_on_invalid_params=False,
                          **params)
    ret = {'cloud_id': cloud.id}
    if provider == 'bare_metal' and monitoring:
        # Let's overload this a bit more by also combining monitoring.
        machine = Machine.objects.get(cloud=cloud)

        ret['monitoring'] = enable_monitoring(
            owner,
            cloud.id,
            machine.machine_id,
            no_ssh=not (machine.os_type == 'unix'
                        and machine.key_associations))

    # SEC
    owner.mapper.update(cloud)

    log.info("Cloud with id '%s' added succesfully.", cloud.id)
    trigger_session_update(owner, ['clouds'])
    c_count = Cloud.objects(owner=owner, deleted=None).count()
    if owner.clouds_count != c_count:
        owner.clouds_count = c_count
        owner.save()

    cloud.polling_interval = 1800  # 30 min * 60 sec/min
    cloud.save()
    ListMachinesPollingSchedule.add(cloud=cloud)

    return ret