def get_cluster_by_id(self, context, cluster_id): query = model_query(context, models.Cluster).filter_by(id=cluster_id) try: cluster = query.one() except db_exception.DBError: # Todo(dagnello): User input will be validated from REST API and # not from DB transactions. raise exception.Invalid(_("badly formed cluster_id UUID string")) except sql_exception.NoResultFound: raise exception.NotFound(_("Cluster was not found")) return cluster
def create_broker_metadata(self, context, metadata_values): broker_query = (model_query( context, models.Broker).filter_by(id=metadata_values['broker_id'])) try: # check to see if the broker_id exists broker_query.one() broker_metadata = models.BrokerMetadata() broker_metadata.update(metadata_values) db_session = get_session() broker_metadata.save(db_session) except db_exception.DBError: raise exception.Invalid(_("Badly formed broker_id UUID string")) except sql_exception.NoResultFound: raise exception.NotFound(_("Broker was not found")) return broker_metadata
def _validate_flavor(self, image_id, cluster_flavor): """Checks if flavor satisfies minimum requirement of image metadata. :param image_id: image id of the broker. :param cluster_flavor: flavor id of the cluster. :raises: exception.ConfigurationError :raises: exception.InternalServerError :raises: exception.Invalid """ nova_client = client.nova_client() # get image metadata try: image_metadata = nova_client.images.get(image_id) image_minRam = image_metadata.minRam image_minDisk = image_metadata.minDisk except nova_exc.ClientException as ex: if ex.http_status == 404: raise exception.ConfigurationError( _('Invalid image %s ' 'configured') % image_id) else: raise exception.InternalServerError # get flavor metadata try: flavor_metadata = nova_client.flavors.get(cluster_flavor) flavor_ram = flavor_metadata.ram flavor_disk = flavor_metadata.disk except nova_exc.ClientException as ex: if ex.http_status == 404: raise exception.Invalid( _('Invalid flavor %s provided') % cluster_flavor) else: raise exception.InternalServerError # validate flavor with broker image metadata if (flavor_disk < image_minDisk): raise exception.Invalid( _("Flavor disk is smaller than the " "minimum %s required for broker") % image_minDisk) elif (flavor_ram < image_minRam): raise exception.Invalid( _("Flavor ram is smaller than the " "minimum %s required for broker") % image_minRam)
def delete(self, cluster_id): """Delete this Cluster.""" # validate cluster_id is of type Uuid try: wtypes.UuidType().validate(cluster_id) except ValueError: raise exception.Invalid(_("Invalid cluster ID format provided")) context = pecan.request.context delete_complete_cluster(context, cluster_id)
def check(rule, ctxt, target=None, do_raise=True, exc=exception.NotAuthorized): #creds = ctxt.to_dict() target = target or {} try: result = _ENFORCER.enforce(rule, target, ctxt, do_raise, exc) except Exception: result = False raise else: return result finally: extra = {'policy': {'rule': rule, 'target': target}} if result: LOG.info(_("Policy check succeeded for rule '%(rule)s' " "on target %(target)s") % {'rule': rule, 'target': repr(target)}, extra=extra) else: LOG.info(_("Policy check failed for rule '%(rule)s' " "on target %(target)s") % {'rule': rule, 'target': repr(target)}, extra=extra)
def update_cluster_deleting(self, context, cluster_id): values = {'status': models.Status.DELETING} cluster_query = (model_query(context, models.Cluster).filter_by(id=cluster_id)) try: cluster_query.one() except db_exception.DBError: # Todo(dagnello): User input will be validated from REST API and # not from DB transactions. raise exception.Invalid(_("badly formed cluster_id UUID string")) except sql_exception.NoResultFound: raise exception.NotFound(_("Cluster was not found")) db_session = get_session() with db_session.begin(): cluster_query.update(values) nodes_query = model_query( context, models.Node).filter_by(cluster_id=cluster_id) nodes_query.update(values)
def __init__(self, app, conf, public_api_routes=[]): route_pattern_tpl = '%s(\.json|\.xml)?$' try: self.public_api_routes = [re.compile(route_pattern_tpl % route_tpl) for route_tpl in public_api_routes] except re.error as e: msg = _('Cannot compile public API routes: %s') % e LOG.error(msg) raise exception.ConfigInvalid(error_msg=msg) super(AuthTokenMiddleware, self).__init__(app, conf)
def datetime_or_none(dt): """Validate a datetime or None value.""" if dt is None: return None elif isinstance(dt, datetime.datetime): if dt.utcoffset() is None: # NOTE(danms): Legacy objects from sqlalchemy are stored in UTC, # but are returned without a timezone attached. # As a transitional aid, assume a tz-naive object is in UTC. return dt.replace(tzinfo=iso8601.iso8601.Utc()) else: return dt raise ValueError(_("A datetime.datetime is required here"))
def check(rule, ctxt, target=None, do_raise=True, exc=exception.NotAuthorized): creds = ctxt.to_dict() target = target or {} try: result = _ENFORCER.enforce(rule, target, creds, do_raise, exc) except Exception: result = False raise else: return result finally: extra = {'policy': {'rule': rule, 'target': target}} if result: LOG.info(_("Policy check succeeded for rule '%(rule)s' " "on target %(target)s") % {'rule': rule, 'target': repr(target)}, extra=extra) else: LOG.info(_("Policy check failed for rule '%(rule)s' " "on target %(target)s") % {'rule': rule, 'target': repr(target)}, extra=extra)
def get_one(self, cluster_id): """Return this cluster.""" # validate cluster_id is of type Uuid try: wtypes.UuidType().validate(cluster_id) except ValueError: raise exception.Invalid(_("Invalid cluster ID format provided")) context = pecan.request.context cluster = get_complete_cluster(context, cluster_id) cluster.unset_empty_fields() return cluster
class CueException(Exception): """Base Cue Exception To correctly use this class, inherit from it and define a 'message' property. That message will get printf'd with the keyword arguments provided to the constructor. """ message = _("An unknown exception occurred.") code = 500 headers = {} safe = False def __init__(self, message=None, **kwargs): self.kwargs = kwargs if 'code' not in self.kwargs: try: self.kwargs['code'] = self.code except AttributeError: # pragma: no cover pass if not message: try: message = self.message % kwargs except Exception as e: # kwargs doesn't match a variable in the message # log the issue and the kwargs LOG.exception(_LE('Exception in string format operation')) for name, value in kwargs.items(): LOG.error("%s: %s" % (name, value)) if CONF.fatal_exception_format_errors: raise e else: # at least get the core message out if something happened message = self.message super(CueException, self).__init__(message) def format_message(self): if self.__class__.__name__.endswith('_Remote'): return self.args[0] else: return six.text_type(self)
def replacement_start_response(status, headers, exc_info=None): """Overrides the default response to make errors parsable.""" try: status_code = int(status.split(' ')[0]) state['status_code'] = status_code except (ValueError, TypeError): # pragma: nocover raise Exception(_( 'ErrorDocumentMiddleware received an invalid ' 'status %s') % status) else: if (state['status_code'] // 100) not in (2, 3): # Remove some headers so we can replace them later # when we have the full error message and can # compute the length. headers = [(h, v) for (h, v) in headers if h not in ('Content-Length', 'Content-Type') ] # Save the headers in case we need to modify them. state['headers'] = headers return start_response(status, headers, exc_info)
def replacement_start_response(status, headers, exc_info=None): """Overrides the default response to make errors parsable.""" try: status_code = int(status.split(' ')[0]) state['status_code'] = status_code except (ValueError, TypeError): # pragma: nocover raise Exception(_( 'ErrorDocumentMiddleware received an invalid ' 'status %s') % status) else: if (state['status_code'] // 100) not in (2, 3): # Remove some headers so we can replace them later # when we have the full error message and can # compute the length. headers = [(h, v) for (h, v) in headers if h not in ('Content-Length', 'Content-Type') ] # Save the headers in case we need to modify them. state['headers'] = headers return start_response(status, headers, exc_info)
def get_image_id_by_broker_name(self, context, broker_name): broker_query = model_query( context, models.Broker).filter_by(active=True).filter_by(name=broker_name) try: selected_broker_id = broker_query.one().id # select the recently created image id metadata_query = (model_query( context, models.BrokerMetadata).filter_by(key='IMAGE').filter_by( broker_id=selected_broker_id).order_by( (models.BrokerMetadata.created_at.desc())).limit(1)) selected_image = metadata_query.one() except sql_exception.NoResultFound: raise exception.NotFound(_("Broker was not found")) image_id = selected_image['value'] return image_id
def ssh_connect(connection): """Method to connect to a remote system using ssh protocol. :param connection: a dict of connection parameters. :returns: paramiko.SSHClient -- an active ssh connection. :raises: SSHConnectFailed """ try: ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) key_contents = connection.get('key_contents') if key_contents: data = six.moves.StringIO(key_contents) if "BEGIN RSA PRIVATE" in key_contents: pkey = paramiko.RSAKey.from_private_key(data) elif "BEGIN DSA PRIVATE" in key_contents: pkey = paramiko.DSSKey.from_private_key(data) else: # Can't include the key contents - secure material. raise ValueError(_("Invalid private key")) else: pkey = None ssh.connect(connection.get('host'), username=connection.get('username'), password=connection.get('password'), port=connection.get('port', 22), pkey=pkey, key_filename=connection.get('key_filename'), timeout=connection.get('timeout', 10)) # send TCP keepalive packets every 20 seconds ssh.get_transport().set_keepalive(20) except Exception as e: LOG.debug("SSH connect failed: %s" % e) raise exception.SSHConnectFailed(host=connection.get('host')) return ssh
def add_metadata(self, broker_id, image_id, sec_group): """Add broker metadata - image and sec group for the given broker_id. """ if image_id is not None: metadata_value = { 'key': models.MetadataKey.IMAGE, 'value': image_id, 'broker_id': broker_id } metadata = objects.BrokerMetadata(**metadata_value) metadata.create_broker_metadata(self.context) if sec_group is not None: metadata_value = { 'key': models.MetadataKey.SEC_GROUP, 'value': sec_group, 'broker_id': broker_id } metadata = objects.BrokerMetadata(**metadata_value) metadata.create_broker_metadata(self.context) if image_id is None and sec_group is None: raise exception.Invalid(_("Requires atleast one argument"))
class Conflict(CueException): message = _('Conflict.') code = 409
class RequestEntityTooLarge(CueException): message = _('Request too large for server.') code = 413
class TemporaryFailure(CueException): message = _("Resource temporarily unavailable, please retry.") code = 503
class InvalidState(Conflict): message = _("Invalid resource state.")
class NodeAlreadyExists(Conflict): message = _("A node with UUID %(uuid)s already exists.")
class VmErrorException(CueException): message = _("VM is not in a building state")
class MissingKwargException(exception.CueException): message = _("%s %s") # noqa
class NotFound(CueException): message = _("Not Found") code = 404
class InternalServerError(CueException): message = _("Internal Server Error") code = 500
def test_remote_exception(self): e = Exception_Remote() msg = e.format_message() self.assertEqual(_("Remote Error"), msg)
class Exception_Remote(exception.CueException): message = _("Remote Error")
class OperationNotPermitted(NotAuthorized): message = _("Operation not permitted.")
def post(self, data): """Create a new Cluster. :param data: cluster parameters within the request body. """ context = pecan.request.context request_data = data.as_dict() cluster_flavor = request_data['flavor'] if data.size <= 0: raise exception.Invalid(_("Invalid cluster size provided")) elif data.size > CONF.api.max_cluster_size: raise exception.RequestEntityTooLarge( _("Invalid cluster size, max size is: %d") % CONF.api.max_cluster_size) if len(data.network_id) > 1: raise exception.Invalid(_("Invalid number of network_id's")) # extract username/password if (data.authentication and data.authentication.type and data.authentication.token): auth_validator = auth_validate.AuthTokenValidator.validate_token( auth_type=data.authentication.type, token=data.authentication.token) if not auth_validator or not auth_validator.validate(): raise exception.Invalid( _("Invalid broker authentication " "parameter(s)")) else: raise exception.Invalid( _("Missing broker authentication " "parameter(s)")) default_rabbit_user = data.authentication.token['username'] default_rabbit_pass = data.authentication.token['password'] broker_name = CONF.default_broker_name # get the image id of default broker image_id = objects.BrokerMetadata.get_image_id_by_broker_name( context, broker_name) # validate cluster flavor self._validate_flavor(image_id, cluster_flavor) # convert 'network_id' from list to string type for objects/cluster # compatibility request_data['network_id'] = request_data['network_id'][0] # create new cluster object with required data from user new_cluster = objects.Cluster(**request_data) # create new cluster with node related data from user new_cluster.create(context) # retrieve cluster data cluster = get_complete_cluster(context, new_cluster.id) nodes = objects.Node.get_nodes_by_cluster_id(context, cluster.id) # create list with node id's for create cluster flow node_ids = [node.id for node in nodes] # prepare and post cluster create job to backend flow_kwargs = { 'cluster_id': cluster.id, 'node_ids': node_ids, 'user_network_id': cluster.network_id[0], 'management_network_id': CONF.management_network_id, } # generate unique erlang cookie to be used by all nodes in the new # cluster, erlang cookies are strings of up to 255 characters erlang_cookie = uuidutils.generate_uuid() job_args = { 'tenant_id': new_cluster.project_id, 'flavor': cluster.flavor, 'image': image_id, 'volume_size': cluster.volume_size, 'port': '5672', 'context': context.to_dict(), # TODO(sputnik13: this needs to come from the create request # and default to a configuration value rather than always using # config value 'security_groups': [CONF.os_security_group], 'port': CONF.rabbit_port, 'key_name': CONF.openstack.os_key_name, 'erlang_cookie': erlang_cookie, 'default_rabbit_user': default_rabbit_user, 'default_rabbit_pass': default_rabbit_pass, } job_client = task_flow_client.get_client_instance() # TODO(dagnello): might be better to use request_id for job_uuid job_uuid = uuidutils.generate_uuid() job_client.post(create_cluster, job_args, flow_kwargs=flow_kwargs, tx_uuid=job_uuid) LOG.info( _LI('Create Cluster Request Cluster ID %(cluster_id)s ' 'Cluster size %(size)s network ID %(network_id)s ' 'Job ID %(job_id)s Broker name %(broker_name)s') % ({ "cluster_id": cluster.id, "size": cluster.size, "network_id": cluster.network_id, "job_id": job_uuid, "broker_name": broker_name })) cluster.additional_information = [] cluster.additional_information.append( dict(def_rabbit_user=default_rabbit_user)) cluster.additional_information.append( dict(def_rabbit_pass=default_rabbit_pass)) cluster.unset_empty_fields() return cluster
class VmBuildingException(CueException): message = _("VM is in building state")
class Invalid(CueException): message = _("Unacceptable parameters.") code = 400
class ConfigurationError(CueException): message = _("Configuration Error")
class NotAuthorized(CueException): message = _("Not authorized.") code = 403
def validator(val, objclass=objclass): if val is None or isinstance(val, objclass): return val raise ValueError( _("An object of class %s is required here") % objclass)