예제 #1
0
def _get_ksclient(token=None):
    auth_url = CONF.keystone_authtoken.www_authenticate_uri
    if not auth_url:
        raise exception.KeystoneFailure(_('Keystone API endpoint is missing'))

    auth_version = CONF.keystone_authtoken.auth_version
    api_v3 = _is_apiv3(auth_url, auth_version)

    if api_v3:
        from keystoneclient.v3 import client
    else:
        from keystoneclient.v2_0 import client

    auth_url = get_keystone_url(auth_url, auth_version)
    try:
        if token:
            return client.Client(token=token, auth_url=auth_url)
        else:
            return client.Client(
                username=CONF.keystone_authtoken.admin_user,
                password=CONF.keystone_authtoken.admin_password,
                tenant_name=CONF.keystone_authtoken.admin_tenant_name,
                region_name=CONF.keystone.region_name,
                auth_url=auth_url)
    except ksexception.Unauthorized:
        raise exception.KeystoneUnauthorized()
    except ksexception.AuthorizationFailure as err:
        raise exception.KeystoneFailure(_('Could not authorize in Keystone:'
                                          ' %s') % err)
예제 #2
0
def update_port_address(port_id, address):
    """Update a port's mac address.

    :param port_id: Neutron port id.
    :param address: new MAC address.
    :raises: FailedToUpdateMacOnPort
    """
    client = get_client()
    port_req_body = {'port': {'mac_address': address}}

    try:
        msg = (_("Failed to get the current binding on Neutron "
                 "port %s.") % port_id)
        port = client.show_port(port_id).get('port', {})
        binding_host_id = port.get('binding:host_id')
        binding_profile = port.get('binding:profile')

        if binding_host_id:
            # Unbind port before we update it's mac address, because you can't
            # change a bound port's mac address.
            msg = (_("Failed to remove the current binding from "
                     "Neutron port %s, while updating its MAC "
                     "address.") % port_id)
            unbind_neutron_port(port_id, client=client)
            port_req_body['port']['binding:host_id'] = binding_host_id
            port_req_body['port']['binding:profile'] = binding_profile

        msg = (_("Failed to update MAC address on Neutron port %s.") % port_id)
        client.update_port(port_id, port_req_body)
    except (neutron_exceptions.NeutronClientException, exception.NetworkError):
        LOG.exception(msg)
        raise exception.FailedToUpdateMacOnPort(port_id=port_id)
예제 #3
0
def _verify_security_groups(security_groups, client):
    """Verify that the security groups exist.

    :param security_groups: a list of security group UUIDs; may be None or
        empty
    :param client: Neutron client
    :raises: NetworkError
    """

    if not security_groups:
        return
    try:
        neutron_sec_groups = (
            client.list_security_groups().get('security_groups', []))
    except neutron_exceptions.NeutronClientException as e:
        msg = (_("Could not retrieve security groups from neutron: %(exc)s") %
               {'exc': e})
        LOG.exception(msg)
        raise exception.NetworkError(msg)

    existing_sec_groups = [sec_group['id'] for sec_group in neutron_sec_groups]
    missing_sec_groups = set(security_groups) - set(existing_sec_groups)
    if missing_sec_groups:
        msg = (_('Could not find these security groups '
                 '(specified via iotronic '
                 'config) in neutron: %(ir-sg)s')
               % {'ir-sg': list(missing_sec_groups)})
        LOG.error(msg)
        raise exception.NetworkError(msg)
예제 #4
0
파일: base.py 프로젝트: openstack/iotronic
    def parse_headers(headers, default_version, latest_version):
        """Determine the API version requested based on the headers supplied.

        :param headers: webob headers
        :param default_version: version to use if not specified in headers
        :param latest_version: version to use if latest is requested
        :returns: a tuple of (major, minor) version numbers
        :raises: webob.HTTPNotAcceptable
        """
        version_str = headers.get(Version.string, default_version)

        if version_str.lower() == 'latest':
            parse_str = latest_version
        else:
            parse_str = version_str

        try:
            version = tuple(int(i) for i in parse_str.split('.'))
        except ValueError:
            version = ()

        if len(version) != 2:
            raise exc.HTTPNotAcceptable(_(
                "Invalid value for %s header") % Version.string)
        return version
