Blame cloudinit/config/cc_chef.py

Packit Service a04d08
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
Packit Service a04d08
#
Packit Service a04d08
# Author: Avishai Ish-Shalom <avishai@fewbytes.com>
Packit Service a04d08
# Author: Mike Moulton <mike@meltmedia.com>
Packit Service a04d08
# Author: Juerg Haefliger <juerg.haefliger@hp.com>
Packit Service a04d08
#
Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service 751c4a
"""Chef: module that configures, starts and installs chef."""
Packit Service a04d08
Packit Service a04d08
import itertools
Packit Service a04d08
import json
Packit Service a04d08
import os
Packit Service 751c4a
from textwrap import dedent
Packit Service a04d08
Packit Service 751c4a
from cloudinit import subp
Packit Service 751c4a
from cloudinit.config.schema import (
Packit Service 751c4a
    get_schema_doc, validate_cloudconfig_schema)
Packit Service a04d08
from cloudinit import templater
Packit Service 751c4a
from cloudinit import temp_utils
Packit Service a04d08
from cloudinit import url_helper
Packit Service a04d08
from cloudinit import util
Packit Service 751c4a
from cloudinit.settings import PER_ALWAYS
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
RUBY_VERSION_DEFAULT = "1.8"
Packit Service a04d08
Packit Service a04d08
CHEF_DIRS = tuple([
Packit Service a04d08
    '/etc/chef',
Packit Service a04d08
    '/var/log/chef',
Packit Service a04d08
    '/var/lib/chef',
Packit Service a04d08
    '/var/cache/chef',
Packit Service a04d08
    '/var/backups/chef',
Packit Service 11b429
    '/var/run/chef',
Packit Service a04d08
])
Packit Service a04d08
REQUIRED_CHEF_DIRS = tuple([
Packit Service a04d08
    '/etc/chef',
Packit Service a04d08
])
Packit Service a04d08
Packit Service a04d08
# Used if fetching chef from a omnibus style package
Packit Service a04d08
OMNIBUS_URL = "https://www.chef.io/chef/install.sh"
Packit Service a04d08
OMNIBUS_URL_RETRIES = 5
Packit Service a04d08
Packit Service a04d08
CHEF_VALIDATION_PEM_PATH = '/etc/chef/validation.pem'
Packit Service 751c4a
CHEF_ENCRYPTED_DATA_BAG_PATH = '/etc/chef/encrypted_data_bag_secret'
Packit Service 751c4a
CHEF_ENVIRONMENT = '_default'
Packit Service a04d08
CHEF_FB_PATH = '/etc/chef/firstboot.json'
Packit Service a04d08
CHEF_RB_TPL_DEFAULTS = {
Packit Service a04d08
    # These are ruby symbols...
Packit Service a04d08
    'ssl_verify_mode': ':verify_none',
Packit Service a04d08
    'log_level': ':info',
Packit Service a04d08
    # These are not symbols...
Packit Service a04d08
    'log_location': '/var/log/chef/client.log',
Packit Service a04d08
    'validation_key': CHEF_VALIDATION_PEM_PATH,
Packit Service a04d08
    'validation_cert': None,
Packit Service 751c4a
    'client_key': '/etc/chef/client.pem',
Packit Service a04d08
    'json_attribs': CHEF_FB_PATH,
Packit Service 751c4a
    'file_cache_path': '/var/cache/chef',
Packit Service 751c4a
    'file_backup_path': '/var/backups/chef',
Packit Service 751c4a
    'pid_file': '/var/run/chef/client.pid',
Packit Service a04d08
    'show_time': True,
Packit Service a04d08
    'encrypted_data_bag_secret': None,
Packit Service a04d08
}
Packit Service a04d08
CHEF_RB_TPL_BOOL_KEYS = frozenset(['show_time'])
Packit Service a04d08
CHEF_RB_TPL_PATH_KEYS = frozenset([
Packit Service a04d08
    'log_location',
Packit Service a04d08
    'validation_key',
Packit Service a04d08
    'client_key',
Packit Service a04d08
    'file_cache_path',
Packit Service a04d08
    'json_attribs',
Packit Service a04d08
    'pid_file',
Packit Service a04d08
    'encrypted_data_bag_secret',
Packit Service 751c4a
    'chef_license',
Packit Service a04d08
])
Packit Service a04d08
CHEF_RB_TPL_KEYS = list(CHEF_RB_TPL_DEFAULTS.keys())
Packit Service a04d08
CHEF_RB_TPL_KEYS.extend(CHEF_RB_TPL_BOOL_KEYS)
Packit Service a04d08
CHEF_RB_TPL_KEYS.extend(CHEF_RB_TPL_PATH_KEYS)
Packit Service a04d08
CHEF_RB_TPL_KEYS.extend([
Packit Service a04d08
    'server_url',
Packit Service a04d08
    'node_name',
Packit Service a04d08
    'environment',
Packit Service a04d08
    'validation_name',
Packit Service a04d08
])
Packit Service a04d08
CHEF_RB_TPL_KEYS = frozenset(CHEF_RB_TPL_KEYS)
Packit Service a04d08
CHEF_RB_PATH = '/etc/chef/client.rb'
Packit Service a04d08
CHEF_EXEC_PATH = '/usr/bin/chef-client'
Packit Service a04d08
CHEF_EXEC_DEF_ARGS = tuple(['-d', '-i', '1800', '-s', '20'])
Packit Service a04d08
Packit Service a04d08
Packit Service 751c4a
frequency = PER_ALWAYS
Packit Service 751c4a
distros = ["all"]
Packit Service 751c4a
schema = {
Packit Service 751c4a
    'id': 'cc_chef',
Packit Service 751c4a
    'name': 'Chef',
Packit Service 751c4a
    'title': 'module that configures, starts and installs chef',
Packit Service 751c4a
    'description': dedent("""\
Packit Service 751c4a
        This module enables chef to be installed (from packages,
Packit Service 751c4a
        gems, or from omnibus). Before this occurs, chef configuration is
Packit Service 751c4a
        written to disk (validation.pem, client.pem, firstboot.json,
Packit Service 751c4a
        client.rb), and required directories are created (/etc/chef and
Packit Service 751c4a
        /var/log/chef and so-on). If configured, chef will be
Packit Service 751c4a
        installed and started in either daemon or non-daemon mode.
Packit Service 751c4a
        If run in non-daemon mode, post run actions are executed to do
Packit Service 751c4a
        finishing activities such as removing validation.pem."""),
Packit Service 751c4a
    'distros': distros,
Packit Service 751c4a
    'examples': [dedent("""
Packit Service 751c4a
        chef:
Packit Service 751c4a
          directories:
Packit Service 751c4a
            - /etc/chef
Packit Service 751c4a
            - /var/log/chef
Packit Service 751c4a
          validation_cert: system
Packit Service 751c4a
          install_type: omnibus
Packit Service 751c4a
          initial_attributes:
Packit Service 751c4a
            apache:
Packit Service 751c4a
              prefork:
Packit Service 751c4a
                maxclients: 100
Packit Service 751c4a
              keepalive: off
Packit Service 751c4a
          run_list:
Packit Service 751c4a
            - recipe[apache2]
Packit Service 751c4a
            - role[db]
Packit Service 751c4a
          encrypted_data_bag_secret: /etc/chef/encrypted_data_bag_secret
Packit Service 751c4a
          environment: _default
Packit Service 751c4a
          log_level: :auto
Packit Service 751c4a
          omnibus_url_retries: 2
Packit Service 751c4a
          server_url: https://chef.yourorg.com:4000
Packit Service 751c4a
          ssl_verify_mode: :verify_peer
Packit Service 751c4a
          validation_name: yourorg-validator""")],
Packit Service 751c4a
    'frequency': frequency,
Packit Service 751c4a
    'type': 'object',
Packit Service 751c4a
    'properties': {
Packit Service 751c4a
        'chef': {
Packit Service 751c4a
            'type': 'object',
Packit Service 751c4a
            'additionalProperties': False,
Packit Service 751c4a
            'properties': {
Packit Service 751c4a
                'directories': {
Packit Service 751c4a
                    'type': 'array',
Packit Service 751c4a
                    'items': {
Packit Service 751c4a
                        'type': 'string'
Packit Service 751c4a
                    },
Packit Service 751c4a
                    'uniqueItems': True,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Create the necessary directories for chef to run. By
Packit Service 751c4a
                        default, it creates the following directories:
Packit Service 751c4a
Packit Service 751c4a
                        {chef_dirs}""").format(
Packit Service 751c4a
                        chef_dirs="\n".join(
Packit Service 751c4a
                            ["   - ``{}``".format(d) for d in CHEF_DIRS]
Packit Service 751c4a
                        )
Packit Service 751c4a
                    )
Packit Service 751c4a
                },
Packit Service 751c4a
                'validation_cert': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Optional string to be written to file validation_key.
Packit Service 751c4a
                        Special value ``system`` means set use existing file.
Packit Service 751c4a
                        """)
Packit Service 751c4a
                },
Packit Service 751c4a
                'validation_key': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_VALIDATION_PEM_PATH,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Optional path for validation_cert. default to
Packit Service 751c4a
                        ``{}``.""".format(CHEF_VALIDATION_PEM_PATH))
Packit Service 751c4a
                },
Packit Service 751c4a
                'firstboot_path': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_FB_PATH,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Path to write run_list and initial_attributes keys that
Packit Service 751c4a
                        should also be present in this configuration, defaults
Packit Service 751c4a
                        to ``{}``.""".format(CHEF_FB_PATH))
Packit Service 751c4a
                },
Packit Service 751c4a
                'exec': {
Packit Service 751c4a
                    'type': 'boolean',
Packit Service 751c4a
                    'default': False,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        define if we should run or not run chef (defaults to
Packit Service 751c4a
                        false, unless a gem installed is requested where this
Packit Service 751c4a
                        will then default to true).""")
Packit Service 751c4a
                },
Packit Service 751c4a
                'client_key': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_RB_TPL_DEFAULTS['client_key'],
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Optional path for client_cert. default to
Packit Service 751c4a
                        ``{}``.""".format(CHEF_RB_TPL_DEFAULTS['client_key']))
Packit Service 751c4a
                },
