Exemplo n.º 1
0
def add_command_parsers(subparsers):
    command_object = DBCommand()

    parser = subparsers.add_parser(
        'upgrade',
        help=_("Upgrade the database schema to the latest version. "
               "Optionally, use --revision to specify an alembic revision "
               "string to upgrade to."))
    parser.set_defaults(func=command_object.upgrade)
    parser.add_argument('--revision', nargs='?')

    parser = subparsers.add_parser('stamp')
    parser.add_argument('--revision', nargs='?')
    parser.set_defaults(func=command_object.stamp)

    parser = subparsers.add_parser(
        'revision',
        help=_("Create a new alembic revision. "
               "Use --message to set the message string."))
    parser.add_argument('-m', '--message')
    parser.add_argument('--autogenerate', action='store_true')
    parser.set_defaults(func=command_object.revision)

    parser = subparsers.add_parser(
        'version', help=_("Print the current version information and exit."))
    parser.set_defaults(func=command_object.version)

    parser = subparsers.add_parser('create_schema',
                                   help=_("Create the database schema."))
    parser.set_defaults(func=command_object.create_schema)
Exemplo n.º 2
0
    def _wait_for_active(self, server):
        """Wait for the node to be marked as ACTIVE in Ironic."""
        server.refresh()
        if server.status in (states.DELETING, states.ERROR, states.DELETED):
            raise exception.ServerDeployAborted(
                _("Server %s provisioning was aborted") % server.uuid)

        node = self._validate_server_and_node(server)
        if node.provision_state == ironic_states.ACTIVE:
            # job is done
            LOG.debug("Ironic node %(node)s is now ACTIVE",
                      dict(node=node.uuid),
                      server=server)
            raise loopingcall.LoopingCallDone()

        if node.target_provision_state in (ironic_states.DELETED,
                                           ironic_states.AVAILABLE):
            # ironic is trying to delete it now
            raise exception.ServerNotFound(server=server.uuid)

        if node.provision_state in (ironic_states.NOSTATE,
                                    ironic_states.AVAILABLE):
            # ironic already deleted it
            raise exception.ServerNotFound(server=server.uuid)

        if node.provision_state == ironic_states.DEPLOYFAIL:
            # ironic failed to deploy
            msg = (_("Failed to provision server %(server)s: %(reason)s") % {
                'server': server.uuid,
                'reason': node.last_error
            })
            raise exception.ServerDeployFailure(msg)

        _log_ironic_polling('become ACTIVE', node, server)
Exemplo n.º 3
0
def check_string_length(value, name=None, min_length=0, max_length=None):
    """Check the length of specified string
    :param value: the value of the string
    :param name: the name of the string
    :param min_length: the min_length of the string
    :param max_length: the max_length of the string
    """
    if not isinstance(value, six.string_types):
        if name is None:
            msg = "The input is not a string or unicode"
        else:
            msg = "%s is not a string or unicode" % name
        raise exception.Invalid(message=msg)

    if name is None:
        name = value

    if len(value) < min_length:
        msg = _("%(name)s has a minimum character requirement of "
                "%(min_length)s.") % {
                    'name': name,
                    'min_length': min_length
                }
        raise exception.Invalid(message=msg)

    if max_length and len(value) > max_length:
        msg = _("%(name)s has more than %(max_length)s "
                "characters.") % {
                    'name': name,
                    'max_length': max_length
                }
        raise exception.Invalid(message=msg)
Exemplo n.º 4
0
    def _build_networks(self, context, server, requested_networks):

        # TODO(zhenguo): This seems not needed as our scheduler has already
        # guaranteed this.
        ports = self.manager.driver.get_ports_from_node(server.node_uuid)
        if len(requested_networks) > len(ports):
            raise exception.InterfacePlugException(
                _("Ironic node: %(id)s virtual to physical interface count"
                  "  mismatch"
                  " (Vif count: %(vif_count)d, Pif count: %(pif_count)d)") % {
                      'id': server.node_uuid,
                      'vif_count': len(requested_networks),
                      'pif_count': len(ports)
                  })

        nics_obj = objects.ServerNics(context)

        for vif in requested_networks:
            try:
                if vif.get('net_id'):
                    port = self.manager.network_api.create_port(
                        context, vif['net_id'], server.uuid)
                    port_dict = port['port']
                elif vif.get('port_id'):
                    port_dict = self.manager.network_api.show_port(
                        context, vif.get('port_id'))

                nic_dict = {
                    'port_id': port_dict['id'],
                    'network_id': port_dict['network_id'],
                    'mac_address': port_dict['mac_address'],
                    'fixed_ips': port_dict['fixed_ips'],
                    'server_uuid': server.uuid
                }

                server_nic = objects.ServerNic(context, **nic_dict)
                nics_obj.objects.append(server_nic)

                self.manager.driver.plug_vif(server.node_uuid, port_dict['id'])
                # Get updated VIF info
                port_dict = self.manager.network_api.show_port(
                    context, port_dict.get('id'))

                # Update the real physical mac address from ironic.
                server_nic.mac_address = port_dict['mac_address']
            except Exception as e:
                # Set nics here, so we can clean up the
                # created networks during reverting.
                server.nics = nics_obj
                LOG.error(
                    "Server %(server)s: create or get network "
                    "failed. The reason is %(reason)s", {
                        "server": server.uuid,
                        "reason": e
                    })
                raise exception.NetworkError(
                    _("Build network for server failed."))

        return nics_obj
