def action(self, req, body, tenant_id, 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: 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(instance, body) else: raise exception.BadRequest(_("Invalid request body."))
def action(self, req, body, tenant_id, id): LOG.info("req : '%s'\n\n" % req) LOG.info("Committing an ACTION against 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.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, body) else: raise exception.BadRequest(_("Invalid request body."))
def _action_resize(self, instance, body): """ Handles 2 cases 1. resize volume body only contains {volume: {size: x}} 2. resize instance body only contains {flavorRef: http.../2} If the body has both we will throw back an error. """ options = { 'volume': self._action_resize_volume, 'flavorRef': self._action_resize_flavor } selected_option = None args = None for key in options: if key in body['resize']: if selected_option is not None: msg = _("Not allowed to resize volume and flavor at the " "same time.") raise exception.BadRequest(msg) selected_option = options[key] args = body['resize'][key] if selected_option: return selected_option(instance, args) else: raise exception.BadRequest(_("Missing resize arguments."))
def validate(cls, body): """Validate that the request has all the required parameters""" if not body: raise exception.BadRequest("The request contains an empty body") if not body.get('databases', []): raise exception.MissingKey(key='databases') if type(body['databases']) is not list: raise exception.BadRequest("Databases must be provided as a list.") for database in body.get('databases'): if not database.get('name', ''): raise exception.MissingKey(key='name')
def resize_volume(self, new_size): 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: msg = ("The new volume 'size' must be larger than the current " "volume size of '%s'") raise exception.BadRequest(msg % 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 update(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(_("req : '%s'\n\n") % req) context = req.environ[wsgi.CONTEXT_KEY] self.validate(body) 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 _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 exceptions.ValueError as ve: raise exception.BadRequest("Username %s is not valid: %s" % (username, ve.message)) with LocalSqlClient(get_engine()) as client: q = 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("Result: %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 _validate_resize_volume(volume): """ We are going to check that volume resizing data is present. """ if 'size' not in volume: raise exception.BadRequest( "Missing 'size' property of 'volume' in request body.") InstanceController._validate_volume_size(volume['size'])
def validate(cls, body): """Validate that the request has all the required parameters""" if not body: raise exception.BadRequest("The request contains an empty body") if not body.get('databases', ''): raise exception.MissingKey(key='databases') for database in body.get('databases'): if not database.get('name', ''): raise exception.MissingKey(key='name')
def _get_user(self, context, instance_id, user_id): username, hostname = unquote_user_host(user_id) 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=user_id) return user
def validate(cls, body): """Validate that the request has all the required parameters""" if not body: raise exception.BadRequest("The request contains an empty body") if body.get('users') is None: raise exception.MissingKey(key='users') for user in body.get('users'): if not user.get('name'): raise exception.MissingKey(key='name') if not user.get('password'): raise exception.MissingKey(key='password')
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] try: user = guest_models.MySQLUser() user.name = id models.User.delete(context, instance_id, user.serialize()) except ValueError as ve: raise exception.BadRequest(ve.message) return wsgi.Result(None, 202)
def delete(self, req, tenant_id, instance_id, id): LOG.info(_("Deleting schema for instance '%s'") % instance_id) LOG.info(_("req : '%s'\n\n") % req) context = req.environ[wsgi.CONTEXT_KEY] try: schema = guest_models.ValidatedMySQLDatabase() schema.name = id models.Schema.delete(context, instance_id, schema.serialize()) except (ValueError, AttributeError) as e: raise exception.BadRequest(msg=str(e)) 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 '%s'") % instance_id) LOG.info(_("req : '%s'\n\n") % req) LOG.info(_("body : '%s'\n\n") % body) context = req.environ[wsgi.CONTEXT_KEY] self.validate(body) users = body['users'] try: model_users = populate_users(users) models.User.create(context, instance_id, model_users) except (ValueError, AttributeError) as e: raise exception.BadRequest(msg=str(e)) return wsgi.Result(None, 202)
def action(self, req, body, tenant_id, host_id): LOG.info("req : '%s'\n\n" % req) LOG.info("Committing an ACTION against host %s for tenant '%s'" % (host_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 show(self, req, tenant_id, instance_id, id): """Return a single user.""" LOG.info(_("Showing a user for instance '%s'") % instance_id) LOG.info(_("req : '%s'\n\n") % req) context = req.environ[wsgi.CONTEXT_KEY] username, host = unquote_user_host(id) user = None try: user = models.User.load(context, instance_id, username, host) except (ValueError, AttributeError) as e: raise exception.BadRequest(msg=str(e)) if not user: raise exception.UserNotFound(uuid=id) view = views.UserView(user) return wsgi.Result(view.data(), 200)
def populate_databases(dbs): """ Create a serializable request with user provided data for creating new databases. """ try: databases = [] for database in dbs: mydb = guest_models.MySQLDatabase() mydb.name = database.get('name', '') mydb.character_set = database.get('character_set', '') mydb.collate = database.get('collate', '') databases.append(mydb.serialize()) return databases except ValueError as ve: raise exception.BadRequest(str(ve))
def populate_users(users): """Create a serializable request containing users""" try: users_data = [] for user in users: u = guest_models.MySQLUser() u.name = user.get('name', '') u.password = user.get('password', '') dbs = user.get('databases', '') if dbs: for db in dbs: u.databases = db.get('name', '') users_data.append(u.serialize()) return users_data except ValueError as ve: raise exception.BadRequest(ve.message)
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] username, host = unquote_user_host(id) user = None try: user = guest_models.MySQLUser() user.name = username user.host = host found_user = models.User.load(context, instance_id, username, host) except (ValueError, AttributeError) as e: raise exception.BadRequest(msg=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): # TODO(hub-cap): turn this into middleware LOG.info(_("Creating a database instance for tenant '%s'") % tenant_id) LOG.info(_("req : '%s'\n\n") % req) LOG.info(_("body : '%s'\n\n") % body) context = req.environ[wsgi.CONTEXT_KEY] # Set the service type to mysql if its not in the request service_type = (body['instance'].get('service_type') or CONF.service_type) service = models.ServiceImage.find_by(service_name=service_type) image_id = service['image_id'] name = body['instance']['name'] flavor_ref = body['instance']['flavorRef'] flavor_id = utils.get_id_from_href(flavor_ref) databases = populate_validated_databases(body['instance'].get( 'databases', [])) users = None try: users = populate_users(body['instance'].get('users', [])) except ValueError as ve: raise exception.BadRequest(msg=ve) if 'volume' in body['instance']: try: volume_size = int(body['instance']['volume']['size']) except ValueError as e: raise exception.BadValue(msg=e) else: volume_size = None if 'restorePoint' in body['instance']: backupRef = body['instance']['restorePoint']['backupRef'] backup_id = utils.get_id_from_href(backupRef) else: backup_id = None instance = models.Instance.create(context, name, flavor_id, image_id, databases, users, service_type, volume_size, backup_id) view = views.InstanceDetailView(instance, req=req) return wsgi.Result(view.data(), 200)
def populate_validated_databases(dbs): """ Create a serializable request with user provided data for creating new databases. """ try: databases = [] for database in dbs: mydb = guest_models.ValidatedMySQLDatabase() mydb.name = database.get('name', '') mydb.character_set = database.get('character_set', '') mydb.collate = database.get('collate', '') databases.append(mydb.serialize()) return databases except ValueError as ve: # str(ve) contains user input and may include '%' which can cause a # format str vulnerability. Escape the '%' to avoid this. This is # okay to do since we're not using dict args here in any case. safe_string = str(ve).replace('%', '%%') raise exception.BadRequest(safe_string)