Пример #1
0
def _validate_template(template_name):
    template_path = template_location(template_name)
    if not template_path or not os.path.exists(template_path):
        print(_('template-not-found').format(template_name))
        exit(1)
    universe_file_path = universe_file_location(template_name)
    if not os.path.exists(universe_file_path):
        print(_('template-invalid').format(template_name))
        exit(1)
Пример #2
0
def _get_temp_dir_from_argument(temp_dir_argument):
    if temp_dir_argument is not None:
        temp_dir = temp_dir_argument
    else:
        temp_dir = gettempdir()
    if ' ' in temp_dir:
        print(_('spaces-in-temp-error'))
        exit(1)
    return temp_dir
Пример #3
0
def run_ansible(universe_name, chroot_path, user_vars, user_secrets,
                slingring_vars, verbose):
    """
    Runs the universe playbook on the given chroot.
    :param universe_name: The universe name.
    :param chroot_path: The path to the chroot.
    :param user_vars: A dictionary containing user vars (key: name, value: value)
    :param user_secrets: A dictionary containing user secrets (key: name, value: value)
    :param slingring_vars: A dictionary containing slingring vars (key: name, value: value)
    :param verbose: True, if a more verbose output is desired.
    """
    print(_('config-files'))
    with open(playbook_hosts_file_path(universe_name), 'w') as hosts_file:
        hosts_file.write('"{}" {}'.format(chroot_path,
                                          " ansible_connection=chroot"))

    # create ansible variable files
    playbook_directory = playbook_directory_path(universe_name)
    run_command(['mkdir', '-p', playbook_directory], 'create-cache-dir-phase',
                verbose)
    ansible.write_vars_file(playbook_user_vars_path(universe_name), user_vars,
                            'user_vars')
    ansible.write_vars_file(playbook_slingring_vars_path(universe_name),
                            slingring_vars, 'slingring')

    if user_secrets:
        password = key.create_random_password(20)
        ansible.write_vars_vault_file(
            playbook_user_secrets_path(universe_name), user_secrets, password,
            'user_secrets', 'write-user-secret-phase', verbose)
    else:
        password = None

    # mount chroot
    print(_('mount-chroot'))
    try:
        mount(chroot_path, verbose)
        # run ansible
        print(_('ansible'))
        ansible.run_playbook(playbook_directory, verbose, password)
        print(_('umount-chroot'))
    finally:
        umount(chroot_path, verbose)
Пример #4
0
def update_universe(universe_name, verbose):
    """"
    Re-runs the Ansible playbook saved in the local Slingring home
    for the given universe on its chroot.
    :param universe_name: The name of the universe
    :param verbose: True, for more verbose output.
    """
    local_installation_path = local_universe_dir(universe_name)

    if not os.path.exists(local_installation_path):
        print(_('universe-does-not-exist'))
        exit(1)

    installation_configuration_path = installation_file_path(universe_name)
    universe_path = configuration.read_configuration(installation_configuration_path)['location']

    seed_universe_file_path = universe_file_path(universe_name)
    seed_dictionary = configuration.read_seed_file(seed_universe_file_path)

    print(_('update-start').format(universe_name))

    # retrieve ansible variable files from the user
    user_vars, user_secrets = gather_variables_from_user(seed_dictionary)

    print_spaced(_('coffee-time'))

    user_name = user.get_user()
    user_group = user.get_user_group()
    user_home = user_home_in_chroot(user_name)

    slingring_vars = create_slingring_vars_dict(user_name, user_group, user_home, seed_dictionary['mirror'],
                                                universe_name,
                                                seed_dictionary['version'])

    chroot.run_ansible(universe_name, universe_path, user_vars, user_secrets,
                       slingring_vars, verbose)

    if ' ' in universe_name:
        quote = '"'
    else:
        quote = ''

    print_spaced(_('update-done').format(quote, universe_name, quote))
