Example #1
0
    def init_from_id(cls, service_stack_id):
        # split service id into service and stack components
        service_id = os.path.dirname(service_stack_id)
        stack_name = os.path.basename(service_stack_id)

        # retrieve stack information
        query = PlanetStateDbQuery.init_from_id(service_stack_id)
        stack_info = query.format_result_set(query.execute())

        # initialize class using primary constructor
        return cls(service_id, stack_name, stack_info)
Example #2
0
    def execute(self):
        # initialize service status query using skybase service registry id
        query = PlanetStateDbQuery.init_from_id(
            self.args['skybase_id'],
            query_type = PlanetStateQueryTypes.WILDCARD)

        # execute query and return standard result
        query_result = query.format_result_set(query.execute())

        # tabular output header
        service_output = '\n{0}\t\t{1}\t\t{2}\n\n'.format('ip_address', 'role_name', 'stack_name')

        # gather and format state information for each stack, role, and
        # instance ip address for query result
        for result in query_result:

            # unpack query result
            recid, instance_info = result.items()[0]
            stackname = instance_info['cloud']['stack_name']

            # TODO: performance / DRY enhancement: register planet and only init when not present
            planet_name = recid.split('/')[1]
            planet = Planet(planet_name)

            # get stack status
            stack_status = call_cloud_api(
                    planet=planet,
                    stack_name=stackname,
                    action='get_stack_status',
            )

            # report state information if stack launch complete
            stack_output = ''
            if stack_status == 'CREATE_COMPLETE':
                # call cloud provider for ip addresses
                stack_info = call_cloud_api(
                    planet=planet,
                    stack_name=stackname,
                    action='get_instance_ip',
                )
                
                # parse stack, role, instance info for ip addresses and
                # present in tabular format
                for instance_role_name, instances in stack_info.items():
                    # prepare output line for each ip address
                    for inst in instances:
                        # prepare complete line of output
                        role_ip_info = '{0}\t\t{1}\t\t{2}\n\n'.format(str(inst['private_ip_address']), instance_role_name, stackname)

                        # accumulate stack output
                        stack_output += role_ip_info
            else:
                # accumulate stack output
                stack_output += '\n\nWARNING: Stack "{0}" Status is "{1}" - no IP info \n'.format(
                    stackname, stack_status)

            # accumulate service output
            service_output = service_output + stack_output

        # prepare results
        self.result.output = service_output.strip()
        self.result.format = skytask.output_format_raw
        return self.result
Example #3
0
    def preflight_check(self):
        # container for preflight check issues
        preflight_result = []

        # instantiate planet
        try:
            self.planet = Planet(self.args.get('planet_name'))
        except Exception as e:
            self.preflight_check_result.status = 'FAIL'
            preflight_result.append(skybase.exceptions.SkyBaseValidationError('planet init: {0}'.format(simple_error_format(e))))

        # validate required options to delete one or all stacks
        if not (self.args.get('stack_name') or self.args.get('delete_all_stacks'))\
           or (self.args.get('stack_name') and self.args.get('delete_all_stacks')):
            self.preflight_check_result.status = 'FAIL'
            preflight_result.append(('specify one stack or option to delete all stacks for {0}'.format(self.args.get('service_name'))))

        # validate existence of requested service/stack in state registry
        query = PlanetStateDbQuery(
            planet=self.args.get('planet_name'),
            service=self.args.get('service_name'),
            tag=self.runtime.tag,
            stack=self.args.get('stack_name'),
            query_type='exact',
        )

        # verify unique pointer to service or service/stack
        if not query.can_find_exact():
            self.preflight_check_result.status = 'FAIL'
            preflight_result.append((skybase.exceptions.SkyBaseDeployError(
                'options do not identify a unique service or stack: {0}'.format(query.show_query_path())
            )))

        # TODO: push stack path into task result
        # save validated query path for postprocessing
        self.stack_path = query.query

        # reconfigure query to read resources for one or many service stacks
        query.query_type = query.WILDCARD
        query.query = query.make_query()

        # collect all stacks for deletion
        result_set = query.execute()

        # collect status of launched stacks
        for record in result_set:
            # accumulate list of provider stack ids for deletion
            self.stack_deletion_list.append(record.cloud.stack_id)

            try:
                # verify cloud provider DELETE* status for stack id
                stack_status = skybase.actions.skycloud.call_cloud_api(
                    planet=self.planet,
                    stack_name=record.cloud.stack_id,
                    action='get_stack_status')
            except Exception as e:
                raise skybase.exceptions.SkyBaseDeployError(skybase.utils.simple_error_format(e))

            if stack_status.startswith('DELETE'):
                self.preflight_check_result.status = 'FAIL'
                preflight_result.append(skybase.exceptions.SkyBaseDeployError(
                    'cannot delete stack {0} with status {1}'.format(record.cloud.stack_id, stack_status)))

            # accumulate stack information for deleting state db records and logging result
            self.stack_deletion_info[record.cloud.id] = {
                'stack_id': record.cloud.stack_id,
                'stack_name': record.cloud.stack_name,
            }

        # determine if deployed service used chef server. if so, then prepare to delete chef nodes

        # TODO: find authoritative location/source for skybase id definition
        # skybase state DB id
        skybase_id = '/{0}/{1}/{2}'.format(
            self.args.get('planet_name'),
            self.args.get('service_name'),
            self.runtime.tag,
        )

        # init service registry record and examine blueprint chef type
        service_record = ServiceRegistryRecord.init_from_id(skybase_id)
        self.chef_type = service_record.blueprint.definition.get('chef_type')
        self.is_chef_type_server = (self.chef_type and self.chef_type == 'server')

        # prepopulate list of host/instance names for use in chef node delete when chef_type server
        # NOTE:
        self.stack_chef_nodes = dict()

        if self.is_chef_type_server:

            for skybase_stack_id, stack_info in self.stack_deletion_info.items():

                self.stack_chef_nodes[stack_info['stack_name']] = skybase.actions.skychef.get_stack_chef_nodes(
                    skybase_stack_id=skybase_stack_id,
                    runner_cfg=self.runner_cfg,
                )

        self.preflight_check_result.set_output(preflight_result)
        return self.preflight_check_result