예제 #5
0
파일: base.py 프로젝트: openstack/iotronic
    def save(self, context):
        """Save the changed fields back to the store.

        This is optional for subclasses, but is presented here in the base
        class for consistency among those that do.
        """
        raise NotImplementedError(_("Cannot save anything in the base class"))
예제 #6
0
def unbind_neutron_port(port_id, client=None):
    """Unbind a neutron port

    Remove a neutron port's binding profile and host ID so that it returns to
    an unbound state.

    :param port_id: Neutron port ID.
    :param client: Optional a Neutron client object.
    :raises: NetworkError
    """

    if not client:
        client = get_client()

    body = {'port': {'binding:host_id': '',
                     'binding:profile': {}}}

    try:
        client.update_port(port_id, body)
    # NOTE(vsaienko): Ignore if port was deleted before calling vif detach.
    except neutron_exceptions.PortNotFoundClient:
        LOG.info('Port %s was not found while unbinding.', port_id)
    except neutron_exceptions.NeutronClientException as e:
        msg = (_('Unable to clear binding profile for '
                 'neutron port %(port_id)s. Error: '
                 '%(err)s') % {'port_id': port_id, 'err': e})
        LOG.exception(msg)
        raise exception.NetworkError(msg)
예제 #7
0
def get_service_url(service_type='iot', endpoint_type='internal'):
    """Wrapper for get service url from keystone service catalog.

    Given a service_type and an endpoint_type, this method queries keystone
    service catalog and provides the url for the desired endpoint.

    :param service_type: the keystone service for which url is required.
    :param endpoint_type: the type of endpoint for the service.
    :returns: an http/https url for the desired endpoint.
    """
    ksclient = _get_ksclient()

    if not ksclient.has_service_catalog():
        raise exception.KeystoneFailure(_('No Keystone service catalog '
                                          'loaded'))

    try:
        endpoint = ksclient.service_catalog.url_for(
            service_type=service_type,
            endpoint_type=endpoint_type,
            region_name=CONF.keystone.region_name)

    except ksexception.EndpointNotFound:
        raise exception.CatalogNotFound(service_type=service_type,
                                        endpoint_type=endpoint_type)

    return endpoint
예제 #8
0
파일: utils.py 프로젝트: openstack/iotronic
def validate_limit(limit):
    if limit is None:
        return CONF.api.max_limit

    if limit <= 0:
        raise wsme.exc.ClientSideError(_("Limit must be positive"))

    return min(CONF.api.max_limit, limit)
예제 #9
0
파일: utils.py 프로젝트: openstack/iotronic
def apply_jsonpatch(doc, patch):
    for p in patch:
        if p['op'] == 'add' and p['path'].count('/') == 1:
            if p['path'].lstrip('/') not in doc:
                msg = _('Adding a new attribute (%s) to the root of '
                        ' the resource is not allowed')
                raise wsme.exc.ClientSideError(msg % p['path'])
    return jsonpatch.apply_patch(doc, jsonpatch.JsonPatch(patch))
예제 #10
0
파일: base.py 프로젝트: openstack/iotronic
    def obj_load_attr(self, attrname):
        """Load an additional attribute from the real object.

        This should use self._conductor, and cache any data that might
        be useful for future load operations.
        """
        raise NotImplementedError(
            _("Cannot load '%(attrname)s' in the base class") %
            {'attrname': attrname})
예제 #11
0
파일: base.py 프로젝트: openstack/iotronic
    def obj_attr_is_set(self, attrname):
        """Test object to see if attrname is present.

        Returns True if the named attribute has a value set, or
        False if not. Raises AttributeError if attrname is not
        a valid attribute for this object.
        """
        if attrname not in self.obj_fields:
            raise AttributeError(
                _("%(objname)s object has no attribute '%(attrname)s'") %
                {'objname': self.obj_name(), 'attrname': attrname})
        return hasattr(self, get_attrname(attrname))
