bootstrap.py 4.02 KB
#!/usr/bin/env python2.7

import os
import apt
import apt_pkg
import locale
import platform
import subprocess
import urllib

from apt import debfile
from distutils.version import StrictVersion
from pkg_resources import parse_requirements
from shutil import copyfile
from subprocess import check_output


PUPPET_TARGET_VERSION="3.4.3-1"
PUPPET_DIR = os.path.join(os.path.dirname(__file__))
MODULES_FILE_PATH = os.path.join(PUPPET_DIR, 'modules.txt')


def get_package(name):
    cache = apt.cache.Cache()
    if name in cache:
        return cache[name], cache

    return None, None


def pkg_available(name):
    pkg = get_package(name)[0]
    if pkg and pkg.versions.get(PUPPET_TARGET_VERSION):
        return True

    return False


def config_puppetlabs_repo():
    dist = platform.dist()[-1]

    url = 'http://apt.puppetlabs.com/puppetlabs-release-{}.deb'.format(dist)
    filename = '/tmp/puppet_apt.deb'
    try:
        urllib.urlretrieve(url, filename)
    except IOError:
        print "Could not install puppet"
        raise

    deb_pkg = debfile.DebPackage(filename)
    if deb_pkg.check():
        deb_pkg.install()
        cache = apt.cache.Cache()
        cache.update()
        cache.open()


def install_puppet(upgrade=False):
    pkg, cache = get_package('puppet')

    pkg.candidate = pkg.versions.get(PUPPET_TARGET_VERSION)
    if upgrade:
        pkg.mark_upgrade()
    else:
        pkg.mark_install()

    cache.commit()


def get_modules_installed():
    modules_list = check_output(['puppet', 'module', 'list']).split('\n')
    modules_list = [line for line in modules_list if 'no modules' not in line]
    modules_list = [item.split()[1:] for item in modules_list]
    modules_list = [item for item in modules_list if item]
    modules_dict = {}
    for name, version in modules_list:
        modules_dict[name] = version.split('v')[1].replace(
            '\x1b[0m)',
            ''
        )
    return modules_dict


def run(cmd, module, version=''):
    if version:
        version = ' --version {}'.format(version)

    cmd = 'puppet module {} {}{}'.format(cmd, module, version)
    process = subprocess.Popen(cmd, shell=True, executable='/bin/bash')
    process.wait()


def install_puppet_modules():
    modules_installed = get_modules_installed()

    with open(MODULES_FILE_PATH) as modules_file:
        modules_requirements = modules_file.read().replace('/', '-')

    for module in parse_requirements(modules_requirements):

        current_cmd, compare, version, version_comparison = '', '', '', None
        if module.project_name in modules_installed:

            if module.specs:
                compare, version = module.specs[0]
                version_comparison = apt_pkg.version_compare(
                    modules_installed[module.project_name],
                    version
                )
            else:
                continue

            if version_comparison == 0 and compare is not '>':
                # module version installed is equal version
                continue
            else:
                # module version installed is smaller or bigger than version
                current_cmd = 'upgrade'
        else:
            current_cmd = 'install'

        if version and compare and '>' not in compare:
            run(current_cmd, module.project_name, version)
        else:
            if not version_comparison or version_comparison < 0:
                run(current_cmd, module.project_name)

def main():
    # If the package not found or if the version is outdated, install puppet
    if not pkg_available('puppet'):
        config_puppetlabs_repo()

    pkg = get_package('puppet')[0]
    if not pkg.is_installed:
        install_puppet()
    elif apt_pkg.version_compare(pkg.installed.version,
                                 PUPPET_TARGET_VERSION) < 0:
        install_puppet(upgrade=True)

    if os.path.isfile('/vagrant/puppet/hiera.yaml'):
        copyfile('/vagrant/puppet/hiera.yaml', '/etc/puppet/hiera.yaml')

    locale.setlocale(locale.LC_ALL, '')

    install_puppet_modules()


if __name__ == '__main__':
    main()