Пример #1
0
def set_machine_tags(request):
    """
    Set tags on a machine
    Set tags for a machine, given the cloud and machine id.
    READ permission required on cloud.
    EDIT_TAGS permission required on machine.
    ---
    cloud_id:
      in: path
      required: true
      type: string
    machine_id:
      in: path
      required: true
      type: string
    tags:
      items:
        type: object
      type: array
    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    cloud_id = request.matchdict["cloud_id"]
    machine_id = request.matchdict["machine_id"]
    auth_context.check_perm("cloud", "read", cloud_id)
    try:
        machine = Machine.objects.get(cloud=cloud_id, machine_id=machine_id)
    except me.DoesNotExist:
        raise NotFoundError('Resource with that id does not exist')

    # SEC require EDIT_TAGS permission on machine
    auth_context.check_perm("machine", "edit_tags", machine.id)

    tags = params.get("tags")
    if type(tags) != dict:
        raise BadRequestError('tags should be dictionary of tags')

    if not modify_security_tags(auth_context, tags, machine):
        raise auth_context._raise('machine', 'edit_security_tags')

    # FIXME: This is f***** up! This method is utilized by the Ember UI in
    # order to update a machine's tags by providing the entire list of tags
    # to be re-set. However, `add_tags_to_resource` simply appends the new
    # tags without deleting any.

    old_tags = get_tags_for_resource(auth_context.owner, machine)
    add_tags_to_resource(auth_context.owner, machine, tags.items())

    if config.MACHINE_PATCHES:
        new_tags = get_tags_for_resource(auth_context.owner, machine)

        patch = jsonpatch.JsonPatch.from_diff(old_tags, new_tags).patch
        for item in patch:
            item['path'] = '/%s-%s/tags%s' % (machine.id, machine.machine_id,
                                              item['path'])
        amqp_publish_user(auth_context.owner.id,
                          routing_key='patch_machines',
                          data={'cloud_id': cloud_id,
                                'patch': patch})
    return {}
Пример #2
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
    }
Пример #3
0
def add_script(add_script_request=None):  # noqa: E501
    """Add script

    Add script to user scripts # noqa: E501

    :param add_script_request:
    :type add_script_request: dict | bytes

    :rtype: InlineResponse200
    """
    if connexion.request.is_json:
        add_script_request = AddScriptRequest.from_dict(
            connexion.request.get_json())  # noqa: E501
    params = add_script_request.to_dict()
    try:
        auth_context = connexion.context['token_info']['auth_context']
    except KeyError:
        return 'Authentication failed', 401
    try:
        script_tags, _ = auth_context.check_perm("script", "add", None)
    except PolicyUnauthorizedError:
        return 'You are not authorized to perform this action', 403
    kwargs = {}
    for key in params:
        if key is None:
            kwargs[key] = {}
        else:
            kwargs[key] = params[key]
    name = kwargs.pop('name')
    exec_type = kwargs.pop('exec_type')
    if exec_type == 'executable':
        script_cls = ExecutableScript
    elif exec_type == 'ansible':
        script_cls = AnsibleScript
    else:
        return "Param 'exec_type' must be in ('executable', 'ansible').", 400
    try:
        script = script_cls.add(auth_context.owner, name, **kwargs)
    except BadRequestError as e:
        return str(e), 400
    except ScriptNameExistsError as e:
        return str(e), 409
    # Set ownership.
    script.assign_to(auth_context.user)
    if script_tags:
        add_tags_to_resource(auth_context.owner, script,
                             list(script_tags.items()))
    script = script.as_dict()
    if 'job_id' in params:
        script['job_id'] = params['job_id']
    async_session_update.send(auth_context.owner.id, ['scripts'])
    return script, 200
Пример #4
0
def create_network(create_network_request=None):  # noqa: E501
    """Create network

    Creates one or more networks on the specified cloud. If async is true, a jobId will be returned. READ permission required on cloud. CREATE_RESOURCES permission required on cloud. CREATE permission required on network. # noqa: E501

    :param create_network_request:
    :type create_network_request: dict | bytes

    :rtype: CreateNetworkResponse
    """
    from mist.api.methods import list_resources
    if connexion.request.is_json:
        create_network_request = CreateNetworkRequest.from_dict(connexion.request.get_json())  # noqa: E501
    try:
        auth_context = connexion.context['token_info']['auth_context']
    except KeyError:
        return 'Authentication failed', 401
    params = delete_none(create_network_request.to_dict())
    try:
        tags, _ = auth_context.check_perm("network", "add", None)
    except PolicyUnauthorizedError:
        return 'You are not authorized to perform this action', 403
    try:
        [cloud], total = list_resources(
            auth_context, 'cloud', search=params.pop('cloud'), limit=1)
    except ValueError:
        return 'Cloud does not exist', 404
    try:
        auth_context.check_perm('cloud', 'read', cloud.id)
        auth_context.check_perm('cloud', 'create_resources', cloud.id)
    except PolicyUnauthorizedError:
        return 'You are not authorized to perform this action', 403
    if not hasattr(cloud.ctl, 'network'):
        return 'Network support is not available', 501
    # Create the new network
    network_params = {'name': params['name']}
    if 'extra' in params:
        network_params.update(params['extra'])
    try:
        network = NETWORKS[cloud.ctl.provider].add(
            cloud=cloud, **network_params)
    except BadRequestError as e:
        return str(e), 400
    except NetworkListingError as e:
        return str(e), 503
    network.assign_to(auth_context.user)
    if tags:
        add_tags_to_resource(auth_context.owner, network, tags)
    return network.as_dict()
Пример #5
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, list(key_tags.items()))

    return {
        'id': key.id,
        'name': key.name,
        'machines': [],
        'isDefault': key.default
    }
Пример #6
0
def set_key_tags(request):
    """
    Set tags to owner's key
    EDIT_TAGS permission required on KEY
    ---
    key_id:
      in: path
      required: true
      type: string
    tags:
      type: dict
      required: true
    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    key_id = request.matchdict["key_id"]

    # SEC require EDIT_TAGS permission on key
    auth_context.check_perm("key", "edit_tags", key_id)

    try:
        key = Key.objects.get(owner=auth_context.owner,
                              id=key_id, deleted=None)
    except Key.DoesNotExist:
        raise NotFoundError('Resource with that id does not exist')

    tags = params.get("tags")
    if type(tags) != dict:
        raise BadRequestError('tags should be dictionary of tags')

    if not modify_security_tags(auth_context, tags, key):
        raise auth_context._raise('key', 'edit_security_tags')

    return add_tags_to_resource(auth_context.owner, key, tags.items())
