Пример #1
0
def startup_sanity_check():
    if (not cfg.CONF.stack_user_domain_id
            and not cfg.CONF.stack_user_domain_name):
        # FIXME(shardy): Legacy fallback for folks using old heat.conf
        # files which lack domain configuration
        LOG.warning(
            _LW('stack_user_domain_id or stack_user_domain_name not '
                'set in heat.conf falling back to using default'))
    else:
        domain_admin_user = cfg.CONF.stack_domain_admin
        domain_admin_password = cfg.CONF.stack_domain_admin_password
        if not (domain_admin_user and domain_admin_password):
            raise exception.Error(
                _('heat.conf misconfigured, cannot '
                  'specify "stack_user_domain_id" or '
                  '"stack_user_domain_name" without '
                  '"stack_domain_admin" and '
                  '"stack_domain_admin_password"'))
    auth_key_len = len(cfg.CONF.auth_encryption_key)
    if auth_key_len in (16, 24):
        LOG.warning(
            _LW('Please update auth_encryption_key to be 32 characters.'))
    elif auth_key_len != 32:
        raise exception.Error(
            _('heat.conf misconfigured, auth_encryption_key '
              'must be 32 characters'))
Пример #2
0
    def handle_resume(self):
        """Resume an instance.

        Note we do not wait for the ACTIVE state, this is polled for by
        check_resume_complete in a similar way to the create logic so we can
        take advantage of coroutines.
        """
        if self.resource_id is None:
            raise exception.Error(
                _('Cannot resume %s, resource_id not set') % self.name)

        try:
            server = self.client().servers.get(self.resource_id)
        except Exception as e:
            if self.client_plugin().is_not_found(e):
                raise exception.NotFound(
                    _('Failed to find instance %s') % self.resource_id)
            else:
                raise
        else:
            # if the instance has been resumed successful,
            # no need to resume again
            if self.client_plugin().get_status(server) != 'ACTIVE':
                LOG.debug("resuming instance %s" % self.resource_id)
                server.resume()
            return server.id
Пример #3
0
    def create_stack_user(self, username, password=''):
        """Create a user defined as part of a stack.

        The user is defined either via template or created internally by a
        resource.  This user will be added to the heat_stack_user_role as
        defined in the config.

        Returns the keystone ID of the resulting user.
        """
        # FIXME(shardy): There's duplicated logic between here and
        # create_stack_domain user, but this function is expected to
        # be removed after the transition of all resources to domain
        # users has been completed
        stack_user_role = self.client.roles.list(
            name=cfg.CONF.heat_stack_user_role)
        if len(stack_user_role) == 1:
            role_id = stack_user_role[0].id
            # Create the user
            user = self.client.users.create(
                name=self._get_username(username), password=password,
                default_project=self.context.tenant_id)
            # Add user to heat_stack_user_role
            LOG.debug("Adding user %(user)s to role %(role)s" % {
                      'user': user.id, 'role': role_id})
            self.client.roles.grant(role=role_id, user=user.id,
                                    project=self.context.tenant_id)
        else:
            LOG.error(_LE("Failed to add user %(user)s to role %(role)s, "
                          "check role exists!"), {
                      'user': username,
                      'role': cfg.CONF.heat_stack_user_role})
            raise exception.Error(_("Can't find role %s")
                                  % cfg.CONF.heat_stack_user_role)

        return user.id
Пример #4
0
def reload_loadbalancers(group, load_balancers, exclude=None):
    """Notify the LoadBalancer to reload its config.

    This must be done after activation (instance in ACTIVE state), otherwise
    the instances' IP addresses may not be available.
    """
    exclude = exclude or []
    id_list = grouputils.get_member_refids(group, exclude=exclude)
    for name, lb in six.iteritems(load_balancers):
        props = copy.copy(lb.properties.data)
        if 'Instances' in lb.properties_schema:
            props['Instances'] = id_list
        elif 'members' in lb.properties_schema:
            props['members'] = id_list
        else:
            raise exception.Error(
                _("Unsupported resource '%s' in LoadBalancerNames") % name)

        lb_defn = rsrc_defn.ResourceDefinition(
            lb.name,
            lb.type(),
            properties=props,
            metadata=lb.t.metadata(),
            deletion_policy=lb.t.deletion_policy())

        scheduler.TaskRunner(lb.update, lb_defn)()
