def create(self, req, body): context = req.environ['engine.context'] group_id = body['security_group_rule']['parent_group_id'] self.compute_api.ensure_default_security_group(context) security_group = db.security_group_get(context, group_id) if not security_group: raise exception.SecurityGroupNotFound(security_group_id=group_id) msg = "Authorize security group ingress %s" LOG.audit(_(msg), security_group['name'], context=context) values = self._revoke_rule_args_to_dict(context, **body['security_group_rule']) if values is None: raise exception.ApiError( _("Not enough parameters to build a " "valid rule.")) values['parent_group_id'] = security_group.id if self._security_group_rule_exists(security_group, values): raise exception.ApiError( _('This rule already exists in group %s') % group_id) security_group_rule = db.security_group_rule_create(context, values) self.compute_api.trigger_security_group_rules_refresh( context, security_group_id=security_group['id']) return { 'security_group_rule': self._format_security_group_rule(context, security_group_rule) }
def check_attach(self, context, volume_id): volume = self.get(context, volume_id) # TODO(vish): abstract status checking? if volume['status'] != "available": raise exception.ApiError(_("Volume status must be available")) if volume['attach_status'] == "attached": raise exception.ApiError(_("Volume is already attached"))
def _check_storage_parameters(self, context, vsa_name, storage, shared, first_index=0): """ Translates storage array of disks to the list of volumes :param storage: List of dictionaries with following keys: disk_name, num_disks, size :param shared: Specifies if storage is dedicated or shared. For shared storage disks split into partitions """ volume_params = [] for node in storage: name = node.get('drive_name', None) num_disks = node.get('num_drives', 1) if name is None: raise exception.ApiError( _("No drive_name param found in %s") % node) try: vol_type = volume_types.get_volume_type_by_name(context, name) except exception.NotFound: raise exception.ApiError( _("Invalid drive type name %s") % name) self._check_volume_type_correctness(vol_type) # if size field present - override disk size specified in DB size = int( node.get('size', vol_type['extra_specs'].get('drive_size'))) if shared: part_size = FLAGS.vsa_part_size_gb total_capacity = num_disks * size num_volumes = total_capacity / part_size size = part_size else: num_volumes = num_disks size = 0 # special handling for full drives for i in range(num_volumes): volume_name = "drive-%03d" % first_index first_index += 1 volume_desc = 'BE volume for VSA %s type %s' % \ (vsa_name, name) volume = { 'size': size, 'name': volume_name, 'description': volume_desc, 'volume_type_id': vol_type['id'], } volume_params.append(volume) return volume_params
def test_return_valid_error(self): # without 'code' arg err = exception.ApiError('fake error') self.assertEqual(err.__str__(), 'fake error') self.assertEqual(err.code, None) self.assertEqual(err.msg, 'fake error') # with 'code' arg err = exception.ApiError('fake error', 'blah code') self.assertEqual(err.__str__(), 'blah code: fake error') self.assertEqual(err.code, 'blah code') self.assertEqual(err.msg, 'fake error')
def _create_snapshot(self, context, volume_id, name, description, force=False): volume = self.get(context, volume_id) if ((not force) and (volume['status'] != "available")): raise exception.ApiError(_("Volume status must be available")) options = { 'volume_id': volume_id, 'user_id': context.user_id, 'project_id': context.project_id, 'status': "creating", 'progress': '0%', 'volume_size': volume['size'], 'display_name': name, 'display_description': description } snapshot = self.db.snapshot_create(context, options) rpc.cast( context, FLAGS.scheduler_topic, { "method": "create_snapshot", "args": { "topic": FLAGS.volume_topic, "volume_id": volume_id, "snapshot_id": snapshot['id'] } }) return snapshot
def modify_user_role(self, context, user, role, project=None, operation='add', **kwargs): """Add or remove a role for a user and project.""" if operation == 'add': if project: msg = _("Adding role %(role)s to user %(user)s" " for project %(project)s") % locals() LOG.audit(msg, context=context) else: msg = _("Adding sitewide role %(role)s to" " user %(user)s") % locals() LOG.audit(msg, context=context) manager.AuthManager().add_role(user, role, project) elif operation == 'remove': if project: msg = _("Removing role %(role)s from user %(user)s" " for project %(project)s") % locals() LOG.audit(msg, context=context) else: msg = _("Removing sitewide role %(role)s" " from user %(user)s") % locals() LOG.audit(msg, context=context) manager.AuthManager().remove_role(user, role, project) else: raise exception.ApiError(_('operation must be add or remove')) return True
def block_external_addresses(self, context, cidr): """Add provider-level firewall rules to block incoming traffic.""" LOG.audit(_('Blocking traffic to all projects incoming from %s'), cidr, context=context) cidr = urllib.unquote(cidr).decode() # raise if invalid netaddr.IPNetwork(cidr) rule = {'cidr': cidr} tcp_rule = rule.copy() tcp_rule.update({'protocol': 'tcp', 'from_port': 1, 'to_port': 65535}) udp_rule = rule.copy() udp_rule.update({'protocol': 'udp', 'from_port': 1, 'to_port': 65535}) icmp_rule = rule.copy() icmp_rule.update({ 'protocol': 'icmp', 'from_port': -1, 'to_port': None }) rules_added = 0 if not self._provider_fw_rule_exists(context, tcp_rule): db.provider_fw_rule_create(context, tcp_rule) rules_added += 1 if not self._provider_fw_rule_exists(context, udp_rule): db.provider_fw_rule_create(context, udp_rule) rules_added += 1 if not self._provider_fw_rule_exists(context, icmp_rule): db.provider_fw_rule_create(context, icmp_rule) rules_added += 1 if not rules_added: raise exception.ApiError(_('Duplicate rule')) self.compute_api.trigger_provider_fw_rules_refresh(context) return {'status': 'OK', 'message': 'Added %s rules' % rules_added}
def get_instance_type_by_flavor_id(flavorid): """Retrieve instance type by flavorid.""" ctxt = context.get_admin_context() try: return db.instance_type_get_by_flavor_id(ctxt, flavorid) except exception.DBError: raise exception.ApiError(_("Unknown instance type: %s") % flavorid)
def get_default_instance_type(): """Get the default instance type.""" name = FLAGS.default_instance_type try: return get_instance_type_by_name(name) except exception.DBError: raise exception.ApiError(_("Unknown instance type: %s") % name)
def create(self, context, size, snapshot_id, name, description, volume_type=None, metadata=None, availability_zone=None): if snapshot_id is not None: snapshot = self.get_snapshot(context, snapshot_id) if snapshot['status'] != "available": raise exception.ApiError( _("Snapshot status must be available")) if not size: size = snapshot['volume_size'] if quota.allowed_volumes(context, 1, size) < 1: pid = context.project_id LOG.warn( _("Quota exceeded for %(pid)s, tried to create" " %(size)sG volume") % locals()) raise exception.QuotaError( _("Volume quota exceeded. You cannot " "create a volume of size %sG") % size) if availability_zone is None: availability_zone = FLAGS.storage_availability_zone if volume_type is None: volume_type_id = None else: volume_type_id = volume_type.get('id', None) options = { 'size': size, 'user_id': context.user_id, 'project_id': context.project_id, 'snapshot_id': snapshot_id, 'availability_zone': availability_zone, 'status': "creating", 'attach_status': "detached", 'display_name': name, 'display_description': description, 'volume_type_id': volume_type_id, 'metadata': metadata, } volume = self.db.volume_create(context, options) rpc.cast( context, FLAGS.scheduler_topic, { "method": "create_volume", "args": { "topic": FLAGS.volume_topic, "volume_id": volume['id'], "snapshot_id": snapshot_id } }) return volume
def _check_volume_type_correctness(self, vol_type): if vol_type.get('extra_specs') is None or\ vol_type['extra_specs'].get('type') != 'vsa_drive' or\ vol_type['extra_specs'].get('drive_type') is None or\ vol_type['extra_specs'].get('drive_size') is None: raise exception.ApiError( _("Invalid drive type %s") % vol_type['name'])
def get_volume_type_by_name(context, name): """Retrieves single volume type by name.""" if name is None: raise exception.InvalidVolumeType(volume_type=name) try: return db.volume_type_get_by_name(context, name) except exception.DBError: raise exception.ApiError(_("Unknown volume type: %s") % name)
def destroy(context, name): """Marks volume types as deleted.""" if name is None: raise exception.InvalidVolumeType(volume_type=name) else: try: db.volume_type_destroy(context, name) except exception.NotFound: LOG.exception(_('Volume type %s not found for deletion') % name) raise exception.ApiError(_("Unknown volume type: %s") % name)
def create(context, name, extra_specs={}): """Creates volume types.""" try: db.volume_type_create(context, dict(name=name, extra_specs=extra_specs)) except exception.DBError, e: LOG.exception(_('DB error: %s') % e) raise exception.ApiError( _("Cannot create volume_type with " "name %(name)s and specs %(extra_specs)s") % locals())
def purge(context, name): """Removes volume types from database.""" if name is None: raise exception.InvalidVolumeType(volume_type=name) else: try: db.volume_type_purge(context, name) except exception.NotFound: LOG.exception(_('Volume type %s not found for purge') % name) raise exception.ApiError(_("Unknown volume type: %s") % name)
def get_instance_type_by_name(name): """Retrieves single instance type by name.""" if name is None: return get_default_instance_type() ctxt = context.get_admin_context() try: return db.instance_type_get_by_name(ctxt, name) except exception.DBError: raise exception.ApiError(_("Unknown instance type: %s") % name)
def get_instance_type(instance_type_id): """Retrieves single instance type by id.""" if instance_type_id is None: return get_default_instance_type() ctxt = context.get_admin_context() try: return db.instance_type_get(ctxt, instance_type_id) except exception.DBError: msg = _("Unknown instance type: %s") % instance_type_id raise exception.ApiError(msg)
def get_volume_type(ctxt, id): """Retrieves single volume type by id.""" if id is None: raise exception.InvalidVolumeType(volume_type=id) if ctxt is None: ctxt = context.get_admin_context() try: return db.volume_type_get(ctxt, id) except exception.DBError: raise exception.ApiError(_("Unknown volume type: %s") % id)
def delete_snapshot(self, context, snapshot_id): snapshot = self.get_snapshot(context, snapshot_id) if snapshot['status'] != "available": raise exception.ApiError(_("Snapshot status must be available")) self.db.snapshot_update(context, snapshot_id, {'status': 'deleting'}) rpc.cast( context, FLAGS.scheduler_topic, { "method": "delete_snapshot", "args": { "topic": FLAGS.volume_topic, "snapshot_id": snapshot_id } })
def modify_project_member(self, context, user, project, operation, **kwargs): """Add or remove a user from a project.""" if operation == 'add': msg = _("Adding user %(user)s to project %(project)s") % locals() LOG.audit(msg, context=context) manager.AuthManager().add_to_project(user, project) elif operation == 'remove': msg = _("Removing user %(user)s from" " project %(project)s") % locals() LOG.audit(msg, context=context) manager.AuthManager().remove_from_project(user, project) else: raise exception.ApiError(_('operation must be add or remove')) return True
def start_vpn(self, context, project): instance = self._vpn_for(context, project) if not instance: # NOTE(vish) import delayed because of __init__.py from engine.cloudpipe import pipelib pipe = pipelib.CloudPipe() proj = manager.AuthManager().get_project(project) user_id = proj.project_manager_id try: pipe.launch_vpn_instance(project, user_id) except db.NoMoreNetworks: raise exception.ApiError("Unable to claim IP for VPN instance" ", ensure it isn't running, and try " "again in a few minutes") instance = self._vpn_for(context, project) return {'instance_id': ec2utils.id_to_ec2_id(instance['id'])}
def delete(self, context, volume_id): volume = self.get(context, volume_id) if volume['status'] != "available": raise exception.ApiError(_("Volume status must be available")) now = utils.utcnow() self.db.volume_update(context, volume_id, { 'status': 'deleting', 'terminated_at': now }) host = volume['host'] rpc.cast(context, self.db.queue_get_for(context, FLAGS.volume_topic, host), { "method": "delete_volume", "args": { "volume_id": volume_id } })
def create(self, req, body): context = req.environ['engine.context'] self.compute_api.ensure_default_security_group(context) name = body['security_group'].get('name') description = body['security_group'].get('description') if db.security_group_exists(context, context.project_id, name): raise exception.ApiError(_('group %s already exists') % name) group = { 'user_id': context.user_id, 'project_id': context.project_id, 'name': name, 'description': description } group_ref = db.security_group_create(context, group) return { 'security_group': self._format_security_group(context, group_ref) }
def delete(self, req, id): context = req.environ['engine.context'] rule = sqlalchemy_api.security_group_rule_get(context, id) if not rule: raise exception.ApiError(_("Rule not found")) group_id = rule.parent_group_id self.compute_api.ensure_default_security_group(context) security_group = db.security_group_get(context, group_id) if not security_group: raise exception.SecurityGroupNotFound(security_group_id=group_id) msg = "Revoke security group ingress %s" LOG.audit(_(msg), security_group['name'], context=context) db.security_group_rule_destroy(context, rule['id']) self.compute_api.trigger_security_group_rules_refresh( context, security_group_id=security_group['id']) return exc.HTTPAccepted()
def create(self, req, body): """Create a new cloudpipe instance, if none exists. Parameters: {cloudpipe: {project_id: XYZ}} """ ctxt = req.environ['engine.context'] params = body.get('cloudpipe', {}) project_id = params.get('project_id', ctxt.project_id) instance = self._get_cloudpipe_for_project(ctxt, project_id) if not instance: proj = self.auth_manager.get_project(project_id) user_id = proj.project_manager_id try: self.cloudpipe.launch_vpn_instance(project_id, user_id) except db.NoMoreNetworks: msg = _("Unable to claim IP for VPN instances, ensure it " "isn't running, and try again in a few minutes") raise exception.ApiError(msg) instance = self._get_cloudpipe_for_project(ctxt, proj) return {'instance_id': instance['uuid']}
def create(name, memory, vcpus, local_gb, flavorid, swap=0, rxtx_factor=1): """Creates instance types.""" kwargs = { 'memory_mb': memory, 'vcpus': vcpus, 'local_gb': local_gb, 'swap': swap, 'rxtx_factor': rxtx_factor, } # ensure some attributes are integers and greater than or equal to 0 for option in kwargs: try: kwargs[option] = int(kwargs[option]) assert kwargs[option] >= 0 except (ValueError, AssertionError): msg = _("create arguments must be positive integers") raise exception.InvalidInput(reason=msg) # some value are required to be nonzero, not just positive for option in ['memory_mb', 'vcpus']: try: assert kwargs[option] > 0 except AssertionError: msg = _("create arguments must be positive integers") raise exception.InvalidInput(reason=msg) kwargs['name'] = name kwargs['flavorid'] = flavorid try: return db.instance_type_create(context.get_admin_context(), kwargs) except exception.DBError, e: LOG.exception(_('DB error: %s') % e) msg = _("Cannot create instance_type with name %(name)s and " "flavorid %(flavorid)s") % locals() raise exception.ApiError(msg)
def get_diagnostics(self, instance): """Return data about VM diagnostics.""" raise exception.ApiError("get_diagnostics not implemented for " "vmwareapi")
def unpause(self, instance): """Un-Pause a VM instance.""" raise exception.ApiError("unpause not supported for vmwareapi")
def create(self, context, display_name='', display_description='', vc_count=1, instance_type=None, image_name=None, availability_zone=None, storage=[], shared=None): """ Provision VSA instance with corresponding compute instances and associated volumes :param storage: List of dictionaries with following keys: disk_name, num_disks, size :param shared: Specifies if storage is dedicated or shared. For shared storage disks split into partitions """ LOG.info(_("*** Experimental VSA code ***")) if vc_count > FLAGS.max_vcs_in_vsa: LOG.warning(_("Requested number of VCs (%d) is too high."\ " Setting to default"), vc_count) vc_count = FLAGS.max_vcs_in_vsa if instance_type is None: instance_type = self._get_default_vsa_instance_type() if availability_zone is None: availability_zone = FLAGS.storage_availability_zone if storage is None: storage = [] if not shared or shared == 'False': shared = False else: shared = True # check if image is ready before starting any work if image_name is None: image_name = FLAGS.vc_image_name try: image_service = self.compute_api.image_service vc_image = image_service.show_by_name(context, image_name) vc_image_href = vc_image['id'] except exception.ImageNotFound: raise exception.ApiError( _("Failed to find configured image %s") % image_name) options = { 'display_name': display_name, 'display_description': display_description, 'project_id': context.project_id, 'availability_zone': availability_zone, 'instance_type_id': instance_type['id'], 'image_ref': vc_image_href, 'vc_count': vc_count, 'status': VsaState.CREATING, } LOG.info(_("Creating VSA: %s") % options) # create DB entry for VSA instance try: vsa_ref = self.db.vsa_create(context, options) except exception.Error: raise exception.ApiError(_(sys.exc_info()[1])) vsa_id = vsa_ref['id'] vsa_name = vsa_ref['name'] # check storage parameters try: volume_params = self._check_storage_parameters( context, vsa_name, storage, shared) except exception.ApiError: self.db.vsa_destroy(context, vsa_id) raise exception.ApiError( _("Error in storage parameters: %s") % storage) # after creating DB entry, re-check and set some defaults updates = {} if (not hasattr(vsa_ref, 'display_name') or vsa_ref.display_name is None or vsa_ref.display_name == ''): updates['display_name'] = display_name = vsa_name updates['vol_count'] = len(volume_params) vsa_ref = self.update(context, vsa_id, **updates) # create volumes if FLAGS.vsa_multi_vol_creation: if len(volume_params) > 0: request_spec = { 'num_volumes': len(volume_params), 'vsa_id': str(vsa_id), 'volumes': volume_params, } rpc.cast( context, FLAGS.scheduler_topic, { "method": "create_volumes", "args": { "topic": FLAGS.volume_topic, "request_spec": request_spec, "availability_zone": availability_zone } }) else: # create BE volumes one-by-one for vol in volume_params: try: vol_name = vol['name'] vol_size = vol['size'] vol_type_id = vol['volume_type_id'] LOG.debug(_("VSA ID %(vsa_id)d %(vsa_name)s: Create "\ "volume %(vol_name)s, %(vol_size)d GB, "\ "type %(vol_type_id)s"), locals()) vol_type = volume_types.get_volume_type( context, vol['volume_type_id']) vol_ref = self.volume_api.create( context, vol_size, None, vol_name, vol['description'], volume_type=vol_type, metadata=dict(to_vsa_id=str(vsa_id)), availability_zone=availability_zone) except Exception: self.update_vsa_status(context, vsa_id, status=VsaState.PARTIAL) raise if len(volume_params) == 0: # No BE volumes - ask VSA manager to start VCs rpc.cast(context, FLAGS.vsa_topic, { "method": "create_vsa", "args": { "vsa_id": str(vsa_id) } }) return vsa_ref