Exemplo n.º 5
0
 def _max_attempts(self):
     max_attempts = CONF.scheduler.scheduler_max_attempts
     if max_attempts < 1:
         raise exception.InvalidParameterValue(
             err=_("Invalid value for 'scheduler_max_attempts', "
                   "must be >=1"))
     return max_attempts
Exemplo n.º 6
0
    def _create_server(self, context, server, requested_networks,
                       user_data, injected_files, key_pair, request_spec=None,
                       filter_properties=None):
        """Perform a deployment."""
        LOG.debug("Starting server...", server=server)
        notifications.notify_about_server_action(
            context, server, self.host,
            action=fields.NotificationAction.CREATE,
            phase=fields.NotificationPhase.START)

        fsm = utils.get_state_machine(start_state=server.status,
                                      target_state=states.ACTIVE)

        try:
            flow_engine = create_server.get_flow(
                context,
                self,
                server,
                requested_networks,
                user_data,
                injected_files,
                key_pair,
                request_spec,
                filter_properties,
            )
        except Exception:
            with excutils.save_and_reraise_exception():
                utils.process_event(fsm, server, event='error')
                self._rollback_servers_quota(context, -1)
                msg = _("Create manager server flow failed.")
                LOG.exception(msg)

        def _run_flow():
            # This code executes create server flow. If something goes wrong,
            # flow reverts all job that was done and reraises an exception.
            # Otherwise, all data that was generated by flow becomes available
            # in flow engine's storage.
            with flow_utils.DynamicLogListener(flow_engine, logger=LOG):
                flow_engine.run()

        try:
            _run_flow()
        except Exception as e:
            with excutils.save_and_reraise_exception():
                server.power_state = states.NOSTATE
                utils.process_event(fsm, server, event='error')
                self._rollback_servers_quota(context, -1)
                LOG.error("Created server %(uuid)s failed."
                          "Exception: %(exception)s",
                          {"uuid": server.uuid,
                           "exception": e})
        else:
            # Advance the state model for the given event. Note that this
            # doesn't alter the server in any way. This may raise
            # InvalidState, if this event is not allowed in the current state.
            server.power_state = self.driver.get_power_state(context,
                                                             server.uuid)
            server.launched_at = timeutils.utcnow()
            utils.process_event(fsm, server, event='done')
            LOG.info("Created server %s successfully.", server.uuid)
Exemplo n.º 7
0
        def _wait_for_provision_state():
            try:
                node = self._validate_server_and_node(server)
            except exception.ServerNotFound:
                LOG.debug("Server already removed from Ironic", server=server)
                raise loopingcall.LoopingCallDone()
            if node.provision_state in (ironic_states.NOSTATE,
                                        ironic_states.CLEANING,
                                        ironic_states.CLEANWAIT,
                                        ironic_states.CLEANFAIL,
                                        ironic_states.AVAILABLE):
                # From a user standpoint, the node is unprovisioned. If a node
                # gets into CLEANFAIL state, it must be fixed in Ironic, but we
                # can consider the server unprovisioned.
                LOG.debug(
                    "Ironic node %(node)s is in state %(state)s, "
                    "server is now unprovisioned.",
                    dict(node=node.uuid, state=node.provision_state),
                    server=server)
                raise loopingcall.LoopingCallDone()

            if data['tries'] >= CONF.ironic.api_max_retries + 1:
                msg = (_("Error destroying the server on node %(node)s. "
                         "Provision state still '%(state)s'.") % {
                             'state': node.provision_state,
                             'node': node.uuid
                         })
                LOG.error(msg)
                raise exception.MoganException(msg)
            else:
                data['tries'] += 1

            _log_ironic_polling('unprovision', node, server)