Пример #7
0
def set_cloud_tags(request):
    """
    Tags: tags
    ---
    Set tags to owner's cloud.
    EDIT_TAGS permission required on SCRIPT
    ---
    tags:
      type: dict
      required: true
    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    cloud_id = request.matchdict["cloud_id"]

    # SEC require EDIT_TAGS permission on cloud
    auth_context.check_perm("cloud", "edit_tags", cloud_id)
    try:
        cloud = Cloud.objects.get(owner=auth_context.owner,
                                  id=cloud_id,
                                  deleted=None)
    except me.DoesNotExist:
        raise NotFoundError('Resource with that id does not exist')

    tags = params.get("tags")
    if type(tags) != dict:
        raise BadRequestError('tags should be dictionary of tags')

    if not modify_security_tags(auth_context, tags, cloud):
        raise auth_context._raise('cloud', 'edit_security_tags')

    return add_tags_to_resource(auth_context.owner, cloud, list(tags.items()))
Пример #8
0
def set_script_tags(request):
    """
    Tags: tags
    ---
    Set tags to owner's script.
    EDIT_TAGS permission required on SCRIPT
    ---
    script:
      in: path
      required: true
      type: string
    tags:
      type: dict
      required: true
    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    script_id = request.matchdict["script_id"]

    # SEC require EDIT_TAGS permission on script
    auth_context.check_perm("script", "edit_tags", script_id)

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

    tags = params.get("tags")
    if type(tags) != dict:
        raise BadRequestError('tags should be dictionary of tags')

    if not modify_security_tags(auth_context, tags, script):
        raise auth_context._raise('script', 'edit_security_tags')

    return add_tags_to_resource(auth_context.owner, script, list(tags.items()))