예제 #12
0
파일: base.py 프로젝트: openstack/iotronic
    def get(self, key, value=NotSpecifiedSentinel):
        """For backwards-compatibility with dict-based objects.

        NOTE(danms): May be removed in the future.
        """
        if key not in self.obj_fields:
            raise AttributeError(
                _("'%(objclass)s' object has no attribute '%(attrname)s'") %
                {'objclass': self.__class__, 'attrname': key})
        if value != NotSpecifiedSentinel and not self.obj_attr_is_set(key):
            return value
        else:
            return self[key]
예제 #13
0
파일: utils.py 프로젝트: openstack/iotronic
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.UTC)
        else:
            return dt
    raise ValueError(_("A datetime.datetime is required here"))
예제 #14
0
 def _check_version(self, version, headers=None):
     if headers is None:
         headers = {}
     # ensure that major version in the URL matches the header
     if version.major != BASE_VERSION:
         raise exc.HTTPNotAcceptable(_(
             "Mutually exclusive versions requested. Version %(ver)s "
             "requested but not supported by this service. The supported "
             "version range is: [%(min)s, %(max)s].") % {
             'ver': version,
             'min': versions.MIN_VERSION_STRING,
             'max': versions.MAX_VERSION_STRING
         }, headers=headers)
     # ensure the minor version is within the supported range
     if version < MIN_VER or version > MAX_VER:
         raise exc.HTTPNotAcceptable(_(
             "Version %(ver)s was requested but the minor version is not "
             "supported by this service. The supported version range is: "
             "[%(min)s, %(max)s].") % {
             'ver': version,
             'min': versions.MIN_VERSION_STRING,
             'max': versions.MAX_VERSION_STRING
         }, headers=headers)
예제 #15
0
파일: utils.py 프로젝트: openstack/iotronic
def check_for_invalid_fields(fields, object_fields):
    """Check for requested non-existent fields.

    Check if the user requested non-existent fields.

    :param fields: A list of fields requested by the user
    :object_fields: A list of fields supported by the object.
    :raises: InvalidParameterValue if invalid fields were requested.

    """
    invalid_fields = set(fields) - set(object_fields)
    if invalid_fields:
        raise exception.InvalidParameterValue(
            _('Field(s) "%s" are not valid') % ', '.join(invalid_fields))
예제 #16
0
파일: api.py 프로젝트: openstack/iotronic
    def update_service(self, service_id, values):
        # NOTE(dtantsur): this can lead to very strange errors
        if 'uuid' in values:
            msg = _("Cannot overwrite UUID for an existing Service.")
            raise exception.InvalidParameterValue(err=msg)

        try:
            return self._do_update_service(service_id, values)
        except db_exc.DBDuplicateEntry as e:
            if 'name' in e.columns:
                raise exception.DuplicateName(name=values['name'])
            elif 'uuid' in e.columns:
                raise exception.ServiceAlreadyExists(uuid=values['uuid'])
            else:
                raise e
예제 #17
0
파일: api.py 프로젝트: openstack/iotronic
    def update_injection_plugin(self, plugin_injection_id, values):

        if 'uuid' in values:
            msg = _("Cannot overwrite UUID for an existing Plugin.")
            raise exception.InvalidParameterValue(err=msg)
        try:
            return self._do_update_injection_plugin(
                plugin_injection_id, values)

        except db_exc.DBDuplicateEntry as e:
            if 'name' in e.columns:
                raise exception.DuplicateName(name=values['name'])
            elif 'uuid' in e.columns:
                raise exception.PluginAlreadyExists(uuid=values['uuid'])
            else:
                raise e
예제 #18
0
파일: base.py 프로젝트: openstack/iotronic
def check_object_version(server, client):
    try:
        client_major, _client_minor = client.split('.')
        server_major, _server_minor = server.split('.')
        client_minor = int(_client_minor)
        server_minor = int(_server_minor)
    except ValueError:
        raise exception.IncompatibleObjectVersion(
            _('Invalid version string'))

    if client_major != server_major:
        raise exception.IncompatibleObjectVersion(
            dict(client=client_major, server=server_major))
    if client_minor > server_minor:
        raise exception.IncompatibleObjectVersion(
            dict(client=client_minor, server=server_minor))