Exemplo n.º 8
0
 def validate(value):
     try:
         json.dumps(value)
     except TypeError:
         raise exception.Invalid(_('%s is not JSON serializable') % value)
     else:
         return value
Exemplo n.º 9
0
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
Exemplo n.º 10
0
    def post(self, aggregate_uuid, node):
        """Add node to the given aggregate."""
        validation.check_schema(node, agg_schema.add_aggregate_node)

        node = node['node']
        # check whether the node is already in another az
        db_aggregate = objects.Aggregate.get(pecan.request.context,
                                             aggregate_uuid)
        if 'availability_zone' in db_aggregate['metadata']:
            node_aggs = pecan.request.engine_api.list_node_aggregates(
                pecan.request.context, node)
            aggregates = objects.AggregateList.get_by_metadata_key(
                pecan.request.context, 'availability_zone')
            agg_az = db_aggregate.metadata['availability_zone']
            conflict_azs = [
                agg.metadata['availability_zone'] for agg in aggregates
                if agg.uuid in node_aggs['aggregates']
                and agg.metadata['availability_zone'] != agg_az
            ]
            if conflict_azs:
                msg = _("Node %(node)s is already in availability zone(s) "
                        "%(az)s") % {
                            "node": node,
                            "az": conflict_azs
                        }
                raise wsme.exc.ClientSideError(
                    msg, status_code=http_client.BAD_REQUEST)

        pecan.request.engine_api.add_aggregate_node(pecan.request.context,
                                                    aggregate_uuid, node)
Exemplo n.º 11
0
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)
Exemplo n.º 12
0
    def _check_metadata_conflicts(self, aggregate_uuid, key, value):
        """Check if metadata conflict with the given key"""

        nodes = pecan.request.engine_api.list_aggregate_nodes(
            pecan.request.context, aggregate_uuid)
        aggregates = objects.AggregateList.get_by_metadata_key(
            pecan.request.context, key)
        filtered_aggs = []
        for agg in aggregates:
            agg_nodes = \
                pecan.request.engine_api.list_aggregate_nodes(
                    pecan.request.context, agg.uuid)
            for node in agg_nodes['nodes']:
                if node in nodes['nodes']:
                    filtered_aggs.append(agg)
                    break

        conflicts = [agg.metadata[key] for agg in filtered_aggs
                     if agg.metadata[key] != value and
                     agg.uuid != aggregate_uuid]
        if conflicts:
            msg = _("One or more nodes already in different "
                    "%(key)s(s) %(conflicts)s") % {"key": key,
                                                   "conflicts": conflicts}
            raise wsme.exc.ClientSideError(
                msg, status_code=http_client.BAD_REQUEST)
Exemplo n.º 13
0
    def rebuild(self, context, server):
        """Rebuild/redeploy a server.

        :param context: The security context.
        :param server: The server object.
        """
        LOG.debug('Rebuild called for server', server=server)

        node_uuid = server.node_uuid
        node = self._get_node(node_uuid)
        self._add_server_info_to_node(node, server)

        # trigger the node rebuild
        try:
            self.ironicclient.call("node.set_provision_state", node_uuid,
                                   ironic_states.REBUILD)
        except (ironic_exc.InternalServerError, ironic_exc.BadRequest) as e:
            msg = (_("Failed to request Ironic to rebuild server "
                     "%(server)s: %(reason)s") % {
                         'server': server.uuid,
                         'reason': six.text_type(e)
                     })
            raise exception.ServerDeployFailure(msg)

        # Although the target provision state is REBUILD, it will actually go
        # to ACTIVE once the redeploy is finished.
        timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_active,
                                                     server)
        timer.start(interval=CONF.ironic.api_retry_interval).wait()
        LOG.info('Server was successfully rebuilt', server=server)
Exemplo n.º 14
0
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))
Exemplo n.º 15
0
    def _validate_target_state(self, target):
        """Validate the target state.

        A target state must be a valid state that is 'stable'.

        :param target: The target state
        :raises exception.InvalidState: if it is an invalid target state
        """
        if target is None:
            return

        if target not in self._states:
            raise excp.InvalidState(
                _("Target state '%s' does not exist") % target)
        if not self.is_stable(target):
            raise excp.InvalidState(
                _("Target state '%s' is not a 'stable' state") % target)
Exemplo n.º 16
0
    def _choose_nodes(self, filtered_nodes, request_spec):
        num_servers = request_spec['num_servers']
        if num_servers > len(filtered_nodes):
            msg = 'Not enough nodes found for servers, request ' \
                  'servers: %s, but only available nodes: %s' \
                  % (str(num_servers), str(len(filtered_nodes)))
            raise exception.NoValidNode(_("Choose Node: %s") % msg)

        return filtered_nodes[:num_servers]