Пример #9
0
def set_machine_tags(request):
    """
    Set tags on a machine
    Set tags for a machine, given the cloud and machine id.
    READ permission required on cloud.
    EDIT_TAGS permission required on machine.
    ---
    cloud_id:
      in: path
      required: true
      type: string
    machine_id:
      in: path
      required: true
      type: string
    tags:
      items:
        type: object
      type: array
    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    cloud_id = request.matchdict["cloud_id"]
    machine_id = request.matchdict["machine_id"]
    auth_context.check_perm("cloud", "read", cloud_id)
    try:
        machine = Machine.objects.get(cloud=cloud_id, machine_id=machine_id)
    except me.DoesNotExist:
        raise NotFoundError('Resource with that id does not exist')

    # SEC require EDIT_TAGS permission on machine
    auth_context.check_perm("machine", "edit_tags", machine.id)

    tags = params.get("tags")
    if type(tags) != dict:
        raise BadRequestError('tags should be dictionary of tags')

    if not modify_security_tags(auth_context, tags, machine):
        raise auth_context._raise('machine', 'edit_security_tags')

    # FIXME: This is f***** up! This method is utilized by the Ember UI in
    # order to update a machine's tags by providing the entire list of tags
    # to be re-set. However, `add_tags_to_resource` simply appends the new
    # tags without deleting any.
    return add_tags_to_resource(auth_context.owner, machine, tags.items())
Пример #10
0
def set_network_tags(request):
    """
    Tags: tags
    ---
    Sets tags for a network, given the cloud and network id.
    READ permission required on cloud.
    EDIT_TAGS permission required on network.
    ---
    cloud_id:
      in: path
      required: true
      type: string
    network_id:
      in: path
      required: true
      type: string
    tags:
      items:
        type: object
      type: array
    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    cloud_id = request.matchdict["cloud_id"]
    network_id = request.matchdict["network_id"]
    auth_context.check_perm('cloud', 'read', cloud_id)
    try:
        network = Network.objects.get(cloud=cloud_id, id=network_id)
    except Network.DoesNotExist:
        raise NotFoundError('Resource with that id does not exist')

    # SEC require EDIT_TAGS permission on network
    auth_context.check_perm("network", "edit_tags", network_id)

    tags = params.get("tags")
    if type(tags) != dict:
        raise BadRequestError('tags should be dictionary of tags')

    if not modify_security_tags(auth_context, tags, network):
        raise auth_context._raise('network', 'edit_security_tags')

    return add_tags_to_resource(auth_context.owner, network,
                                list(tags.items()))
Пример #11
0
def tag_resources(request):
    """
    Tags: tags
    ---
    Batch operation for adding/removing tags from a list of resources.
    This api call provides the ability to modify the tags of a large number
    of resources. For each resource a list of dicts is passed with a key, a
    value and optionally an op field. The op field should be either '+' or '-'
    and defines whether or not the tag should be added or removed from the
    resource. If no op value is defined in the dict then '+' is assumed.
    ---
    tags:
      required: true
      type: array
    resource:
      required: true
      type: object
    """

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

    # FIXME: This implementation is far from OK. We need to re-code the way
    # tags are handled and make sure that RBAC is properly enforced on tags
    for resource in params:
        # list of dicts of key-value pairs
        resource_tags = resource.get('tags', '')
        # dict of resource info
        resource_data = resource.get('resource', '')

        if not resource_data:
            raise RequiredParameterMissingError("resources")
        if not resource_tags:
            raise RequiredParameterMissingError("tags")
        if not resource_data.get('type') or not resource_data.get('item_id'):
            raise BadRequestError('No type or rid provided for some of the '
                                  'resources')

        # ui send this var only for machine. image, network, location
        cloud_id = resource_data.get('cloud_id')

        if cloud_id:
            auth_context.check_perm('cloud', 'read', cloud_id)
        elif resource_data['type'] in [
                'machine', 'image', 'network', 'volume'
        ]:
            raise RequiredParameterMissingError("cloud_id")
        else:
            del resource_data['cloud_id']

        query = {}
        rtype = resource_data['type']
        rid = resource_data['item_id']
        if rtype == 'machine':
            query['machine_id'] = rid
        else:
            query['id'] = rid

        if cloud_id:
            query['cloud'] = cloud_id

        try:
            resource_obj = get_resource_model(rtype).objects.get(**query)
        except me.DoesNotExist:
            # if the resource can not be found just go on and process the next
            continue

        # SEC require EDIT_TAGS permission on resource
        auth_context.check_perm(rtype, 'edit_tags', resource_obj.id)

        # normalized_resources.append(resource_data)
        query['rtype'] = rtype

        # split the tags into two lists: those that will be added and those
        # that will be removed
        tags_to_add = [
            (tag['key'], tag['value']) for tag in
            [tag for tag in resource_tags if tag.get('op', '+') == '+']
        ]
        # also extract the keys from all the tags to be deleted
        tags_to_remove = [
            tag['key'] for tag in
            [tag for tag in resource_tags if tag.get('op', '+') == '-']
        ]

        # SEC only Org Owners may edit the secure tags
        tags = {tag[0]: tag[1] for tag in tags_to_add}
        if not modify_security_tags(auth_context, tags, resource_obj):
            auth_context._raise(rtype, 'edit_security_tags')

        old_tags = get_tags_for_resource(auth_context.owner, resource_obj)
        if tags_to_add:
            add_tags_to_resource(auth_context.owner, resource_obj, tags_to_add)
        if tags_to_remove:
            remove_tags_from_resource(auth_context.owner, resource_obj,
                                      tags_to_remove)

        if rtype in ['machine', 'network', 'volume', 'zone', 'record']:
            new_tags = get_tags_for_resource(auth_context.owner, resource_obj)
            try:
                external_id = getattr(resource_obj, rtype + '_id')
            except AttributeError:
                external_id = getattr(resource_obj, 'external_id')
            patch = jsonpatch.JsonPatch.from_diff(old_tags, new_tags).patch
            for item in patch:
                item['path'] = '/%s-%s/tags%s' % (resource_obj.id, external_id,
                                                  item['path'])
            if amqp_owner_listening(resource_obj.cloud.owner.id):
                amqp_publish_user(auth_context.owner.id,
                                  routing_key='patch_%ss' % rtype,
                                  data={
                                      'cloud_id': resource_obj.cloud.id,
                                      'patch': patch
                                  })
    return OK
