def _modify_instance(self, context, req, instance, **kwargs): if 'detach_replica' in kwargs and kwargs['detach_replica']: LOG.debug("Detaching replica from source.") context.notification = notification.DBaaSInstanceDetach( context, request=req) with StartNotification(context, instance_id=instance.id): instance.detach_replica() if 'configuration_id' in kwargs: if kwargs['configuration_id']: context.notification = ( notification.DBaaSInstanceAttachConfiguration(context, request=req)) configuration_id = kwargs['configuration_id'] with StartNotification(context, instance_id=instance.id, configuration_id=configuration_id): instance.assign_configuration(configuration_id) else: context.notification = ( notification.DBaaSInstanceDetachConfiguration(context, request=req)) with StartNotification(context, instance_id=instance.id): instance.unassign_configuration() if 'datastore_version' in kwargs: datastore_version = datastore_models.DatastoreVersion.load( instance.datastore, kwargs['datastore_version']) context.notification = (notification.DBaaSInstanceUpgrade( context, request=req)) with StartNotification(context, instance_id=instance.id, datastore_version_id=datastore_version.id): instance.upgrade(datastore_version) if kwargs: instance.update_db(**kwargs)
def action(self, context, req, action, param): if action == 'grow': context.notification = DBaaSClusterGrow(context, request=req) with StartNotification(context, cluster_id=self.id): instances = [] for node in param: instance = { 'flavor_id': utils.get_id_from_href(node['flavorRef']) } if 'name' in node: instance['name'] = node['name'] if 'volume' in node: instance['volume_size'] = int(node['volume']['size']) if 'modules' in node: instance['modules'] = node['modules'] if 'nics' in node: instance['nics'] = node['nics'] if 'availability_zone' in node: instance['availability_zone'] = ( node['availability_zone']) instances.append(instance) return self.grow(instances) elif action == 'shrink': context.notification = DBaaSClusterShrink(context, request=req) with StartNotification(context, cluster_id=self.id): instance_ids = [instance['id'] for instance in param] return self.shrink(instance_ids) elif action == "reset-status": context.notification = DBaaSClusterResetStatus(context, request=req) with StartNotification(context, cluster_id=self.id): return self.reset_status() else: raise exception.BadRequest(_("Action %s not supported") % action)
def _modify_instance(self, context, req, instance, **kwargs): """Modifies the instance using the specified keyword arguments 'detach_replica': ignored if not present or False, if True, specifies the instance is a replica that will be detached from its master 'configuration_id': Ignored if not present, if None, detaches an an attached configuration group, if not None, attaches the specified configuration group """ if 'detach_replica' in kwargs and kwargs['detach_replica']: LOG.debug("Detaching replica from source.") context.notification = notification.DBaaSInstanceDetach( context, request=req) with StartNotification(context, instance_id=instance.id): instance.detach_replica() if 'configuration_id' in kwargs: if kwargs['configuration_id']: context.notification = ( notification.DBaaSInstanceAttachConfiguration(context, request=req)) configuration_id = kwargs['configuration_id'] with StartNotification(context, instance_id=instance.id, configuration_id=configuration_id): instance.assign_configuration(configuration_id) else: context.notification = ( notification.DBaaSInstanceDetachConfiguration(context, request=req)) with StartNotification(context, instance_id=instance.id): instance.unassign_configuration() if kwargs: instance.update_db(**kwargs)
def action(self, context, req, action, param): if action == 'grow': context.notification = DBaaSClusterGrow(context, request=req) with StartNotification(context, cluster_id=self.id): return self.grow( [self._parse_grow_item(item) for item in param]) elif action == 'add_shard': context.notification = DBaaSClusterGrow(context, request=req) with StartNotification(context, cluster_id=self.id): return self.add_shard() else: super(MongoDbCluster, self).action(context, req, action, param)
def update(self, req, body, tenant_id, instance_id, id): """Change attributes for one user.""" LOG.info("Updating user attributes for instance '%(id)s'\n" "req : '%(req)s'\n\n", {"id": instance_id, "req": strutils.mask_password(req)}) context = req.environ[wsgi.CONTEXT_KEY] self.authorize_target_action(context, 'user:update', instance_id) id = correct_id_with_req(id, req) username, hostname = unquote_user_host(id) user = None user_attrs = body['user'] context.notification = notification.DBaaSUserUpdateAttributes( context, request=req) with StartNotification(context, instance_id=instance_id, username=username): try: user = models.User.load(context, instance_id, username, hostname) except (ValueError, AttributeError) as e: raise exception.BadRequest(_("Error loading user: %(e)s") % {'e': e}) if not user: raise exception.UserNotFound(uuid=id) try: models.User.update_attributes(context, instance_id, username, hostname, user_attrs) except (ValueError, AttributeError) as e: raise exception.BadRequest(_("User update error: %(e)s") % {'e': e}) return wsgi.Result(None, 202)
def create(self, req, body, tenant_id): LOG.debug(("Creating a Cluster for Tenant '%(tenant_id)s'\n" "req : '%(req)s'\n\nbody : '%(body)s'\n\n") % { "tenant_id": tenant_id, "req": req, "body": body }) context = req.environ[wsgi.CONTEXT_KEY] name = body['cluster']['name'] datastore_args = body['cluster'].get('datastore', {}) datastore, datastore_version = (datastore_models.get_datastore_version( **datastore_args)) # TODO(saurabhs): add extended_properties to apischema extended_properties = body['cluster'].get('extended_properties', {}) try: clusters_enabled = (CONF.get( datastore_version.manager).get('cluster_support')) except NoSuchOptError: clusters_enabled = False if not clusters_enabled: raise exception.ClusterDatastoreNotSupported( datastore=datastore.name, datastore_version=datastore_version.name) nodes = body['cluster']['instances'] instances = [] for node in nodes: flavor_id = utils.get_id_from_href(node['flavorRef']) volume_size = volume_type = nics = availability_zone = None if 'volume' in node: volume_size = int(node['volume']['size']) volume_type = node['volume'].get('volume_type') if 'nics' in node: nics = node['nics'] if 'availability_zone' in node: availability_zone = node['availability_zone'] instances.append({ "flavor_id": flavor_id, "volume_size": volume_size, "volume_type": volume_type, "nics": nics, "availability_zone": availability_zone }) context.notification = notification.DBaaSClusterCreate(context, request=req) with StartNotification(context, name=name, datastore=datastore.name, datastore_version=datastore_version.name): cluster = models.Cluster.create(context, name, datastore, datastore_version, instances, extended_properties) view = views.load_view(cluster, req=req, load_servers=False) return wsgi.Result(view.data(), 200)
def _action_resize_volume(self, context, req, instance, volume): context.notification = notification.DBaaSInstanceResizeVolume( context, request=req) with StartNotification(context, instance_id=instance.id, new_size=volume['size']): instance.resize_volume(volume['size']) return wsgi.Result(None, 202)
def create(self, req, body, tenant_id, instance_id): """Creates a set of users.""" LOG.info( _("Creating users for instance '%(id)s'\n" "req : '%(req)s'\n\n" "body: '%(body)s'\n'n") % { "id": instance_id, "req": strutils.mask_password(req), "body": strutils.mask_password(body) }) context = req.environ[wsgi.CONTEXT_KEY] self.authorize_target_action(context, 'user:create', instance_id) context.notification = notification.DBaaSUserCreate(context, request=req) users = body['users'] with StartNotification(context, instance_id=instance_id, username="******".join( [user['name'] for user in users])): try: model_users = populate_users(users) models.User.create(context, instance_id, model_users) except (ValueError, AttributeError) as e: raise exception.BadRequest( _("User create error: %(e)s") % {'e': e}) return wsgi.Result(None, 202)
def delete(self, req, tenant_id, instance_id, user_id, id): """Revoke access for a user.""" LOG.info( _("Revoking user access for instance '%(id)s'\n" "req : '%(req)s'\n\n") % { "id": instance_id, "req": req }) context = req.environ[wsgi.CONTEXT_KEY] self.authorize_target_action(context, 'user_access:delete', instance_id) context.notification = notification.DBaaSUserRevoke(context, request=req) user_id = correct_id_with_req(user_id, req) user = self._get_user(context, instance_id, user_id) if not user: LOG.error(_("No such user: %(user)s ") % {'user': user}) raise exception.UserNotFound(uuid=user) username, hostname = unquote_user_host(user_id) access = models.User.access(context, instance_id, username, hostname) databases = [db.name for db in access.databases] with StartNotification(context, instance_id=instance_id, username=username, database=databases): if id not in databases: raise exception.DatabaseNotFound(uuid=id) models.User.revoke(context, instance_id, username, hostname, id) return wsgi.Result(None, 202)
def update(self, req, body, tenant_id, id): msg = _("Updating configuration group %(cfg_id)s for tenant " "id %(tenant_id)s") LOG.info(msg % {"tenant_id": tenant_id, "cfg_id": id}) context = req.environ[wsgi.CONTEXT_KEY] group = models.Configuration.load(context, id) # if name/description are provided in the request body, update the # model with these values as well. if 'name' in body['configuration']: group.name = body['configuration']['name'] if 'description' in body['configuration']: group.description = body['configuration']['description'] context.notification = notification.DBaaSConfigurationUpdate( context, request=req) with StartNotification(context, configuration_id=id, name=group.name, description=group.description): items = self._configuration_items_list(group, body['configuration']) deleted_at = datetime.utcnow() models.Configuration.remove_all_items(context, group.id, deleted_at) models.Configuration.save(group, items) self._refresh_on_all_instances(context, id) return wsgi.Result(None, 202)
def test_taskmanager_call(self): with patch.object(self.context, "notification", server_type='taskmanager') as notification: with StartNotification(self.context): pass self.assertTrue(notification.notify_start.called)
def update_all(self, req, body, tenant_id, instance_id): """Change the password of one or more users.""" LOG.info( _("Updating user password for instance '%(id)s'\n" "req : '%(req)s'\n\n") % { "id": instance_id, "req": strutils.mask_password(req) }) context = req.environ[wsgi.CONTEXT_KEY] context.notification = notification.DBaaSUserChangePassword( context, request=req) users = body['users'] with StartNotification(context, instance_id=instance_id, username="******".join( [user['name'] for user in users])): model_users = [] for user in users: try: mu = guest_models.MySQLUser() mu.name = user['name'] mu.host = user.get('host') mu.password = user['password'] found_user = models.User.load(context, instance_id, mu.name, mu.host) if not found_user: user_and_host = mu.name if mu.host: user_and_host += '@' + mu.host raise exception.UserNotFound(uuid=user_and_host) model_users.append(mu) except (ValueError, AttributeError) as e: raise exception.BadRequest(msg=str(e)) models.User.change_password(context, instance_id, model_users) return wsgi.Result(None, 202)
def delete(self, req, tenant_id, instance_id, id): LOG.info(_("Deleting user for instance '%s'") % instance_id) LOG.info(_("req : '%s'\n\n") % req) context = req.environ[wsgi.CONTEXT_KEY] id = correct_id_with_req(id, req) username, host = unquote_user_host(id) context.notification = notification.DBaaSUserDelete(context, request=req) with StartNotification(context, instance_id=instance_id, username=username): user = None try: user = guest_models.MySQLUser() user.name = username user.host = host found_user = models.User.load(context, instance_id, username, host) if not found_user: user = None except (ValueError, AttributeError) as e: raise exception.BadRequest(msg=str(e)) if not user: raise exception.UserNotFound(uuid=id) models.User.delete(context, instance_id, user.serialize()) return wsgi.Result(None, 202)
def update(self, req, body, tenant_id, instance_id, id): """Change attributes for one user.""" LOG.info(_("Updating user attributes for instance '%s'") % instance_id) LOG.info(_("req : '%s'\n\n") % strutils.mask_password(req)) context = req.environ[wsgi.CONTEXT_KEY] id = correct_id_with_req(id, req) username, hostname = unquote_user_host(id) user = None user_attrs = body['user'] context.notification = notification.DBaaSUserUpdateAttributes( context, request=req) with StartNotification(context, instance_id=instance_id, username=username): try: user = models.User.load(context, instance_id, username, hostname) except (ValueError, AttributeError) as e: raise exception.BadRequest(msg=str(e)) if not user: raise exception.UserNotFound(uuid=id) try: models.User.update_attributes(context, instance_id, username, hostname, user_attrs) except (ValueError, AttributeError) as e: raise exception.BadRequest(msg=str(e)) return wsgi.Result(None, 202)
def update(self, req, body, tenant_id, instance_id, user_id): """Grant access for a user to one or more databases.""" LOG.info( _("Granting user access for instance '%(id)s'\n" "req : '%(req)s'\n\n") % { "id": instance_id, "req": req }) context = req.environ[wsgi.CONTEXT_KEY] self.authorize_target_action(context, 'user_access:update', instance_id) context.notification = notification.DBaaSUserGrant(context, request=req) user_id = correct_id_with_req(user_id, req) user = self._get_user(context, instance_id, user_id) if not user: LOG.error(_("No such user: %(user)s ") % {'user': user}) raise exception.UserNotFound(uuid=user) username, hostname = unquote_user_host(user_id) databases = [db['name'] for db in body['databases']] with StartNotification(context, instance_id=instance_id, username=username, database=databases): models.User.grant(context, instance_id, username, hostname, databases) return wsgi.Result(None, 202)
def delete(self, req, tenant_id, instance_id, id): LOG.info("Delete instance '%(id)s'\n" "req : '%(req)s'\n\n", {"id": instance_id, "req": req}) context = req.environ[wsgi.CONTEXT_KEY] self.authorize_target_action(context, 'user:delete', instance_id) id = correct_id_with_req(id, req) username, host = unquote_user_host(id) user = None context.notification = notification.DBaaSUserDelete(context, request=req) with StartNotification(context, instance_id=instance_id, username=username): try: user = guest_models.MySQLUser(name=username, host=host) found_user = models.User.load(context, instance_id, username, host) if not found_user: user = None except (ValueError, AttributeError) as e: raise exception.BadRequest(_("User delete error: %(e)s") % {'e': e}) if not user: raise exception.UserNotFound(uuid=id) models.User.delete(context, instance_id, user.serialize()) return wsgi.Result(None, 202)
def create(self, req, body, tenant_id, instance_id): """Creates a set of schemas.""" LOG.info("Creating schema for instance '%(id)s'\n" "req : '%(req)s'\n\n" "body: '%(body)s'\n'n", {"id": instance_id, "req": req, "body": body}) context = req.environ[wsgi.CONTEXT_KEY] self.authorize_target_action( context, 'database:create', instance_id) schemas = body['databases'] context.notification = notification.DBaaSDatabaseCreate(context, request=req) with StartNotification(context, instance_id=instance_id, dbname=".".join([db['name'] for db in schemas])): try: model_schemas = populate_validated_databases(schemas) models.Schema.create(context, instance_id, model_schemas) except (ValueError, AttributeError) as e: raise exception.BadRequest(_("Database create error: %(e)s") % {'e': e}) return wsgi.Result(None, 202)
def rolling_configuration_update(self, configuration_id, apply_on_all=True): cluster_notification = self.context.notification request_info = cluster_notification.serialize(self.context) self.validate_cluster_available() self.db_info.update(task_status=ClusterTasks.UPDATING_CLUSTER) try: configuration = config_models.Configuration.find( self.context, configuration_id, self.datastore_version.id) instances = [inst_models.Instance.load(self.context, instance.id) for instance in self.instances] LOG.debug("Persisting changes on cluster nodes.") # Allow re-applying the same configuration (e.g. on configuration # updates). for instance in instances: if not (instance.configuration and instance.configuration.id != configuration_id): self.context.notification = ( DBaaSInstanceAttachConfiguration(self.context, **request_info)) with StartNotification(self.context, instance_id=instance.id, configuration_id=configuration_id): with EndNotification(self.context): instance.save_configuration(configuration) else: LOG.debug( "Node '%s' already has the configuration '%s' " "attached." % (instance.id, configuration_id)) # Configuration has been persisted to all instances. # The cluster is in a consistent state with all nodes # requiring restart. # We therefore assign the configuration group ID now. # The configuration can be safely detached at this point. self.update_db(configuration_id=configuration_id) LOG.debug("Applying runtime configuration changes.") if instances[0].apply_configuration(configuration): LOG.debug( "Runtime changes have been applied successfully to the " "first node.") remaining_nodes = instances[1:] if apply_on_all: LOG.debug( "Applying the changes to the remaining nodes.") for instance in remaining_nodes: instance.apply_configuration(configuration) else: LOG.debug( "Releasing restart-required task on the remaining " "nodes.") for instance in remaining_nodes: instance.update_db(task_status=InstanceTasks.NONE) finally: self.update_db(task_status=ClusterTasks.NONE) return self.__class__(self.context, self.db_info, self.ds, self.ds_version)
def delete(self, req, tenant_id, id): """Delete a single instance.""" LOG.info( _LI("Deleting database instance '%(instance_id)s' for tenant " "'%(tenant_id)s'"), { 'instance_id': id, 'tenant_id': tenant_id }) LOG.debug("req : '%s'\n\n", req) context = req.environ[wsgi.CONTEXT_KEY] instance = models.load_any_instance(context, id) context.notification = notification.DBaaSInstanceDelete(context, request=req) with StartNotification(context, instance_id=instance.id): marker = 'foo' while marker: instance_modules, marker = module_models.InstanceModules.load( context, instance_id=id) for instance_module in instance_modules: instance_module = module_models.InstanceModule.load( context, instance_module['instance_id'], instance_module['module_id']) module_models.InstanceModule.delete( context, instance_module) instance.delete() return wsgi.Result(None, 202)
def create(self, req, body, tenant_id): LOG.info("Creating a backup for tenant %s", tenant_id) context = req.environ[wsgi.CONTEXT_KEY] policy.authorize_on_tenant(context, 'backup:create') data = body['backup'] instance = data['instance'] name = data['name'] desc = data.get('description') parent = data.get('parent_id') incremental = data.get('incremental') swift_container = data.get('swift_container') context.notification = notification.DBaaSBackupCreate(context, request=req) if not swift_container: instance_id = utils.get_id_from_href(instance) backup_strategy = BackupStrategy.get(context, instance_id) if backup_strategy: swift_container = backup_strategy.swift_container with StartNotification(context, name=name, instance_id=instance, description=desc, parent_id=parent): backup = Backup.create(context, instance, name, desc, parent_id=parent, incremental=incremental, swift_container=swift_container) return wsgi.Result(views.BackupView(backup).data(), 202)
def _action_restart(self, context, req, instance, body): context.notification = notification.DBaaSInstanceRestart(context, request=req) self.authorize_instance_action(context, 'restart', instance) with StartNotification(context, instance_id=instance.id): instance.restart() return wsgi.Result(None, 202)
def test_conductor_call(self): with patch.object(conductor_api, 'API'): with patch.object(self.context, "notification", server_type='conductor') as notification: with StartNotification(self.context): pass self.assertTrue(notification.notify_start.called)
def _action_eject_replica_source(self, context, req, instance, body): self.authorize_instance_action( context, 'eject_replica_source', instance) context.notification = notification.DBaaSInstancePromote(context, request=req) with StartNotification(context, instance_id=instance.id): instance.eject_replica_source() return wsgi.Result(None, 202)
def _action_resize_flavor(self, context, req, instance, flavorRef): context.notification = notification.DBaaSInstanceResizeInstance( context, request=req) new_flavor_id = utils.get_id_from_href(flavorRef) with StartNotification(context, instance_id=instance.id, new_flavor_id=new_flavor_id): instance.resize_flavor(new_flavor_id) return wsgi.Result(None, 202)
def _action_reboot(self, context, instance, req, body): LOG.debug("Rebooting instance %s.", instance.id) context.notification = notification.DBaaSInstanceReboot(context, request=req) with StartNotification(context, instance_id=instance.id): instance.reboot() return wsgi.Result(None, 202)
def _action_migrate(self, context, instance, req, body): LOG.debug("Migrating instance %s.", instance.id) LOG.debug("body['migrate']= %s", body['migrate']) host = body['migrate'].get('host', None) context.notification = notification.DBaaSInstanceMigrate(context, request=req) with StartNotification(context, host=host): instance.migrate(host) return wsgi.Result(None, 202)
def delete(self, req, tenant_id, id): LOG.info(_('Deleting backup for tenant %(tenant_id)s ' 'ID: %(backup_id)s') % {'tenant_id': tenant_id, 'backup_id': id}) context = req.environ[wsgi.CONTEXT_KEY] context.notification = notification.DBaaSBackupDelete(context, request=req) with StartNotification(context, backup_id=id): Backup.delete(context, id) return wsgi.Result(None, 202)
def _action_reset_status(self, context, req, instance, body): context.notification = notification.DBaaSInstanceResetStatus( context, request=req) with StartNotification(context, instance_id=instance.id): instance.reset_status() LOG.debug("Failing backups for instance %s." % instance.id) backup_model.fail_for_instance(instance.id) return wsgi.Result(None, 202)
def edit(self, req, body, tenant_id, id): context = req.environ[wsgi.CONTEXT_KEY] context.notification = notification.DBaaSConfigurationEdit(context, request=req) with StartNotification(context, configuration_id=id): group = models.Configuration.load(context, id) items = self._configuration_items_list(group, body['configuration']) models.Configuration.save(group, items) self._refresh_on_all_instances(context, id)
def rolling_configuration_remove(self, apply_on_all=True): cluster_notification = self.context.notification request_info = cluster_notification.serialize(self.context) self.validate_cluster_available() self.db_info.update(task_status=ClusterTasks.UPDATING_CLUSTER) try: instances = [inst_models.Instance.load(self.context, instance.id) for instance in self.instances] LOG.debug("Removing changes from cluster nodes.") for instance in instances: if instance.configuration: self.context.notification = ( DBaaSInstanceDetachConfiguration(self.context, **request_info)) with StartNotification(self.context, instance_id=instance.id): with EndNotification(self.context): instance.delete_configuration() else: LOG.debug( "Node '%s' has no configuration attached.", instance.id) # The cluster is in a consistent state with all nodes # requiring restart. # New configuration can be safely attached at this point. configuration_id = self.configuration_id self.update_db(configuration_id=None) LOG.debug("Applying runtime configuration changes.") if instances[0].reset_configuration(configuration_id): LOG.debug( "Runtime changes have been applied successfully to the " "first node.") remaining_nodes = instances[1:] if apply_on_all: LOG.debug( "Applying the changes to the remaining nodes.") for instance in remaining_nodes: instance.reset_configuration(configuration_id) else: LOG.debug( "Releasing restart-required task on the remaining " "nodes.") for instance in remaining_nodes: instance.update_db(task_status=InstanceTasks.NONE) finally: self.update_db(task_status=ClusterTasks.NONE) return self.__class__(self.context, self.db_info, self.ds, self.ds_version)