Example #4
0
    def execute(self):
        # initialize service status query using skybase service registry id
        query = PlanetStateDbQuery.init_from_id(
            self.args['skybase_id'], query_type=PlanetStateQueryTypes.WILDCARD)

        # execute query and return standard result
        query_result = query.format_result_set(query.execute())

        # tabular output header
        service_output = '\n{0}\t\t{1}\t\t{2}\n\n'.format(
            'ip_address', 'role_name', 'stack_name')

        # gather and format state information for each stack, role, and
        # instance ip address for query result
        for result in query_result:

            # unpack query result
            recid, instance_info = result.items()[0]
            stackname = instance_info['cloud']['stack_name']

            # TODO: performance / DRY enhancement: register planet and only init when not present
            planet_name = recid.split('/')[1]
            planet = Planet(planet_name)

            # get stack status
            stack_status = call_cloud_api(
                planet=planet,
                stack_name=stackname,
                action='get_stack_status',
            )

            # report state information if stack launch complete
            stack_output = ''
            if stack_status == 'CREATE_COMPLETE':
                # call cloud provider for ip addresses
                stack_info = call_cloud_api(
                    planet=planet,
                    stack_name=stackname,
                    action='get_instance_ip',
                )

                # parse stack, role, instance info for ip addresses and
                # present in tabular format
                for instance_role_name, instances in stack_info.items():
                    # prepare output line for each ip address
                    for inst in instances:
                        # prepare complete line of output
                        role_ip_info = '{0}\t\t{1}\t\t{2}\n\n'.format(
                            str(inst['private_ip_address']),
                            instance_role_name, stackname)

                        # accumulate stack output
                        stack_output += role_ip_info
            else:
                # accumulate stack output
                stack_output += '\n\nWARNING: Stack "{0}" Status is "{1}" - no IP info \n'.format(
                    stackname, stack_status)

            # accumulate service output
            service_output = service_output + stack_output

        # prepare results
        self.result.output = service_output.strip()
        self.result.format = skytask.output_format_raw
        return self.result
Example #5
0
    def execute(self):
        # unpack args
        skybase_id = self.args.get('skybase_id')
        planet_name = self.args.get('planet_name')
        service_name = self.args.get('service_name')
        continent_tag = self.args.get('tag')
        stack_name = self.args.get('stack_name')
        verbose = self.args.get('verbose')

        # test if any query filtering args are provided to drive type of query
        no_query_args = skybase_id == planet_name == service_name == continent_tag == stack_name == None

        # initialize service status query
        if no_query_args:
            # no query filter args provided; limit output to planet list
            query = PlanetStateDbQuery(
                planet=planet_name,
                service=service_name,
                tag=continent_tag,
                stack=stack_name,
                query_type=PlanetStateQueryTypes.DRILLDOWN,
            )
        elif skybase_id:
            # query by unique skybase id
            query = PlanetStateDbQuery.init_from_id(skybase_id,)
        else:
            # query by provided arguments
            query = PlanetStateDbQuery(
                planet=planet_name,
                service=service_name,
                tag=continent_tag,
                stack=stack_name,
                query_type=PlanetStateQueryTypes.WILDCARD,
            )

        # execute query and return standard result
        query_result = query.format_result_set(query.execute())


        # extend query results if working with skybase ID or filter args that return stacks
        if not no_query_args:
            for result in query_result:
                # unpack query result
                recid, info = result.items()[0]
                stackname = info['cloud']['stack_name']

                # TODO: performance / DRY enhancement: register planet and only init when not present
                planet_name = recid.split('/')[1]
                planet = Planet(planet_name)

                # get stack status
                try:
                    stack_status = call_cloud_api(
                            planet=planet,
                            stack_name=stackname,
                            action='get_stack_status',
                    )
                except Exception as e:
                    stack_status = e.message

                # add skybase ID
                info['skybase_id'] = recid

                # add status to results
                info['cloud'].update({'stack_status': stack_status})

                # query cloud provider for current state information
                if verbose and stack_status == 'CREATE_COMPLETE':
                    instance_info = call_cloud_api(
                        planet=planet,
                        stack_name=stackname,
                        action='get_instance_info',
                    )
                    # insert roles info into query result object
                    info['roles'] = instance_info

        # execute query
        self.result.output = query_result
        self.result.format = skytask.output_format_json
        return self.result