Пример #12
0
def create_volume(request):
    """
    Tags: volumes
    ---
    Create a new volume.

    READ permission required on cloud.
    CREATE_RESOURCES permission required on cloud.
    READ permission required on location.
    CREATE_RESOURCES permission required on location.
    ADD permission required on volumes
    ---
    cloud:
      in: path
      required: true
      type: string
    size:
      required: true
      type: integer
      description: Size of disk in Gb
    name:
      required: true
      type: string
      description: Name of the disk
    location:
      required: true
      type: string
    ex_disk_type:
      type: string
      description: GCE-specific. One of 'pd-standard'(default) or 'pd-ssd'
    ex_volume_type:
      type: string
      description: EC2-specific. One of 'standard', 'io1', 'gp2', 'sc1', 'st1'
    ex_iops:
      type: string
      description: EC2-specific. Needs to be specified if volume_type='io1'
    """
    cloud_id = request.matchdict['cloud']
    params = params_from_request(request)
    name = params.get('name')
    size = params.get('size')
    location = params.get('location')

    auth_context = auth_context_from_request(request)
    owner = auth_context.owner

    if not size:
        raise RequiredParameterMissingError('size')

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

    auth_context.check_perm("cloud", "read", cloud_id)
    auth_context.check_perm("cloud", "create_resources", cloud_id)
    auth_context.check_perm("location", "read", location)
    auth_context.check_perm("location", "create_resources", location)
    tags, _ = auth_context.check_perm("volume", "add", None)

    if not name and cloud.ctl.provider != 'equinixmetal':
        raise RequiredParameterMissingError('name')

    if not hasattr(cloud.ctl, 'storage'):
        raise NotImplementedError()

    volume = cloud.ctl.storage.create_volume(**params)
    # ensure logging_view_decorator will log the right volume id
    request.matchdict['volume'] = volume.id

    if tags:
        add_tags_to_resource(auth_context.owner, volume, tags)

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

    trigger_session_update(owner.id, ['volumes'])

    # SEC
    # Update the RBAC & User/Ownership mappings with the new volume and finally
    # trigger a session update by registering it as a chained task.
    if config.HAS_RBAC:
        owner.mapper.update(volume,
                            callback=async_session_update,
                            args=(
                                owner.id,
                                ['volumes'],
                            ))

    return volume.as_dict()
Пример #13
0
def tag_resources(request):
    """
    Batch operation for adding/removing tags from a list of resources.
    This api call provides the ability to modify the tags of a large number
    of resources. For each resource a list of dicts is passed with a key, a
    value and optionally an op field. The op field should be either '+' or '-'
    and defines whether or not the tag should be added or removed from the
    resource. If no op value is defined in the dict then '+' is assumed.
    ---
    tags:
      required: true
      type: list
    resource:
      required: true
      type: dict
    """

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

    # FIXME: This implementation is far from OK. We need to re-code the way
    # tags are handled and make sure that RBAC is properly enforced on tags

    for resource in params:
        # list of dicts of key-value pairs
        resource_tags = resource.get('tags', '')
        # dict of resource info
        resource_data = resource.get('resource', '')

        if not resource_data:
            raise RequiredParameterMissingError("resources")
        if not resource_tags:
            raise RequiredParameterMissingError("tags")
        if not resource_data.get('type') or not resource_data.get('item_id'):
            raise BadRequestError('No type or rid provided for some of the '
                                  'resources')

        # ui send this var only for machine. image, network, location
        cloud_id = resource_data.get('cloud_id')

        if cloud_id:
            auth_context.check_perm('cloud', 'read', cloud_id)
        elif resource_data['type'] in [
                'machine', 'image', 'network', 'location'
        ]:
            raise RequiredParameterMissingError("cloud_id")
        else:
            del resource_data['cloud_id']

        query = {}
        rtype = resource_data['type']
        rid = resource_data['item_id']
        if rtype == 'machine':
            query['machine_id'] = rid
        else:
            query['id'] = rid
            query['deleted'] = None

        if cloud_id:
            query['cloud'] = cloud_id

        try:
            resource_obj = get_resource_model(rtype).objects.get(**query)
        except me.DoesNotExist:
            # if the resource can not be found just go on and process the next
            continue

        # SEC require EDIT_TAGS permission on resource
        auth_context.check_perm(rtype, 'edit_tags', resource_obj.id)

        # normalized_resources.append(resource_data)
        query['rtype'] = rtype

        # split the tags into two lists: those that will be added and those
        # that will be removed
        tags_to_add = [(tag['key'], tag['value']) for tag in filter(
            lambda tag: tag.get('op', '+') == '+', resource_tags)]
        # also extract the keys from all the tags to be deleted
        tags_to_remove = map(
            lambda tag: tag['key'],
            filter(lambda tag: tag.get('op', '+') == '-', resource_tags))

        # SEC only Org Owners may edit the secure tags
        tags = {tag[0]: tag[1] for tag in tags_to_add}
        if not modify_security_tags(auth_context, tags, resource_obj):
            auth_context._raise(rtype, 'edit_security_tags')

        if tags_to_add:
            add_tags_to_resource(auth_context.owner, resource_obj, tags_to_add)
        if tags_to_remove:
            remove_tags_from_resource(auth_context.owner, resource_obj,
                                      tags_to_remove)

    return OK
