Beispiel #1
0
    def get_smallest_gap(self, db, service):
        """Check if there's a gap in the hostname numbers."""
        gaps = list(db.servers.find({'instance_id': '', 'service': service}))
        if len(gaps) > 0:
            # There is a gap
            logging.info('Gap in hostnames detected.')
            gaps.sort(key=operator.itemgetter('hostname'))

            return gaps[0]['hostname']
Beispiel #2
0
    def get_smallest_gap(self, db, service):
        """Check if there's a gap in the hostname numbers."""
        gaps = list(db.servers.find({"instance_id": "", "service": service}))
        if len(gaps) > 0:
            # There is a gap
            logging.info("Gap in hostnames detected.")
            gaps.sort(key=operator.itemgetter("hostname"))

            return gaps[0]["hostname"]
Beispiel #3
0
    def pick_name(self, db, service, service_type, instance_id):
        """Check against the names in the aerostat database.

        This is the basic logic behind deciding which names are available.
        It checks the aerostat database, and using a combination of the
        service_type and the instance_id, it determines if there are:
            1) duplicate entries - in which case, it overwrites the older entry.
            2) depending on type, it will determine the next logical name in the
            services progression.
            3) this function then returns that string value.

        Args:
            db: a pymongo.Connection.db instance.
            service: str, the name retrieved from /etc/aerostat_info.
            service_type: str, kind of service hierarchy, masterful or iterative.
            instance_id: str, name of instance, to check for dups.
        Returns:
            str, the appropriate hostname for the client node.
        """
        hostname = None
        # Check for duplicates. But only if instances have names.
        if self.check_dup(db, instance_id) and aerostat.get_hostname(
                db, instance_id):
            logging.warn('Duplicate instance found')
            return None

        results = list(db.servers.find({'service': service}))
        # We only want to count instances in our service with hostnames.
        named_in_service = [item for item in results if item['hostname']]
        num = len(named_in_service)
        logging.info('%s number of hosts with same service found' % num)

        if service_type == 'masterful':
            master_hostname = '%s-master' % (service,)
            if not named_in_service:
                hostname = master_hostname  # first instance will be master.
            elif aerostat.hostname_exists(db,
                        master_hostname) and not self.hostname_instance_exists(
                                db, master_hostname):
                hostname = master_hostname  # replace fallen master.
            else:
                smallest_slave_gap = self.get_smallest_gap(db, service)
                if smallest_slave_gap:
                    hostname = smallest_slave_gap
                else:
                    hostname = '%s-slave-%s' % (service, num)
        else:  # We're iterative.
            smallest_gap = self.get_smallest_gap(db, service)
            # find out if there are gaps in the hostnames, use smallest.
            if smallest_gap:
                hostname = smallest_gap
            else:
                hostname =  '%s-%s' % (service, num) # New instance, no gaps.

        return hostname
Beispiel #4
0
    def hostname_instance_exists(self, db, hostname):
        """Check to see if a given hostname has an instance attached."""

        result = db.servers.find_one({'hostname': hostname})
        # Should only ever have one instance_id in aerostat.
        if result and result['instance_id']:
            logging.info('Hostname/instance pair exists for %s' % hostname)
            return True
        else:
            logging.info('Hostname/inst pair does\'t exist for %s' % hostname)
            return False
Beispiel #5
0
    def alias_exists(self, db, aliases):
        """Check if alias exists for any host, regardless of number.

        Args:
            db: pymongo.Connection.db instnace.
            aliases: a list of str, all of the aliases for a row.
        Returns:
            If matches are found, it returns the aliases for those rows.
        """
        results = list(db.servers.find({'aliases' : { '$in' : aliases}}))
        if len(results) > 0:
            logging.info('Detected at least one alias.')
            ret_val = []
            [ret_val.extend(result['aliases']) for result in results]
            return ret_val
Beispiel #6
0
    def delete_aero_sect(self, hosts_content):
        """Remove aerostat section and return remaining lines.

        Args:
            hosts_content: list of str, /etc/hosts values as read from file.
        Returns:
            list of str, only those lines that do not belong to Aerostat.
        """
        preceding = []
        for line in hosts_content:
            if line.strip() == "# AEROSTAT":
                logging.info("Scanned to Aerostat Section. Removing.")
                break
            else:
                preceding.append(line.strip())

        return preceding
Beispiel #7
0
    def do_update(self, db, dry_run=None, legacy_updater=None):
        """Update /etc/hosts.

        Args:
            db: mongdb db reference.
            dry_run: bool, whether or not to actually update /etc/hosts.
            legacy_updater: binary to run in order to update /etc/hosts
            (helpful for transitions).
        Returns:
            bool, True if changes are made to the system.
        """

        if legacy_updater:
            # Call legacy host updater, allow it to write to /etc/hosts.
            retcode = subprocess.call([legacy_updater])
            if retcode < 0:
                logging.error('Call to %s failed!' % legacy_updater)
                sys.exit(1)

        self.hosts_data = ['127.0.0.1 localhost']  # Reset data, otherwise we append
        aerostat_data = db.servers.find()

        # extract hostname, ip and aliases
        for item in aerostat_data:
            if item['ip']:
                self.append_hosts_line(item['ip'], item['hostname'])
            if item['aliases']:
                self.format_aliases(item['ip'], item['aliases'])

        if dry_run:
            dry_run_output = '\n'.join(self.hosts_data) + '\n'
            logging.debug(
                    ('DRY RUN: Your /etc/hosts file would look'
                    'like this: \n%s' % dry_run_output))
            return False

        # Only make any changes if there are actual data available to write.
        if self.hosts_data:
            logging.info('Copying /etc/hosts to /etc/hosts.bak')
            shutil.copyfile('/etc/hosts', '/etc/hosts.bak')
            logging.info('Writing new /etc/hosts file.')
            self.write_hosts_file()
        else:
            logging.error('No data returned from aerostat. Write aborted.')

        return True
Beispiel #8
0
    def _create_dir_path(self, path):
        """Create the directory path for the configs, if necssary.

        Args:
            path: str, path of config.
        Returns:
            bool, True if exit code for mkdir is 0, or if
            directory already exists.
        """
        base_path = '/'.join(path.split('/')[:-1])
        if not os.path.exists(base_path):
            mkdir_cmd = ['mkdir', '-p', '-m', '761', base_path]
            mkdir_ret = subprocess.call(mkdir_cmd)
            if mkdir_ret == 0:
                logging.info('Mkdir (%s) successful' % path)
            else:
                logging.error('Mkdir (%s) unsuccessful' % path)

            return mkdir_ret == 0

        return True