def post(self, data): """Create a new assembly.""" policy.check('create_assembly', pecan.request.security_context) host_url = pecan.request.application_url.rstrip('/') js_data = data.as_dict(objects.registry.Assembly) if data.plan_uri is not wsme.Unset: plan_uri = data.plan_uri if plan_uri.startswith(host_url): pl_uuid = plan_uri.split('/')[-1] pl = objects.registry.Plan.get_by_uuid( pecan.request.security_context, pl_uuid) js_data['plan_id'] = pl.id else: # TODO(asalkeld) we are not hosting the plan so # download the plan and insert it into our db. raise exception.BadRequest(reason=_( 'The plan was not hosted in solum')) if js_data.get('plan_id') is None: raise exception.BadRequest(reason=_( 'The plan was not given or could not be found')) handler = assembly_handler.AssemblyHandler( pecan.request.security_context) return assembly.Assembly.from_db_model( handler.create(js_data), host_url)
def post(self, data): """Create a new pipeline.""" policy.check('create_pipeline', pecan.request) js_data = data.as_dict(objects.registry.Pipeline) host_url = pecan.request.application_url.rstrip('/') if data.plan_uri is not wsme.Unset: plan_uri = data.plan_uri if plan_uri.startswith(host_url): pl_uuid = plan_uri.split('/')[-1] pl = objects.registry.Plan.get_by_uuid( pecan.request.security_context, pl_uuid) js_data['plan_id'] = pl.id else: # TODO(asalkeld) we are not hosting the plan so # download the plan and insert it into our db. raise exception.BadRequest(reason=_( 'The plan was not hosted in solum')) if js_data.get('plan_id') is None: raise exception.BadRequest(reason=_( 'The plan was not given or could not be found')) handler = pipeline_handler.PipelineHandler( pecan.request.security_context) return pipeline.Pipeline.from_db_model( handler.create(js_data), host_url)
def get(url, max_size, chunk_size=None, allowed_schemes=('http', 'https')): """Get the data at the specified URL. The URL must use the http: or https: schemes. The file: scheme is also supported if you override the allowed_schemes argument. The max_size represents the total max byte of your file. The chunk_size is by default set at max_size, it represents the size of your chunk. Raise an IOError if getting the data fails. Raise an IOError if max_size is less than 1. Raise an IOError if chunk_size is less than 1. """ LOG.info(_('Fetching data from %s') % url) components = moves.urllib.parse.urlparse(url) if components.scheme not in allowed_schemes: raise IOError(_('Invalid URL scheme %s') % components.scheme) if chunk_size is None: chunk_size = max_size if max_size < 1: raise IOError("max_size should be greater than 0") if chunk_size < 1: raise IOError("chunk_size should be greater than 0") if components.scheme == 'file': try: return moves.urllib.request.urlopen(url).read() except moves.urllib.error.URLError as uex: raise IOError(_('Failed to read file: %s') % str(uex)) try: resp = requests.get(url, stream=True) resp.raise_for_status() # We cannot use resp.text here because it would download the # entire file, and a large enough file would bring down the # engine. The 'Content-Length' header could be faked, so it's # necessary to download the content in chunks to until # max_size is reached. The chunk_size we use needs # to balance CPU-intensive string concatenation with accuracy # (eg. it's possible to fetch 1000 bytes greater than # max_size with a chunk_size of 1000). reader = resp.iter_content(chunk_size=chunk_size) result = "" for chunk in reader: result += chunk if len(result) > max_size: raise IOError("File exceeds maximum allowed size (%s " "bytes)" % max_size) return result except exceptions.RequestException as ex: raise IOError(_('Failed to retrieve file: %s') % str(ex))
def set_name(self, value): if len(value) > 100: raise ValueError(_('Names must not be longer than 100 ' 'characters')) allowed_chars = string.ascii_lowercase + string.digits + '-_' for ch in value: if ch not in allowed_chars: raise ValueError(_('Names must only contain a-z,0-9,-,_')) self.__name = value
def set_name(self, value): if len(value) > 100: raise ValueError( _('Names must not be longer than 100 ' 'characters')) allowed_chars = string.ascii_lowercase + string.digits + '-_' for ch in value: if ch not in allowed_chars: raise ValueError(_('Names must only contain a-z,0-9,-,_')) self.__name = value
def _v3_client_init(self): kwargs = {'auth_url': self.endpoint, 'endpoint': self.endpoint} # Note try trust_id first, as we can't reuse auth_token in that case if self.context.trust_id is not None: # We got a trust_id, so we use the admin credentials # to authenticate with the trust_id so we can use the # trust impersonating the trustor user. kwargs.update(self._service_admin_creds()) kwargs['trust_id'] = self.context.trust_id kwargs.pop('project_name') elif self.context.auth_token_info is not None: # The auth_ref version must be set according to the token version if 'access' in self.context.auth_token_info: kwargs['auth_ref'] = copy.deepcopy( self.context.auth_token_info['access']) kwargs['auth_ref']['version'] = 'v2.0' kwargs['auth_ref']['token']['id'] = self.context.auth_token elif 'token' in self.context.auth_token_info: kwargs['auth_ref'] = copy.deepcopy( self.context.auth_token_info['token']) kwargs['auth_ref']['version'] = 'v3' kwargs['auth_ref']['auth_token'] = self.context.auth_token else: LOG.error("Unknown version in auth_token_info") raise exception.AuthorizationFailure() elif self.context.auth_token is not None: kwargs['token'] = self.context.auth_token kwargs['project_id'] = self.context.tenant else: LOG.error( _("Keystone v3 API connection failed, no password " "trust or auth_token!")) raise exception.AuthorizationFailure() client = kc_v3.Client(**kwargs) if 'auth_ref' not in kwargs: client.authenticate() # If we are authenticating with a trust set the context auth_token # with the trust scoped token if 'trust_id' in kwargs: # Sanity check if not client.auth_ref.trust_scoped: LOG.error(_("trust token re-scoping failed!")) raise exception.AuthorizationFailure() # All OK so update the context with the token self.context.auth_token = client.auth_ref.auth_token self.context.auth_url = self.endpoint self.context.user = client.auth_ref.user_id self.context.tenant = client.auth_ref.project_id self.context.user_name = client.auth_ref.username return client
def test_unittest(self, fake_LOG): git_info = test_shell.mock_git_info() args = [5, git_info, 'new_app', '1-2-3-4', 'heroku', 'docker', 44, 'pep8'] noop_handler.Handler().unittest(self.ctx, *args) message = 'Unittest ' + ', '.join([str(a) for a in args]) fake_LOG.debug.assert_called_once_with(_("%s") % message)
def main(): priv_context.init(root_helper=shlex.split(utils.get_root_helper())) cfg.CONF.register_cli_opts(cli_opts) service.prepare_service(sys.argv) solum.TLS.trace = trace_data.TraceData() LOG.info(_('Starting server in PID %s') % os.getpid()) LOG.debug("Configuration:") logging.setup(cfg.CONF, 'solum') cfg.CONF.import_opt('topic', 'solum.worker.config', group='worker') cfg.CONF.import_opt('host', 'solum.worker.config', group='worker') cfg.CONF.import_opt('handler', 'solum.worker.config', group='worker') handlers = { 'noop': noop_handler.Handler, 'default': default_handler.Handler, 'shell': shell_handler.Handler, } endpoints = [ handlers[cfg.CONF.worker.handler](), ] server = rpc_service.Service(cfg.CONF.worker.topic, cfg.CONF.worker.host, endpoints) server.serve()
class SolumException(Exception): """Base Solum Exception To correctly use this class, inherit from it and define a 'msg_fmt' property. That msg_fmt will get printf'd with the keyword arguments provided to the constructor. """ message = _("An unknown exception occurred.") code = 500 def __init__(self, **kwargs): self.kwargs = kwargs if CONF.fatal_exception_format_errors: assert isinstance(self.msg_fmt, six.text_type) try: self.message = self.msg_fmt % kwargs except KeyError: # kwargs doesn't match a variable in the message # log the issue and the kwargs LOG.exception( _('Exception in string format operation'), extra=dict(private=dict(msg=self.msg_fmt, args=kwargs))) if CONF.fatal_exception_format_errors: raise def __str__(self): return self.message
def test_destroy(self, fake_LOG, fake_registry): fake_assembly = fakes.FakeAssembly() fake_registry.Assembly.get_by_id.return_value = fake_assembly args = [fake_assembly.id] noop_handler.Handler().destroy_assembly(self.ctx, *args) fake_assembly.destroy.assert_called_once_with(self.ctx) message = 'Destroy %s' % tuple(args) fake_LOG.debug.assert_called_once_with(_("%s") % message)
def _v3_client_init(self): kwargs = { 'auth_url': self.endpoint, 'endpoint': self.endpoint } # Note try trust_id first, as we can't reuse auth_token in that case if self.context.trust_id is not None: # We got a trust_id, so we use the admin credentials # to authenticate with the trust_id so we can use the # trust impersonating the trustor user. kwargs.update(self._service_admin_creds()) kwargs['trust_id'] = self.context.trust_id kwargs.pop('project_name') auth = ka_loading.load_auth_from_conf_options( cfg.CONF, 'keystone_authtoken', **kwargs) elif self.context.auth_token is not None: kwargs['token'] = self.context.auth_token kwargs['project_id'] = self.context.tenant auth = identity.Token( auth_url=kwargs['auth_url'], token=kwargs['token'], project_id=kwargs['project_id']) else: LOG.error(_("Keystone v3 API connection failed, no password " "trust or auth_token!")) raise exception.AuthorizationFailure() session = ks_session.Session(auth=auth) client = kc_v3.Client(session=session) client.auth_ref = client.session.auth.get_access(client.session) # If we are authenticating with a trust set the context auth_token # with the trust scoped token if 'trust_id' in kwargs: # Sanity check if not client.auth_ref.trust_scoped: LOG.error(_("trust token re-scoping failed!")) raise exception.AuthorizationFailure() # All OK so update the context with the token self.context.auth_token = client.auth_ref.auth_token self.context.auth_url = self.endpoint self.context.user = client.auth_ref.user_id self.context.tenant = client.auth_ref.project_id self.context.user_name = client.auth_ref.username return client
def get_value(self): if self.sensor_type == 'int': if int(self._value) != float(self._value): raise ValueError( _('Value "%s" is not an integer.') % str(self._value)) return int(self._value) elif self.sensor_type == 'float': return float(self._value) else: return str(self._value)
def get_value(self): if self.sensor_type == 'int': if int(self._value) != float(self._value): raise ValueError(_('Value "%s" is not an integer.') % str(self._value)) return int(self._value) elif self.sensor_type == 'float': return float(self._value) else: return str(self._value)
def install(app, conf): if conf.get('enable_authentication'): return AuthProtocolWrapper(app, conf=dict(conf.get(OPT_GROUP_NAME))) else: LOG.warning(_('Keystone authentication is disabled by Solum ' 'configuration parameter enable_authentication. ' 'Solum will not authenticate incoming request. ' 'In order to enable authentication set ' 'enable_authentication option to True.')) return app
def _v3_client_init(self): kwargs = {'auth_url': self.endpoint, 'endpoint': self.endpoint} # Note try trust_id first, as we can't reuse auth_token in that case if self.context.trust_id is not None: # We got a trust_id, so we use the admin credentials # to authenticate with the trust_id so we can use the # trust impersonating the trustor user. kwargs.update(self._service_admin_creds()) kwargs['trust_id'] = self.context.trust_id kwargs.pop('project_name') auth = ka_loading.load_auth_from_conf_options( cfg.CONF, 'keystone_authtoken', **kwargs) elif self.context.auth_token is not None: kwargs['token'] = self.context.auth_token kwargs['project_id'] = self.context.tenant auth = identity.Token(auth_url=kwargs['auth_url'], token=kwargs['token'], project_id=kwargs['project_id']) else: LOG.error( _("Keystone v3 API connection failed, no password " "trust or auth_token!")) raise exception.AuthorizationFailure() session = ks_session.Session(auth=auth) client = kc_v3.Client(session=session) client.auth_ref = client.session.auth.get_access(client.session) # If we are authenticating with a trust set the context auth_token # with the trust scoped token if 'trust_id' in kwargs: # Sanity check if not client.auth_ref.trust_scoped: LOG.error(_("trust token re-scoping failed!")) raise exception.AuthorizationFailure() # All OK so update the context with the token self.context.auth_token = client.auth_ref.auth_token self.context.auth_url = self.endpoint self.context.user = client.auth_ref.user_id self.context.tenant = client.auth_ref.project_id self.context.user_name = client.auth_ref.username return client
def _get_roles(self, req): """Get the list of roles.""" if 'X-Roles' in req.headers: roles = req.headers.get('X-Roles', '') else: # Fallback to deprecated role header: roles = req.headers.get('X-Role', '') if roles: LOG.warning(_("X-Roles is missing. Using deprecated X-Role " "header")) return [r.strip() for r in roles.split(',')]
def validate(self, value): for t in self.types: try: return wtypes.validate_value(t, value) except (ValueError, TypeError): pass else: raise ValueError( _("Wrong type. Expected '%(type)s', got '%(value)s'") % { 'type': self.types, 'value': type(value) })
def main(): eventlet.monkey_patch(socket=True, select=True, time=True) service.prepare_service(sys.argv) app = api_app.setup_app() # Create the WSGI server and start it host, port = cfg.CONF.api.host, cfg.CONF.api.port LOG.info(_('Starting server in PID %s') % os.getpid()) LOG.debug("Configuration:") logging.setup(cfg.CONF, 'solum') if host == '0.0.0.0': LOG.info(_('serving on 0.0.0.0:%(port)s, ' 'view at http://127.0.0.1:%(port)s') % dict(port=port)) else: LOG.info(_('serving on http://%(host)s:%(port)s') % dict(host=host, port=port)) wsgi.server(eventlet.listen((host, port)), app)
def main(): service.prepare_service(sys.argv) LOG.info(_('Starting server in PID %s') % os.getpid()) LOG.debug("Configuration:") logging.setup(cfg.CONF, 'solum') cfg.CONF.import_opt('topic', 'solum.conductor.config', group='conductor') cfg.CONF.import_opt('host', 'solum.conductor.config', group='conductor') endpoints = [ default_handler.Handler(), ] server = rpc_service.Service(cfg.CONF.conductor.topic, cfg.CONF.conductor.host, endpoints) server.serve()
def post(self, data): """Create a new assembly.""" js_data = data.as_dict(objects.registry.Assembly) if data.plan_uri is not wsme.Unset: plan_uri = data.plan_uri if plan_uri.startswith(pecan.request.host_url): pl_uuid = plan_uri.split('/')[-1] pl = objects.registry.Plan.get_by_uuid( pecan.request.security_context, pl_uuid) js_data['plan_id'] = pl.id else: # TODO(asalkeld) we are not hosting the plan so # download the plan and insert it into our db. raise exception.BadRequest(reason=_( 'The plan was not hosted in solum')) if js_data.get('plan_id') is None: raise exception.BadRequest(reason=_( 'The plan was not given or could not be found')) handler = assembly_handler.AssemblyHandler( pecan.request.security_context) return assembly.Assembly.from_db_model( handler.create(js_data), pecan.request.host_url)
def __init__(self, **kwargs): self.kwargs = kwargs if CONF.fatal_exception_format_errors: assert isinstance(self.msg_fmt, six.text_type) try: self.message = self.msg_fmt % kwargs except KeyError: # kwargs doesn't match a variable in the message # log the issue and the kwargs LOG.exception( _('Exception in string format operation'), extra=dict(private=dict(msg=self.msg_fmt, args=kwargs))) if CONF.fatal_exception_format_errors: raise
class Checks(upgradecheck.UpgradeCommands): """Upgrade checks for the solum-status upgrade check command Upgrade checks should be added as separate methods in this class and added to _upgrade_checks tuple. """ def _check_placeholder(self): # This is just a placeholder for upgrade checks, it should be # removed when the actual checks are added return upgradecheck.Result(upgradecheck.Code.SUCCESS) # The format of the check functions is to return an # oslo_upgradecheck.upgradecheck.Result # object with the appropriate # oslo_upgradecheck.upgradecheck.Code and details set. # If the check hits warnings or failures then those should be stored # in the returned Result's "details" attribute. The # summary will be rolled up at the end of the check() method. _upgrade_checks = ( # In the future there should be some real checks added here (_('Placeholder'), _check_placeholder), )
def main(): service.prepare_service(sys.argv) LOG.info(_('Starting server in PID %s') % os.getpid()) LOG.debug("Configuration:") logging.setup(cfg.CONF, 'solum') cfg.CONF.import_opt('topic', 'solum.deployer.config', group='deployer') cfg.CONF.import_opt('host', 'solum.deployer.config', group='deployer') cfg.CONF.import_opt('handler', 'solum.deployer.config', group='deployer') handlers = { 'noop': noop_handler.Handler, 'heat': heat_handler.Handler, } endpoints = [ handlers[cfg.CONF.deployer.handler](), ] server = rpc_service.Service(cfg.CONF.deployer.topic, cfg.CONF.deployer.host, endpoints) server.serve()
class MaxRetryReached(Exception): msg_fmt = _("Maximum retries has been reached.")
class InvalidObjectSizeError(Exception): msg_fmt = _("Invalid object size.")
class AuthorizationFailure(SolumException): msg_fmt = _("%(client)s connection failed. %(message)s")
class NotImplemented(SolumException): msg_fmt = _("The requested operation is not implemented.") code = 501
class LPStillReferenced(ResourceStillReferenced): msg_fmt = _("Languagepack %(name)s cannot be deleted because one or more" " applications reference it.")
class PlanStillReferenced(ResourceStillReferenced): msg_fmt = _("Plan %(name)s cannot be deleted because one or more" " Assemblies reference it.")
import keystoneclient.exceptions as kc_exception from keystoneclient.v3 import client as kc_v3 from oslo_config import cfg from oslo_log import log as logging from oslo_utils import importutils from solum.common import context from solum.common import exception from solum.i18n import _ LOG = logging.getLogger(__name__) trust_opts = [ cfg.ListOpt('trusts_delegated_roles', default=['solum_assembly_update'], help=_('Subset of trustor roles to be delegated to solum.')), ] cfg.CONF.register_opts(trust_opts) cfg.CONF.import_opt('www_authenticate_uri', 'keystonemiddleware.auth_token', group='keystone_authtoken') AUTH_OPTS = [ cfg.StrOpt('keystone_version', default='3', help='The keystone version to use with Solum'), ] def list_opts(): yield None, AUTH_OPTS yield None, trust_opts
class UnsupportedMediaType(SolumException): msg_fmt = _("\'%(name)s\' is not a supported media type for the %(method)s" " method of this resource") code = 415
class ResourceStillReferenced(SolumException): msg_fmt = _("The %(name)s resource cannot be deleted because one or more" " resources reference it.") code = 409
class ResourceExists(ObjectNotUnique): msg_fmt = _("The %(name)s resource already exists.") code = 409
class ResourceNotFound(ObjectNotFound): msg_fmt = _("The %(name)s resource %(id)s could not be found.") code = 404
from neutronclient.neutron import client as neutronclient from oslo_config import cfg from swiftclient import client as swiftclient from zaqarclient.queues.v1 import client as zaqarclient from solum.common import exception from solum.common import solum_barbicanclient from solum.common import solum_keystoneclient from solum.i18n import _ GLOBAL_CLIENT_OPTS = [ cfg.StrOpt('region_name', default='RegionOne', help=_( 'Region of endpoint in Identity service catalog to use' ' for all clients.')), ] barbican_client_opts = [ cfg.BoolOpt('insecure', default=False, help=_("If set, then the server's certificate for barbican " "will not be verified.")), ] # Note: this config is duplicated in many projects that use OpenStack # clients. This should really be in the client. # There is a place holder bug here: # https://bugs.launchpad.net/solum/+bug/1292334 # that we use to track this. glance_client_opts = [
def test_echo(self, fake_LOG): noop_handler.Handler().echo({}, 'foo') fake_LOG.debug.assert_called_once_with(_('%s') % 'foo')
def build_lp(self, ctxt, image_id, git_info, name, source_format, image_format, artifact_type, lp_params): LOG.debug("Building languagepack %s" % name) update_lp_status(ctxt, image_id, name, IMAGE_STATES.BUILDING) solum.TLS.trace.clear() solum.TLS.trace.import_context(ctxt) source_uri = git_info['source_url'] build_cmd = self._get_build_command(ctxt, 'build', source_uri, name, str(image_id), source_format, 'docker', '', artifact_type) lp_access = get_lp_access_method(ctxt.tenant) user_env = {} try: user_env = self._get_environment(ctxt, git_info, lp_access=lp_access) except exception.SolumException as env_ex: LOG.exception(_("Failed to successfully get environment for " "building languagepack: `%s`"), image_id) LOG.exception(env_ex) log_env = user_env.copy() if 'OS_AUTH_TOKEN' in log_env: del log_env['OS_AUTH_TOKEN'] if 'OPER_AUTH_TOKEN' in log_env: del log_env['OPER_AUTH_TOKEN'] if 'OPER_OS_STORAGE_URL' in log_env: del log_env['OPER_OS_STORAGE_URL'] solum.TLS.trace.support_info(environment=log_env) logpath = "%s/%s-%s.log" % (user_env['SOLUM_TASK_DIR'], 'languagepack', user_env['BUILD_ID']) LOG.debug("Languagepack logs for LP %s stored at %s" % (image_id, logpath)) out = None status = IMAGE_STATES.ERROR image_external_ref = None docker_image_name = None try: try: out = priv_rootwrap.execute( *build_cmd, run_as_root=True, env_variables=user_env)[0] except Exception as e: LOG.exception("Failed to build languagepack: %s" % image_id) LOG.exception(e) out = '' if isinstance(out, six.binary_type): out = out.decode('utf-8') LOG.debug("#######out is %s" % out) # we expect two lines in the output that looks like: # image_external_ref=<external storage ref> # docker_image_name=<DU name> for line in out.split('\n'): # Won't break out until we get the final # matching which is the expected value if line.startswith('image_external_ref'): solum.TLS.trace.support_info(build_lp_out_line=line) image_external_ref = line.replace('image_external_ref=', '').strip() elif line.startswith('docker_image_name'): docker_image_name = line.replace('docker_image_name=', '') if image_external_ref and docker_image_name: status = IMAGE_STATES.READY else: status = IMAGE_STATES.ERROR except OSError as subex: LOG.exception(_("Failed to successfully build languagepack: `%s`"), image_id) LOG.exception(subex) img = get_image_by_id(ctxt, image_id) img.type = 'languagepack' update_lp_status(ctxt, image_id, name, status, image_external_ref, docker_image_name) upload_task_log(ctxt, logpath, img, img.uuid, 'languagepack')
class Unprocessable(SolumException): msg_fmt = _("Server is incapable of processing the specified request.") code = 422