Пример #5
0
 def handle_resume(self):
     stack = self.nested()
     if stack is None:
         raise exception.Error(
             _('Cannot resume %s, stack not created') % self.name)
     stack_identity = identifier.HeatIdentifier(
         self.context.tenant_id, self.physical_resource_name(),
         self.resource_id)
     self.rpc_client().stack_resume(self.context, dict(stack_identity))
Пример #6
0
 def _check_complete(self):
     sd = self.rpc_client().check_software_deployment(
         self.context, self.resource_id, self.stack.time_remaining())
     status = sd[rpc_api.SOFTWARE_DEPLOYMENT_STATUS]
     if status == SoftwareDeployment.COMPLETE:
         return True
     elif status == SoftwareDeployment.FAILED:
         status_reason = sd[rpc_api.SOFTWARE_DEPLOYMENT_STATUS_REASON]
         message = _("Deployment to server failed: %s") % status_reason
         LOG.info(message)
         raise exception.Error(message)
Пример #7
0
 def get_external_network_id(client):
     ext_filter = {'router:external': True}
     ext_nets = client.list_networks(**ext_filter)['networks']
     if len(ext_nets) != 1:
         # TODO(sbaker) if there is more than one external network
         # add a heat configuration variable to set the ID of
         # the default one
         raise exception.Error(
             _('Expected 1 external network, found %d') % len(ext_nets))
     external_network_id = ext_nets[0]['id']
     return external_network_id
Пример #8
0
 def detach_volume(self, server_id, attach_id):
     # detach the volume using volume_attachment
     try:
         self.client().volumes.delete_server_volume(server_id, attach_id)
     except Exception as ex:
         if not (self.is_not_found(ex) or self.is_bad_request(ex)):
             raise exception.Error(
                 _("Could not detach attachment %(att)s "
                   "from server %(srv)s.") % {
                       'srv': server_id,
                       'att': attach_id
                   })
Пример #9
0
    def check_rebuild(self, server_id):
        """Verify that a rebuilding server is rebuilt.

        Raise error if it ends up in an ERROR state.
        """
        server = self.fetch_server(server_id)
        if server is None or server.status == 'REBUILD':
            return False
        if server.status == 'ERROR':
            raise exception.Error(
                _("Rebuilding server failed, status '%s'") % server.status)
        else:
            return True
Пример #10
0
 def router_for_vpc(client, network_id):
     # first get the neutron net
     net = VPC.network_for_vpc(client, network_id)
     # then find a router with the same name
     routers = client.list_routers(name=net['name'])['routers']
     if len(routers) == 0:
         # There may be no router if the net was created manually
         # instead of in another stack.
         return None
     if len(routers) > 1:
         raise exception.Error(
             _('Multiple routers found with name %s') % net['name'])
     return routers[0]
Пример #11
0
    def _service_swift_signal(self):
        swift_client = self.client('swift')
        try:
            container = swift_client.get_container(self.stack.id)
        except Exception as exc:
            self.client_plugin('swift').ignore_not_found(exc)
            LOG.debug("Swift container %s was not found" % self.stack.id)
            return

        index = container[1]
        if not index:  # Swift objects were deleted by user
            LOG.debug("Swift objects in container %s were not found" %
                      self.stack.id)
            return

        # Remove objects that are for other resources, given that
        # multiple swift signals in the same stack share a container
        object_name = self.physical_resource_name()
        filtered = [obj for obj in index if object_name in obj['name']]

        # Fetch objects from Swift and filter results
        signal_names = []
        for obj in filtered:
            try:
                signal = swift_client.get_object(self.stack.id, obj['name'])
            except Exception as exc:
                self.client_plugin('swift').ignore_not_found(exc)
                continue

            body = signal[1]
            if body == swift.IN_PROGRESS:  # Ignore the initial object
                continue
            signal_names.append(obj['name'])

            if body == "":
                self.signal(details={})
                continue
            try:
                self.signal(details=jsonutils.loads(body))
            except ValueError:
                raise exception.Error(_("Failed to parse JSON data: %s") %
                                      body)

        # remove the signals that were consumed
        for signal_name in signal_names:
            if signal_name != object_name:
                swift_client.delete_object(self.stack.id, signal_name)
        if object_name in signal_names:
            swift_client.delete_object(self.stack.id, object_name)