Exemplo n.º 17
0
 def quota_update(self, context, project_id, resource_name, updates):
     if 'resource_name' in updates or 'project_id' in updates:
         msg = _("Cannot overwrite resource_name/project_id for "
                 "an existing Quota.")
         raise exception.InvalidParameterValue(err=msg)
     try:
         return self._do_update_quota(context, project_id, resource_name,
                                      updates)
     except db_exc.DBDuplicateEntry:
         pass
Exemplo n.º 18
0
    def server_update(self, context, server_id, values):
        if 'uuid' in values:
            msg = _("Cannot overwrite UUID for an existing Server.")
            raise exception.InvalidParameterValue(err=msg)

        try:
            return self._do_update_server(context, server_id, values)
        except db_exc.DBDuplicateEntry as e:
            if 'name' in e.columns:
                raise exception.DuplicateName(name=values['name'])
Exemplo n.º 19
0
    def validate(patch):
        _path = '/' + patch.path.split('/')[1]
        if _path in patch.internal_attrs():
            msg = _("'%s' is an internal attribute and can not be updated")
            raise wsme.exc.ClientSideError(msg % patch.path)

        if patch.path in patch.non_removable_attrs() and patch.op == 'remove':
            msg = _("'%s' is a mandatory attribute and can not be removed")
            raise wsme.exc.ClientSideError(msg % patch.path)

        if patch.op != 'remove':
            if patch.value is wsme.Unset:
                msg = _("'add' and 'replace' operations need a value")
                raise wsme.exc.ClientSideError(msg)

        ret = {'path': patch.path, 'op': patch.op}
        if patch.value is not wsme.Unset:
            ret['value'] = patch.value
        return ret
Exemplo n.º 20
0
def get_session(group):
    auth = mogan_auth.load_auth(CONF, group) or _get_legacy_auth()
    if not auth:
        msg = _("Failed to load auth from either [%(new)s] or [%(old)s] "
                "config sections.")
        raise exception.ConfigInvalid(message=msg,
                                      new=group,
                                      old=mogan_auth.LEGACY_SECTION)
    session = kaloading.load_session_from_conf_options(CONF, group, auth=auth)
    return session
Exemplo n.º 21
0
def main():
    command_opt = cfg.SubCommandOpt('command',
                                    title='Command',
                                    help=_('Available commands'),
                                    handler=add_command_parsers)

    CONF.register_cli_opt(command_opt)

    service.prepare_service(sys.argv)
    CONF.command.func()
Exemplo n.º 22
0
class MoganException(Exception):
    """Base Mogan Exception

    To correctly use this class, inherit from it and define
    a '_msg_fmt' property. That message will get printf'd
    with the keyword arguments provided to the constructor.

    If you need to access the message from an exception you should use
    six.text_type(exc)

    """
    _msg_fmt = _("An unknown exception occurred.")
    code = http_client.INTERNAL_SERVER_ERROR
    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:
                pass

        if not message:
            try:
                message = self._msg_fmt % kwargs

            except Exception:
                # kwargs doesn't match a variable in self._msg_fmt
                # log the issue and the kwargs
                LOG.exception('Exception in string format operation')
                for name, value in kwargs.items():
                    LOG.error("%s: %s" % (name, value))

                if CONF.fatal_exception_format_errors:
                    raise
                else:
                    # at least get the core self._msg_fmt out if something
                    # happened
                    message = self._msg_fmt

        super(MoganException, self).__init__(message)

    def __str__(self):
        """Encode to utf-8 then wsme api can consume it as well."""
        if not six.PY3:
            return unicode(self.args[0]).encode('utf-8')

        return self.args[0]

    def __unicode__(self):
        """Return a unicode representation of the exception message."""
        return unicode(self.args[0])