Example #6
0
    def preflight_check(self):
        # container for preflight check issues
        preflight_result = []

        # instantiate planet
        try:
            self.planet = Planet(self.args.get('planet_name'))
        except Exception as e:
            self.preflight_check_result.status = 'FAIL'
            preflight_result.append(
                skybase.exceptions.SkyBaseValidationError(
                    'planet init: {0}'.format(simple_error_format(e))))

        # validate required options to delete one or all stacks
        if not (self.args.get('stack_name') or self.args.get('delete_all_stacks'))\
           or (self.args.get('stack_name') and self.args.get('delete_all_stacks')):
            self.preflight_check_result.status = 'FAIL'
            preflight_result.append(
                ('specify one stack or option to delete all stacks for {0}'.
                 format(self.args.get('service_name'))))

        # validate existence of requested service/stack in state registry
        query = PlanetStateDbQuery(
            planet=self.args.get('planet_name'),
            service=self.args.get('service_name'),
            tag=self.runtime.tag,
            stack=self.args.get('stack_name'),
            query_type='exact',
        )

        # verify unique pointer to service or service/stack
        if not query.can_find_exact():
            self.preflight_check_result.status = 'FAIL'
            preflight_result.append((skybase.exceptions.SkyBaseDeployError(
                'options do not identify a unique service or stack: {0}'.
                format(query.show_query_path()))))

        # TODO: push stack path into task result
        # save validated query path for postprocessing
        self.stack_path = query.query

        # reconfigure query to read resources for one or many service stacks
        query.query_type = query.WILDCARD
        query.query = query.make_query()

        # collect all stacks for deletion
        result_set = query.execute()

        # collect status of launched stacks
        for record in result_set:
            # accumulate list of provider stack ids for deletion
            self.stack_deletion_list.append(record.cloud.stack_id)

            try:
                # verify cloud provider DELETE* status for stack id
                stack_status = skybase.actions.skycloud.call_cloud_api(
                    planet=self.planet,
                    stack_name=record.cloud.stack_id,
                    action='get_stack_status')
            except Exception as e:
                raise skybase.exceptions.SkyBaseDeployError(
                    skybase.utils.simple_error_format(e))

            if stack_status.startswith('DELETE'):
                self.preflight_check_result.status = 'FAIL'
                preflight_result.append(
                    skybase.exceptions.SkyBaseDeployError(
                        'cannot delete stack {0} with status {1}'.format(
                            record.cloud.stack_id, stack_status)))

            # accumulate stack information for deleting state db records and logging result
            self.stack_deletion_info[record.cloud.id] = {
                'stack_id': record.cloud.stack_id,
                'stack_name': record.cloud.stack_name,
            }

        # determine if deployed service used chef server. if so, then prepare to delete chef nodes

        # TODO: find authoritative location/source for skybase id definition
        # skybase state DB id
        skybase_id = '/{0}/{1}/{2}'.format(
            self.args.get('planet_name'),
            self.args.get('service_name'),
            self.runtime.tag,
        )

        # init service registry record and examine blueprint chef type
        service_record = ServiceRegistryRecord.init_from_id(skybase_id)
        self.chef_type = service_record.blueprint.definition.get('chef_type')
        self.is_chef_type_server = (self.chef_type
                                    and self.chef_type == 'server')

        # prepopulate list of host/instance names for use in chef node delete when chef_type server
        # NOTE:
        self.stack_chef_nodes = dict()

        if self.is_chef_type_server:

            for skybase_stack_id, stack_info in self.stack_deletion_info.items(
            ):

                self.stack_chef_nodes[stack_info[
                    'stack_name']] = skybase.actions.skychef.get_stack_chef_nodes(
                        skybase_stack_id=skybase_stack_id,
                        runner_cfg=self.runner_cfg,
                    )

        self.preflight_check_result.set_output(preflight_result)
        return self.preflight_check_result