def module_apply(self, req, body, tenant_id, id): """Apply modules to an instance.""" context = req.environ[wsgi.CONTEXT_KEY] instance = models.Instance.load(context, id) if not instance: raise exception.NotFound(uuid=id) self.authorize_instance_action(context, 'module_apply', instance) module_ids = [mod['id'] for mod in body.get('modules', [])] modules = module_models.Modules.load_by_ids(context, module_ids) module_models.Modules.validate(modules, instance.datastore.id, instance.datastore_version.id) module_list = module_views.convert_modules_to_list(modules) client = create_guest_client(context, id) result_list = client.module_apply(module_list) models.Instance.add_instance_modules(context, id, modules) return wsgi.Result({'modules': result_list}, 200)
def __init__(self, flavor=None, context=None, flavor_id=None): if flavor: self.flavor = flavor return if flavor_id and context: try: client = create_nova_client(context) self.flavor = client.flavors.get(flavor_id) except nova_exceptions.NotFound as e: raise exception.NotFound(uuid=flavor_id) except nova_exceptions.ClientException as e: raise exception.TroveError(str(e)) return msg = ("Flavor is not defined, and" " context and flavor_id were not specified.") raise exception.InvalidModelError(errors=msg)
def load_parameter_by_name(cls, datastore_version_id, config_param_name, show_deleted=False): try: if show_deleted: return DBDatastoreConfigurationParameters.find_by( datastore_version_id=datastore_version_id, name=config_param_name) else: return DBDatastoreConfigurationParameters.find_by( datastore_version_id=datastore_version_id, name=config_param_name, deleted=False) except exception.NotFound: raise exception.NotFound(uuid=config_param_name)
def module_list(self, req, tenant_id, id): """Return information about modules on an instance.""" context = req.environ[wsgi.CONTEXT_KEY] instance = models.Instance.load(context, id) if not instance: raise exception.NotFound(uuid=id) from_guest = bool(req.GET.get('from_guest', '').lower()) include_contents = bool(req.GET.get('include_contents', '').lower()) if from_guest: return self._module_list_guest(context, id, include_contents=include_contents) else: return self._module_list(context, id, include_contents=include_contents)
def guest_log_action(self, context, log_name, enable, disable, publish, discard): if enable and disable: raise exception.BadRequest("Cannot enable and disable log '%s'." % log_name) # Enable if we are publishing, unless told to disable if publish and not disable: enable = True LOG.info(_("Processing guest log '%(log)s' " "(enable=%(en)s, disable=%(dis)s, " "publish=%(pub)s, discard=%(disc)s).") % {'log': log_name, 'en': enable, 'dis': disable, 'pub': publish, 'disc': discard}) self.guest_log_context = context gl_cache = self.guest_log_cache if log_name in gl_cache: if ((gl_cache[log_name].type == guest_log.LogType.SYS) and not publish): if enable or disable: if enable: action_text = "enable" else: action_text = "disable" raise exception.BadRequest("Cannot %s a SYSTEM log ('%s')." % (action_text, log_name)) if gl_cache[log_name].type == guest_log.LogType.USER: requires_change = ( (gl_cache[log_name].enabled and disable) or (not gl_cache[log_name].enabled and enable)) if requires_change: restart_required = self.guest_log_enable( context, log_name, disable) if restart_required: self.set_guest_log_status( guest_log.LogStatus.Restart_Required, log_name) gl_cache[log_name].enabled = enable log_details = gl_cache[log_name].show() if discard: log_details = gl_cache[log_name].discard_log() if publish: log_details = gl_cache[log_name].publish_log() LOG.info(_("Details for log '%(log)s': %(det)s") % {'log': log_name, 'det': log_details}) return log_details raise exception.NotFound("Log '%s' is not defined." % log_name)
def module_remove(self, req, tenant_id, id, module_id): """Remove module from an instance.""" context = req.environ[wsgi.CONTEXT_KEY] instance = models.Instance.load(context, id) if not instance: raise exception.NotFound(uuid=id) module = module_models.Module.load(context, module_id) module_info = module_views.DetailedModuleView(module).data() client = create_guest_client(context, id) client.module_remove(module_info) instance_modules = module_models.InstanceModules.load_all( context, instance_id=id, module_id=module_id) for instance_module in instance_modules: module_models.InstanceModule.delete(context, instance_module) LOG.debug("Deleted IM record %s (instance %s, module %s)." % (instance_module.id, id, module_id)) return wsgi.Result(None, 200)
def guest_log_list(self, req, tenant_id, id): """Return all information about all logs for an instance.""" LOG.debug("Listing logs for tenant %s", tenant_id) context = req.environ[wsgi.CONTEXT_KEY] try: backup_model.verify_swift_auth_token(context) except exception.SwiftNotFound: raise exception.LogsNotAvailable() instance = models.Instance.load(context, id) if not instance: raise exception.NotFound(uuid=id) self.authorize_instance_action(context, 'guest_log_list', instance) client = create_guest_client(context, id) guest_log_list = client.guest_log_list() return wsgi.Result({'logs': guest_log_list}, 200)
def guest_log_action(self, req, body, tenant_id, id): """Processes a guest log.""" LOG.info(_("Processing log for tenant %s"), tenant_id) context = req.environ[wsgi.CONTEXT_KEY] instance = models.Instance.load(context, id) if not instance: raise exception.NotFound(uuid=id) log_name = body['name'] enable = body.get('enable', None) disable = body.get('disable', None) publish = body.get('publish', None) discard = body.get('discard', None) if enable and disable: raise exception.BadRequest(_("Cannot enable and disable log.")) client = create_guest_client(context, id) guest_log = client.guest_log_action(log_name, enable, disable, publish, discard) return wsgi.Result({'log': guest_log}, 200)
def remove_module(cls, driver, module_type, module_id, name, datastore, ds_version): datastore = datastore or cls.MODULE_APPLY_TO_ALL ds_version = ds_version or cls.MODULE_APPLY_TO_ALL module_dir = cls.build_module_dir(module_type, module_id) contents_file = cls.build_contents_filename(module_dir) if not operating_system.exists(cls.get_result_filename(module_dir)): raise exception.NotFound( _("Module '%s' has not been applied") % name) try: removed, message = driver.remove(name, datastore, ds_version, contents_file) cls.remove_module_result(module_dir) except Exception: LOG.exception(_("Could not remove module '%s'") % name) raise return removed, message
def guest_log_action(self, context, log_name, enable, disable, publish, discard): if enable and disable: raise exception.BadRequest("Cannot enable and disable log '%s'." % log_name) # Enable if we are publishing, unless told to disable if publish and not disable: enable = True LOG.debug("Processing guest log '%s' " "(enable=%s, disable=%s, publish=%s, discard=%s)." % (log_name, enable, disable, publish, discard)) self.guest_log_context = context gl_cache = self.guest_log_cache response = None if log_name in gl_cache: if ((gl_cache[log_name].type == guest_log.LogType.SYS) and not publish): if enable or disable: if enable: action_text = "enable" else: action_text = "disable" raise exception.BadRequest( "Cannot %s a SYSTEM log ('%s')." % (action_text, log_name)) if gl_cache[log_name].type == guest_log.LogType.USER: requires_change = ((gl_cache[log_name].enabled and disable) or (not gl_cache[log_name].enabled and enable)) if requires_change: restart_required = self.guest_log_enable( context, log_name, disable) if restart_required: self.set_guest_log_status( guest_log.LogStatus.Restart_Required, log_name) gl_cache[log_name].enabled = enable response = gl_cache[log_name].show() if discard: response = gl_cache[log_name].discard_log() if publish: response = gl_cache[log_name].publish_log() else: raise exception.NotFound("Log '%s' is not defined." % log_name) return response
def module_apply(self, req, body, tenant_id, id): """Apply modules to an instance.""" context = req.environ[wsgi.CONTEXT_KEY] instance = models.Instance.load(context, id) if not instance: raise exception.NotFound(uuid=id) module_ids = [mod['id'] for mod in body.get('modules', [])] modules = module_models.Modules.load_by_ids(context, module_ids) module_list = [] for module in modules: module.contents = module_models.Module.deprocess_contents( module.contents) module_info = module_views.DetailedModuleView(module).data( include_contents=True) module_list.append(module_info) client = create_guest_client(context, id) result_list = client.module_apply(module_list) models.Instance.add_instance_modules(context, id, modules) return wsgi.Result({'modules': result_list}, 200)
def does_configuration_need_restart(self): datastore_v = Configuration.load_configuration_datastore_version( self.context, self.configuration_id) config_items = Configuration.load_items(self.context, id=self.configuration_id) LOG.debug("config_items: %s" % config_items) detail_list = DatastoreConfigurationParameters.load_parameters( datastore_v.id, show_deleted=True) for i in config_items: LOG.debug("config item: %s" % i) details = Configuration.find_parameter_details( i.configuration_key, detail_list) LOG.debug("parameter details: %s" % details) if not details: raise exception.NotFound(uuid=i.configuration_key) if bool(details.restart_required): return True return False
def get_db_info(context, id): """ Retrieves an instance of the managed datastore from the persisted storage based on the ID and Context :param context: the context which owns the instance :type context: trove.common.context.TroveContext :param id: the unique ID of the instance :type id: unicode or str :return: a record of the instance as its state exists in persisted storage :rtype: trove.instance.models.DBInstance """ if context is None: raise TypeError("Argument context not defined.") elif id is None: raise TypeError("Argument id not defined.") try: db_info = DBInstance.find_by(context=context, id=id, deleted=False) except exception.NotFound: raise exception.NotFound(uuid=id) return db_info
def assign_configuration(self, configuration_id): self._validate_can_perform_assign() try: configuration = Configuration.load(self.context, configuration_id) except exception.ModelNotFoundError: raise exception.NotFound( message='Configuration group id: %s could not be found.' % configuration_id) config_ds_v = configuration.datastore_version_id inst_ds_v = self.db_info.datastore_version_id if (config_ds_v != inst_ds_v): raise exception.ConfigurationDatastoreNotMatchInstance( config_datastore_version=config_ds_v, instance_datastore_version=inst_ds_v) config = Configuration(self.context, configuration.id) LOG.debug("Config config is %s.", config) self.update_db(configuration_id=configuration.id) self.update_overrides(config)
def __init__(self, volume_type=None, context=None, volume_type_id=None): """ Initialize the volume type either from the volume_type parameter, or by querying cinder using the context provided. """ if volume_type and not (volume_type_id or context): self.volume_type = volume_type elif volume_type_id and context: try: client = create_cinder_client(context) self.volume_type = client.volume_types.get(volume_type_id) except cinder_exception.NotFound: raise trove_exception.NotFound(uuid=volume_type_id) except cinder_exception.ClientException as ce: raise trove_exception.TroveError(str(ce)) return else: raise trove_exception.InvalidModelError( errors="An invalid set of arguments were provided.")
def assign_configuration(self, configuration_id): try: configuration = Configuration.load(self.context, configuration_id) except exception.ModelNotFoundError: raise exception.NotFound( message='Configuration group id: %s could not be found' % configuration_id) config_ds_v = configuration.datastore_version_id inst_ds_v = self.db_info.datastore_version_id if (config_ds_v != inst_ds_v): raise exception.ConfigurationDatastoreNotMatchInstance( config_datastore_version=config_ds_v, instance_datastore_version=inst_ds_v) overrides = Configuration.get_configuration_overrides( self.context, configuration.id) LOG.info(overrides) self.update_overrides(overrides) self.update_db(configuration_id=configuration.id)
def create(self, req, body, tenant_id): LOG.info("Creating a database instance for tenant '%s'", tenant_id) LOG.debug("req : '%s'\n\n", strutils.mask_password(req)) LOG.debug("body : '%s'\n\n", strutils.mask_password(body)) context = req.environ[wsgi.CONTEXT_KEY] policy.authorize_on_tenant(context, 'instance:create') context.notification = notification.DBaaSInstanceCreate(context, request=req) name = body['instance']['name'] slave_of_id = body['instance'].get('replica_of') replica_count = body['instance'].get('replica_count') flavor_ref = body['instance'].get('flavorRef') datastore_args = body['instance'].get('datastore', {}) volume_info = body['instance'].get('volume', {}) availability_zone = body['instance'].get('availability_zone') nics = body['instance'].get('nics', []) locality = body['instance'].get('locality') region_name = body['instance'].get( 'region_name', CONF.service_credentials.region_name) access = body['instance'].get('access', None) if slave_of_id: if flavor_ref: msg = 'Cannot specify flavor when creating replicas.' raise exception.BadRequest(message=msg) if datastore_args: msg = 'Cannot specify datastore when creating replicas.' raise exception.BadRequest(message=msg) if volume_info: msg = 'Cannot specify volume when creating replicas.' raise exception.BadRequest(message=msg) if locality: msg = 'Cannot specify locality when creating replicas.' raise exception.BadRequest(message=msg) backup_model.verify_swift_auth_token(context) else: if replica_count and replica_count > 1: msg = (f"Replica count only valid when creating replicas. " f"Cannot create {replica_count} instances.") raise exception.BadRequest(message=msg) flavor_id = utils.get_id_from_href(flavor_ref) if volume_info: volume_size = int(volume_info.get('size')) volume_type = volume_info.get('type') else: volume_size = None volume_type = None if slave_of_id: try: replica_source = models.DBInstance.find_by(context, id=slave_of_id, deleted=False) flavor_id = replica_source.flavor_id except exception.ModelNotFoundError: LOG.error(f"Cannot create a replica of {slave_of_id} as that " f"instance could not be found.") raise exception.NotFound(uuid=slave_of_id) if replica_source.slave_of_id: raise exception.Forbidden( f"Cannot create a replica of a replica {slave_of_id}") datastore_version = ds_models.DatastoreVersion.load_by_uuid( replica_source.datastore_version_id) datastore = ds_models.Datastore.load( datastore_version.datastore_id) else: datastore, datastore_version = ds_models.get_datastore_version( **datastore_args) # If only image_tags is configured in the datastore version, get # the image ID using the tags. glance_client = clients.create_glance_client(context) image_id = common_glance.get_image_id(glance_client, datastore_version.image_id, datastore_version.image_tags) LOG.info(f'Using image {image_id} for creating instance') databases = populate_validated_databases(body['instance'].get( 'databases', [])) database_names = [database.get('_name', '') for database in databases] users = None try: users = populate_users(body['instance'].get('users', []), database_names) except ValueError as ve: raise exception.BadRequest(message=str(ve)) if slave_of_id and (databases or users): raise exception.ReplicaCreateWithUsersDatabasesError() configuration = self._configuration_parse(context, body) modules = body['instance'].get('modules') # The following operations have their own API calls. # We need to make sure the same policies are enforced when # creating an instance. # i.e. if attaching configuration group to an existing instance is not # allowed, it should not be possible to create a new instance with the # group attached either if configuration: policy.authorize_on_tenant(context, 'instance:update') if modules: policy.authorize_on_tenant(context, 'instance:module_apply') if users: policy.authorize_on_tenant(context, 'instance:extension:user:create') if databases: policy.authorize_on_tenant(context, 'instance:extension:database:create') if 'restorePoint' in body['instance']: backupRef = body['instance']['restorePoint']['backupRef'] backup_id = utils.get_id_from_href(backupRef) else: backup_id = None # Only 1 nic is allowed as defined in API jsonschema. # Use list just for backward compatibility. if len(nics) > 0: nic = nics[0] LOG.info('Checking user provided instance network %s', nic) if slave_of_id and nic.get('ip_address'): msg = "Cannot specify IP address when creating replicas." raise exception.BadRequest(message=msg) self._check_nic(context, nic) if locality: locality_domain = ['affinity', 'anti-affinity'] locality_domain_msg = ("Invalid locality '%s'. " "Must be one of ['%s']" % (locality, "', '".join(locality_domain))) if locality not in locality_domain: raise exception.BadRequest(message=locality_domain_msg) instance = models.Instance.create(context, name, flavor_id, image_id, databases, users, datastore, datastore_version, volume_size, backup_id, availability_zone, nics, configuration, slave_of_id, replica_count=replica_count, volume_type=volume_type, modules=modules, locality=locality, region_name=region_name, access=access) view = views.InstanceDetailView(instance, req=req) return wsgi.Result(view.data(), 200)
def create(cls, context, name, flavor_id, image_id, databases, users, datastore, datastore_version, volume_size, backup_id, availability_zone=None, nics=None, configuration_id=None, slave_of_id=None, cluster_config=None): datastore_cfg = CONF.get(datastore_version.manager) client = create_nova_client(context) try: flavor = client.flavors.get(flavor_id) except nova_exceptions.NotFound: raise exception.FlavorNotFound(uuid=flavor_id) deltas = {'instances': 1} volume_support = datastore_cfg.volume_support if volume_support: validate_volume_size(volume_size) deltas['volumes'] = volume_size # Instance volume should have enough space for the backup # Backup, and volume sizes are in GBs target_size = volume_size else: target_size = flavor.disk # local_storage if volume_size is not None: raise exception.VolumeNotSupported() if datastore_cfg.device_path: if flavor.ephemeral == 0: raise exception.LocalStorageNotSpecified(flavor=flavor_id) target_size = flavor.ephemeral # ephemeral_Storage if backup_id is not None: backup_info = Backup.get_by_id(context, backup_id) if backup_info.is_running: raise exception.BackupNotCompleteError(backup_id=backup_id) if backup_info.size > target_size: raise exception.BackupTooLarge(backup_size=backup_info.size, disk_size=target_size) if not backup_info.check_swift_object_exist( context, verify_checksum=CONF.verify_swift_checksum_on_restore): raise exception.BackupFileNotFound( location=backup_info.location) if (backup_info.datastore_version_id and backup_info.datastore.name != datastore.name): raise exception.BackupDatastoreMismatchError( datastore1=backup_info.datastore.name, datastore2=datastore.name) if slave_of_id: replication_support = datastore_cfg.replication_strategy if not replication_support: raise exception.ReplicationNotSupported( datastore=datastore.name) try: # looking for replica source replica_source = DBInstance.find_by(context, id=slave_of_id, deleted=False) if replica_source.slave_of_id: raise exception.Forbidden( _("Cannot create a replica of a replica %(id)s.") % {'id': slave_of_id}) except exception.ModelNotFoundError: LOG.exception( _("Cannot create a replica of %(id)s " "as that instance could not be found.") % {'id': slave_of_id}) raise exception.NotFound(uuid=slave_of_id) if not nics: nics = [] if CONF.default_neutron_networks: nics = [{ "net-id": net_id } for net_id in CONF.default_neutron_networks] + nics def _create_resources(): if cluster_config: cluster_id = cluster_config.get("id", None) shard_id = cluster_config.get("shard_id", None) instance_type = cluster_config.get("instance_type", None) else: cluster_id = shard_id = instance_type = None db_info = DBInstance.create( name=name, flavor_id=flavor_id, tenant_id=context.tenant, volume_size=volume_size, datastore_version_id=datastore_version.id, task_status=InstanceTasks.BUILDING, configuration_id=configuration_id, slave_of_id=slave_of_id, cluster_id=cluster_id, shard_id=shard_id, type=instance_type) LOG.debug("Tenant %(tenant)s created new Trove instance %(db)s.", { 'tenant': context.tenant, 'db': db_info.id }) # if a configuration group is associated with an instance, # generate an overrides dict to pass into the instance creation # method config = Configuration(context, configuration_id) overrides = config.get_configuration_overrides() service_status = InstanceServiceStatus.create( instance_id=db_info.id, status=tr_instance.ServiceStatuses.NEW) if CONF.trove_dns_support: dns_client = create_dns_client(context) hostname = dns_client.determine_hostname(db_info.id) db_info.hostname = hostname db_info.save() root_password = None if cls.get_root_on_create( datastore_version.manager) and not backup_id: root_password = utils.generate_random_password() task_api.API(context).create_instance( db_info.id, name, flavor, image_id, databases, users, datastore_version.manager, datastore_version.packages, volume_size, backup_id, availability_zone, root_password, nics, overrides, slave_of_id, cluster_config) return SimpleInstance(context, db_info, service_status, root_password) return run_with_quotas(context.tenant, deltas, _create_resources)
def load_parameter(cls, config_id): try: return DBDatastoreConfigurationParameters.find_by(id=config_id, deleted=False) except exception.NotFound: raise exception.NotFound(uuid=config_id)
def load(context, name): client = create_nova_client(context) try: return DetailedHost(client.rdhosts.get(name)) except nova_exceptions.NotFound: raise exception.NotFound(uuid=name)
def _validate_flavor_id(self, id): try: if int(id) != float(id): raise exception.NotFound(uuid=id) except ValueError: raise exception.NotFound(uuid=id)
def _create_resources(): # parse the ID from the Ref instance_id = utils.get_id_from_href(instance) # verify that the instance exists and can perform actions from trove.instance.models import Instance instance_model = Instance.load(context, instance_id) instance_model.validate_can_perform_action() cls.validate_can_perform_action(instance_model, 'backup_create') cls.verify_swift_auth_token(context) if instance_model.cluster_id is not None: raise exception.ClusterInstanceOperationNotSupported() ds = instance_model.datastore ds_version = instance_model.datastore_version parent = None parent_backup = None parent_backup_id = None if parent_id: # Look up the parent info or fail early if not found or if # the user does not have access to the parent. if parent_id == 'last': # Need to assign parent_id to a new variable # parent_backup_id, otherwise an unbound variable error # will be thrown parent_backup = Backup.get_last_completed( context, instance_id, True) if parent_backup is None: raise exception.NotFound() parent_backup_id = parent_backup.id else: parent_backup_id = parent_id _parent = cls.get_by_id(context, parent_backup_id) parent = { 'id': parent_backup_id, 'location': _parent.location, 'checksum': _parent.checksum, } try: db_info = DBBackup.create(name=name, description=description, tenant_id=context.tenant, state=BackupState.NEW, instance_id=instance_id, parent_id=parent_backup_id, datastore_version_id=ds_version.id, deleted=False) except exception.InvalidModelError as ex: LOG.exception( _("Unable to create backup record for " "instance: %s"), instance_id) raise exception.BackupCreationError(str(ex)) backup_info = { 'id': db_info.id, 'name': name, 'description': description, 'instance_id': instance_id, 'backup_type': db_info.backup_type, 'checksum': db_info.checksum, 'parent': parent, 'datastore': ds.name, 'datastore_version': ds_version.name, } api.API(context).create_backup(backup_info, instance_id) return db_info