Packit Service 751c4a
                'encrypted_data_bag_secret': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': None,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Specifies the location of the secret key used by chef
Packit Service 751c4a
                        to encrypt data items. By default, this path is set
Packit Service 751c4a
                        to None, meaning that chef will have to look at the
Packit Service 751c4a
                        path ``{}`` for it.
Packit Service 751c4a
                        """.format(CHEF_ENCRYPTED_DATA_BAG_PATH))
Packit Service 751c4a
                },
Packit Service 751c4a
                'environment': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_ENVIRONMENT,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Specifies which environment chef will use. By default,
Packit Service 751c4a
                        it will use the ``{}`` configuration.
Packit Service 751c4a
                        """.format(CHEF_ENVIRONMENT))
Packit Service 751c4a
                },
Packit Service 751c4a
                'file_backup_path': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_RB_TPL_DEFAULTS['file_backup_path'],
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Specifies the location in which backup files are
Packit Service 751c4a
                        stored. By default, it uses the
Packit Service 751c4a
                        ``{}`` location.""".format(
Packit Service 751c4a
                            CHEF_RB_TPL_DEFAULTS['file_backup_path']))
Packit Service 751c4a
                },
Packit Service 751c4a
                'file_cache_path': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_RB_TPL_DEFAULTS['file_cache_path'],
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Specifies the location in which chef cache files will
Packit Service 751c4a
                        be saved. By default, it uses the ``{}``
Packit Service 751c4a
                        location.""".format(
Packit Service 751c4a
                            CHEF_RB_TPL_DEFAULTS['file_cache_path']))
