def clean_old_host():
    """ Method call by cron to clean instances """
    logging.info("########## Start Cleaning ###########")

    metrics = {
        'hosts_ok': {
            'description':
            'count of hosts which have a report in the defined delay',
            'value': 0
        },
        'hosts_deleted': {
            'description':
            'count of hosts successfully deleted from foreman puppet and ds',
            'value': 0
        },
        'hosts_skipped': {
            'description':
            'count of hosts skipped because they are still in EC2',
            'value': 0
        },
        'hosts_delete_failed': {
            'description':
            'count hosts unsuccessfully deleted from foreman puppet and ds',
            'value': 0
        },
    }

    # connect to Foreman and ForemanProxy
    f = Foreman(FOREMAN_URL, (FOREMAN_USER, FOREMAN_PASSWORD), api_version=2)
    fp = ForemanProxy(FOREMAN_PROXY_URL)

    # Connect to the DS
    try:
        ds = AwsDs(LDAP_HOST, COMPUTERS_BASE_DN, BIND_USER_DN, BIND_PASSWORD)
    except ldap.INVALID_CREDENTIALS:
        raise "Your username or password is incorrect."

    # Get the the current date
    currentdate = datetime.datetime.utcnow()

    # check for all host
    instance_id_dict = foreman_wrapper(
        f.do_get,
        call_args={
            'url': '/api/fact_values?&search=+name+%3D+ec2_instance_id',
            'kwargs': {
                'per_page': 1000
            }
        })
    result = foreman_wrapper(f.index_hosts, call_args={"per_page": 1000})
    for host in result:
        # get the compile date
        lastcompile = None
        if host["last_compile"]:
            lastcompile = host["last_compile"]
        elif host["last_report"]:
            lastcompile = host["last_report"]
        elif host["created_at"]:
            lastcompile = host["created_at"]

        # Convert the string date to datetime format
        if not host["last_compile"] and not host["last_report"] and host[
                "created_at"]:
            logging.info(
                "Can't retrieve last compile/report date for {}, will use create time ({})"
                .format(host["certname"], host["created_at"]))

        hostdate = datetime.datetime.strptime(lastcompile,
                                              '%Y-%m-%dT%H:%M:%S.%fZ')
        # Get the delta between the last puppet repport and the current date
        elapsed = currentdate - hostdate
        # if the deta is more than $delay days we delete the host
        if elapsed > datetime.timedelta(hours=int(DELAY)):
            # Make the following 2 call only at the end in order to avoid useless consuming API call
            try:
                instance_id = instance_id_dict[host['name']]['ec2_instance_id']
                is_terminated = (
                    get_ec2_instance_state(instance_id) == 'terminated')
            except KeyError:
                if host['ip']:
                    is_terminated = (get_ec2_instance_state(
                        '', ip=host['ip']) == 'terminated')
                elif host['mac']:
                    is_terminated = (get_ec2_instance_state(
                        '', ip=host['ip'], mac=host['mac']) == 'terminated')
                else:
                    logging.warning(
                        "Can't retrieve EC2 id or ip, skipping {}".format(
                            host["certname"]))
                    metrics["hosts_skipped"]["value"] += 1
                    continue
            except Exception as e:
                logging.warning(
                    "Can't retrieve EC2 state, skipping {} : {}".format(
                        host["certname"], e))
                metrics["hosts_skipped"]["value"] += 1
                continue

            if is_terminated:
                try:
                    logging.info(
                        "I will destroy the server {} because the last report was {}"
                        .format(host["certname"], str(lastcompile)))
                    # destroy the host in foreman
                    f.destroy_hosts(id=host["id"])
                    # remove the certificate in puppet
                    fp.delete_certificate(host["certname"])
                    # remove host in the DS
                    ds.delete_computer(host["certname"])
                    metrics["hosts_deleted"]["value"] += 1
                except Exception as e:
                    logging.error("Something went wrong : {}".format(e))
                    metrics["hosts_delete_failed"]["value"] += 1
            else:
                metrics["hosts_skipped"]["value"] += 1
        else:
            metrics["hosts_ok"]["value"] += 1
            logging.debug("{} OK: Last puppet's run : {}".format(
                host["certname"], lastcompile))

    logging.info("Push metrics to prometheus")
    push_metrics(metrics)