Пример #12
0
 def attach_volume(self, server_id, volume_id, device):
     try:
         va = self.client().volumes.create_server_volume(
             server_id=server_id, volume_id=volume_id, device=device)
     except Exception as ex:
         if self.is_client_exception(ex):
             raise exception.Error(
                 _("Failed to attach volume %(vol)s to server %(srv)s "
                   "- %(err)s") % {
                       'vol': volume_id,
                       'srv': server_id,
                       'err': ex
                   })
         else:
             raise
     return va.id
Пример #13
0
    def check_resize(self, server_id, flavor):
        """Verify that a resizing server is properly resized.

        If that's the case, confirm the resize, if not raise an error.
        """
        server = self.fetch_server(server_id)
        # resize operation is asynchronous so the server resize may not start
        # when checking server status (the server may stay ACTIVE instead
        # of RESIZE).
        if not server or server.status in ('RESIZE', 'ACTIVE'):
            return False
        if server.status == 'VERIFY_RESIZE':
            return True
        else:
            raise exception.Error(
                _("Resizing to '%(flavor)s' failed, status '%(status)s'") %
                dict(flavor=flavor, status=server.status))
Пример #14
0
 def handle_create(self):
     router_id = self.properties.get(self.ROUTER_ID)
     routes = self.client().show_router(
         router_id).get('router').get('routes')
     if not routes:
         routes = []
     new_route = {'destination': self.properties[self.DESTINATION],
                  'nexthop': self.properties[self.NEXTHOP]}
     if new_route in routes:
         msg = _('Route duplicates an existing route.')
         raise exception.Error(msg)
     routes.append(new_route)
     self.client().update_router(router_id,
                                 {'router': {'routes': routes}})
     new_route['router_id'] = router_id
     self.resource_id_set(
         '%(router_id)s:%(destination)s:%(nexthop)s' % new_route)
Пример #15
0
    def _create(self):
        con = self.context

        volume_api_version = self.get_volume_api_version()
        if cfg.CONF.FusionSphere.pubcloud:
            service_type = self.EVS
            client_version = '2'
        elif volume_api_version == 1:
            service_type = self.VOLUME
            client_version = '1'
        elif volume_api_version == 2:
            service_type = self.VOLUME_V2
            client_version = '2'
        else:
            raise exception.Error(_('No volume service available.'))
        LOG.info(_LI('Creating Cinder client with volume API version %d.'),
                 volume_api_version)

        endpoint_type = self._get_client_option(CLIENT_NAME, 'endpoint_type')
        args = {
            'service_type': service_type,
            'auth_url': con.auth_url or '',
            'project_id': con.tenant_id,
            'username': None,
            'api_key': None,
            'endpoint_type': endpoint_type,
            'http_log_debug': self._get_client_option(CLIENT_NAME,
                                                      'http_log_debug'),
            'cacert': self._get_client_option(CLIENT_NAME, 'ca_file'),
            'insecure': self._get_client_option(CLIENT_NAME, 'insecure'),
            'timeout': self._get_client_option(CLIENT_NAME, 'timeout')
        }

        client = cc.Client(client_version, **args)
        management_url = self.url_for(service_type=service_type,
                                      endpoint_type=endpoint_type)
        client.client.auth_token = self.auth_token
        client.client.management_url = management_url

        if cfg.CONF.FusionSphere.pubcloud:
            client.volume_api_version = 2
        else:
            client.volume_api_version = volume_api_version

        return client
Пример #16
0
    def _delete_volume(self):
        """Call the volume delete API.

        Returns False if further checking of volume status is required,
        True otherwise.
        """
        try:
            cinder = self.client()
            vol = cinder.volumes.get(self.resource_id)
            if vol.status == 'in-use':
                raise exception.Error(_('Volume in use'))
            # if the volume is already in deleting status,
            # just wait for the deletion to complete
            if vol.status != 'deleting':
                cinder.volumes.delete(self.resource_id)
            return False
        except Exception as ex:
            self.client_plugin().ignore_not_found(ex)
            return True
Пример #17
0
    def stack_domain_user_token(self, user_id, project_id, password):
        """Get a token for a stack domain user."""
        if not self.stack_domain:
            # Note, no legacy fallback path as we don't want to deploy
            # tokens for non stack-domain users inside instances
            msg = _('Cannot get stack domain user token, no stack domain id '
                    'configured, please fix your heat.conf')
            raise exception.Error(msg)

        # Create a keystoneclient session, then request a token with no
        # catalog (the token is expected to be used inside an instance
        # where a specific endpoint will be specified, and user-data
        # space is limited..)
        auth = kc_auth_v3.Password(auth_url=self.v3_endpoint,
                                   user_id=user_id,
                                   password=password,
                                   project_id=project_id,
                                   include_catalog=False)

        return auth.get_token(self.session)
Пример #18
0
    def create_stack_domain_user(self, username, project_id, password=None):
        """Create a domain user defined as part of a stack.

        The user is defined either via template or created internally by a
        resource.  This user will be added to the heat_stack_user_role as
        defined in the config, and created in the specified project (which is
        expected to be in the stack_domain).

        Returns the keystone ID of the resulting user.
        """
        if not self.stack_domain:
            # FIXME(shardy): Legacy fallback for folks using old heat.conf
            # files which lack domain configuration
            return self.create_stack_user(username=username, password=password)
        # We add the new user to a special keystone role
        # This role is designed to allow easier differentiation of the
        # heat-generated "stack users" which will generally have credentials
        # deployed on an instance (hence are implicitly untrusted)
        stack_user_role = self.domain_admin_client.roles.list(
            name=cfg.CONF.heat_stack_user_role)
        if len(stack_user_role) == 1:
            role_id = stack_user_role[0].id
            # Create user
            user = self.domain_admin_client.users.create(
                name=self._get_username(username), password=password,
                default_project=project_id, domain=self.stack_domain_id)
            # Add to stack user role
            LOG.debug("Adding user %(user)s to role %(role)s" % {
                      'user': user.id, 'role': role_id})
            self.domain_admin_client.roles.grant(role=role_id, user=user.id,
                                                 project=project_id)
        else:
            LOG.error(_LE("Failed to add user %(user)s to role %(role)s, "
                          "check role exists!"),
                      {'user': username,
                       'role': cfg.CONF.heat_stack_user_role})
            raise exception.Error(_("Can't find role %s")
                                  % cfg.CONF.heat_stack_user_role)

        return user.id
Пример #19
0
    def check_create_complete(self, create_data):
        if timeutils.is_older_than(*create_data):
            raise SwiftSignalTimeout(self)

        statuses = self.get_status()
        if not statuses:
            return False

        for status in statuses:
            if status == self.STATUS_FAILURE:
                failure = SwiftSignalFailure(self)
                LOG.info(_LI('%(name)s Failed (%(failure)s)'), {
                    'name': str(self),
                    'failure': str(failure)
                })
                raise failure
            elif status != self.STATUS_SUCCESS:
                raise exception.Error(_("Unknown status: %s") % status)

        if len(statuses) >= self.properties[self.COUNT]:
            LOG.info(_LI("%s Succeeded"), str(self))
            return True
        return False
Пример #20
0
    def _create_keypair(self):
        # Subclasses may optionally call this in handle_create to create
        # an ec2 keypair associated with the user, the resulting keys are
        # stored in resource_data
        if self.data().get('credential_id'):
            return  # a keypair was created already

        user_id = self._get_user_id()
        kp = self.keystone().create_stack_domain_user_keypair(
            user_id=user_id, project_id=self.stack.stack_user_project_id)
        if not kp:
            raise exception.Error(
                _("Error creating ec2 keypair for user %s") % user_id)
        else:
            try:
                credential_id = kp.id
            except AttributeError:
                # keystone v2 keypairs do not have an id attribute. Use the
                # access key instead.
                credential_id = kp.access
            self.data_set('credential_id', credential_id, redact=True)
            self.data_set('access_key', kp.access, redact=True)
            self.data_set('secret_key', kp.secret, redact=True)
        return kp
Пример #21
0
    def get_image_id_by_name(self, image_identifier):
        """Return the ID for the specified image name.

        :param image_identifier: image name
        :returns: the id of the requested :image_identifier:
        :raises: exception.EntityNotFound,
                 exception.PhysicalResourceNameAmbiguity
        """
        try:
            filters = {'name': image_identifier}
            image_list = self.client().images.find(**filters)
        except sahara_base.APIException as ex:
            raise exception.Error(
                _("Error retrieving image list from sahara: "
                  "%s") % six.text_type(ex))
        num_matches = len(image_list)
        if num_matches == 0:
            raise exception.EntityNotFound(entity='Image',
                                           name=image_identifier)
        elif num_matches > 1:
            raise exception.PhysicalResourceNameAmbiguity(
                name=image_identifier)
        else:
            return image_list[0].id
Пример #22
0
    def get_signals(self):
        try:
            container = self.client().get_container(self.stack.id)
        except Exception as exc:
            self.client_plugin().ignore_not_found(exc)
            LOG.debug("Swift container %s was not found" % self.stack.id)
            return []

        index = container[1]
        if not index:
            LOG.debug("Swift objects in container %s were not found" %
                      self.stack.id)
            return []

        # Remove objects in that are for other handle resources, since
        # multiple SwiftSignalHandle resources in the same stack share
        # a container
        filtered = [obj for obj in index if self.obj_name in obj['name']]

        # Fetch objects from Swift and filter results
        obj_bodies = []
        for obj in filtered:
            try:
                signal = self.client().get_object(self.stack.id, obj['name'])
            except Exception as exc:
                self.client_plugin().ignore_not_found(exc)
                continue

            body = signal[1]
            if body == swift.IN_PROGRESS:  # Ignore the initial object
                continue
            if body == "":
                obj_bodies.append({})
                continue
            try:
                obj_bodies.append(jsonutils.loads(body))
            except ValueError:
                raise exception.Error(
                    _("Failed to parse JSON data: %s") % body)

        # Set default values on each signal
        signals = []
        signal_num = 1
        for signal in obj_bodies:

            # Remove previous signals with the same ID
            sig_id = self.UNIQUE_ID
            ids = [s.get(sig_id) for s in signals if sig_id in s]
            if ids and sig_id in signal and ids.count(signal[sig_id]) > 0:
                [
                    signals.remove(s) for s in signals
                    if s.get(sig_id) == signal[sig_id]
                ]

            # Make sure all fields are set, since all are optional
            signal.setdefault(self.DATA, None)
            unique_id = signal.setdefault(sig_id, signal_num)
            reason = 'Signal %s received' % unique_id
            signal.setdefault(self.REASON, reason)
            signal.setdefault(self.STATUS, self.STATUS_SUCCESS)

            signals.append(signal)
            signal_num += 1

        return signals
Пример #23
0
 def handle_check(self):
     server = self.client().servers.get(self.resource_id)
     if not self.client_plugin()._check_active(server, 'Instance'):
         raise exception.Error(
             _("Instance is not ACTIVE (was: %s)") % server.status.strip())
Пример #24
0
 def handle_suspend(self):
     if self.resource_id is None:
         raise exception.Error(
             _('Cannot suspend %s, resource not found') % self.name)
     self.heat().actions.suspend(stack_id=self.resource_id)