예제 #19
0
파일: api.py 프로젝트: openstack/iotronic
def _paginate_query(model, limit=None, marker=None, sort_key=None,
                    sort_dir=None, query=None):
    if not query:
        query = model_query(model)
    sort_keys = ['id']
    if sort_key and sort_key not in sort_keys:
        sort_keys.insert(0, sort_key)
    try:
        query = db_utils.paginate_query(query, model, limit, sort_keys,
                                        marker=marker, sort_dir=sort_dir)
    except db_exc.InvalidSortKey:
        raise exception.InvalidParameterValue(
            _('The sort_key value "%(key)s" is an invalid field for sorting')
            % {'key': sort_key})

    return query.all()
예제 #20
0
    def __init__(self, app, conf, public_api_routes=None):
        api_routes = [] if public_api_routes is None else public_api_routes
        self._iotronic_app = app
        # TODO(mrda): Remove .xml and ensure that doesn't result in a
        # 401 Authentication Required instead of 404 Not Found
        route_pattern_tpl = '%s(\.json|\.xml)?$'

        try:
            self.public_api_routes = [re.compile(route_pattern_tpl % route_tpl)
                                      for route_tpl in 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)
예제 #21
0
 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)
예제 #22
0
파일: utils.py 프로젝트: openstack/iotronic
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
예제 #23
0
class FailedToParseSensorData(IotronicException):
    message = _("Failed to parse sensor data for node %(node)s. "
                "Error: %(error)s")
예제 #24
0
class InsufficientDiskSpace(IotronicException):
    message = _("Disk volume where '%(path)s' is located doesn't have "
                "enough disk space. Required %(required)d MiB, "
                "only %(actual)d MiB available space present.")
예제 #25
0
 def save(self, context):
     """Save is not supported by Conductor objects."""
     raise NotImplementedError(
         _('Cannot update a conductor record directly.'))
예제 #26
0
class NodeNotLocked(Invalid):
    message = _("Node %(node)s found not to be locked on release")
예제 #27
0
class HardwareInspectionFailure(IotronicException):
    message = _("Failed to inspect hardware. Reason: %(error)s")
예제 #28
0
class PathNotFound(IotronicException):
    message = _("Path %(dir)s does not exist.")
예제 #29
0
class SNMPFailure(IotronicException):
    message = _("SNMP operation '%(operation)s' failed: %(error)s")
예제 #30
0
class IRMCOperationError(IotronicException):
    message = _('iRMC %(operation)s failed. Reason: %(error)s')
예제 #31
0
파일: utils.py 프로젝트: openstack/iotronic
 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)
예제 #32
0
class ImageCreationFailed(IotronicException):
    message = _('Creating %(image_type)s image failed: %(error)s')
예제 #33
0
 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)
예제 #34
0
from iotronic.objects import base as objects_base
from iotronic.openstack.common import service

service_opts = [
    cfg.IntOpt('periodic_interval',
               default=60,
               help='Seconds between running periodic tasks.'),
    cfg.StrOpt('host',
               default=socket.getfqdn(),
               help='Name of this board.  This can be an opaque identifier.  '
               'It is not necessarily a hostname, FQDN, or IP address. '
               'However, the board name must be valid within '
               'an AMQP key, and if using ZeroMQ, a valid '
               'hostname, FQDN, or IP address.'),
    cfg.StrOpt('notification_level',
               choices=[('debug', _('"debug" level')),
                        ('info', _('"info" level')),
                        ('warning', _('"warning" level')),
                        ('error', _('"error" level')),
                        ('critical', _('"critical" level'))],
               help=_('Specifies the minimum level for which to send '
                      'notifications. If not set, no notifications will '
                      'be sent. The default is for this option to be unset.')),
]

cfg.CONF.register_opts(service_opts)

LOG = log.getLogger(__name__)


class RPCService(service.Service):
예제 #35
0
파일: utils.py 프로젝트: openstack/iotronic
def validate_sort_dir(sort_dir):
    if sort_dir not in ['asc', 'desc']:
        raise wsme.exc.ClientSideError(_("Invalid sort direction: %s. "
                                         "Acceptable values are "
                                         "'asc' or 'desc'") % sort_dir)
    return sort_dir