Exemple #2
0
class ForemanClient(Client):

    per_page = 100

    def __init__(self, config_path, debug=False, version='1', log=None):
        super(ForemanClient, self).__init__(config_path, debug, log)
        self.logger.debug('=> config file: %s' % config_path)
        foreman_url = self.get_config('foreman', 'url')
        self.logger.debug('=> foreman url: %s' % foreman_url)
        foreman_user = self.get_config('foreman', 'user')
        foreman_password = self.get_config('foreman', 'password')
        self.foreman = Foreman(foreman_url,
                               (foreman_user, foreman_password),
                               api_version=2,
                               version=version,
                               verify=False)

    def set_per_page(self, per_page):
        self.per_page = per_page

    def get_config(self, section, option):
        try:
            value = self.config.get(section, option)
            return value
        except ConfigParser.NoOptionError:
            self.logger.debug('=> config file section [%s] missing option %s'
                              % (section, option))
        except ConfigParser.NoSectionError:
            self.logger.debug('=> config file missing section %s' % section)
        return None

    def get_config_section(self, section):
        try:
            openstack = self.config.items(section)
        except ConfigParser.NoSectionError:
            self.logger.debug('missing [%s]' % section)
            self.logger.debug('Could not find section [%s] in %s', section, self.config_path)
            sys.exit(1)
        return dict(openstack)

    def get_logger(self):
        return self.logger

    def get_client(self):
        return self.foreman

    def get_compute_resources(self):
        resources = self.foreman.index_computeresources()
        found_resources = dict({})
        for r in resources['results']:
            found_resources[r['name']] = r['id']
        return found_resources

    def get_compute_profiles(self):
        profiles = self.foreman.index_computeprofiles()
        found_profiles = dict({})
        for p in profiles['results']:
            found_profiles[p['name']] = p['id']
        return found_profiles

    def get_profile_id(self, profile_name):
        profile = self.foreman.show_computeprofiles(profile_name)
        return profile['id']

    def get_host(self, host):
        host = self.__set_host(host)
        return self.foreman.show_hosts(id=host)

    def get_fact(self, host, fact):
        host = self.__set_host(host)
        facts = self.get_facts(host)
        fact = facts['results'][host][fact]
        return fact

    def get_facts(self, host_id):
        host = self.__set_host(host_id)
        return self.foreman.hosts.fact_values_index(host_id=host, per_page=self.per_page)

    def set_host_build(self, host, build=True):
        host = self.__set_host(host)
        if len(self.foreman.show_hosts(id=host)) > 0:
            self.foreman.update_hosts(id=host, host={'build': build})

    def get_hosts(self, search=None):
        hosts = self.foreman.index_hosts(per_page=self.per_page)
        self.logger.debug("=> fetch %s page(s) with a total of %s hosts" %
                          (hosts['page'], hosts['total']))
        return hosts

    def create_host(self, host):
        if 'name' not in host:
            self.logger.debug('host dict missing name')
            return
        self.logger.debug('=> create new host %s' % host['name'])
        result = self.foreman.create_host(host)
        self.logger.debug('=> host created: %s' % result)

    def create_node(self, name, node_data, region):
        if self.get_host(name):
            self.logger.debug('=> node %s found, dropping create' % name)
            return
        found_resources = self.get_compute_resources()
        host = dict()
        host['name'] = name
        host['build'] = self.__get_node_data('build', node_data, '1')
        host['hostgroup_id'] = self.__get_node_data('hostgroup', node_data, '1')
        host['compute_profile_id'] = self.get_profile_id(
            self.__get_node_data('compute_profile',
                                 node_data,
                                 'small'))
        host['interfaces_attributes'] = self.__get_node_data(
            'interfaces_attributes', node_data, {})
        host['compute_attributes'] = self.__get_node_data(
            'compute_attributes', node_data, {})
        host['host_parameters_attributes'] = self.__get_node_data(
            'host_parameters_attributes', node_data, {})
        if 'mac' in node_data:
            host['mac'] = node_data['mac']
        if 'compute_resource' in node_data:
            compute_resource = '%s-%s' % (region, node_data['compute_resource'])
            if compute_resource in found_resources:
                host['compute_resource_id'] = found_resources[compute_resource]
            else:
                self.logger.debug('=> compute resource %s not found' % compute_resource)
                return
        elif 'mac' not in node_data:
            self.logger.debug('=> mac or compute resource are mandatory for %s' % name)
            return
        if not self.dry_run:
            result = self.foreman.create_hosts(host)
            if not result:
                self.log_error('Could not create host. Check production.log on foreman host!')
                return
            if 'mac' not in node_data:
                self.foreman.hosts.power(id=result['name'], power_action='start')
            self.logger.debug('=> create host %s' % result)
        else:
            self.logger.debug('=> dry run: host config %s' % host)

    def delete_node(self, host):
        host = self.__set_host(host)
        if not self.dry_run:
            result = self.foreman.destroy_hosts(host)
            if not result:
                self.log_error('Could not delete host.')
                return
            self.logger.debug('=> deleted node %s' % host)
        else:
            self.logger.debug('=> dry run: deleted node %s' % host)

    def __set_host(self, host):
        if not host:
            self.host = None
            return
        domain = self.config.get('openstack', 'domain')
        if domain and not '.' in host:
            self.logger.debug("=> prepend %s to %s" % (domain, host))
            host = host + '.' + domain
        return host

    @staticmethod
    def log_error(msg, code=0):
        sys.stderr.write("%s\n" % msg)
        if code > 0:
            sys.exit(code)

    @staticmethod
    def __get_node_data(var, node_data, default=None):
        if var in node_data:
            return node_data[var]
        else:
            return default
