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 {}
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 }
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
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()
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 }
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())
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()))
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()))
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())
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()))
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
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()
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
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()
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
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()
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)
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
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
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