def list_storage_classes(request): """ Tags: volumes --- List the volumes of a cloud. READ permission required on cloud. READ permission required on location. --- cloud: in: path required: true type: string """ auth_context = auth_context_from_request(request) cloud_id = request.matchdict.get('cloud') try: cloud = Cloud.objects.get(owner=auth_context.owner, id=cloud_id, deleted=None) except Cloud.DoesNotExist: raise CloudNotFoundError() if cloud.as_dict()['provider'] != 'kubevirt': raise BadRequestError('Only available for KubeVirt clouds') # SEC auth_context.check_perm('cloud', 'read', cloud_id) storage_classes = cloud.ctl.storage.list_storage_classes() return storage_classes
def list_vnfs(request): """ Tags: networks --- List the virtual network functions of a cloud (KVM only) READ permission required on cloud --- cloud: in: path required: true type: string """ cloud_id = request.matchdict['cloud'] auth_context = auth_context_from_request(request) # SEC auth_context.check_perm('cloud', 'read', cloud_id) try: cloud = Cloud.objects.get(owner=auth_context.owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() try: return cloud.ctl.network.list_vnfs() except (AttributeError, NotImplementedError): raise MistNotImplementedError
def delete_dns_zone(request): """ Tags: dns --- Deletes a specific DNS zone under a cloud. REMOVE permission required on zone. --- cloud: in: path required: true type: string zone: in: path required: true type: string """ auth_context = auth_context_from_request(request) cloud_id = request.matchdict['cloud'] zone_id = request.matchdict['zone'] try: cloud = Cloud.objects.get(owner=auth_context.owner, id=cloud_id) except me.DoesNotExist: raise CloudNotFoundError() try: zone = Zone.objects.get(owner=auth_context.owner, id=zone_id, cloud=cloud) except Zone.DoesNotExist: raise NotFoundError('Zone does not exist') auth_context.check_perm("zone", "remove", zone_id) zone.ctl.delete_zone() return OK
def list_networks(owner, cloud_id): """List the networks of the specified cloud""" ret = {'public': [], 'private': [], 'routers': []} # FIXME try: cloud = Cloud.objects.get(owner=owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() if not hasattr(cloud.ctl, 'network'): return ret networks = cloud.ctl.network.list_networks() for network in networks: network_dict = network.as_dict() if hasattr(network, 'location'): network_dict['location'] = network.location network_dict['subnets'] = [ subnet.as_dict() for subnet in network.ctl.list_subnets() ] # TODO: Backwards-compatible network privacy detection, to be replaced if not network_dict.get('router_external'): ret['private'].append(network_dict) else: ret['public'].append(network_dict) return ret
def list_images(owner, cloud_id, term=None): """List the images of the specified cloud""" try: cloud = Cloud.objects.get(owner=owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() images = cloud.ctl.compute.list_images(search=term) return [image.as_dict() for image in images]
def create_dns_record(request): """ Tags: dns --- Creates a new record under a specific zone. CREATE_RESOURCES permission required on cloud. CREATE_RECORDS permission required on zone --- cloud: in: path required: true type: string zone: in: path 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) except me.DoesNotExist: raise CloudNotFoundError() zone_id = request.matchdict['zone'] try: zone = Zone.objects.get(owner=auth_context.owner, id=zone_id, cloud=cloud) except Zone.DoesNotExist: raise NotFoundError('Zone does not exist') auth_context.check_perm("cloud", "read", cloud_id) auth_context.check_perm("zone", "read", zone_id) auth_context.check_perm("zone", "create_records", zone_id) tags = auth_context.check_perm("record", "add", None) params = params_from_request(request) dns_cls = RECORDS[params['type']] rec = dns_cls.add(owner=auth_context.owner, zone=zone, **params) rec.assign_to(auth_context.user) if tags: resolve_id_and_set_tags(auth_context.owner, 'record', rec.id, tags, cloud_id=cloud_id, zone_id=zone_id) trigger_session_update(auth_context.owner, ['zones']) return rec.as_dict()
def list_locations(owner, cloud_id, cached=False): """List the locations of the specified cloud""" try: cloud = Cloud.objects.get(owner=owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() if cached: locations = cloud.ctl.compute.list_cached_locations() else: locations = cloud.ctl.compute.list_locations() return [location.as_dict() for location in locations]
def delete_subnet(request): """ Tags: networks --- Delete a subnet READ permission required on cloud READ permission required on network READ permission required on subnet REMOVE permission required on subnet --- cloud_id: in: path required: true type: string network_id: in: path required: true type: string subnet_id: in: path required: true type: string """ cloud_id = request.matchdict['cloud'] subnet_id = request.matchdict['subnet'] network_id = request.matchdict['network'] auth_context = auth_context_from_request(request) # SEC auth_context.check_perm('cloud', 'read', cloud_id) auth_context.check_perm('network', 'read', network_id) auth_context.check_perm('network', 'edit_subnets', network_id) try: cloud = Cloud.objects.get(id=cloud_id, owner=auth_context.owner) except Cloud.DoesNotExist: raise CloudNotFoundError() try: network = Network.objects.get(id=network_id, cloud=cloud) except Network.DoesNotExist: raise NetworkNotFoundError() try: subnet = Subnet.objects.get(id=subnet_id, network=network) subnet.ctl.delete() except Subnet.DoesNotExist: raise SubnetNotFoundError() # Trigger a UI update. trigger_session_update(auth_context.owner, ['clouds']) return OK
def create_subnet(request): """ Tags: networks --- Create subnet in a given network on a cloud ADD permission required on subnet READ permission required on cloud READ permission required on network CREATE_SUBNETS permission required on network CREATE_RESOURCES permission required on cloud --- cloud_id: in: path required: true description: The Cloud ID type: string network_id: in: path required: true description: The ID of the Network that will contain the new subnet type: string subnet: required: true type: object """ cloud_id = request.matchdict['cloud'] network_id = request.matchdict['network'] params = params_from_request(request) auth_context = auth_context_from_request(request) # SEC auth_context.check_perm('cloud', 'read', cloud_id) auth_context.check_perm('cloud', 'create_resources', cloud_id) auth_context.check_perm('network', 'read', network_id) auth_context.check_perm('network', 'edit_subnets', network_id) try: cloud = Cloud.objects.get(id=cloud_id, owner=auth_context.owner) except Cloud.DoesNotExist: raise CloudNotFoundError() try: network = Network.objects.get(id=network_id, cloud=cloud) except Network.DoesNotExist: raise NetworkNotFoundError() # Create subnet. subnet = SUBNETS[cloud.ctl.provider].add(network=network, **params) return subnet.as_dict()
def list_volumes(owner, cloud_id, cached=False): """List the volumes of the specified cloud""" try: cloud = Cloud.objects.get(owner=owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() if not hasattr(cloud.ctl, 'storage'): return [] if cached: volumes = cloud.ctl.storage.list_cached_volumes() else: volumes = cloud.ctl.storage.list_volumes() return [v.as_dict() for v in volumes]
def delete_network(request): """ Tags: networks --- Delete a network and all corresponding subnets READ permission required on cloud READ permission required on network REMOVE permission required on network --- parameters: - name: cloud_id in: path required: true schema: type: string - name: network_id in: path required: true schema: type: string """ cloud_id = request.matchdict['cloud'] network_id = request.matchdict['network'] auth_context = auth_context_from_request(request) # SEC auth_context.check_perm('cloud', 'read', cloud_id) auth_context.check_perm('network', 'read', network_id) auth_context.check_perm('network', 'remove', network_id) try: cloud = Cloud.objects.get(id=cloud_id, owner=auth_context.owner) except Cloud.DoesNotExist: raise CloudNotFoundError() try: network = Network.objects.get(id=network_id, cloud=cloud) except me.DoesNotExist: raise NetworkNotFoundError() # Delete the network network.ctl.delete() # Schedule a UI update trigger_session_update(auth_context.owner, ['clouds']) return OK
def list_networks(owner, cloud_id, cached=False): """List the networks of the specified cloud""" try: cloud = Cloud.objects.get(owner=owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() if not hasattr(cloud.ctl, 'network'): return [] if cached: networks = cloud.ctl.network.list_cached_networks() else: networks = cloud.ctl.network.list_networks() return [n.as_dict() for n in networks]
def list_zones(owner, cloud_id, cached=False): """List the zones of the specified cloud""" try: cloud = Cloud.objects.get(owner=owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() if not hasattr(cloud.ctl, 'dns') or not cloud.dns_enabled: return [] if cached: zones = cloud.ctl.dns.list_cached_zones() else: zones = cloud.ctl.dns.list_zones() return [z.as_dict() for z in zones]
def star_image(owner, cloud_id, image_id): """Toggle image star (star/unstar)""" try: Cloud.objects.get(owner=owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() from mist.api.images.models import CloudImage try: image = CloudImage.objects.get(cloud=cloud_id, id=image_id) except CloudImage.DoesNotExist: raise NotFoundError('CloudImage does not exist') image.starred = False if image.starred else True image.save() trigger_session_update(owner, ['images']) return image.as_dict()
def list_networks(request): """ Tags: networks --- List the networks of a cloud READ permission required on cloud, networks, and subnets --- parameters: - name: cloud in: path required: true schema: type: string """ auth_context = auth_context_from_request(request) cloud_id = request.matchdict.get('cloud') params = params_from_request(request) if cloud_id: cached = bool(params.get('cached', False)) try: Cloud.objects.get(owner=auth_context.owner, id=cloud_id, deleted=None) except Cloud.DoesNotExist: raise CloudNotFoundError() # SEC auth_context.check_perm('cloud', 'read', cloud_id) networks = filter_list_networks(auth_context, cloud_id, cached=cached) else: cached = bool(params.get('cached', True)) # return cached by default auth_context.check_perm("cloud", "read", None) clouds = filter_list_clouds(auth_context) networks = [] for cloud in clouds: if cloud.get('enabled'): try: networks += filter_list_networks(auth_context, cloud.get('id'), cached=cached) except (CloudUnavailableError, CloudUnauthorizedError): pass return networks
def delete_dns_record(request): """ Tags: dns --- Deletes a specific DNS record under a zone. REMOVE permission required on zone. --- cloud: in: path required: true type: string zone: in: path required: true type: string record: in: path required: true type: string """ auth_context = auth_context_from_request(request) cloud_id = request.matchdict['cloud'] zone_id = request.matchdict['zone'] record_id = request.matchdict['record'] try: cloud = Cloud.objects.get(owner=auth_context.owner, id=cloud_id) except me.DoesNotExist: raise CloudNotFoundError() try: zone = Zone.objects.get(owner=auth_context.owner, id=zone_id, cloud=cloud) except Zone.DoesNotExist: raise NotFoundError('Zone does not exist') try: record = Record.objects.get(zone=zone, id=record_id) except Record.DoesNotExist: raise NotFoundError('Record does not exist') auth_context.check_perm("record", "remove", record_id) record.ctl.delete_record() trigger_session_update(auth_context.owner, ['zones']) return OK
def list_volumes(request): """ Tags: volumes --- List the volumes of a cloud. READ permission required on cloud. READ permission required on location. --- cloud: in: path required: true type: string """ auth_context = auth_context_from_request(request) params = params_from_request(request) cloud_id = request.matchdict.get('cloud') if cloud_id: cached = bool(params.get('cached', False)) try: Cloud.objects.get(owner=auth_context.owner, id=cloud_id, deleted=None) except Cloud.DoesNotExist: raise CloudNotFoundError() # SEC auth_context.check_perm('cloud', 'read', cloud_id) volumes = filter_list_volumes(auth_context, cloud_id, cached=cached) else: auth_context.check_perm("cloud", "read", None) clouds = filter_list_clouds(auth_context) volumes = [] for cloud in clouds: if cloud.get('enabled'): try: vols = filter_list_volumes(auth_context, cloud.get('id')) volumes += vols except (CloudUnavailableError, CloudUnauthorizedError): pass return volumes
def list_subnets(request): """ Tags: networks --- List the subnets of a network READ permission required on cloud READ permission required on network READ permission required on subnets --- cloud: in: path required: true type: string network_id: in: path required: true description: The DB ID of the network whose subnets will be returned type: string """ cloud_id = request.matchdict['cloud'] network_id = request.matchdict['network'] auth_context = auth_context_from_request(request) # SEC auth_context.check_perm('cloud', 'read', cloud_id) auth_context.check_perm('network', 'read', network_id) try: cloud = Cloud.objects.get(owner=auth_context.owner, id=cloud_id) except Cloud.DoesNotExist: raise CloudNotFoundError() try: network = Network.objects.get(cloud=cloud, id=network_id) except Network.DoesNotExist: raise NetworkNotFoundError() return [subnet.as_dict() for subnet in network.ctl.list_subnets()]
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 volume_action(request): """ Tags: volumes --- Attach or detach a volume to/from a machine. READ permission required on cloud. READ permission required on volume. ATTACH or DETACH permission required on volume. --- cloud: in: path required: true type: string volume: in: path required: true type: string machine: in: query required: true type: string device: in: query type: string description: eg /dev/sdh. Required for EC2, optional for OpenStack """ auth_context = auth_context_from_request(request) params = params_from_request(request) action = params.pop('action', '') machine_uuid = params.pop('machine', '') if action not in ('attach', 'detach'): raise BadRequestError() if not machine_uuid: raise RequiredParameterMissingError('machine') cloud_id = request.matchdict.get('cloud') external_id = request.matchdict.get('volume_ext') if external_id: external_id = '/'.join(external_id) volume_id = request.matchdict.get('volume_id') if cloud_id: try: cloud = Cloud.objects.get(id=cloud_id, owner=auth_context.owner, deleted=None) except Cloud.DoesNotExist: raise CloudNotFoundError() if cloud.ctl.provider in ['azure_arm']: external_id = '/' + external_id try: volume = Volume.objects.get(external_id=external_id, cloud=cloud, missing_since=None) # ensure logging_view_decorator will log the right thing request.matchdict['volume'] = volume.id except me.DoesNotExist: raise VolumeNotFoundError() else: try: volume = Volume.objects.get(id=volume_id, missing_since=None) except me.DoesNotExist: raise VolumeNotFoundError() cloud = volume.cloud try: machine = Machine.objects.get(id=machine_uuid, missing_since=None) except Machine.DoesNotExist: raise MachineNotFoundError() auth_context.check_perm("cloud", "read", cloud.id) auth_context.check_perm("volume", "read", volume.id) auth_context.check_perm("volume", action, volume.id) if not hasattr(cloud.ctl, 'storage'): raise NotImplementedError() getattr(volume.ctl, action)(machine, **params) return OK
def delete_volume(request): """ Tags: volumes --- Delete a volume. READ permission required on cloud. READ permission required on volume. REMOVE permission required on volume. --- parameters: - name: cloud in: path required: true schema: type: string - name: volume in: path required: true schema: type: string """ cloud_id = request.matchdict.get('cloud') external_id = request.matchdict.get('volume_ext') if external_id: external_id = '/'.join(external_id) volume_id = request.matchdict.get('volume_id') auth_context = auth_context_from_request(request) if cloud_id: try: cloud = Cloud.objects.get(id=cloud_id, owner=auth_context.owner, deleted=None) except Cloud.DoesNotExist: raise CloudNotFoundError() if cloud.ctl.provider in ['azure_arm']: external_id = '/' + external_id try: volume = Volume.objects.get(external_id=external_id, cloud=cloud, missing_since=None) # ensure logging_view_decorator will log the right volume id request.matchdict['volume'] = volume.id except me.DoesNotExist: raise VolumeNotFoundError() else: try: volume = Volume.objects.get(id=volume_id, missing_since=None) except me.DoesNotExist: raise VolumeNotFoundError() cloud = volume.cloud # SEC auth_context.check_perm('cloud', 'read', cloud.id) auth_context.check_perm('volume', 'read', volume.id) auth_context.check_perm('volume', 'remove', volume.id) volume.ctl.delete() 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()