Exemple #3
0
class ForemanClient(Client):

    per_page = 100

    def __init__(self, config_path, debug=False, version='1', log=None):
        super(ForemanClient, self).__init__(config_path, debug, log)
        self.logger.debug('=> config file: %s' % config_path)
        foreman_url = self.get_config('foreman', 'url')
        self.logger.debug('=> foreman url: %s' % foreman_url)
        foreman_user = self.get_config('foreman', 'user')
        foreman_password = self.get_config('foreman', 'password')
        self.foreman = Foreman(foreman_url, (foreman_user, foreman_password),
                               api_version=2,
                               version=version,
                               verify=False)

    def set_per_page(self, per_page):
        self.per_page = per_page

    def get_config(self, section, option):
        try:
            value = self.config.get(section, option)
            return value
        except ConfigParser.NoOptionError:
            self.logger.debug('=> config file section [%s] missing option %s' %
                              (section, option))
        except ConfigParser.NoSectionError:
            self.logger.debug('=> config file missing section %s' % section)
        return None

    def get_config_section(self, section):
        try:
            openstack = self.config.items(section)
        except ConfigParser.NoSectionError:
            self.logger.debug('missing [%s]' % section)
            self.logger.debug('Could not find section [%s] in %s', section,
                              self.config_path)
            sys.exit(1)
        return dict(openstack)

    def get_location(self):
        locations = self.foreman.index_locations()
        location_id = False
        for l in locations['results']:
            if l['name'] == 'Default Location':
                location_id = l['id']
        return location_id

    def get_organization(self):
        organizations = self.foreman.index_organizations()
        organization_id = False
        for o in organizations['results']:
            if o['name'] == 'Default Organization':
                organization_id = o['id']
        return organization_id

    def get_logger(self):
        return self.logger

    def get_client(self):
        return self.foreman

    def get_compute_resources(self):
        resources = self.foreman.index_computeresources()
        found_resources = dict({})
        for r in resources['results']:
            found_resources[r['name']] = r['id']
        return found_resources

    def get_compute_profiles(self):
        profiles = self.foreman.index_computeprofiles()
        found_profiles = dict({})
        for p in profiles['results']:
            found_profiles[p['name']] = p['id']
        return found_profiles

    def get_profile_id(self, profile_name):
        profile = self.foreman.show_computeprofiles(profile_name)
        return profile['id']

    def get_host(self, host):
        host = self.__set_host(host)
        return self.foreman.show_hosts(id=host)

    def get_fact(self, host, fact):
        host = self.__set_host(host)
        facts = self.get_facts(host)
        fact = facts['results'][host][fact]
        return fact

    def get_facts(self, host_id):
        host = self.__set_host(host_id)
        return self.foreman.hosts.fact_values_index(host_id=host,
                                                    per_page=self.per_page)

    def set_host_build(self, host, build=True):
        host = self.__set_host(host)
        if len(self.foreman.show_hosts(id=host)) > 0:
            self.foreman.update_hosts(id=host, host={'build': build})

    def get_hosts(self, search=None):
        hosts = self.foreman.index_hosts(per_page=self.per_page)
        self.logger.debug("=> fetch %s page(s) with a total of %s hosts" %
                          (hosts['page'], hosts['total']))
        return hosts

    def create_host(self, host):
        if 'name' not in host:
            self.logger.debug('host dict missing name')
            return
        self.logger.debug('=> create new host %s' % host['name'])
        result = self.foreman.create_host(host)
        self.logger.debug('=> host created: %s' % result)

    def create_node(self, name, node_data, region):
        if self.get_host(name):
            self.logger.debug('=> node %s found, dropping create' % name)
            return
        found_resources = self.get_compute_resources()
        host = dict()
        host['name'] = name
        host['build'] = self.__get_node_data('build', node_data, '1')
        host['hostgroup_id'] = self.__get_node_data('hostgroup', node_data,
                                                    '1')
        host['compute_profile_id'] = self.get_profile_id(
            self.__get_node_data('compute_profile', node_data, 'small'))
        host['organization_id'] = self.get_organization()
        host['location_id'] = self.get_location()
        host['interfaces_attributes'] = self.__get_node_data(
            'interfaces_attributes', node_data, {})
        host['compute_attributes'] = self.__get_node_data(
            'compute_attributes', node_data, {})
        host['host_parameters_attributes'] = self.__get_node_data(
            'host_parameters_attributes', node_data, {})
        if 'mac' in node_data:
            host['mac'] = node_data['mac']
        if 'compute_resource' in node_data:
            compute_resource = '%s-%s' % (region,
                                          node_data['compute_resource'])
            if compute_resource in found_resources:
                host['compute_resource_id'] = found_resources[compute_resource]
            else:
                self.logger.debug('=> compute resource %s not found' %
                                  compute_resource)
                return
        elif 'mac' not in node_data:
            self.logger.debug(
                '=> mac or compute resource are mandatory for %s' % name)
            return
        if not self.dry_run:
            result = self.foreman.create_hosts(host)
            if not result:
                self.log_error(
                    'Could not create host. Check production.log on foreman host!'
                )
                return
            if 'mac' not in node_data:
                self.foreman.hosts.power(id=result['name'],
                                         power_action='start')
            self.logger.debug('=> create host %s' % result)
        else:
            self.logger.debug('=> dry run: host config %s' % host)

    def delete_node(self, host):
        host = self.__set_host(host)
        if not self.dry_run:
            result = self.foreman.destroy_hosts(host)
            if not result:
                self.log_error('Could not delete host.')
                return
            self.logger.debug('=> deleted node %s' % host)
        else:
            self.logger.debug('=> dry run: deleted node %s' % host)

    def __set_host(self, host):
        if not host:
            self.host = None
            return
        domain = self.config.get('openstack', 'domain')
        if domain and not '.' in host:
            self.logger.debug("=> prepend %s to %s" % (domain, host))
            host = host + '.' + domain
        return host

    @staticmethod
    def log_error(msg, code=0):
        sys.stderr.write("%s\n" % msg)
        if code > 0:
            sys.exit(code)

    @staticmethod
    def __get_node_data(var, node_data, default=None):
        if var in node_data:
            return node_data[var]
        else:
            return default