Пример #5
0
def _validate_seed_dictionaries(old_seed_dict, new_seed_dict):
    if old_seed_dict['arch'] != new_seed_dict['arch']:
        print(_('different_arch_error'))
        exit(1)
    if old_seed_dict['suite'] != new_seed_dict['suite']:
        print(_('different_suite_error'))
        exit(1)
    if old_seed_dict['variant'] != new_seed_dict['variant']:
        print(_('different_variant_error'))
        exit(1)
    if old_seed_dict['name'] != new_seed_dict['name']:
        if not yes_no_prompt(_('different_name_warning').format(
                old_seed_dict['name'], new_seed_dict['name']),
                             default='no'):
            exit(1)
        else:
            print()
    if old_seed_dict['version'] == new_seed_dict['version']:
        if not yes_no_prompt(_('same_version_warning'), default='no'):
            exit(1)
        else:
            print()
Пример #6
0
def gather_variables_from_user(seed_dictionary):
    """
    Gathers the variables defined in the given description.
    :param seed_dictionary: The seed universe file contents (as a dictionary).
    :return: the retrieved user vars, the retrieved user secrets as dictionaries
             or None, None if no variables are defined in the description.
    """
    if 'variables' in seed_dictionary:
        print('')
        print(_('input-header'))
        return retrieve_variables_from_user(seed_dictionary['variables'])
    else:
        return None, None
Пример #7
0
def remove_universe(universe_name, verbose):
    """
    Removes a universe from the local machine.
    :param universe_name: The name of the universe which should be removed.
    :param verbose: True, for more verbose output.
    """
    print(_('remove-intro').format(universe_name))

    installation_configuration_path = installation_file_path(universe_name)

    if not os.path.exists(installation_configuration_path):
        print(_('universe-does-not-exist'))
        exit(1)

    installation_path = configuration.read_configuration(
        installation_configuration_path)['location']
    schroot_path = schroot_config_file_path(universe_name)

    if mount.contains_active_mount_point(session_mount_point(universe_name)) \
            or mount.contains_active_mount_point(installation_path):
        print(_('still-mounted-error'))
        exit(1)

    if os.path.exists(installation_path):
        run_command(['sudo', 'rm', '-rf', installation_path], 'deletion-phase',
                    verbose)
        print(_('installation-path-removed'))
    else:
        print(_('installation-path-does-not-exist'))

    if os.path.exists(schroot_path):
        run_command(['sudo', 'rm', schroot_path], 'deletion-phase', verbose)
        print(_('schroot-config-removed'))
    else:
        print(_('schroot-config-does-not-exist'))

    local_universe_path = local_universe_dir(universe_name)
    if os.path.exists(local_universe_path):
        run_command(['rm', '-rf', local_universe_path], 'deletion-phase',
                    verbose)
        print(_('local-cache-removed'))
    else:
        print(_('local-cache-does-not-exist'))
Пример #8
0
def list_universes(verbose):
    """
    Lists all universes on the local machine.
    """
    multiverse_directory = _get_directories_in_multiverse()
    universe_list = []
    for universe in multiverse_directory:
        installation_file_path = paths.installation_file_path(universe)
        if os.path.exists(installation_file_path):
            install_path = configuration.read_configuration(
                installation_file_path)['location']
            if verbose:
                output = '   - {} ({})'.format(universe, install_path)
            else:
                output = '   - {}'.format(universe)
            universe_list.append(output)

    if universe_list:
        print(_('list-start'))
        for universe in universe_list:
            print(universe)
    else:
        print(_('no-universes-found'))