Packit Service 751c4a
                },
Packit Service 751c4a
                'json_attribs': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_FB_PATH,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Specifies the location in which some chef json data is
Packit Service 751c4a
                        stored. By default, it uses the
Packit Service 751c4a
                        ``{}`` location.""".format(CHEF_FB_PATH))
Packit Service 751c4a
                },
Packit Service 751c4a
                'log_level': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_RB_TPL_DEFAULTS['log_level'],
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Defines the level of logging to be stored in the log
Packit Service 751c4a
                        file. By default this value is set to ``{}``.
Packit Service 751c4a
                        """.format(CHEF_RB_TPL_DEFAULTS['log_level']))
Packit Service 751c4a
                },
Packit Service 751c4a
                'log_location': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_RB_TPL_DEFAULTS['log_location'],
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Specifies the location of the chef lof file. By
Packit Service 751c4a
                        default, the location is specified at
Packit Service 751c4a
                        ``{}``.""".format(
Packit Service 751c4a
                            CHEF_RB_TPL_DEFAULTS['log_location']))
Packit Service 751c4a
                },
Packit Service 751c4a
                'node_name': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        The name of the node to run. By default, we will
Packit Service 751c4a
                        use th instance id as the node name.""")
Packit Service 751c4a
                },
Packit Service 751c4a
                'omnibus_url': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': OMNIBUS_URL,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Omnibus URL if chef should be installed through
