Пример #1
0
    def __init__(self, config):
        super(BaseAction, self).__init__(config)

        self.credentials = {
            'region': None,
            'aws_access_key_id': None,
            'aws_secret_access_key': None
        }
        self.debug = config.get('debug', False)

        self.userdata = None
        if config.get('st2_user_data', None):
            # Check if string "looks" like a normal absolute path
            if os.path.isabs(config['st2_user_data']
                             ) and '\n' not in config['st2_user_data']:
                # Read in default user data from file
                try:
                    with open(config['st2_user_data'], 'r') as fp:
                        self.userdata = fp.read()
                except IOError as e:
                    self.logger.error(e)
            else:
                self.userdata = config['st2_user_data']

        # Note: In old static config credentials and region are under "setup" key and with a new
        # dynamic config values are top-level
        access_key_id = config.get('aws_access_key_id', None)
        secret_access_key = config.get('aws_secret_access_key', None)
        region = config.get('region', None)

        if access_key_id == "None":
            access_key_id = None
        if secret_access_key == "None":
            secret_access_key = None

        if access_key_id and secret_access_key:
            self.credentials['aws_access_key_id'] = access_key_id
            self.credentials['aws_secret_access_key'] = secret_access_key
        elif 'setup' in config:
            # Assume old-style config
            self.credentials = config['setup']

        if region:
            self.credentials['region'] = region

        self.session = Session(
            aws_access_key_id=self.credentials['aws_access_key_id'],
            aws_secret_access_key=self.credentials['aws_secret_access_key'])

        self.account_id = self.session.client('sts').get_caller_identity().get(
            'Account')
        self.cross_roles = {
            arn.split(':')[4]: arn
            for arn in self.config.get('actions', {}).get('roles', [])
        }

        self.resultsets = ResultSets()
Пример #2
0
    def __init__(self, config):
        super(BaseAction, self).__init__(config)

        self.credentials = {
            'region': None,
            'aws_access_key_id': None,
            'aws_secret_access_key': None
        }
        self.userdata = None

        if config.get('st2_user_data', None):
            try:
                with open(config['st2_user_data'], 'r') as fp:
                    self.userdata = fp.read()
            except IOError as e:
                self.logger.error(e)

        # Note: In old static config credentials and region are under "setup" key and with a new
        # dynamic config values are top-level
        access_key_id = config.get('aws_access_key_id', None)
        secret_access_key = config.get('aws_secret_access_key', None)
        region = config.get('region', None)

        if access_key_id and secret_access_key:
            self.credentials['aws_access_key_id'] = access_key_id
            self.credentials['aws_secret_access_key'] = secret_access_key
            self.credentials['region'] = region
        elif 'setup' in config:
            # Assume old-style config
            self.credentials = config['setup']

        self.resultsets = ResultSets()
Пример #3
0
 def __init__(self, config):
     super(BaseAction, self).__init__(config)
     if config['st2_user_data'] is not "":
         self.userdata = open(config['st2_user_data'], 'r').read()
     else:
         self.userdata = None
     self.setup = config['setup']
     self.resultsets = ResultSets()