Пример #9
0
def create_seed(args):
    """"
    Creates a new universe seed from a template.
    :param args: The command line arguments as parsed by argparse.
                 This is expected to contain the following information:
                    - name: The intended name for the seed.
                    - directory: The root directory in which the seed should be created.
                                 The complete resulting directory is root + name.
                    - template: The template name (e.g. 'default'). The template will be
                                loaded from the local home. If it cannot be found in the
                                local home, it will be taken from the global share.
    """
    universe_name = args.name
    root_dir = args.directory
    template_name = args.template

    seed_dir = os.path.join(args.directory, args.name)

    _validate_template(template_name)

    if os.path.exists(seed_dir):
        print(_('directory-exists').format(universe_name, root_dir))
        exit(1)

    _copy_base_image(universe_name, template_name, root_dir)

    # Fill in templates, if filters are defined.
    template_path = template_file_location(template_name)
    if os.path.exists(template_path):
        template_config = read_configuration(template_path)
        template_filter_expressions = template_config.get(
            'template_filter', [])
        if template_filter_expressions:
            template_blacklist_expressions = template_config.get(
                'template_blacklist', [])
            result_dir = os.path.join(root_dir, universe_name)
            template_files = _find_template_files(
                result_dir, template_filter_expressions,
                template_blacklist_expressions)
            variables = _get_variable_dict(args.name)
            for file in template_files:
                _fill_in_template(file, variables)
Пример #10
0
def _command_print(cmd_output, phase, command, verbose, pipe_command=None):
    if cmd_output.returncode:
        if verbose:
            print(_('cmd-error-verbose').format(phase))
        else:
            print(_('cmd-error').format(phase))
            print()
            print(_('stdout').format(phase))
            print(cmd_output.stdout)
            print()
            print(_('stderr').format(phase))
            print(cmd_output.stderr)
        print(_('failed-command').format(' '.join(command)))
        if pipe_command:
            print(_('failed-pipe-command').format(' '.join(pipe_command)))
    return cmd_output
Пример #11
0
def upgrade_universe(seed_path, universe_name, verbose):
    """
    Replaces the local seed of an existing universe with a newer
    version and runs the Ansible playbook on the given universe's chroot.
    :param seed_path: The path to the universe seed directory as string.
    :param universe_name: The name of the universe
    :param verbose: True, for more verbose output.
    """
    old_universe_name = universe_name

    local_installation_path = local_universe_dir(old_universe_name)

    if not os.path.exists(local_installation_path):
        print(_('universe-does-not-exist'))
        exit(1)

    # read current information
    old_installation_configuration_path = installation_file_path(
        old_universe_name)
    universe_path = configuration.read_configuration(
        old_installation_configuration_path)['location']

    seed_universe_file_path = universe_file_path(old_universe_name)
    old_seed_dictionary = configuration.read_seed_file(seed_universe_file_path)

    # read new information
    source_seed_directory = get_seed_directory_from_argument(seed_path)
    source_seed_universe_path = source_universe_file_path(
        source_seed_directory)
    new_seed_dictionary = configuration.read_seed_file(
        source_seed_universe_path)
    new_universe_name = new_seed_dictionary['name']

    if not yes_no_prompt(
            _('upgrade-warning').format(new_seed_dictionary['version'],
                                        old_seed_dictionary['version'])):
        exit(1)
    else:
        print()

    # validate
    _validate_seed_dictionaries(old_seed_dictionary, new_seed_dictionary)
    if old_universe_name != new_universe_name:
        _validate_paths_for_collision(new_universe_name)

    # replace old seed with new seed
    run_command(['rm', '-rf', local_installation_path],
                'remove-local-seed-phase', verbose)
    copy_seed_to_local_home(source_seed_directory, new_universe_name)
    new_installation_configuration_path = installation_file_path(
        new_universe_name)
    configuration.write_installation_configuration(
        new_installation_configuration_path, universe_path)

    # take care of the schroot config in case of a universe rename
    if old_universe_name != new_universe_name:
        change_schroot_name(old_universe_name, new_universe_name,
                            schroot_config_file_path(old_universe_name),
                            schroot_config_file_path(new_universe_name),
                            'rename-schroot-phase', verbose)

    # run the new Ansible playbook on the universe as if we just updated
    update_universe(new_universe_name, verbose)
Пример #12
0
def _validate_paths_for_collision(universe_name):
    if colliding_local_or_schroot_paths_exist(universe_name):
        print(_('colliding-paths'))
        exit(1)
Пример #13
0
def create_universe(seed_path, temp_dir, verbose):
    """"
    Creates a new universe from a universe description.
    :param seed_path: The path to the universe seed directory as string.
    :param temp_dir: An alternative temp directory for debootstrapping (must not contain spaces).
    :param verbose: True, for more verbose output.
    """
    source_seed_directory = get_seed_directory_from_argument(seed_path)
    source_seed_universe_path = source_universe_file_path(
        source_seed_directory)
    seed_dictionary = configuration.read_seed_file(source_seed_universe_path)
    universe_name = seed_dictionary['name']
    temp_dir = _get_temp_dir_from_argument(temp_dir)

    _validate_paths_for_collision(universe_name)

    print(_('start').format(universe_name))

    # Phase 1: Retrieve Ansible variable files from the user now, so we don't need user interaction after this point
    user_vars, user_secrets = gather_variables_from_user(seed_dictionary)

    # Phase 2: Copy the universe description to our local home in ~/.slingring and write the installation file
    #          The installation file contains the directory of the chroot, so the 'remove' operation finds it,
    #          even if the installation fails.
    print_spaced(_('coffee-time'))
    universe_path = designated_universe_path(universe_name)
    copy_seed_to_local_home(source_seed_directory, universe_name)
    configuration.write_installation_configuration(
        installation_file_path(universe_name), universe_path)

    # Phase 3: Run debootstrap to create the chroot
    print(
        _('debootstrap').format(seed_dictionary['suite'],
                                seed_dictionary['arch']))
    chroot.bootstrap(universe_path, seed_dictionary, verbose, temp_dir)

    if verbose:
        print()

    # Phase 4: Create schroot config (setup) file.
    print(_('schroot'))
    schroot_config_path = schroot_config_file_path(universe_name)

    user_name = user.get_user()
    user_group = user.get_user_group()
    schroot.create_schroot_config(universe_name, schroot_config_path,
                                  universe_path, user_name, user_group,
                                  'schroot-config-phase', verbose)

    # Phase 4.1: We must run one command in the schroot. Since we create schroots with the setup-profile
    #            This will copy all necessary files like /etc/passwd, /etc/shadow etc. to the chroot.
    print(_('prepare-chroot'))
    user_home = chroot.create_user_home(user_name, user_group, universe_name,
                                        verbose)

    # Phase 4.2: Since everything is set up now, we set schroot config to (runtime) after first command.
    #            This will prevent subsequent schroot calls from overwriting the 'copyfiles' (e.g. /etc/passwd).
    schroot.change_schroot_profile(universe_name, schroot_config_path,
                                   'slingring-runtime',
                                   'enable-runtime-profile-phase', verbose)

    # Phase 5: Run the initializer scripts. These are shell scripts provided by the author of the universe description.
    #          Their task is to prepare the chroot for the Ansible playbooks (install Python, create _apt user for
    #          Debian based distros etc.)
    initializer_directory = initializer_directory_path(universe_name)
    chroot.run_initializers(initializer_directory, universe_path,
                            universe_name, user_name, user_group, verbose)

    # Phase 6: Run the Ansible playbook on our chroot.
    slingring_vars = create_slingring_vars_dict(user_name, user_group,
                                                user_home,
                                                seed_dictionary['mirror'],
                                                universe_name,
                                                seed_dictionary['version'])
    if verbose:
        print()
    chroot.run_ansible(universe_name, universe_path, user_vars, user_secrets,
                       slingring_vars, verbose)

    if ' ' in universe_name:
        quote = '"'
    else:
        quote = ''

    print_spaced(_('done').format(quote, universe_name, quote))
Пример #14
0
def _print_templates(images, key):
    if images:
        print(_(key))
        for image_name in images:
            print('   - {}'.format(image_name))