Пример #14
0
def create_network(request):
    """
    Tags: networks
    ---
    Create a new network

    If subnet parameters are specified, they will be used to create a new
    subnet in the newly created network.

    ADD permission required on network
    ADD permission required on subnet
    READ permission required on cloud
    CREATE_RESOURCES permission required on cloud
    ---
    parameters:
    - name: cloud_id
      in: path
      required: true
      description: The Cloud ID
      schema:
        type: string
    requestBody:
      description: Foo
      required: true
      content:
        'application/json':
          schema:
            type: object
            properties:
              network:
                type: object
              subnet:
                type: object
            required:
            - network
    """
    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')

    if subnet_params and not subnet_params.get('cidr'):
        raise RequiredParameterMissingError('cidr')

    auth_context.check_perm("cloud", "read", cloud_id)
    auth_context.check_perm("cloud", "create_resources", cloud_id)
    tags, _ = auth_context.check_perm("network", "add", None)

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

    # Is network support available?
    if not hasattr(cloud.ctl, 'network'):
        raise NotImplementedError()

    # Create the new network
    network = NETWORKS[cloud.ctl.provider].add(cloud=cloud, **network_params)
    network.assign_to(auth_context.user)

    if tags:
        add_tags_to_resource(auth_context.owner, network, tags)

    # Bundling Subnet creation in this call because it is required for
    # backwards compatibility with the current UI  # FIXME
    if subnet_params:
        try:
            # Create a DB document for the new subnet and call libcloud to
            # declare it on the cloud provider
            SUBNETS[cloud.ctl.provider].add(network=network, **subnet_params)
        except Exception as exc:
            # Cleaning up the network object in case subnet creation fails
            # for any reason
            network.ctl.delete()
            network.delete()
            raise exc

    return network.as_dict()
