diff options
Diffstat (limited to 'cloudinit/config/cc_chef.py')
-rw-r--r-- | cloudinit/config/cc_chef.py | 342 |
1 files changed, 0 insertions, 342 deletions
diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py deleted file mode 100644 index 4c28be6a..00000000 --- a/cloudinit/config/cc_chef.py +++ /dev/null @@ -1,342 +0,0 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Avishai Ish-Shalom <avishai@fewbytes.com> -# Author: Mike Moulton <mike@meltmedia.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 3, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -""" -**Summary:** module that configures, starts and installs chef. - -**Description:** This module enables chef to be installed (from packages or -from gems, or from omnibus). Before this occurs chef configurations are -written to disk (validation.pem, client.pem, firstboot.json, client.rb), -and needed chef folders/directories are created (/etc/chef and /var/log/chef -and so-on). Then once installing proceeds correctly if configured chef will -be started (in daemon mode or in non-daemon mode) and then once that has -finished (if ran in non-daemon mode this will be when chef finishes -converging, if ran in daemon mode then no further actions are possible since -chef will have forked into its own process) then a post run function can -run that can do finishing activities (such as removing the validation pem -file). - -It can be configured with the following option structure:: - - chef: - directories: (defaulting to /etc/chef, /var/log/chef, /var/lib/chef, - /var/cache/chef, /var/backups/chef, /var/run/chef) - validation_cert: (optional string to be written to file validation_key) - special value 'system' means set use existing file - validation_key: (optional the path for validation_cert. default - /etc/chef/validation.pem) - firstboot_path: (path to write run_list and initial_attributes keys that - should also be present in this configuration, defaults - to /etc/chef/firstboot.json) - exec: boolean to run or not run chef (defaults to false, unless - a gem installed is requested - where this will then default - to true) - - chef.rb template keys (if falsey, then will be skipped and not - written to /etc/chef/client.rb) - - chef: - client_key: - environment: - file_backup_path: - file_cache_path: - json_attribs: - log_level: - log_location: - node_name: - pid_file: - server_url: - show_time: - ssl_verify_mode: - validation_cert: - validation_key: - validation_name: -""" - -import itertools -import json -import os - -from cloudinit import templater -from cloudinit import url_helper -from cloudinit import util - -import six - -RUBY_VERSION_DEFAULT = "1.8" - -CHEF_DIRS = tuple([ - '/etc/chef', - '/var/log/chef', - '/var/lib/chef', - '/var/cache/chef', - '/var/backups/chef', - '/var/run/chef', -]) -REQUIRED_CHEF_DIRS = tuple([ - '/etc/chef', -]) - -# Used if fetching chef from a omnibus style package -OMNIBUS_URL = "https://www.getchef.com/chef/install.sh" -OMNIBUS_URL_RETRIES = 5 - -CHEF_VALIDATION_PEM_PATH = '/etc/chef/validation.pem' -CHEF_FB_PATH = '/etc/chef/firstboot.json' -CHEF_RB_TPL_DEFAULTS = { - # These are ruby symbols... - 'ssl_verify_mode': ':verify_none', - 'log_level': ':info', - # These are not symbols... - 'log_location': '/var/log/chef/client.log', - 'validation_key': CHEF_VALIDATION_PEM_PATH, - 'validation_cert': None, - 'client_key': "/etc/chef/client.pem", - 'json_attribs': CHEF_FB_PATH, - 'file_cache_path': "/var/cache/chef", - 'file_backup_path': "/var/backups/chef", - 'pid_file': "/var/run/chef/client.pid", - 'show_time': True, -} -CHEF_RB_TPL_BOOL_KEYS = frozenset(['show_time']) -CHEF_RB_TPL_PATH_KEYS = frozenset([ - 'log_location', - 'validation_key', - 'client_key', - 'file_cache_path', - 'json_attribs', - 'file_cache_path', - 'pid_file', -]) -CHEF_RB_TPL_KEYS = list(CHEF_RB_TPL_DEFAULTS.keys()) -CHEF_RB_TPL_KEYS.extend(CHEF_RB_TPL_BOOL_KEYS) -CHEF_RB_TPL_KEYS.extend(CHEF_RB_TPL_PATH_KEYS) -CHEF_RB_TPL_KEYS.extend([ - 'server_url', - 'node_name', - 'environment', - 'validation_name', -]) -CHEF_RB_TPL_KEYS = frozenset(CHEF_RB_TPL_KEYS) -CHEF_RB_PATH = '/etc/chef/client.rb' -CHEF_EXEC_PATH = '/usr/bin/chef-client' -CHEF_EXEC_DEF_ARGS = tuple(['-d', '-i', '1800', '-s', '20']) - - -def is_installed(): - if not os.path.isfile(CHEF_EXEC_PATH): - return False - if not os.access(CHEF_EXEC_PATH, os.X_OK): - return False - return True - - -def post_run_chef(chef_cfg, log): - delete_pem = util.get_cfg_option_bool(chef_cfg, - 'delete_validation_post_exec', - default=False) - if delete_pem and os.path.isfile(CHEF_VALIDATION_PEM_PATH): - os.unlink(CHEF_VALIDATION_PEM_PATH) - - -def get_template_params(iid, chef_cfg, log): - params = CHEF_RB_TPL_DEFAULTS.copy() - # Allow users to overwrite any of the keys they want (if they so choose), - # when a value is None, then the value will be set to None and no boolean - # or string version will be populated... - for (k, v) in chef_cfg.items(): - if k not in CHEF_RB_TPL_KEYS: - log.debug("Skipping unknown chef template key '%s'", k) - continue - if v is None: - params[k] = None - else: - # This will make the value a boolean or string... - if k in CHEF_RB_TPL_BOOL_KEYS: - params[k] = util.get_cfg_option_bool(chef_cfg, k) - else: - params[k] = util.get_cfg_option_str(chef_cfg, k) - # These ones are overwritten to be exact values... - params.update({ - 'generated_by': util.make_header(), - 'node_name': util.get_cfg_option_str(chef_cfg, 'node_name', - default=iid), - 'environment': util.get_cfg_option_str(chef_cfg, 'environment', - default='_default'), - # These two are mandatory... - 'server_url': chef_cfg['server_url'], - 'validation_name': chef_cfg['validation_name'], - }) - return params - - -def handle(name, cfg, cloud, log, _args): - """Handler method activated by cloud-init.""" - - # If there isn't a chef key in the configuration don't do anything - if 'chef' not in cfg: - log.debug(("Skipping module named %s," - " no 'chef' key in configuration"), name) - return - chef_cfg = cfg['chef'] - - # Ensure the chef directories we use exist - chef_dirs = util.get_cfg_option_list(chef_cfg, 'directories') - if not chef_dirs: - chef_dirs = list(CHEF_DIRS) - for d in itertools.chain(chef_dirs, REQUIRED_CHEF_DIRS): - util.ensure_dir(d) - - vkey_path = chef_cfg.get('validation_key', CHEF_VALIDATION_PEM_PATH) - vcert = chef_cfg.get('validation_cert') - # special value 'system' means do not overwrite the file - # but still render the template to contain 'validation_key' - if vcert: - if vcert != "system": - util.write_file(vkey_path, vcert) - elif not os.path.isfile(vkey_path): - log.warn("chef validation_cert provided as 'system', but " - "validation_key path '%s' does not exist.", - vkey_path) - - # Create the chef config from template - template_fn = cloud.get_template_filename('chef_client.rb') - if template_fn: - iid = str(cloud.datasource.get_instance_id()) - params = get_template_params(iid, chef_cfg, log) - # Do a best effort attempt to ensure that the template values that - # are associated with paths have there parent directory created - # before they are used by the chef-client itself. - param_paths = set() - for (k, v) in params.items(): - if k in CHEF_RB_TPL_PATH_KEYS and v: - param_paths.add(os.path.dirname(v)) - util.ensure_dirs(param_paths) - templater.render_to_file(template_fn, CHEF_RB_PATH, params) - else: - log.warn("No template found, not rendering to %s", - CHEF_RB_PATH) - - # Set the firstboot json - fb_filename = util.get_cfg_option_str(chef_cfg, 'firstboot_path', - default=CHEF_FB_PATH) - if not fb_filename: - log.info("First boot path empty, not writing first boot json file") - else: - initial_json = {} - if 'run_list' in chef_cfg: - initial_json['run_list'] = chef_cfg['run_list'] - if 'initial_attributes' in chef_cfg: - initial_attributes = chef_cfg['initial_attributes'] - for k in list(initial_attributes.keys()): - initial_json[k] = initial_attributes[k] - util.write_file(fb_filename, json.dumps(initial_json)) - - # Try to install chef, if its not already installed... - force_install = util.get_cfg_option_bool(chef_cfg, - 'force_install', default=False) - if not is_installed() or force_install: - run = install_chef(cloud, chef_cfg, log) - elif is_installed(): - run = util.get_cfg_option_bool(chef_cfg, 'exec', default=False) - else: - run = False - if run: - run_chef(chef_cfg, log) - post_run_chef(chef_cfg, log) - - -def run_chef(chef_cfg, log): - log.debug('Running chef-client') - cmd = [CHEF_EXEC_PATH] - if 'exec_arguments' in chef_cfg: - cmd_args = chef_cfg['exec_arguments'] - if isinstance(cmd_args, (list, tuple)): - cmd.extend(cmd_args) - elif isinstance(cmd_args, six.string_types): - cmd.append(cmd_args) - else: - log.warn("Unknown type %s provided for chef" - " 'exec_arguments' expected list, tuple," - " or string", type(cmd_args)) - cmd.extend(CHEF_EXEC_DEF_ARGS) - else: - cmd.extend(CHEF_EXEC_DEF_ARGS) - util.subp(cmd, capture=False) - - -def install_chef(cloud, chef_cfg, log): - # If chef is not installed, we install chef based on 'install_type' - install_type = util.get_cfg_option_str(chef_cfg, 'install_type', - 'packages') - run = util.get_cfg_option_bool(chef_cfg, 'exec', default=False) - if install_type == "gems": - # This will install and run the chef-client from gems - chef_version = util.get_cfg_option_str(chef_cfg, 'version', None) - ruby_version = util.get_cfg_option_str(chef_cfg, 'ruby_version', - RUBY_VERSION_DEFAULT) - install_chef_from_gems(ruby_version, chef_version, cloud.distro) - # Retain backwards compat, by preferring True instead of False - # when not provided/overriden... - run = util.get_cfg_option_bool(chef_cfg, 'exec', default=True) - elif install_type == 'packages': - # This will install and run the chef-client from packages - cloud.distro.install_packages(('chef',)) - elif install_type == 'omnibus': - # This will install as a omnibus unified package - url = util.get_cfg_option_str(chef_cfg, "omnibus_url", OMNIBUS_URL) - retries = max(0, util.get_cfg_option_int(chef_cfg, - "omnibus_url_retries", - default=OMNIBUS_URL_RETRIES)) - content = url_helper.readurl(url=url, retries=retries) - with util.tempdir() as tmpd: - # Use tmpdir over tmpfile to avoid 'text file busy' on execute - tmpf = "%s/chef-omnibus-install" % tmpd - util.write_file(tmpf, content, mode=0o700) - util.subp([tmpf], capture=False) - else: - log.warn("Unknown chef install type '%s'", install_type) - run = False - return run - - -def get_ruby_packages(version): - # return a list of packages needed to install ruby at version - pkgs = ['ruby%s' % version, 'ruby%s-dev' % version] - if version == "1.8": - pkgs.extend(('libopenssl-ruby1.8', 'rubygems1.8')) - return pkgs - - -def install_chef_from_gems(ruby_version, chef_version, distro): - distro.install_packages(get_ruby_packages(ruby_version)) - if not os.path.exists('/usr/bin/gem'): - util.sym_link('/usr/bin/gem%s' % ruby_version, '/usr/bin/gem') - if not os.path.exists('/usr/bin/ruby'): - util.sym_link('/usr/bin/ruby%s' % ruby_version, '/usr/bin/ruby') - if chef_version: - util.subp(['/usr/bin/gem', 'install', 'chef', - '-v %s' % chef_version, '--no-ri', - '--no-rdoc', '--bindir', '/usr/bin', '-q'], capture=False) - else: - util.subp(['/usr/bin/gem', 'install', 'chef', - '--no-ri', '--no-rdoc', '--bindir', - '/usr/bin', '-q'], capture=False) |