Packit Service 751c4a
                        Omnibus. By default, it uses the
Packit Service 751c4a
                        ``{}``.""".format(OMNIBUS_URL))
Packit Service 751c4a
                },
Packit Service 751c4a
                'omnibus_url_retries': {
Packit Service 751c4a
                    'type': 'integer',
Packit Service 751c4a
                    'default': OMNIBUS_URL_RETRIES,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        The number of retries that will be attempted to reach
Packit Service 751c4a
                        the Omnibus URL""")
Packit Service 751c4a
                },
Packit Service 751c4a
                'omnibus_version': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Optional version string to require for omnibus
Packit Service 751c4a
                        install.""")
Packit Service 751c4a
                },
Packit Service 751c4a
                'pid_file': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_RB_TPL_DEFAULTS['pid_file'],
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        The location in which a process identification
Packit Service 751c4a
                        number (pid) is saved. By default, it saves
Packit Service 751c4a
                        in the ``{}`` location.""".format(
Packit Service 751c4a
                            CHEF_RB_TPL_DEFAULTS['pid_file']))
Packit Service 751c4a
                },
Packit Service 751c4a
                'server_url': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'description': 'The URL for the chef server'
Packit Service 751c4a
                },
Packit Service 751c4a
                'show_time': {
Packit Service 751c4a
                    'type': 'boolean',
Packit Service 751c4a
                    'default': True,
Packit Service 751c4a
                    'description': 'Show time in chef logs'
Packit Service 751c4a
                },
Packit Service 751c4a
                'ssl_verify_mode': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': CHEF_RB_TPL_DEFAULTS['ssl_verify_mode'],
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Set the verify mode for HTTPS requests. We can have
Packit Service 751c4a
                        two possible values for this parameter:
Packit Service 751c4a
Packit Service 751c4a
                            - ``:verify_none``: No validation of SSL \
Packit Service 751c4a
                            certificates.
Packit Service 751c4a
                            - ``:verify_peer``: Validate all SSL certificates.
Packit Service 751c4a
Packit Service 751c4a
                        By default, the parameter is set as ``{}``.
Packit Service 751c4a
                        """.format(CHEF_RB_TPL_DEFAULTS['ssl_verify_mode']))
Packit Service 751c4a
                },
Packit Service 751c4a
                'validation_name': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        The name of the chef-validator key that Chef Infra
Packit Service 751c4a
                        Client uses to access the Chef Infra Server during
Packit Service 751c4a
                        the initial Chef Infra Client run.""")
Packit Service 751c4a
                },
Packit Service 751c4a
                'force_install': {
Packit Service 751c4a
                    'type': 'boolean',
Packit Service 751c4a
                    'default': False,
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        If set to ``True``, forces chef installation, even
Packit Service 751c4a
                        if it is already installed.""")
Packit Service 751c4a
                },
Packit Service 751c4a
                'initial_attributes': {
Packit Service 751c4a
                    'type': 'object',
Packit Service 751c4a
                    'items': {
Packit Service 751c4a
                        'type': 'string'
Packit Service 751c4a
                    },
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        Specify a list of initial attributes used by the
Packit Service 751c4a
                        cookbooks.""")
Packit Service 751c4a
                },