Пример #4
0
class BaseAction(Action):
    def __init__(self, config):
        super(BaseAction, self).__init__(config)

        self.credentials = {
            'region': None,
            'aws_access_key_id': None,
            'aws_secret_access_key': None
        }
        self.debug = config.get('debug', False)

        self.userdata = None
        if config.get('st2_user_data', None):
            # Check if string "looks" like a normal absolute path
            if os.path.isabs(config['st2_user_data']
                             ) and '\n' not in config['st2_user_data']:
                # Read in default user data from file
                try:
                    with open(config['st2_user_data'], 'r') as fp:
                        self.userdata = fp.read()
                except IOError as e:
                    self.logger.error(e)
            else:
                self.userdata = config['st2_user_data']

        # Note: In old static config credentials and region are under "setup" key and with a new
        # dynamic config values are top-level
        access_key_id = config.get('aws_access_key_id', None)
        secret_access_key = config.get('aws_secret_access_key', None)
        region = config.get('region', None)

        if access_key_id == "None":
            access_key_id = None
        if secret_access_key == "None":
            secret_access_key = None

        if access_key_id and secret_access_key:
            self.credentials['aws_access_key_id'] = access_key_id
            self.credentials['aws_secret_access_key'] = secret_access_key
        elif 'setup' in config:
            # Assume old-style config
            self.credentials = config['setup']

        if region:
            self.credentials['region'] = region

        self.session = Session(
            aws_access_key_id=self.credentials['aws_access_key_id'],
            aws_secret_access_key=self.credentials['aws_secret_access_key'])

        self.account_id = self.session.client('sts').get_caller_identity().get(
            'Account')
        self.cross_roles = {
            arn.split(':')[4]: arn
            for arn in self.config.get('actions', {}).get('roles', [])
        }

        self.resultsets = ResultSets()

    def assume_role(self, account_id):
        ''' Assumes role and setup Boto3 session for the cross-account capability'''
        if account_id == self.account_id:
            return

        try:
            assumed_role = self.session.client('sts').assume_role(
                RoleArn=self.cross_roles[account_id],
                RoleSessionName='StackStormEvents')
        except ClientError:
            self.logger.error(
                "Failed to assume role as account %s when using the AWS session "
                "client. Check the roles configured for the AWS pack and ensure "
                "that the '%s' is still valid.", account_id,
                self.cross_roles[account_id])
            raise
        except KeyError:
            self.logger.error(
                "Could not find the role referring %s account in the config file. "
                "Please, introduce it in 'aws.yaml' file.", account_id)
            raise

        self.credentials.update({
            'aws_access_key_id':
            assumed_role["Credentials"]["AccessKeyId"],
            'aws_secret_access_key':
            assumed_role["Credentials"]["SecretAccessKey"],
            'security_token':
            assumed_role["Credentials"]["SessionToken"]
        })

    def ec2_connect(self):
        region = self.credentials['region']
        del self.credentials['region']
        return boto.ec2.connect_to_region(region, **self.credentials)

    def vpc_connect(self):
        region = self.credentials['region']
        del self.credentials['region']
        return boto.vpc.connect_to_region(region, **self.credentials)

    def cf_connect(self):
        region = self.credentials['region']
        del self.credentials['region']
        return boto.cloudformation.connect_to_region(region,
                                                     **self.credentials)

    def r53_connect(self):
        route53_credentials = {
            key: self.credentials[key]
            for key in self.credentials if key != 'region'
        }
        return boto.route53.connection.Route53Connection(**route53_credentials)

    def get_r53zone(self, zone):
        conn = self.r53_connect()
        return conn.get_zone(zone)

    def st2_user_data(self):
        return self.userdata

    def get_boto3_session(self, resource):
        region = self.credentials['region']
        del self.credentials['region']
        if 'security_token' in self.credentials:
            self.credentials['aws_session_token'] = self.credentials.pop(
                'security_token', None)
        return boto3.client(resource, region_name=region, **self.credentials)

    def split_tags(self, tags):
        tag_dict = {}
        split_tags = tags.split(',')
        for tag in split_tags:
            if re.search('=', tag):
                k, v = tag.split('=', 1)
                tag_dict[k] = v
        return tag_dict

    def wait_for_state(self,
                       instance_id,
                       state,
                       account_id=None,
                       region=None,
                       timeout=10,
                       retries=3):
        state_list = {}

        if account_id:
            self.assume_role(account_id)
        if region:
            self.credentials['region'] = region

        obj = self.ec2_connect()
        eventlet.sleep(timeout)
        instance_list = []

        for _ in range(retries + 1):
            try:
                instance_list = obj.get_only_instances([
                    instance_id,
                ])
            except Exception:
                self.logger.info("Waiting for instance to become available")
                eventlet.sleep(timeout)

        for instance in instance_list:
            try:
                current_state = instance.update()
            except Exception as e:
                self.logger.info("Instance (%s) not listed. Error: %s" %
                                 (instance_id, e))
                eventlet.sleep(timeout)

            while current_state != state:
                current_state = instance.update()
            state_list[instance_id] = current_state
        return state_list

    def do_method(self, module_path, cls, action, **kwargs):
        module = importlib.import_module(module_path)

        if 'account_id' in kwargs:
            self.assume_role(kwargs.pop('account_id'))
        if 'region' in kwargs:
            self.credentials['region'] = kwargs.pop('region')

        # hack to connect to correct region
        if cls == 'EC2Connection':
            obj = self.ec2_connect()
        elif cls == 'VPCConnection':
            obj = self.vpc_connect()
        elif cls == 'CloudFormationConnection':
            obj = self.cf_connect()
        elif module_path == 'boto.route53.zone' and cls == 'Zone':
            zone = kwargs['zone']
            del kwargs['zone']
            obj = self.get_r53zone(zone)
        elif module_path == 'boto3.s3.transfer':
            for k, v in kwargs.items():
                if not v:
                    del kwargs[k]
                    continue
                if k == 'filename':
                    kwargs['Filename'] = kwargs.pop(k)
                elif k == 'bucket':
                    kwargs['Bucket'] = kwargs.pop(k)
                elif k == 'key':
                    kwargs['Key'] = kwargs.pop(k)
            obj = self.get_boto3_session('s3')
        elif 'boto3' in module_path:
            for k, v in kwargs.items():
                if not v:
                    del kwargs[k]
            obj = self.get_boto3_session(cls)
        else:
            del self.credentials['region']
            obj = getattr(module, cls)(**self.credentials)

        if not obj:
            raise ValueError(
                'Invalid or missing credentials (aws_access_key_id,'
                'aws_secret_access_key) or region')

        if self.debug:
            method_fqdn = '%s.%s.%s' % (module_path, cls, action)
            self.logger.debug('Calling method "%s" with kwargs: %s' %
                              (method_fqdn, str(kwargs)))

        resultset = getattr(obj, action)(**kwargs)
        formatted = self.resultsets.formatter(resultset)
        return formatted if isinstance(formatted, list) else [formatted]

    def do_function(self, module_path, action, **kwargs):
        module = __import__(module_path)

        if self.debug:
            function_fqdn = '%s.%s' % (module_path, action)
            self.logger.debug('Calling function "%s" with kwargs: %s' %
                              (function_fqdn, str(kwargs)))

        return getattr(module, action)(**kwargs)
