def action(self, req, body, tenant_id, host_id): LOG.info( _("Committing an ACTION against host %(host_id)s for " "tenant '%(tenant_id)s'\n" "req : '%(req)s'\n\n"), { "req": req, "host_id": host_id, "tenant_id": tenant_id }) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] host = models.DetailedHost.load(context, host_id) _actions = {'update': self._action_update} selected_action = None for key in body: if key in _actions: if selected_action is not None: msg = _("Only one action can be specified per request.") raise exception.BadRequest(msg) selected_action = _actions[key] else: msg = _("Invalid host action: %s") % key raise exception.BadRequest(msg) if selected_action: return selected_action(context, host, body) else: raise exception.BadRequest(_("Invalid request body."))
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 grant_access(self, username, databases): if self._get_user(username, None).name != username: raise exception.BadRequest( _('Cannot grant access for non-existant user: '******'%(user)s') % {'user': username}) else: user = models.CouchDBUser() user.name = username if not self._is_modifiable_user(user.name): LOG.warning( _('Cannot grant access for reserved user ' '%(user)s') % {'user': username}) if not user: raise exception.BadRequest( _('Cannot grant access for reserved or non-existant user ' '%(user)s') % {'user': username}) for db_name in databases: out, err = utils.execute_with_timeout( system.GRANT_ACCESS_COMMAND % { 'admin_name': self._admin_user().name, 'admin_password': self._admin_user().password, 'dbname': db_name, 'username': username }, shell=True)
def action(self, req, body, tenant_id, id): LOG.info( "Committing an ACTION against a database " "instance %(id)s for tenant '%(tenant_id)s'\n" "req : '%(req)s'\n\n", { "tenant_id": tenant_id, "req": req, "id": id }) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] instance = models.MgmtInstance.load(context=context, id=id) _actions = { 'stop': self._action_stop, 'reboot': self._action_reboot, 'migrate': self._action_migrate, 'reset-task-status': self._action_reset_task_status } selected_action = None for key in body: if key in _actions: if selected_action is not None: msg = _("Only one action can be specified per request.") raise exception.BadRequest(msg) selected_action = _actions[key] else: msg = _("Invalid instance action: %s") % key raise exception.BadRequest(msg) if selected_action: return selected_action(context, instance, req, body) else: raise exception.BadRequest(_("Invalid request body."))
def action(self, req, body, tenant_id, id): LOG.debug(("Committing Action Against Cluster for " "Tenant '%(tenant_id)s'\n" "req : '%(req)s'\n\nid : '%(id)s'\n\n") % { "req": req, "id": id, "tenant_id": tenant_id }) if not body: raise exception.BadRequest(_("Invalid request body.")) if len(body) != 1: raise exception.BadRequest( _("Action request should have exactly" " one action specified in body")) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.Cluster.load(context, id) if ('reset-status' in body and 'force_delete' not in body['reset-status']): self.authorize_cluster_action(context, 'reset-status', cluster) elif ('reset-status' in body and 'force_delete' in body['reset-status']): self.authorize_cluster_action(context, 'force_delete', cluster) else: self.authorize_cluster_action(context, 'action', cluster) cluster.action(context, req, *next(iter(body.items()))) view = views.load_view(cluster, req=req, load_servers=False) wsgi_result = wsgi.Result(view.data(), 202) return wsgi_result
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 action(self, req, body, tenant_id, id): LOG.debug("Committing an action against cluster %(cluster)s for " "tenant '%(tenant)s'." % { 'cluster': id, 'tenant': tenant_id }) LOG.info(_("req : '%s'\n\n") % req) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.MgmtCluster.load(context=context, id=id) _actions = {'reset-task': self._action_reset_task} selected_action = None for key in body: if key in _actions: if selected_action is not None: msg = _("Only one action can be specified per request.") raise exception.BadRequest(msg) selected_action = _actions[key] else: msg = _("Invalid cluster action: %s.") % key raise exception.BadRequest(msg) if selected_action: return selected_action(context, cluster, body) else: raise exception.BadRequest(_("Invalid request body."))
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 _resize_resources(): self.validate_can_perform_action() LOG.info("Resizing volume of instance %s..." % self.id) if not self.volume_size: raise exception.BadRequest(_("Instance %s has no volume.") % self.id) old_size = self.volume_size if int(new_size) <= old_size: raise exception.BadRequest(_("The new volume 'size' must be " "larger than the current volume " "size of '%s'") % old_size) # Set the task to Resizing before sending off to the taskmanager self.update_db(task_status=InstanceTasks.RESIZING) task_api.API(self.context).resize_volume(new_size, self.id)
def action(self, req, body, tenant_id, id): LOG.debug("Committing an action against cluster %(cluster)s for " "tenant '%(tenant)s'." % {'cluster': id, 'tenant': tenant_id}) LOG.info(_("req : '%s'\n\n") % req) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.MgmtCluster.load(context=context, id=id) if 'reset-task' in body: return self._action_reset_task(context, cluster, body) else: msg = _("Invalid cluster action requested.") raise exception.BadRequest(msg)
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 action(self, req, body, tenant_id, id): LOG.debug(("Committing Action Against Cluster for " "Tenant '%(tenant_id)s'\n" "req : '%(req)s'\n\nid : '%(id)s'\n\n") % {"req": req, "id": id, "tenant_id": tenant_id}) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.Cluster.load(context, id) manager = cluster.datastore_version.manager api_strategy = strategy.load_api_strategy(manager) _actions = api_strategy.cluster_controller_actions selected_action = None for key in body: if key in _actions: selected_action = _actions[key] break else: message = _("No action '%(action)s' supplied " "by strategy for manager '%(manager)s'") % ( {'action': key, 'manager': manager}) raise exception.TroveError(message) cluster = selected_action(cluster, body) if cluster: view = views.load_view(cluster, req=req, load_servers=False) wsgi_result = wsgi.Result(view.data(), 202) else: wsgi_result = wsgi.Result(None, 202) return wsgi_result
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 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 upgrade(self, datastore_version): # pylint: disable=no-self-use """Return the source code for the definition.""" LOG.debug("Upgrading cluster %s", datastore_version) if not datastore_version: LOG.error("no datastore_version") return False raise exception.BadRequest("Action 'upgrade' not supported")
def action(self, req, body, tenant_id, id): """ Handles requests that modify existing instances in some manner. Actions could include 'resize', 'restart', 'reset_password' :param req: http request object :param body: deserialized body of the request as a dict :param tenant_id: the tenant id for whom owns the instance :param id: instance id """ LOG.debug("instance action req : '%s'\n\n", req) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] instance = models.Instance.load(context, id) _actions = { 'restart': self._action_restart, 'resize': self._action_resize, 'reset_password': self._action_reset_password, 'promote_to_replica_source': self._action_promote_to_replica_source, 'eject_replica_source': self._action_eject_replica_source, } selected_action = None action_name = None for key in body: if key in _actions: selected_action = _actions[key] action_name = key LOG.info(_LI("Performing %(action_name)s action against " "instance %(instance_id)s for tenant '%(tenant_id)s'"), {'action_name': action_name, 'instance_id': id, 'tenant_id': tenant_id}) return selected_action(context, req, instance, body)
def action(self, req, body, tenant_id, id): LOG.debug("Committing Action Against Cluster for " "Tenant '%s'" % tenant_id) LOG.info(_("req : '%s'\n\n") % req) LOG.info(_("id : '%s'\n\n") % id) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.Cluster.load(context, id) manager = cluster.datastore_version.manager api_strategy = strategy.load_api_strategy(manager) _actions = api_strategy.cluster_controller_actions selected_action = None for key in body: if key in _actions: selected_action = _actions[key] break else: message = _( "No action '%(action)s' supplied " "by strategy for manager '%(manager)s'") % ({ 'action': key, 'manager': manager }) raise exception.TroveError(message) return selected_action(cluster, body)
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 grant_access(self, username, hostname, databases): """Grant a user permission to use a given database.""" user = self._get_user(username, hostname) mydb = None # cache the model as we just want name validation with mysql_util.SqlClient(self.mysql_app.get_engine(), use_flush=True) as client: for database in databases: try: if mydb: mydb.name = database else: mydb = models.MySQLSchema(name=database) mydb.check_reserved() except ValueError: LOG.exception("Error granting access") raise exception.BadRequest( _("Grant access to %s is not allowed") % database) g = sql_query.Grant(permissions='ALL', database=mydb.name, user=user.name, host=user.host, hashed=user.password) t = text(str(g)) client.execute(t)
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 action(self, req, body, tenant_id, id): """ Handles requests that modify existing instances in some manner. Actions could include 'resize', 'restart', 'reset_password' :param req: http request object :param body: deserialized body of the request as a dict :param tenant_id: the tenant id for whom owns the instance :param id: ??? """ LOG.info("req : '%s'\n\n" % req) LOG.info("Comitting an ACTION again instance %s for tenant '%s'" % (id, tenant_id)) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] instance = models.Instance.load(context, id) _actions = { 'restart': self._action_restart, 'resize': self._action_resize, 'reset_password': self._action_reset_password } selected_action = None for key in body: if key in _actions: selected_action = _actions[key] return selected_action(instance, body)
def list_datastore_version_flavor_associations(cls, context, datastore_type, datastore_version_id): if datastore_type and datastore_version_id: """ All nova flavors are permitted for a datastore_version unless one or more entries are found in datastore_version_metadata, in which case only those are permitted. """ (datastore, datastore_version) = get_datastore_version( type=datastore_type, version=datastore_version_id) # If datastore_version_id and flavor key exists in the # metadata table return all the associated flavors for # that datastore version. nova_flavors = create_nova_client(context).flavors.list() bound_flavors = DBDatastoreVersionMetadata.find_all( datastore_version_id=datastore_version.id, key='flavor', deleted=False) if (bound_flavors.count() != 0): bound_flavors = tuple(f.value for f in bound_flavors) # Generate a filtered list of nova flavors ds_nova_flavors = (f for f in nova_flavors if f.id in bound_flavors) associated_flavors = tuple( flavor_model(flavor=item) for item in ds_nova_flavors) else: # Return all nova flavors if no flavor metadata found # for datastore_version. associated_flavors = tuple( flavor_model(flavor=item) for item in nova_flavors) return associated_flavors else: msg = _("Specify both the datastore and datastore_version_id.") raise exception.BadRequest(msg)
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 _get_user(self, username, hostname): """Return a single user matching the criteria.""" user = None try: # Could possibly throw a ValueError here. user = models.MySQLUser(name=username) user.check_reserved() except ValueError as ve: LOG.exception(_("Error Getting user information")) err_msg = encodeutils.exception_to_unicode(ve) raise exception.BadRequest( _("Username %(user)s is not valid" ": %(reason)s") % { 'user': username, 'reason': err_msg }) with self.local_sql_client(self.mysql_app.get_engine()) as client: q = sql_query.Query() q.columns = ['User', 'Host'] q.tables = ['mysql.user'] q.where = [ "Host != 'localhost'", "User = '******'" % username, "Host = '%s'" % hostname ] q.order = ['User', 'Host'] t = text(str(q)) result = client.execute(t).fetchall() LOG.debug("Getting user information %s.", result) if len(result) != 1: return None found_user = result[0] user.host = found_user['Host'] self._associate_dbs(user) return user
def _get_user(self, username, hostname): """Return a single user matching the criteria.""" user = models.MySQLUser() try: user.name = username # Could possibly throw a BadRequest here. except exception.ValueError as ve: LOG.exception(_("Error Getting user information")) raise exception.BadRequest(_("Username %(user)s is not valid" ": %(reason)s") % {'user': username, 'reason': ve.message} ) with LocalSqlClient(get_engine()) as client: q = sql_query.Query() q.columns = ['User', 'Host', 'Password'] q.tables = ['mysql.user'] q.where = ["Host != 'localhost'", "User = '******'" % username, "Host = '%s'" % hostname] q.order = ['User', 'Host'] t = text(str(q)) result = client.execute(t).fetchall() LOG.debug("Getting user information %s." % result) if len(result) != 1: return None found_user = result[0] user.password = found_user['Password'] user.host = found_user['Host'] self._associate_dbs(user) return user
def update_all(self, req, body, tenant_id, instance_id): """Change the password of one or more users.""" LOG.info(_("Updating user passwords for instance '%s'") % instance_id) LOG.info(logging.mask_password(_("req : '%s'\n\n") % req)) context = req.environ[wsgi.CONTEXT_KEY] users = body['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 update(self, req, body, tenant_id, id): LOG.info("req : '%s'\n\n" % req) LOG.info("Updating quota limits for tenant '%s'" % id) if not body: raise exception.BadRequest(_("Invalid request body.")) quotas = {} quota = None registered_resources = quota_engine.resources for resource, limit in body['quotas'].items(): if limit is None: continue if resource == "xmlns": continue if resource not in registered_resources: raise exception.QuotaResourceUnknown(unknown=resource) try: quota = Quota.find_by(tenant_id=id, resource=resource) quota.hard_limit = limit quota.save() except exception.ModelNotFoundError: quota = Quota.create(tenant_id=id, resource=resource, hard_limit=limit) quotas[resource] = quota return wsgi.Result(views.QuotaView(quotas).data(), 200)
def action(self, req, body, tenant_id, id): LOG.debug(("Committing Action Against Cluster for " "Tenant '%(tenant_id)s'\n" "req : '%(req)s'\n\nid : '%(id)s'\n\n") % {"req": req, "id": id, "tenant_id": tenant_id}) if not body: raise exception.BadRequest(_("Invalid request body.")) if len(body) != 1: raise exception.BadRequest(_("Action request should have exactly" " one action specified in body")) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.Cluster.load(context, id) cluster.action(context, req, *body.items()[0]) view = views.load_view(cluster, req=req, load_servers=False) wsgi_result = wsgi.Result(view.data(), 202) return wsgi_result
def _parse_name(value): """The name will be <database>.<username>, so split it.""" parts = value.split('.', 1) if len(parts) != 2: raise exception.BadRequest( _('MongoDB user name "%s" not in <database>.<username> format.' ) % value) return parts[0], parts[1]
def detach_replica(self): self.validate_can_perform_action() LOG.info(_LI("Detaching instance %s from its replication source."), self.id) if not self.slave_of_id: raise exception.BadRequest( _("Instance %s is not a replica.") % self.id) task_api.API(self.context).detach_replica(self.id)