Пример #15
0
def add_cloud(request):
    """
    Tags: clouds
    ---
    Adds a new cloud and returns the cloud's id.
    ADD permission required on cloud.
    ---
    api_key:
      type: string
      description: Required for Clearcenter
    api_secret:
      type: string
    apikey:
      type: string
      description: Required for Ec2, Hostvirtual, Linode, \
      EquinixMetal, Rackspace, OnApp, SoftLayer, Vultr
    apisecret:
      type: string
      description: Required for Ec2
    apiurl:
      type: string
    auth_password:
      description: Optional for Docker
      type: string
    auth_url:
      type: string
      description: Required for OpenStack
    auth_user:
      description: Optional for Docker
      type: string
    authentication:
      description: Required for Docker
      enum:
      - tls
      - basic
    ca_cert_file:
      type: string
      description: Optional for Docker
    cert_file:
      type: string
      description: Optional for Docker
    certificate:
      type: string
      description: Required for Azure
    compute_endpoint:
      type: string
      description: Optional for OpenStack
    dns_enabled:
      type: boolean
    docker_host:
      description: Required for Docker
    docker_port:
      type: string
    domain:
      type: string
      description: Optional for OpenStack
    host:
      type: string
      description: Required for OnApp, Vcloud, vSphere
    images_location:
      type: string
      description: Required for KVM
    key:
      type: string
      description: Required for Azure_arm
    key_file:
      type: string
      description: Optional for Docker
    machine_hostname:
      type: string
      description: Required for KVM
    machine_key:
      type: string
      description: Id of the key. Required for KVM
    machine_port:
      type: string
    machine_user:
      type: string
      description: Required for KVM
    organization:
      type: string
      description: Required for Vcloud
    password:
      type: string
      description: Required for OpenStack, Vcloud, vSphere
    port:
      type: integer
      description: Required for Vcloud
    private_key:
      type: string
      description: Required for GCE
    project_id:
      type: string
      description: Required for GCE. Optional for EquinixMetal
    provider:
      description: The cloud provider.
      required: True
      enum:
      - vcloud
      - bare_metal
      - docker
      - libvirt
      - openstack
      - vsphere
      - ec2
      - rackspace
      - digitalocean
      - softlayer
      - gce
      - azure
      - azure_arm
      - linode
      - onapp
      - hostvirtual
      - vultr
      - aliyun_ecs
      required: true
      type: string
    region:
      type: string
      description: Required for Ec2, Alibaba, Rackspace. Optional for Openstack
    remove_on_error:
      type: string
    secret:
      type: string
      description: Required for Azure_arm
    show_all:
      type: boolean
      description: Show stopped containers. Required for Docker.
    ssh_port:
      type: integer
      description: Required for KVM
    subscription_id:
      type: string
      description: Required for Azure, Azure_arm
    tenant_id:
      type: string
      description: Required for Azure_arm
    tenant_name:
      type: string
      description: Required for OpenStack
    title:
      description: The human readable title of the cloud.
      type: string
      required: True
    token:
      type: string
      description: Required for Digitalocean
    username:
      type: string
      description: Required for Rackspace, OnApp, \
      SoftLayer, OpenStack, Vcloud, vSphere
    """
    auth_context = auth_context_from_request(request)
    cloud_tags, _ = auth_context.check_perm("cloud", "add", None)
    owner = auth_context.owner
    params = params_from_request(request)
    # remove spaces from start/end of string fields that are often included
    # when pasting keys, preventing thus succesfull connection with the
    # cloud
    for key in list(params.keys()):
        if type(params[key]) in [str, str]:
            params[key] = params[key].rstrip().lstrip()

    # api_version = request.headers.get('Api-Version', 1)
    title = params.get('title', '')
    provider = params.get('provider', '')

    if not provider:
        raise RequiredParameterMissingError('provider')

    monitoring = None
    result = add_cloud_v_2(owner, title, provider, params)
    cloud_id = result['cloud_id']
    monitoring = result.get('monitoring')
    errors = result.get('errors')

    cloud = Cloud.objects.get(owner=owner, id=cloud_id)

    if cloud_tags:
        add_tags_to_resource(owner, cloud, list(cloud_tags.items()))

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

    trigger_session_update(owner.id, ['clouds'])

    # SEC
    # Update the RBAC & User/Ownership mappings with the new Cloud and finally
    # trigger a session update by registering it as a chained task.
    if config.HAS_RBAC:
        owner.mapper.update(cloud,
                            callback=async_session_update,
                            args=(
                                owner.id,
                                ['clouds'],
                            ))

    c_count = Cloud.objects(owner=owner, deleted=None).count()
    ret = cloud.as_dict()
    ret['index'] = c_count - 1
    if errors:
        ret['errors'] = errors
    if monitoring:
        ret['monitoring'] = monitoring

    return ret
Пример #16
0
def create_volume(create_volume_request=None):  # noqa: E501
    """Create volume

    Creates one or more volumes on the specified cloud. If async is true, a jobId will be returned. READ permission required on cloud. CREATE_RESOURCES permission required on cloud. READ permission required on location. CREATE_RESOURCES permission required on location. CREATE permission required on volume. # noqa: E501

    :param create_volume_request:
    :type create_volume_request: dict | bytes

    :rtype: CreateVolumeResponse
    """
    from mist.api.methods import list_resources
    if connexion.request.is_json:
        create_volume_request = CreateVolumeRequest.from_dict(
            connexion.request.get_json())  # noqa: E501
    params = delete_none(create_volume_request.to_dict())
    try:
        auth_context = connexion.context['token_info']['auth_context']
    except KeyError:
        return 'Authentication failed', 401
    try:
        tags, _ = auth_context.check_perm("network", "add", None)
    except PolicyUnauthorizedError:
        return 'You are not authorized to perform this action', 403
    try:
        [cloud], total = list_resources(auth_context,
                                        'cloud',
                                        search=params.pop('cloud'),
                                        limit=1)
    except ValueError:
        return 'Cloud does not exist', 404
    if not hasattr(cloud.ctl, 'storage'):
        return 'Volume support is not available', 501
    try:
        [location], total = list_resources(auth_context,
                                           'location',
                                           search=params.pop('location'),
                                           limit=1)
    except ValueError:
        return 'Location does not exist', 404
    params['location'] = location.id
    try:
        auth_context.check_perm("cloud", "read", cloud.id)
        auth_context.check_perm("cloud", "create_resources", cloud.id)
        auth_context.check_perm("location", "read", location.id)
        auth_context.check_perm("location", "create_resources", location.id)
        tags, _ = auth_context.check_perm("volume", "create", None)
    except PolicyUnauthorizedError:
        return 'You are not authorized to perform this action', 403
    try:
        volume = cloud.ctl.storage.create_volume(**params)
    except (VolumeCreationError, VolumeListingError) as e:
        return str(e), 503
    owner = auth_context.owner
    if tags:
        add_tags_to_resource(owner, volume, tags)
    volume.assign_to(auth_context.user)
    trigger_session_update(owner.id, ['volumes'])
    if config.HAS_RBAC:
        owner.mapper.update(volume,
                            callback=async_session_update,
                            args=(
                                owner.id,
                                ['volumes'],
                            ))
    return volume.as_dict()
Пример #17
0
def add_key(add_key_request=None):  # noqa: E501
    """Add key

    Adds a new key and returns the key's id. ADD permission required on key. # noqa: E501

    :param add_key_request:
    :type add_key_request: dict | bytes

    :rtype: AddKeyResponse
    """
    if connexion.request.is_json:
        add_key_request = AddKeyRequest.from_dict(connexion.request.get_json())  # noqa: E501

    from mist.api.exceptions import BadRequestError, KeyExistsError
    from mist.api.keys.models import SignedSSHKey, SSHKey
    from mist.api.tag.methods import add_tags_to_resource
    try:
        auth_context = connexion.context['token_info']['auth_context']
    except KeyError:
        return 'Authentication failed', 401
    try:
        key_tags, _ = auth_context.check_perm("key", "add", None)
    except PolicyUnauthorizedError:
        return 'You are not authorized to perform this action', 403

    if add_key_request.generate:
        key = SSHKey()
        key.ctl.generate()
        if add_key_request.dry:  # If dry generate requested then we're done
            log_event(
                auth_context.owner.id, 'request', 'generate_key',
                key_id=key.id, user_id=auth_context.user.id,
            )
            return AddKeyResponse(private=key.private, public=key.public)

        add_key_request.private = key.private

    try:
        if add_key_request.certificate:
            key = SignedSSHKey.add(
                auth_context.owner,
                add_key_request.name,
                private=add_key_request.private,
                certificate=add_key_request.certificate
            )
        else:
            key = SSHKey.add(
                auth_context.owner,
                add_key_request.name,
                private=add_key_request.private
            )
    except BadRequestError as exc:
        return exc.args[0], 400
    except KeyExistsError as exc:
        return exc.args[0], 409
    # Set ownership.
    key.assign_to(auth_context.user)

    # Add tags returned by RBAC check
    if key_tags:
        add_tags_to_resource(auth_context.owner, key, list(key_tags.items()))

    log_event(
        auth_context.owner.id, 'request', 'add_key',
        key_id=key.id, user_id=auth_context.user.id,
    )
    return AddKeyResponse(key.id)
Пример #18
0
def add_cloud(request):
    """
    Add a new cloud
    Adds a new cloud to the user and returns the cloud_id
    ADD permission required on cloud.

    ---
    api_key:
      type: string
    api_secret:
      type: string
    apiurl:
      type: string
    docker_port:
      type: string
    machine_key:
      type: string
    machine_port:
      type: string
    machine_user:
      type: string
    provider:
      description: The id of the cloud provider.
      enum:
      - vcloud
      - bare_metal
      - docker
      - libvirt
      - openstack
      - vsphere
      - ec2
      - rackspace
      - nephoscale
      - digitalocean
      - softlayer
      - gce
      - azure
      - azure_arm
      - linode
      - onapp
      - hostvirtual
      - vultr
      required: true
      type: string
    remove_on_error:
      type: string
    tenant_name:
      type: string
    title:
      description: The human readable title of the cloud.
      required: true
      type: string
    """
    auth_context = auth_context_from_request(request)
    cloud_tags = auth_context.check_perm("cloud", "add", None)
    owner = auth_context.owner
    params = params_from_request(request)
    # remove spaces from start/end of string fields that are often included
    # when pasting keys, preventing thus succesfull connection with the
    # cloud
    for key in params.keys():
        if type(params[key]) in [unicode, str]:
            params[key] = params[key].rstrip().lstrip()

    # api_version = request.headers.get('Api-Version', 1)
    title = params.get('title', '')
    provider = params.get('provider', '')

    if not provider:
        raise RequiredParameterMissingError('provider')

    monitoring = None
    ret = add_cloud_v_2(owner, title, provider, params)

    cloud_id = ret['cloud_id']
    monitoring = ret.get('monitoring')

    cloud = Cloud.objects.get(owner=owner, id=cloud_id)

    # If insights enabled on org, set poller with half hour period.
    if auth_context.org.insights_enabled:
        cloud.ctl.set_polling_interval(1800)

    if cloud_tags:
        add_tags_to_resource(owner, cloud, cloud_tags.items())

    c_count = Cloud.objects(owner=owner, deleted=None).count()
    ret = cloud.as_dict()
    ret['index'] = c_count - 1
    if monitoring:
        ret['monitoring'] = monitoring
    return ret
