def _decrypt_image(self, context, encrypted_filename, encrypted_key, encrypted_iv, decrypted_filename): elevated = context.elevated() try: key = self.cert_rpcapi.decrypt_text(elevated, project_id=context.project_id, text=base64.b64encode(encrypted_key)) except Exception as exc: msg = _('Failed to decrypt private key: %s') % exc raise exception.NovaException(msg) try: iv = self.cert_rpcapi.decrypt_text(elevated, project_id=context.project_id, text=base64.b64encode(encrypted_iv)) except Exception as exc: raise exception.NovaException(_('Failed to decrypt initialization ' 'vector: %s') % exc) try: utils.execute('openssl', 'enc', '-d', '-aes-128-cbc', '-in', '%s' % (encrypted_filename,), '-K', '%s' % (key,), '-iv', '%s' % (iv,), '-out', '%s' % (decrypted_filename,)) except processutils.ProcessExecutionError as exc: raise exception.NovaException(_('Failed to decrypt image file ' '%(image_file)s: %(err)s') % {'image_file': encrypted_filename, 'err': exc.stdout})
def create_shadow_table(migrate_engine, table_name=None, table=None, **col_name_col_instance): """This method create shadow table for table with name ``table_name`` or table instance ``table``. :param table_name: Autoload table with this name and create shadow table :param table: Autoloaded table, so just create corresponding shadow table. :param col_name_col_instance: contains pair column_name=column_instance. column_instance is instance of Column. These params are required only for columns that have unsupported types by sqlite. For example BigInteger. :returns: The created shadow_table object. """ meta = MetaData(bind=migrate_engine) if table_name is None and table is None: raise exception.NovaException( _("Specify `table_name` or `table` " "param")) if not (table_name is None or table is None): raise exception.NovaException( _("Specify only one param `table_name` " "`table`")) if table is None: table = Table(table_name, meta, autoload=True) columns = [] for column in table.columns: if isinstance(column.type, NullType): new_column = oslodbutils._get_not_supported_column( col_name_col_instance, column.name) columns.append(new_column) else: columns.append(column.copy()) shadow_table_name = db._SHADOW_TABLE_PREFIX + table.name shadow_table = Table(shadow_table_name, meta, *columns, mysql_engine='InnoDB') try: shadow_table.create() return shadow_table except (db_exc.DBError, OperationalError): # NOTE(ekudryashova): At the moment there is a case in oslo.db code, # which raises unwrapped OperationalError, so we should catch it until # oslo.db would wraps all such exceptions LOG.info(repr(shadow_table)) LOG.exception(_LE('Exception while creating table.')) raise exception.ShadowTableExists(name=shadow_table_name) except Exception: LOG.info(repr(shadow_table)) LOG.exception(_LE('Exception while creating table.'))
def get_my_linklocal(interface): try: if_str = execute('ip', '-f', 'inet6', '-o', 'addr', 'show', interface) condition = '\s+inet6\s+([0-9a-f:]+)/\d+\s+scope\s+link' links = [re.search(condition, x) for x in if_str[0].split('\n')] address = [w.group(1) for w in links if w is not None] if address[0] is not None: return address[0] else: msg = _('Link Local address is not found.:%s') % if_str raise exception.NovaException(msg) except Exception as ex: msg = _("Couldn't get Link Local IP of %(interface)s" " :%(ex)s") % {'interface': interface, 'ex': ex} raise exception.NovaException(msg)
def _compute_host(host, instance): '''Get the destination host for a message. :param host: explicit host to send the message to. :param instance: If an explicit host was not specified, use instance['host'] :returns: A host ''' if host: return host if not instance: raise exception.NovaException(_('No compute host specified')) if not instance.host: raise exception.NovaException(_('Unable to find host for ' 'Instance %s') % instance.uuid) return instance.host
def _test_for_malicious_tarball(path, filename): """Raises exception if extracting tarball would escape extract path.""" tar_file = tarfile.open(filename, 'r|gz') for n in tar_file.getnames(): if not os.path.abspath(os.path.join(path, n)).startswith(path): tar_file.close() raise exception.NovaException(_('Unsafe filenames in image')) tar_file.close()
def check_shadow_table(migrate_engine, table_name): """This method checks that table with ``table_name`` and corresponding shadow table have same columns. """ meta = MetaData() meta.bind = migrate_engine table = Table(table_name, meta, autoload=True) shadow_table = Table(db._SHADOW_TABLE_PREFIX + table_name, meta, autoload=True) columns = {c.name: c for c in table.columns} shadow_columns = {c.name: c for c in shadow_table.columns} for name, column in columns.items(): if name not in shadow_columns: raise exception.NovaException( _("Missing column %(table)s.%(column)s in shadow table") % { 'column': name, 'table': shadow_table.name }) shadow_column = shadow_columns[name] if not isinstance(shadow_column.type, type(column.type)): raise exception.NovaException( _("Different types in %(table)s.%(column)s and shadow table: " "%(c_type)s %(shadow_c_type)s") % { 'column': name, 'table': table.name, 'c_type': column.type, 'shadow_c_type': shadow_column.type }) for name, column in shadow_columns.items(): if name not in columns: raise exception.NovaException( _("Extra column %(table)s.%(column)s in shadow table") % { 'column': name, 'table': shadow_table.name }) return True
def register_extension(self, ext): if not self._check_extension(ext): return False alias = ext.alias if alias in self.extensions: raise exception.NovaException("Found duplicate extension: %s" % alias) self.extensions[alias] = ext return True
def register(self, ext): # Do nothing if the extension doesn't check out if not self._check_extension(ext): return alias = ext.alias if alias in self.extensions: raise exception.NovaException("Found duplicate extension: %s" % alias) self.extensions[alias] = ext self.sorted_ext_list = None
def _get_resource_tracker(self, nodename): rt = self._resource_tracker_dict.get(nodename) if not rt: if not self.driver.node_is_available(nodename): raise exception.NovaException( _("%s is not a valid node managed by this " "compute host.") % nodename) rt = resource_tracker.ResourceTracker(self.host, self.driver, nodename) self._resource_tracker_dict[nodename] = rt return rt
def call(self, method, *args, **kwargs): """Call an Ironic client method and retry on errors. :param method: Name of the client method to call as a string. :param args: Client method arguments. :param kwargs: Client method keyword arguments. :param retry_on_conflict: Boolean value. Whether the request should be retried in case of a conflict error (HTTP 409) or not. If retry_on_conflict is False the cached instance of the client won't be used. Defaults to True. :raises: NovaException if all retries failed. """ # TODO(dtantsur): drop these once ironicclient 0.8.0 is out and used in # global-requirements. retry_excs = (ironic.exc.ServiceUnavailable, ironic.exc.ConnectionRefused) retry_on_conflict = kwargs.pop('retry_on_conflict', True) # num_attempts should be the times of retry + 1 # eg. retry==0 just means run once and no retry num_attempts = max(0, CONF.ironic.api_max_retries) + 1 for attempt in range(1, num_attempts + 1): client = self._get_client(retry_on_conflict=retry_on_conflict) try: return self._multi_getattr(client, method)(*args, **kwargs) except ironic.exc.Unauthorized: # In this case, the authorization token of the cached # ironic-client probably expired. So invalidate the cached # client and the next try will start with a fresh one. self._invalidate_cached_client() LOG.debug("The Ironic client became unauthorized. " "Will attempt to reauthorize and try again.") except retry_excs: pass # We want to perform this logic for all exception cases listed # above. msg = (_("Error contacting Ironic server for " "'%(method)s'. Attempt %(attempt)d of %(total)d") % { 'method': method, 'attempt': attempt, 'total': num_attempts }) if attempt == num_attempts: LOG.error(msg) raise exception.NovaException(msg) LOG.warning(msg) time.sleep(CONF.ironic.api_retry_interval)
def db_sync(version=None, database='main'): if version is not None: try: version = int(version) except ValueError: raise exception.NovaException(_("version should be an integer")) current_version = db_version(database) repository = _find_migrate_repo(database) if version is None or version > current_version: return versioning_api.upgrade(get_engine(database), repository, version) else: return versioning_api.downgrade(get_engine(database), repository, version)
def db_version(database='main'): repository = _find_migrate_repo(database) try: return versioning_api.db_version(get_engine(database), repository) except versioning_exceptions.DatabaseNotControlledError as exc: meta = sqlalchemy.MetaData() engine = get_engine(database) meta.reflect(bind=engine) tables = meta.tables if len(tables) == 0: db_version_control(INIT_VERSION[database], database) return versioning_api.db_version(get_engine(database), repository) else: LOG.exception(exc) # Some pre-Essex DB's may not be version controlled. # Require them to upgrade using Essex first. raise exception.NovaException( _("Upgrade DB using Essex release first."))
def _get_client(self, retry_on_conflict=True): max_retries = CONF.ironic.api_max_retries if retry_on_conflict else 1 retry_interval = (CONF.ironic.api_retry_interval if retry_on_conflict else 0) # If we've already constructed a valid, authed client, just return # that. if retry_on_conflict and self._cached_client is not None: return self._cached_client auth_token = CONF.ironic.admin_auth_token if auth_token is None: kwargs = { 'os_username': CONF.ironic.admin_username, 'os_password': CONF.ironic.admin_password, 'os_auth_url': CONF.ironic.admin_url, 'os_tenant_name': CONF.ironic.admin_tenant_name, 'os_service_type': 'baremetal', 'os_endpoint_type': 'public', 'ironic_url': CONF.ironic.api_endpoint } else: kwargs = { 'os_auth_token': auth_token, 'ironic_url': CONF.ironic.api_endpoint } # Retries for Conflict exception kwargs['max_retries'] = max_retries kwargs['retry_interval'] = retry_interval kwargs['os_ironic_api_version'] = '%d.%d' % IRONIC_API_VERSION try: cli = ironic.client.get_client(IRONIC_API_VERSION[0], **kwargs) # Cache the client so we don't have to reconstruct and # reauthenticate it every time we need it. if retry_on_conflict: self._cached_client = cli except ironic.exc.Unauthorized: msg = _("Unable to authenticate Ironic client.") LOG.error(msg) raise exception.NovaException(msg) return cli
def new_websocket_client(self): """Called after a new WebSocket connection has been established.""" # Reopen the eventlet hub to make sure we don't share an epoll # fd with parent and/or siblings, which would be bad from eventlet import hubs hubs.use_hub() # The compute expected behavior is to have token # passed to the method GET of the request parse = urlparse.urlparse(self.path) if parse.scheme not in ('http', 'https'): # From a bug in urlparse in Python < 2.7.4 we cannot support # special schemes (cf: http://bugs.python.org/issue9374) if sys.version_info < (2, 7, 4): raise exception.NovaException( _("We do not support scheme '%s' under Python < 2.7.4, " "please use http or https") % parse.scheme) query = parse.query token = urlparse.parse_qs(query).get("token", [""]).pop() if not token: # NoVNC uses it's own convention that forward token # from the request to a cookie header, we should check # also for this behavior hcookie = self.headers.getheader('cookie') if hcookie: cookie = Cookie.SimpleCookie() cookie.load(hcookie) if 'token' in cookie: token = cookie['token'].value ctxt = context.get_admin_context() rpcapi = consoleauth_rpcapi.ConsoleAuthAPI() connect_info = rpcapi.check_token(ctxt, token=token) if not connect_info: raise exception.InvalidToken(token=token) # Verify Origin expected_origin_hostname = self.headers.getheader('Host') if ':' in expected_origin_hostname: e = expected_origin_hostname if '[' in e and ']' in e: expected_origin_hostname = e.split(']')[0][1:] else: expected_origin_hostname = e.split(':')[0] expected_origin_hostnames = CONF.console_allowed_origins expected_origin_hostnames.append(expected_origin_hostname) origin_url = self.headers.getheader('Origin') # missing origin header indicates non-browser client which is OK if origin_url is not None: origin = urlparse.urlparse(origin_url) origin_hostname = origin.hostname origin_scheme = origin.scheme if origin_hostname == '' or origin_scheme == '': detail = _("Origin header not valid.") raise exception.ValidationError(detail=detail) if origin_hostname not in expected_origin_hostnames: detail = _("Origin header does not match this host.") raise exception.ValidationError(detail=detail) if not self.verify_origin_proto(connect_info, origin_scheme): detail = _("Origin header protocol does not match this host.") raise exception.ValidationError(detail=detail) self.msg(_('connect info: %s'), str(connect_info)) host = connect_info['host'] port = int(connect_info['port']) # Connect to the target self.msg( _("connecting to: %(host)s:%(port)s") % { 'host': host, 'port': port }) tsock = self.socket(host, port, connect=True) # Handshake as necessary if connect_info.get('internal_access_path'): tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" % connect_info['internal_access_path']) while True: data = tsock.recv(4096, socket.MSG_PEEK) if data.find("\r\n\r\n") != -1: if data.split("\r\n")[0].find("200") == -1: raise exception.InvalidConnectionInfo() tsock.recv(len(data)) break # Start proxying try: self.do_proxy(tsock) except Exception: if tsock: tsock.shutdown(socket.SHUT_RDWR) tsock.close() self.vmsg( _("%(host)s:%(port)s: Target closed") % { 'host': host, 'port': port }) raise