예제 #36
0
class ConfigInvalid(IotronicException):
    message = _("Invalid configuration file. %(error_msg)s")
예제 #37
0
class NoFreeConductorWorker(TemporaryFailure):
    message = _('Requested action cannot be performed due to lack of free '
                'conductor workers.')
    code = 503  # Service Unavailable (temporary).
예제 #38
0
class SwiftOperationError(IotronicException):
    message = _("Swift operation '%(operation)s' failed: %(error)s")
예제 #39
0
class IloOperationNotSupported(IotronicException):
    message = _("%(operation)s not supported. error: %(error)s")
예제 #40
0
class FileSystemNotSupported(IotronicException):
    message = _("Failed to create a file system. "
                "File system %(fs)s is not supported.")
예제 #41
0
class DracClientError(DracRequestFailed):
    message = _('DRAC client failed. '
                'Last error (cURL error code): %(last_error)s, '
                'fault string: "%(fault_string)s" '
                'response_code: %(response_code)s')
예제 #42
0
class VirtualBoxOperationFailed(IotronicException):
    message = _("VirtualBox operation '%(operation)s' failed. "
                "Error: %(error)s")
예제 #43
0
class DracOperationFailed(DracRequestFailed):
    message = _('DRAC operation failed. Message: %(message)s')
예제 #44
0
class NodeCleaningFailure(IotronicException):
    message = _("Failed to clean node %(node)s: %(reason)s")
예제 #45
0
class DracUnexpectedReturnValue(DracRequestFailed):
    message = _('DRAC operation yielded return value %(actual_return_value)s '
                'that is neither error nor expected %(expected_return_value)s')
예제 #46
0
class DirectoryNotWritable(IotronicException):
    message = _("Directory %(dir)s is not writable.")
예제 #47
0
class DracPendingConfigJobExists(IotronicException):
    message = _('Another job with ID %(job_id)s is already created  '
                'to configure %(target)s. Wait until existing job '
                'is completed or is canceled')
예제 #48
0
class DriverLoadError(IotronicException):
    message = _("Driver %(driver)s could not be loaded. Reason: %(reason)s.")
예제 #49
0
class DracInvalidFilterDialect(IotronicException):
    message = _('Invalid filter dialect \'%(invalid_filter)s\'. '
                'Supported options are %(supported)s')
예제 #50
0
class NoConsolePid(ConsoleError):
    message = _("Could not find pid in pid file %(pid_path)s")
예제 #51
0
class ConsoleSubprocessFailed(ConsoleError):
    message = _("Console subprocess failed to start. %(error)s")
예제 #52
0
 def save(self, context):
     """Save is not supported by Conductor objects."""
     raise NotImplementedError(
         _('Cannot update a conductor record directly.'))
예제 #53
0
class PasswordFileFailedToCreate(IotronicException):
    message = _("Failed to create the password file. %(error)s")
예제 #54
0
class NotAuthorized(IotronicException):
    message = _("Not authorized.")
    code = 403
예제 #55
0
class IloOperationError(IotronicException):
    message = _("%(operation)s failed, error: %(error)s")
예제 #56
0
파일: agent.py 프로젝트: openstack/iotronic
import importlib
from threading import Thread

import ssl

import os
import signal

from autobahn.asyncio.component import Component

LOG = logging.getLogger(__name__)

service_opts = [
    cfg.StrOpt('notification_level',
               choices=[('debug', _('"debug" level')),
                        ('info', _('"info" level')),
                        ('warning', _('"warning" level')),
                        ('error', _('"error" level')),
                        ('critical', _('"critical" level'))],
               help=_('Specifies the minimum level for which to send '
                      'notifications. If not set, no notifications will '
                      'be sent. The default is for this option to be unset.')),
]

wamp_opts = [
    cfg.StrOpt('wamp_transport_url',
               default='ws://localhost:8181/',
               help=('URL of wamp broker')),
    cfg.StrOpt('wamp_realm',
               default='s4t',
예제 #57
0
 def save(self, context):
     """Save is not supported by WampAgent objects."""
     raise NotImplementedError(
         _('Cannot update a wampagent record directly.'))