Пример #19
0
def add_script(request):
    """
    Add script to user scripts
    ADD permission required on SCRIPT
    ---
    name:
      type: string
      required: true
    script:
      type: string
      required: false
    script_inline:
      type: string
      required: false
    script_github:
      type: string
      required: false
    script_url:
      type: string
      required: false
    location_type:
      type: string
      required: true
    entrypoint:
      type: string
    exec_type:
      type: string
      required: true
    description:
      type: string
    extra:
      type: dict
    """

    params = params_from_request(request)

    # SEC
    auth_context = auth_context_from_request(request)
    script_tags = auth_context.check_perm("script", "add", None)

    kwargs = {}

    for key in ('name', 'script', 'location_type', 'entrypoint', 'exec_type',
                'description', 'extra', 'script_inline', 'script_url',
                'script_github'):
        kwargs[key] = params.get(key)  # TODO maybe change this

    kwargs['script'] = choose_script_from_params(kwargs['location_type'],
                                                 kwargs['script'],
                                                 kwargs['script_inline'],
                                                 kwargs['script_url'],
                                                 kwargs['script_github'])
    for key in ('script_inline', 'script_url', 'script_github'):
        kwargs.pop(key)

    name = kwargs.pop('name')
    exec_type = kwargs.pop('exec_type')

    if exec_type == 'executable':
        script = ExecutableScript.add(auth_context.owner, name, **kwargs)
    elif exec_type == 'ansible':
        script = AnsibleScript.add(auth_context.owner, name, **kwargs)
    elif exec_type == 'collectd_python_plugin':
        script = CollectdScript.add(auth_context.owner, name, **kwargs)
    else:
        raise BadRequestError(
            "Param 'exec_type' must be in ('executable', 'ansible', "
            "'collectd_python_plugin').")

    if script_tags:
        add_tags_to_resource(auth_context.owner, script, script_tags.items())

    script = script.as_dict()

    if 'job_id' in params:
        script['job_id'] = params['job_id']

    return script
Пример #20
0
def add_cloud(add_cloud_request=None):  # noqa: E501
    """Add cloud

    Adds a new cloud and returns the cloud's id. ADD permission required on cloud. # noqa: E501

    :param add_cloud_request:
    :type add_cloud_request: dict | bytes

    :rtype: InlineResponse200
    """
    if connexion.request.is_json:
        add_cloud_request = AddCloudRequest.from_dict(
            connexion.request.get_json())  # noqa: E501

    from mist.api.clouds.models import Cloud
    from mist.api.clouds.methods import add_cloud_v_2
    from mist.api.helpers import trigger_session_update
    from mist.api.tasks import async_session_update
    from mist.api.tag.methods import add_tags_to_resource
    try:
        auth_context = connexion.context['token_info']['auth_context']
    except KeyError:
        return 'Authentication failed', 401
    try:
        cloud_tags, _ = auth_context.check_perm('cloud', 'add', None)
    except PolicyUnauthorizedError:
        return 'You are not authorized to perform this action', 403
    provider = add_cloud_request.provider
    provider = PROVIDER_ALIASES.get(provider, provider)
    params = add_cloud_request.to_dict()
    name = params.pop('name')
    credentials = params.pop('credentials')
    features = params.pop('features')
    if features:
        del features['compute']
        params.update(features)
    params.update(credentials)
    try:
        result = add_cloud_v_2(auth_context.owner, name, provider, params)
    except CloudExistsError as exc:
        return exc.args[0], 409
    except CloudUnauthorizedError as exc:
        return exc.args[0], 403

    cloud_id = result['cloud_id']
    monitoring = result.get('monitoring')
    errors = result.get('errors')

    cloud = Cloud.objects.get(owner=auth_context.owner, id=cloud_id)

    if cloud_tags:
        add_tags_to_resource(auth_context.owner, cloud,
                             list(cloud_tags.items()))

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

    trigger_session_update(auth_context.owner.id, ['clouds'])

    # SEC
    # Update the RBAC & User/Ownership mappings with the new Cloud and finally
    # trigger a session update by registering it as a chained task.
    if config.HAS_RBAC:
        auth_context.owner.mapper.update(cloud,
                                         callback=async_session_update,
                                         args=(
                                             auth_context.owner.id,
                                             ['clouds'],
                                         ))

    c_count = Cloud.objects(owner=auth_context.owner, deleted=None).count()
    ret = cloud.as_dict_v2()
    ret['index'] = c_count - 1
    if errors:
        ret['errors'] = errors
    if monitoring:
        ret['monitoring'] = monitoring

    return ret