Ejemplo n.º 1
0
    def validate_template(self, req):
        """
        Implements the ValidateTemplate API action
        Validates the specified template
        """

        con = req.context
        parms = dict(req.params)

        try:
            templ = self._get_template(req)
        except socket.gaierror:
            msg = _('Invalid Template URL')
            return exception.HeatInvalidParameterValueError(detail=msg)
        if templ is None:
            msg = _("TemplateBody or TemplateUrl were not given.")
            return exception.HeatMissingParameterError(detail=msg)

        try:
            template = json.loads(templ)
        except ValueError:
            msg = _("The Template must be a JSON document.")
            return exception.HeatInvalidParameterValueError(detail=msg)

        logger.info('validate_template')
        try:
            return self.engine_rpcapi.validate_template(con, template)
        except rpc_common.RemoteError as ex:
            return exception.map_remote_error(ex)
Ejemplo n.º 2
0
    def validate_template(self, req):
        """
        Implements the ValidateTemplate API action
        Validates the specified template
        """
        self._enforce(req, 'ValidateTemplate')

        con = req.context
        try:
            templ = self._get_template(req)
        except socket.gaierror:
            msg = _('Invalid Template URL')
            return exception.HeatInvalidParameterValueError(detail=msg)
        if templ is None:
            msg = _("TemplateBody or TemplateUrl were not given.")
            return exception.HeatMissingParameterError(detail=msg)

        try:
            template = template_format.parse(templ)
        except ValueError:
            msg = _("The Template must be a JSON or YAML document.")
            return exception.HeatInvalidParameterValueError(detail=msg)

        logger.info('validate_template')

        def format_validate_parameter(key, value):
            """
            Reformat engine output into the AWS "ValidateTemplate" format
            """

            return {
                'ParameterKey': key,
                'DefaultValue': value.get(engine_api.PARAM_DEFAULT, ''),
                'Description': value.get(engine_api.PARAM_DESCRIPTION, ''),
                'NoEcho': value.get(engine_api.PARAM_NO_ECHO, 'false')
            }

        try:
            res = self.engine_rpcapi.validate_template(con, template)
            if 'Error' in res:
                return api_utils.format_response('ValidateTemplate',
                                                 res['Error'])

            res['Parameters'] = [
                format_validate_parameter(k, v)
                for k, v in res['Parameters'].items()
            ]
            return api_utils.format_response('ValidateTemplate', res)
        except Exception as ex:
            return exception.map_remote_error(ex)
Ejemplo n.º 3
0
    def set_alarm_state(self, req):
        """
        Implements SetAlarmState API action
        """
        self._enforce(req, 'SetAlarmState')

        # Map from AWS state names to those used in the engine
        state_map = {'OK': engine_api.WATCH_STATE_OK,
                     'ALARM': engine_api.WATCH_STATE_ALARM,
                     'INSUFFICIENT_DATA': engine_api.WATCH_STATE_NODATA}

        con = req.context
        parms = dict(req.params)

        # Get mandatory parameters
        name = api_utils.get_param_value(parms, 'AlarmName')
        state = api_utils.get_param_value(parms, 'StateValue')

        if state not in state_map:
            msg = _('Invalid state %(state)s, '
                    'expecting one of %(expect)s') % {
                        'state': state,
                        'expect': state_map.keys()}
            logger.error(msg)
            return exception.HeatInvalidParameterValueError(msg)

        logger.debug("setting %(name)s to %(state)s" % {
                     'name': name, 'state': state_map[state]})
        try:
            self.rpc_client.set_watch_state(con, watch_name=name,
                                            state=state_map[state])
        except rpc_common.RemoteError as ex:
            return exception.map_remote_error(ex)

        return api_utils.format_response("SetAlarmState", "")
Ejemplo n.º 4
0
    def set_alarm_state(self, req):
        """
        Implements SetAlarmState API action
        """
        self._enforce(req, 'SetAlarmState')

        # Map from AWS state names to those used in the engine
        state_map = {
            'OK': engine_api.WATCH_STATE_OK,
            'ALARM': engine_api.WATCH_STATE_ALARM,
            'INSUFFICIENT_DATA': engine_api.WATCH_STATE_NODATA
        }

        con = req.context
        parms = dict(req.params)

        # Get mandatory parameters
        name = api_utils.get_param_value(parms, 'AlarmName')
        state = api_utils.get_param_value(parms, 'StateValue')

        if state not in state_map:
            msg = _('Invalid state %(state)s, '
                    'expecting one of %(expect)s') % {
                        'state': state,
                        'expect': state_map.keys()
                    }
            logger.error(msg)
            return exception.HeatInvalidParameterValueError(msg)

        # Check for optional parameters
        # FIXME : We don't actually do anything with these in the engine yet..
        state_reason = None
        state_reason_data = None
        if 'StateReason' in parms:
            state_reason = parms['StateReason']
        if 'StateReasonData' in parms:
            state_reason_data = parms['StateReasonData']

        logger.debug(
            _("setting %(name)s to %(state)s") % {
                'name': name,
                'state': state_map[state]
            })
        try:
            self.engine_rpcapi.set_watch_state(con,
                                               watch_name=name,
                                               state=state_map[state])
        except rpc_common.RemoteError as ex:
            return exception.map_remote_error(ex)

        return api_utils.format_response("SetAlarmState", "")
Ejemplo n.º 5
0
    def _get_template(self, req):
        """
        Get template file contents, either from local file or URL
        """
        if 'TemplateBody' in req.params:
            logger.info('TemplateBody ...')
            return req.params['TemplateBody']
        elif 'TemplateUrl' in req.params:
            logger.info('TemplateUrl %s' % req.params['TemplateUrl'])
            url = urlparse.urlparse(req.params['TemplateUrl'])
            if url.scheme == 'https':
                conn = httplib.HTTPSConnection(url.netloc)
            else:
                conn = httplib.HTTPConnection(url.netloc)

            try:
                conn.request("GET", url.path)
            except Exception as e:
                if e.errno == errno.ECONNREFUSED:
                    msg = _('Connection refused to %s' % url.netloc)
                    raise exception.HeatInvalidParameterValueError(detail=msg)
                raise

            r1 = conn.getresponse()
            logger.info('status %d' % r1.status)
            if r1.status == 200:  # OK
                data = r1.read()
                conn.close()
            elif r1.status == 404:  # NOT_FOUND
                msg = _('No match found for %s' % req.params['TemplateUrl'])
                raise exception.HeatInvalidParameterValueError(detail=msg)
            else:
                msg = _('Unexpected error, request returned %d' % r1.status)
                raise exception.HeatInvalidParameterValueError(detail=msg)
            return data

        return None
Ejemplo n.º 6
0
    def _get_template(self, req):
        """Get template file contents, either from local file or URL."""
        if 'TemplateBody' in req.params:
            LOG.debug('TemplateBody ...')
            return req.params['TemplateBody']
        elif 'TemplateUrl' in req.params:
            url = req.params['TemplateUrl']
            LOG.debug('TemplateUrl %s' % url)
            try:
                return urlfetch.get(url)
            except IOError as exc:
                msg = _('Failed to fetch template: %s') % exc
                raise exception.HeatInvalidParameterValueError(detail=msg)

        return None
Ejemplo n.º 7
0
    def get_template(self, req):
        """
        Implements the GetTemplate API action
        Get the template body for an existing stack
        """

        con = req.context
        try:
            identity = self._get_identity(con, req.params['StackName'])
            templ = self.engine_rpcapi.get_template(con, identity)
        except rpc_common.RemoteError as ex:
            return exception.map_remote_error(ex)

        if templ is None:
            msg = _('stack not not found')
            return exception.HeatInvalidParameterValueError(detail=msg)

        return api_utils.format_response('GetTemplate',
                                         {'TemplateBody': templ})
Ejemplo n.º 8
0
    def create_or_update(self, req, action=None):
        """
        Implements CreateStack and UpdateStack API actions.
        Create or update stack as defined in template file.
        """
        def extract_args(params):
            """
            Extract request parameters/arguments and reformat them to match
            the engine API.  FIXME: we currently only support a subset of
            the AWS defined parameters (both here and in the engine)
            """
            # TODO(shardy) : Capabilities, NotificationARNs
            keymap = {'TimeoutInMinutes': engine_api.PARAM_TIMEOUT,
                      'DisableRollback': engine_api.PARAM_DISABLE_ROLLBACK}

            if 'DisableRollback' in params and 'OnFailure' in params:
                msg = _('DisableRollback and OnFailure '
                        'may not be used together')
                raise exception.HeatInvalidParameterCombinationError(
                    detail=msg)

            result = {}
            for k in keymap:
                if k in params:
                    result[keymap[k]] = params[k]

            if 'OnFailure' in params:
                value = params['OnFailure']
                if value == 'DO_NOTHING':
                    result[engine_api.PARAM_DISABLE_ROLLBACK] = 'true'
                elif value in ('ROLLBACK', 'DELETE'):
                    result[engine_api.PARAM_DISABLE_ROLLBACK] = 'false'

            return result

        if action not in self.CREATE_OR_UPDATE_ACTION:
            msg = _("Unexpected action %(action)s") % ({'action': action})
            # This should not happen, so return HeatInternalFailureError
            return exception.HeatInternalFailureError(detail=msg)

        engine_action = {self.CREATE_STACK: self.engine_rpcapi.create_stack,
                         self.UPDATE_STACK: self.engine_rpcapi.update_stack}

        con = req.context

        # Extract the stack input parameters
        stack_parms = self._extract_user_params(req.params)

        # Extract any additional arguments ("Request Parameters")
        create_args = extract_args(req.params)

        try:
            templ = self._get_template(req)
        except socket.gaierror:
            msg = _('Invalid Template URL')
            return exception.HeatInvalidParameterValueError(detail=msg)

        if templ is None:
            msg = _("TemplateBody or TemplateUrl were not given.")
            return exception.HeatMissingParameterError(detail=msg)

        try:
            stack = template_format.parse(templ)
        except ValueError:
            msg = _("The Template must be a JSON or YAML document.")
            return exception.HeatInvalidParameterValueError(detail=msg)

        args = {'template': stack,
                'params': stack_parms,
                'files': {},
                'args': create_args}
        try:
            stack_name = req.params['StackName']
            if action == self.CREATE_STACK:
                args['stack_name'] = stack_name
            else:
                args['stack_identity'] = self._get_identity(con, stack_name)

            result = engine_action[action](con, **args)
        except Exception as ex:
            return exception.map_remote_error(ex)

        try:
            identity = identifier.HeatIdentifier(**result)
        except (ValueError, TypeError):
            response = result
        else:
            response = {'StackId': identity.arn()}

        return api_utils.format_response(action, response)
Ejemplo n.º 9
0
    def create_or_update(self, req, action=None):
        """
        Implements CreateStack and UpdateStack API actions
        Create or update stack as defined in template file
        """
        def extract_args(params):
            """
            Extract request parameters/arguments and reformat them to match
            the engine API.  FIXME: we currently only support a subset of
            the AWS defined parameters (both here and in the engine)
            """
            # TODO : Capabilities, DisableRollback, NotificationARNs
            keymap = {'TimeoutInMinutes': engine_api.PARAM_TIMEOUT, }

            result = {}
            for k in keymap:
                if k in req.params:
                    result[keymap[k]] = params[k]

            return result

        if action not in self.CREATE_OR_UPDATE_ACTION:
            msg = _("Unexpected action %s" % action)
            # This should not happen, so return HeatInternalFailureError
            return exception.HeatInternalFailureError(detail=msg)

        engine_action = {self.CREATE_STACK: self.engine_rpcapi.create_stack,
                         self.UPDATE_STACK: self.engine_rpcapi.update_stack}

        con = req.context

        # Extract the stack input parameters
        stack_parms = self._extract_user_params(req.params)

        # Extract any additional arguments ("Request Parameters")
        create_args = extract_args(req.params)

        try:
            templ = self._get_template(req)
        except socket.gaierror:
            msg = _('Invalid Template URL')
            return exception.HeatInvalidParameterValueError(detail=msg)

        if templ is None:
            msg = _("TemplateBody or TemplateUrl were not given.")
            return exception.HeatMissingParameterError(detail=msg)

        try:
            stack = json.loads(templ)
        except ValueError:
            msg = _("The Template must be a JSON document.")
            return exception.HeatInvalidParameterValueError(detail=msg)

        args = {'template': stack,
                'params': stack_parms,
                'args': create_args}
        try:
            stack_name = req.params['StackName']
            if action == self.CREATE_STACK:
                args['stack_name'] = stack_name
            else:
                args['stack_identity'] = self._get_identity(con, stack_name)

            result = engine_action[action](con, **args)
        except rpc_common.RemoteError as ex:
            return exception.map_remote_error(ex)

        try:
            identity = identifier.HeatIdentifier(**result)
        except (ValueError, TypeError):
            response = result
        else:
            response = {'StackId': identity.arn()}

        return api_utils.format_response(action, response)