Пример #5
0
class BaseAction(Action):

    def __init__(self, config):
        super(BaseAction, self).__init__(config)

        self.credentials = {
            'region': None,
            'aws_access_key_id': None,
            'aws_secret_access_key': None
        }
        self.debug = config.get('debug', False)

        self.userdata = None
        if config.get('st2_user_data', None):
            # Check if string "looks" like a normal absolute path
            if os.path.isabs(config['st2_user_data']) and '\n' not in config['st2_user_data']:
                # Read in default user data from file
                try:
                    with open(config['st2_user_data'], 'r') as fp:
                        self.userdata = fp.read()
                except IOError as e:
                    self.logger.error(e)
            else:
                self.userdata = config['st2_user_data']

        # Note: In old static config credentials and region are under "setup" key and with a new
        # dynamic config values are top-level
        access_key_id = config.get('aws_access_key_id', None)
        secret_access_key = config.get('aws_secret_access_key', None)
        region = config.get('region', None)

        if access_key_id == "None":
            access_key_id = None
        if secret_access_key == "None":
            secret_access_key = None

        if access_key_id and secret_access_key:
            self.credentials['aws_access_key_id'] = access_key_id
            self.credentials['aws_secret_access_key'] = secret_access_key
        elif 'setup' in config:
            # Assume old-style config
            self.credentials = config['setup']

        if region:
            self.credentials['region'] = region

        self.resultsets = ResultSets()

    def ec2_connect(self):
        region = self.credentials['region']
        del self.credentials['region']
        return boto.ec2.connect_to_region(region, **self.credentials)

    def vpc_connect(self):
        region = self.credentials['region']
        del self.credentials['region']
        return boto.vpc.connect_to_region(region, **self.credentials)

    def cf_connect(self):
        region = self.credentials['region']
        del self.credentials['region']
        return boto.cloudformation.connect_to_region(region, **self.credentials)

    def r53_connect(self):
        route53_credentials = {
            key: self.credentials[key] for key in self.credentials if key != 'region'
        }
        return boto.route53.connection.Route53Connection(**route53_credentials)

    def get_r53zone(self, zone):
        conn = self.r53_connect()
        return conn.get_zone(zone)

    def st2_user_data(self):
        return self.userdata

    def get_boto3_session(self, resource):
        region = self.credentials['region']
        del self.credentials['region']
        return boto3.client(resource, region_name=region, **self.credentials)

    def split_tags(self, tags):
        tag_dict = {}
        split_tags = tags.split(',')
        for tag in split_tags:
            if re.search('=', tag):
                k, v = tag.split('=', 1)
                tag_dict[k] = v
        return tag_dict

    def wait_for_state(self, instance_id, state, timeout=10, retries=3):
        state_list = {}
        obj = self.ec2_connect()
        eventlet.sleep(timeout)
        instance_list = []

        for _ in range(retries + 1):
            try:
                instance_list = obj.get_only_instances([instance_id, ])
            except Exception:
                self.logger.info("Waiting for instance to become available")
                eventlet.sleep(timeout)

        for instance in instance_list:
            try:
                current_state = instance.update()
            except Exception as e:
                self.logger.info("Instance (%s) not listed. Error: %s" %
                                 (instance_id, e))
                eventlet.sleep(timeout)

            while current_state != state:
                current_state = instance.update()
            state_list[instance_id] = current_state
        return state_list

    def do_method(self, module_path, cls, action, **kwargs):
        module = importlib.import_module(module_path)
        # hack to connect to correct region
        if cls == 'EC2Connection':
            obj = self.ec2_connect()
        elif cls == 'VPCConnection':
            obj = self.vpc_connect()
        elif cls == 'CloudFormationConnection':
            obj = self.cf_connect()
        elif module_path == 'boto.route53.zone' and cls == 'Zone':
            zone = kwargs['zone']
            del kwargs['zone']
            obj = self.get_r53zone(zone)
        elif module_path == 'boto3.s3.transfer':
            for k, v in kwargs.items():
                if not v:
                    del kwargs[k]
                    continue
                if k == 'filename':
                    kwargs['Filename'] = kwargs.pop(k)
                elif k == 'bucket':
                    kwargs['Bucket'] = kwargs.pop(k)
                elif k == 'key':
                    kwargs['Key'] = kwargs.pop(k)
            obj = self.get_boto3_session('s3')
        elif 'boto3' in module_path:
            for k, v in kwargs.items():
                if not v:
                    del kwargs[k]
            obj = self.get_boto3_session(cls)
        else:
            del self.credentials['region']
            obj = getattr(module, cls)(**self.credentials)

        if not obj:
            raise ValueError('Invalid or missing credentials (aws_access_key_id,'
                             'aws_secret_access_key) or region')

        if self.debug:
            method_fqdn = '%s.%s.%s' % (module_path, cls, action)
            self.logger.debug('Calling method "%s" with kwargs: %s' % (method_fqdn, str(kwargs)))

        resultset = getattr(obj, action)(**kwargs)
        formatted = self.resultsets.formatter(resultset)
        return formatted if isinstance(formatted, list) else [formatted]

    def do_function(self, module_path, action, **kwargs):
        module = __import__(module_path)

        if self.debug:
            function_fqdn = '%s.%s' % (module_path, action)
            self.logger.debug('Calling function "%s" with kwargs: %s' % (function_fqdn,
                                                                         str(kwargs)))

        return getattr(module, action)(**kwargs)