Exemplo n.º 23
0
    def post(self, server):
        """Create a new server.

        :param server: a server within the request body.
        """
        validation.check_schema(server, server_schemas.create_server)
        scheduler_hints = server.get('scheduler_hints', {})
        server = server.get('server')

        min_count = server.get('min_count', 1)
        max_count = server.get('max_count', min_count)

        if min_count > max_count:
            msg = _('min_count must be <= max_count')
            raise wsme.exc.ClientSideError(msg,
                                           status_code=http_client.BAD_REQUEST)

        requested_networks = server.pop('networks', None)
        flavor_uuid = server.get('flavor_uuid')
        image_uuid = server.get('image_uuid')
        user_data = server.get('user_data')
        key_name = server.get('key_name')
        partitions = server.get('partitions')
        personality = server.pop('personality', None)

        password = self._get_server_admin_password(server)

        injected_files = []
        if personality:
            for item in personality:
                injected_files.append((item['path'], item['contents']))

        flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
        if flavor.disabled:
            raise exception.FlavorDisabled(flavor_id=flavor.uuid)
        servers = pecan.request.engine_api.create(
            pecan.request.context,
            flavor,
            image_uuid=image_uuid,
            name=server.get('name'),
            description=server.get('description'),
            availability_zone=server.get('availability_zone'),
            metadata=server.get('metadata'),
            requested_networks=requested_networks,
            user_data=user_data,
            injected_files=injected_files,
            admin_password=password,
            key_name=key_name,
            min_count=min_count,
            max_count=max_count,
            partitions=partitions,
            scheduler_hints=scheduler_hints)
        # Set the HTTP Location Header for the first server.
        pecan.response.location = link.build_url('server', servers[0].uuid)
        return Server.convert_with_links(servers[0])
Exemplo n.º 24
0
    def is_stable(self, state):
        """Is the state stable?

        :param state: the state of interest
        :raises InvalidState: if the state is invalid
        :returns: True if it is a stable state; False otherwise
        """
        try:
            return self._states[state]['stable']
        except KeyError:
            raise excp.InvalidState(_("State '%s' does not exist") % state)
Exemplo n.º 25
0
    def aggregate_update(self, context, aggregate_id, values):
        if 'uuid' in values:
            msg = _("Cannot overwrite UUID for an existing aggregate.")
            raise exception.InvalidParameterValue(err=msg)

        try:
            result = self._do_update_aggregate(context, aggregate_id, values)
        except db_exc.DBDuplicateEntry as e:
            if 'name' in e.columns:
                raise exception.DuplicateName(name=values['name'])
        return result
Exemplo n.º 26
0
    def post(self, flavor_uuid, tenant):
        """Add flavor access for the given tenant."""
        validation.check_schema(tenant, flavor_access.add_tenant_access)

        flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
        if flavor.is_public:
            msg = _("Can not add access to a public flavor.")
            raise wsme.exc.ClientSideError(msg,
                                           status_code=http_client.CONFLICT)

        flavor.projects.append(tenant['tenant_id'])
        flavor.save()
Exemplo n.º 27
0
    def get_all(self, flavor_uuid):
        """Retrieve a list of extra specs of the queried flavor."""

        flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)

        # public flavor to all projects
        if flavor.is_public:
            msg = _("Access list not available for public flavors.")
            raise wsme.exc.ClientSideError(msg,
                                           status_code=http_client.NOT_FOUND)

        # private flavor to listed projects only
        return _marshall_flavor_access(flavor)
Exemplo n.º 28
0
    def wrapper(**kw):
        obj_type = kw.pop('object_type')
        result = func(**kw)

        extra_args = set(kw) - set(result)
        if extra_args:
            raise exception.InvalidParameterValue(
                _("Unknown keyword arguments (%(extra)s) were passed "
                  "while creating a test %(object_type)s object.") %
                {"extra": ", ".join(extra_args),
                 "object_type": obj_type})

        return result
Exemplo n.º 29
0
def generate_x509_fingerprint(pem_key):
    try:
        if isinstance(pem_key, six.text_type):
            pem_key = pem_key.encode('utf-8')
        cert = x509.load_pem_x509_certificate(pem_key,
                                              backends.default_backend())
        raw_fp = binascii.hexlify(cert.fingerprint(hashes.SHA1()))
        if six.PY3:
            raw_fp = raw_fp.decode('ascii')
        return ':'.join(a + b for a, b in zip(raw_fp[::2], raw_fp[1::2]))
    except (ValueError, TypeError, binascii.Error) as ex:
        raise exception.InvalidKeypair(
            reason=_('failed to generate X509 fingerprint. '
                     'Error message: %s') % ex)
Exemplo n.º 30
0
 def _check_aggregates_conflict(self, node, node_aggregates, key, value):
     """Check aggregates conflict with the given key"""
     aggregates = objects.AggregateList.get_by_metadata_key(
         pecan.request.context, key)
     conflicts = [
         agg.metadata[key] for agg in aggregates
         if agg.uuid in node_aggregates and
         agg.metadata[key] != value]
     if conflicts:
         msg = _("Node %(node)s is already in %(key)s(s) "
                 "%(conflicts)s") % {"node": node, "key": key,
                                     "conflicts": conflicts}
         raise wsme.exc.ClientSideError(
             msg, status_code=http_client.BAD_REQUEST)