Packit Service 751c4a
                'install_type': {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'default': 'packages',
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        The type of installation for chef. It can be one of
Packit Service 751c4a
                        the following values:
Packit Service 751c4a
Packit Service 751c4a
                            - ``packages``
Packit Service 751c4a
                            - ``gems``
Packit Service 751c4a
                            - ``omnibus``""")
Packit Service 751c4a
                },
Packit Service 751c4a
                'run_list': {
Packit Service 751c4a
                    'type': 'array',
Packit Service 751c4a
                    'items': {
Packit Service 751c4a
                        'type': 'string'
Packit Service 751c4a
                    },
Packit Service 751c4a
                    'description': 'A run list for a first boot json.'
Packit Service 751c4a
                },
Packit Service 751c4a
                "chef_license": {
Packit Service 751c4a
                    'type': 'string',
Packit Service 751c4a
                    'description': dedent("""\
Packit Service 751c4a
                        string that indicates if user accepts or not license
Packit Service 751c4a
                        related to some of chef products""")
Packit Service 751c4a
                }
Packit Service 751c4a
            }
Packit Service 751c4a
        }
Packit Service 751c4a
    }
Packit Service 751c4a
}
Packit Service 751c4a
Packit Service 751c4a
__doc__ = get_schema_doc(schema)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def post_run_chef(chef_cfg, log):
Packit Service a04d08
    delete_pem = util.get_cfg_option_bool(chef_cfg,
Packit Service a04d08
                                          'delete_validation_post_exec',
Packit Service a04d08
                                          default=False)
Packit Service a04d08
    if delete_pem and os.path.isfile(CHEF_VALIDATION_PEM_PATH):
Packit Service a04d08
        os.unlink(CHEF_VALIDATION_PEM_PATH)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_template_params(iid, chef_cfg, log):
Packit Service a04d08
    params = CHEF_RB_TPL_DEFAULTS.copy()
Packit Service a04d08
    # Allow users to overwrite any of the keys they want (if they so choose),
Packit Service a04d08
    # when a value is None, then the value will be set to None and no boolean
Packit Service a04d08
    # or string version will be populated...
Packit Service a04d08
    for (k, v) in chef_cfg.items():
Packit Service a04d08
        if k not in CHEF_RB_TPL_KEYS:
Packit Service a04d08
            log.debug("Skipping unknown chef template key '%s'", k)
Packit Service a04d08
            continue
Packit Service a04d08
        if v is None:
Packit Service a04d08
            params[k] = None
Packit Service a04d08
        else:
Packit Service a04d08
            # This will make the value a boolean or string...
Packit Service a04d08
            if k in CHEF_RB_TPL_BOOL_KEYS:
Packit Service a04d08
                params[k] = util.get_cfg_option_bool(chef_cfg, k)
Packit Service a04d08
            else:
Packit Service a04d08
                params[k] = util.get_cfg_option_str(chef_cfg, k)
Packit Service a04d08
    # These ones are overwritten to be exact values...
Packit Service a04d08
    params.update({
Packit Service a04d08
        'generated_by': util.make_header(),
Packit Service a04d08
        'node_name': util.get_cfg_option_str(chef_cfg, 'node_name',
Packit Service a04d08
                                             default=iid),
Packit Service a04d08
        'environment': util.get_cfg_option_str(chef_cfg, 'environment',
Packit Service a04d08
                                               default='_default'),
Packit Service a04d08
        # These two are mandatory...
Packit Service a04d08
        'server_url': chef_cfg['server_url'],
Packit Service a04d08
        'validation_name': chef_cfg['validation_name'],
Packit Service a04d08
    })
Packit Service a04d08
    return params
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def handle(name, cfg, cloud, log, _args):
Packit Service a04d08
    """Handler method activated by cloud-init."""
Packit Service a04d08
Packit Service a04d08
    # If there isn't a chef key in the configuration don't do anything
Packit Service a04d08
    if 'chef' not in cfg:
Packit Service a04d08
        log.debug(("Skipping module named %s,"
Packit Service a04d08
                   " no 'chef' key in configuration"), name)
Packit Service a04d08
        return
Packit Service 751c4a
Packit Service 751c4a
    validate_cloudconfig_schema(cfg, schema)
Packit Service a04d08
    chef_cfg = cfg['chef']
Packit Service a04d08
Packit Service a04d08
    # Ensure the chef directories we use exist
Packit Service a04d08
    chef_dirs = util.get_cfg_option_list(chef_cfg, 'directories')
Packit Service a04d08
    if not chef_dirs:
Packit Service a04d08
        chef_dirs = list(CHEF_DIRS)
Packit Service a04d08
    for d in itertools.chain(chef_dirs, REQUIRED_CHEF_DIRS):
Packit Service a04d08
        util.ensure_dir(d)
Packit Service a04d08
Packit Service a04d08
    vkey_path = chef_cfg.get('validation_key', CHEF_VALIDATION_PEM_PATH)
Packit Service a04d08
    vcert = chef_cfg.get('validation_cert')
Packit Service a04d08
    # special value 'system' means do not overwrite the file
Packit Service a04d08
    # but still render the template to contain 'validation_key'
Packit Service a04d08
    if vcert:
Packit Service a04d08
        if vcert != "system":
Packit Service a04d08
            util.write_file(vkey_path, vcert)
Packit Service a04d08
        elif not os.path.isfile(vkey_path):
Packit Service a04d08
            log.warning("chef validation_cert provided as 'system', but "
Packit Service a04d08
                        "validation_key path '%s' does not exist.",
Packit Service a04d08
                        vkey_path)
Packit Service a04d08
Packit Service a04d08
    # Create the chef config from template
Packit Service a04d08
    template_fn = cloud.get_template_filename('chef_client.rb')
Packit Service a04d08
    if template_fn:
Packit Service a04d08
        iid = str(cloud.datasource.get_instance_id())
Packit Service a04d08
        params = get_template_params(iid, chef_cfg, log)
Packit Service a04d08
        # Do a best effort attempt to ensure that the template values that
Packit Service 751c4a
        # are associated with paths have their parent directory created
Packit Service a04d08
        # before they are used by the chef-client itself.
Packit Service a04d08
        param_paths = set()
Packit Service a04d08
        for (k, v) in params.items():
Packit Service a04d08
            if k in CHEF_RB_TPL_PATH_KEYS and v:
Packit Service a04d08
                param_paths.add(os.path.dirname(v))
Packit Service a04d08
        util.ensure_dirs(param_paths)
Packit Service a04d08
        templater.render_to_file(template_fn, CHEF_RB_PATH, params)
Packit Service a04d08
    else:
Packit Service a04d08
        log.warning("No template found, not rendering to %s",
Packit Service a04d08
                    CHEF_RB_PATH)
Packit Service a04d08
Packit Service a04d08
    # Set the firstboot json
Packit Service a04d08
    fb_filename = util.get_cfg_option_str(chef_cfg, 'firstboot_path',
Packit Service a04d08
                                          default=CHEF_FB_PATH)
Packit Service a04d08
    if not fb_filename:
Packit Service a04d08
        log.info("First boot path empty, not writing first boot json file")
Packit Service a04d08
    else:
Packit Service a04d08
        initial_json = {}
Packit Service a04d08
        if 'run_list' in chef_cfg:
Packit Service a04d08
            initial_json['run_list'] = chef_cfg['run_list']
Packit Service a04d08
        if 'initial_attributes' in chef_cfg:
Packit Service a04d08
            initial_attributes = chef_cfg['initial_attributes']
Packit Service a04d08
            for k in list(initial_attributes.keys()):
Packit Service a04d08
                initial_json[k] = initial_attributes[k]
Packit Service a04d08
        util.write_file(fb_filename, json.dumps(initial_json))
Packit Service a04d08
Packit Service a04d08
    # Try to install chef, if its not already installed...
Packit Service a04d08
    force_install = util.get_cfg_option_bool(chef_cfg,
Packit Service a04d08
                                             'force_install', default=False)
Packit Service 751c4a
    installed = subp.is_exe(CHEF_EXEC_PATH)
Packit Service 751c4a
    if not installed or force_install:
Packit Service a04d08
        run = install_chef(cloud, chef_cfg, log)
Packit Service 751c4a
    elif installed:
Packit Service a04d08
        run = util.get_cfg_option_bool(chef_cfg, 'exec', default=False)
Packit Service a04d08
    else:
Packit Service a04d08
        run = False
Packit Service a04d08
    if run:
Packit Service a04d08
        run_chef(chef_cfg, log)
Packit Service a04d08
        post_run_chef(chef_cfg, log)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def run_chef(chef_cfg, log):
Packit Service a04d08
    log.debug('Running chef-client')
Packit Service a04d08
    cmd = [CHEF_EXEC_PATH]
Packit Service a04d08
    if 'exec_arguments' in chef_cfg:
Packit Service a04d08
        cmd_args = chef_cfg['exec_arguments']
Packit Service a04d08
        if isinstance(cmd_args, (list, tuple)):
Packit Service a04d08
            cmd.extend(cmd_args)
Packit Service 751c4a
        elif isinstance(cmd_args, str):
Packit Service a04d08
            cmd.append(cmd_args)
Packit Service a04d08
        else:
Packit Service a04d08
            log.warning("Unknown type %s provided for chef"
Packit Service a04d08
                        " 'exec_arguments' expected list, tuple,"
Packit Service a04d08
                        " or string", type(cmd_args))
Packit Service a04d08
            cmd.extend(CHEF_EXEC_DEF_ARGS)
Packit Service a04d08
    else:
Packit Service a04d08
        cmd.extend(CHEF_EXEC_DEF_ARGS)
Packit Service 751c4a
    subp.subp(cmd, capture=False)
Packit Service 751c4a
Packit Service 751c4a
Packit Service 751c4a
def subp_blob_in_tempfile(blob, *args, **kwargs):
Packit Service 751c4a
    """Write blob to a tempfile, and call subp with args, kwargs. Then cleanup.
Packit Service 751c4a
Packit Service 751c4a
    'basename' as a kwarg allows providing the basename for the file.
Packit Service 751c4a
    The 'args' argument to subp will be updated with the full path to the
Packit Service 751c4a
    filename as the first argument.
Packit Service 751c4a
    """
Packit Service 751c4a
    basename = kwargs.pop('basename', "subp_blob")
Packit Service 751c4a
Packit Service 751c4a
    if len(args) == 0 and 'args' not in kwargs:
Packit Service 751c4a
        args = [tuple()]
Packit Service 751c4a
Packit Service 751c4a
    # Use tmpdir over tmpfile to avoid 'text file busy' on execute
Packit Service 751c4a
    with temp_utils.tempdir(needs_exe=True) as tmpd:
Packit Service 751c4a
        tmpf = os.path.join(tmpd, basename)
Packit Service 751c4a
        if 'args' in kwargs:
Packit Service 751c4a
            kwargs['args'] = [tmpf] + list(kwargs['args'])
Packit Service 751c4a
        else:
Packit Service 751c4a
            args = list(args)
Packit Service 751c4a
            args[0] = [tmpf] + args[0]
Packit Service 751c4a
Packit Service 751c4a
        util.write_file(tmpf, blob, mode=0o700)
Packit Service 751c4a
        return subp.subp(*args, **kwargs)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def install_chef_from_omnibus(url=None, retries=None, omnibus_version=None):
Packit Service a04d08
    """Install an omnibus unified package from url.
Packit Service a04d08
Packit Service a04d08
    @param url: URL where blob of chef content may be downloaded. Defaults to
Packit Service a04d08
        OMNIBUS_URL.
Packit Service a04d08
    @param retries: Number of retries to perform when attempting to read url.
Packit Service a04d08
        Defaults to OMNIBUS_URL_RETRIES
Packit Service a04d08
    @param omnibus_version: Optional version string to require for omnibus
Packit Service a04d08
        install.
Packit Service a04d08
    """
Packit Service a04d08
    if url is None:
Packit Service a04d08
        url = OMNIBUS_URL
Packit Service a04d08
    if retries is None:
Packit Service a04d08
        retries = OMNIBUS_URL_RETRIES
Packit Service a04d08
Packit Service a04d08
    if omnibus_version is None:
Packit Service a04d08
        args = []
Packit Service a04d08
    else:
Packit Service a04d08
        args = ['-v', omnibus_version]
Packit Service a04d08
    content = url_helper.readurl(url=url, retries=retries).contents
Packit Service 751c4a
    return subp_blob_in_tempfile(
Packit Service a04d08
        blob=content, args=args,
Packit Service a04d08
        basename='chef-omnibus-install', capture=False)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def install_chef(cloud, chef_cfg, log):
Packit Service a04d08
    # If chef is not installed, we install chef based on 'install_type'
Packit Service a04d08
    install_type = util.get_cfg_option_str(chef_cfg, 'install_type',
Packit Service a04d08
                                           'packages')
Packit Service a04d08
    run = util.get_cfg_option_bool(chef_cfg, 'exec', default=False)
Packit Service a04d08
    if install_type == "gems":
Packit Service a04d08
        # This will install and run the chef-client from gems
Packit Service a04d08
        chef_version = util.get_cfg_option_str(chef_cfg, 'version', None)
Packit Service a04d08
        ruby_version = util.get_cfg_option_str(chef_cfg, 'ruby_version',
Packit Service a04d08
                                               RUBY_VERSION_DEFAULT)
Packit Service a04d08
        install_chef_from_gems(ruby_version, chef_version, cloud.distro)
Packit Service a04d08
        # Retain backwards compat, by preferring True instead of False
Packit Service a04d08
        # when not provided/overriden...
Packit Service a04d08
        run = util.get_cfg_option_bool(chef_cfg, 'exec', default=True)
Packit Service a04d08
    elif install_type == 'packages':
Packit Service a04d08
        # This will install and run the chef-client from packages
Packit Service a04d08
        cloud.distro.install_packages(('chef',))
Packit Service a04d08
    elif install_type == 'omnibus':
Packit Service a04d08
        omnibus_version = util.get_cfg_option_str(chef_cfg, "omnibus_version")
Packit Service a04d08
        install_chef_from_omnibus(
Packit Service a04d08
            url=util.get_cfg_option_str(chef_cfg, "omnibus_url"),
Packit Service a04d08
            retries=util.get_cfg_option_int(chef_cfg, "omnibus_url_retries"),
Packit Service a04d08
            omnibus_version=omnibus_version)
Packit Service a04d08
    else:
Packit Service a04d08
        log.warning("Unknown chef install type '%s'", install_type)
Packit Service a04d08
        run = False
Packit Service a04d08
    return run
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def get_ruby_packages(version):
Packit Service a04d08
    # return a list of packages needed to install ruby at version
Packit Service a04d08
    pkgs = ['ruby%s' % version, 'ruby%s-dev' % version]
Packit Service a04d08
    if version == "1.8":
Packit Service a04d08
        pkgs.extend(('libopenssl-ruby1.8', 'rubygems1.8'))
Packit Service a04d08
    return pkgs
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def install_chef_from_gems(ruby_version, chef_version, distro):
Packit Service a04d08
    distro.install_packages(get_ruby_packages(ruby_version))
Packit Service a04d08
    if not os.path.exists('/usr/bin/gem'):
Packit Service a04d08
        util.sym_link('/usr/bin/gem%s' % ruby_version, '/usr/bin/gem')
Packit Service a04d08
    if not os.path.exists('/usr/bin/ruby'):
Packit Service a04d08
        util.sym_link('/usr/bin/ruby%s' % ruby_version, '/usr/bin/ruby')
Packit Service a04d08
    if chef_version:
Packit Service 751c4a
        subp.subp(['/usr/bin/gem', 'install', 'chef',
Packit Service a04d08
                   '-v %s' % chef_version, '--no-ri',
Packit Service a04d08
                   '--no-rdoc', '--bindir', '/usr/bin', '-q'], capture=False)
Packit Service a04d08
    else:
Packit Service 751c4a
        subp.subp(['/usr/bin/gem', 'install', 'chef',
Packit Service a04d08
                   '--no-ri', '--no-rdoc', '--bindir',
Packit Service a04d08
                   '/usr/bin', '-q'], capture=False)
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab