From b9c4a3c2076e3164cce296e8aa5d8b241c0f77a9 Mon Sep 17 00:00:00 2001 From: Mike Moulton Date: Sat, 10 Sep 2011 22:34:05 +0000 Subject: Modifications to properly support both 'gems' and 'packages' install types. Added support for 'node_name' and 'environment' properties. Renamed 'validation_cert' to 'validation_key' to match Chef's nomenclature. --- cloudinit/CloudConfig/cc_chef.py | 84 +++++++++++++++++++------------------- doc/examples/cloud-config-chef.txt | 26 +++++------- templates/chef_client.rb.tmpl | 19 +++++---- 3 files changed, 64 insertions(+), 65 deletions(-) diff --git a/cloudinit/CloudConfig/cc_chef.py b/cloudinit/CloudConfig/cc_chef.py index 5f13c77d..43927f63 100644 --- a/cloudinit/CloudConfig/cc_chef.py +++ b/cloudinit/CloudConfig/cc_chef.py @@ -1,6 +1,7 @@ # vi: ts=4 expandtab # # Author: Avishai Ish-Shalom +# Author: Mike Moulton # # 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 @@ -31,60 +32,59 @@ def handle(name,cfg,cloud,log,args): if not cfg.has_key('chef'): return chef_cfg = cfg['chef'] - # Install chef packages from selected source - install_type = util.get_cfg_option_str(chef_cfg, "install_type", "packages") - if not os.path.isfile('/usr/bin/chef-client'): - if install_type == "gems": - if chef_cfg.has_key('version'): - chef_version = chef_cfg['version'] - else: - chef_version = None - install_chef_from_gems( - util.get_cfg_option_str(chef_cfg, 'ruby_version', '1.8'), - chef_version) - else: - cc.install_packages(('chef',)) + # ensure the chef directories we use exist + mkdirs(['/etc/chef', '/var/log/chef', '/var/lib/chef', '/var/cache/chef', '/var/backups/chef', '/var/run/chef']) # set the validation cert - if chef_cfg.has_key('validation_cert'): - with open('/etc/chef/validation.pem', 'w') as validation_cert_fh: - validation_cert_fh.write(chef_cfg['validation_cert']) + if chef_cfg.has_key('validation_key'): + with open('/etc/chef/validation.pem', 'w') as validation_key_fh: + validation_key_fh.write(chef_cfg['validation_key']) validation_name = chef_cfg.get('validation_name','chef-validator') # create the chef config from template util.render_to_file('chef_client.rb', '/etc/chef/client.rb', {'server_url': chef_cfg['server_url'], + 'node_name': chef_cfg['node_name'], + 'environment': chef_cfg['environment'], 'validation_name': chef_cfg['validation_name']}) - chef_args = ['-d'] # set the firstboot json - if chef_cfg.has_key('run_list'): - with open('/etc/chef/firstboot.json', 'w') as firstboot_json_fh: - firstboot_json_fh.write("{\n\"run_list\":\n[\n") - firstboot_json_fh.write( - ",\n".join(["\"%s\"" % runlist_item for runlist_item in chef_cfg['run_list']]) - ) - firstboot_json_fh.write("]\n\}") - chef_args.append('-j /etc/chef/firstboot.json') + with open('/etc/chef/firstboot.json', 'w') as firstboot_json_fh: + firstboot_json_fh.write("{\n") + if chef_cfg.has_key('run_list'): + firstboot_json_fh.write(" \"run_list\": [\n") + firstboot_json_fh.write(",\n".join([" \"%s\"" % runlist_item for runlist_item in chef_cfg['run_list']])) + firstboot_json_fh.write("\n ]\n") + firstboot_json_fh.write("}\n") - # and finally, run chef - log.debug("running chef-client %s" % chef_args) - subprocess.check_call(['/usr/bin/chef-client'] + chef_args) + # If chef is not installed, we install chef based on 'install_type' + if not os.path.isfile('/usr/bin/chef-client'): + install_type = util.get_cfg_option_str(chef_cfg, 'install_type', 'packages') + 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', '1.8') + install_chef_from_gems(ruby_version, chef_version) + # and finally, run chef-client + log.debug('running chef-client') + subprocess.check_call(['/usr/bin/chef-client', '-d', '-i', '1800', '-s', '20']) + else: + # this will install and run the chef-client from packages + cc.install_packages(('chef',)) def install_chef_from_gems(ruby_version, chef_version = None): cc.install_packages(ruby_packages[ruby_version]) - gem_bin = get_gem_bin() - if not os.path.exists('/usr/bin/gem'): os.symlink(gem_bin, '/usr/bin/gem') - chef_version_arg = "" - if chef_version: chef_version_arg = "-v %s" % chef_version - subprocess.check_call([gem_bin,'install','chef',chef_version_arg, '--no-ri','--no-rdoc','--no-test','-q']) - os.mkdirs('/etc/chef', '/var/log/chef', '/var/lib/chef', '/var/cache/chef', '/var/backups/chef', '/var/run/chef') - os.symlink('/var/lib/gem/%s/bin/chef-client' % ruby_version, '/usr/bin/chef-client') - # Ohai ruby plugin breaks if there is no ruby or gem binaries at /usr/bin, so - try: os.symlink('/usr/bin/gem%s' % ruby_version, '/usr/bin/gem') - except: pass - try: os.symlink('/usr/bin/ruby%s' % ruby_version, '/usr/bin/ruby') - except: pass + if not os.path.exists('/usr/bin/gem'): os.symlink('/usr/bin/gem%s' % ruby_version, '/usr/bin/gem') + if not os.path.exists('/usr/bin/ruby'): os.symlink('/usr/bin/ruby%s' % ruby_version, '/usr/bin/ruby') + if chef_version: + subprocess.check_call(['/usr/bin/gem','install','chef','-v %s' % chef_version, '--no-ri','--no-rdoc','--bindir','/usr/bin','-q']) + else: + subprocess.check_call(['/usr/bin/gem','install','chef','--no-ri','--no-rdoc','--bindir','/usr/bin','-q']) + +def ensure_dir(d): + if not os.path.exists(d): + os.makedirs(d) -def get_gem_bin(): - return '/usr/bin/gem%s' % util.get_cfg_option_str(chef_cfg, 'ruby_version', '1.8') +def mkdirs(dirs): + for d in dirs: + ensure_dir(d) diff --git a/doc/examples/cloud-config-chef.txt b/doc/examples/cloud-config-chef.txt index 42da0b6b..227bd3a3 100644 --- a/doc/examples/cloud-config-chef.txt +++ b/doc/examples/cloud-config-chef.txt @@ -15,23 +15,19 @@ chef: # Chef settings server_url: "https://chef.yourorg.com:4000" + # Node Name + node_name: "Your Node Name" + + # Environment + environment: "production" + # Default validation name is chef-validator validation_name: "yourorg-validator" - validation_cert: | - -----BEGIN CERTIFICATE----- - MIICCTCCAXKgAwIBAgIBATANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDDAJjYTAe - Fw0xMDAyMTUxNzI5MjFaFw0xNTAyMTQxNzI5MjFaMA0xCzAJBgNVBAMMAmNhMIGf - MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu7Q40sm47/E1Pf+r8AYb/V/FWGPgc - b014OmNoX7dgCxTDvps/h8Vw555PdAFsW5+QhsGr31IJNI3kSYprFQcYf7A8tNWu - 1MASW2CfaEiOEi9F1R3R4Qlz4ix+iNoHiUDTjazw/tZwEdxaQXQVLwgTGRwVa+aA - qbutJKi93MILLwIDAQABo3kwdzA4BglghkgBhvhCAQ0EKxYpUHVwcGV0IFJ1Ynkv - T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwDwYDVR0TAQH/BAUwAwEB/zAd - BgNVHQ4EFgQUu4+jHB+GYE5Vxo+ol1OAhevspjAwCwYDVR0PBAQDAgEGMA0GCSqG - SIb3DQEBBQUAA4GBAH/rxlUIjwNb3n7TXJcDJ6MMHUlwjr03BDJXKb34Ulndkpaf - +GAlzPXWa7bO908M9I8RnPfvtKnteLbvgTK+h+zX1XCty+S2EQWk29i2AdoqOTxb - hppiGMp0tT5Havu4aceCXiy2crVcudj3NFciy8X66SoECemW9UYDCb9T5D0d - -----END CERTIFICATE----- - + validation_key: | + -----BEGIN RSA PRIVATE KEY----- + YOUR-ORGS-VALIDATION-KEY-HERE + -----END RSA PRIVATE KEY----- + # A run list for a first boot json run_list: - "recipe[apache2]" diff --git a/templates/chef_client.rb.tmpl b/templates/chef_client.rb.tmpl index d69dedc0..d3d9a922 100644 --- a/templates/chef_client.rb.tmpl +++ b/templates/chef_client.rb.tmpl @@ -1,12 +1,15 @@ -log_level :info -log_location "/var/log/chef/client.log" -ssl_verify_mode :verify_none +log_level :info +log_location "/var/log/chef/client.log" +ssl_verify_mode :verify_none validation_client_name "$validation_name" validation_key "/etc/chef/validation.pem" -client_key "/etc/chef/client.pem" -chef_server_url "$server_url" -file_cache_path "/var/cache/chef" -file_backup_path "/var/backups/chef" -pid_file "/var/run/chef/client.pid" +client_key "/etc/chef/client.pem" +chef_server_url "$server_url" +environment "$environment" +node_name "$node_name" +json_attribs "/etc/chef/firstboot.json" +file_cache_path "/var/cache/chef" +file_backup_path "/var/backups/chef" +pid_file "/var/run/chef/client.pid" Chef::Log::Formatter.show_time = true -- cgit v1.2.3 From 1ef5047ac957afc33113e9a4417e22489ddea084 Mon Sep 17 00:00:00 2001 From: Mike Moulton Date: Mon, 12 Sep 2011 17:36:35 +0000 Subject: Set sane defaults for 'node_name' and 'environment' Support both 'validation_cert' and 'validation_key' for backwards compatibility Cleaned up line length --- cloudinit/CloudConfig/cc_chef.py | 36 +++++++++++++++++++++++++----------- doc/examples/cloud-config-chef.txt | 7 +++++-- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/cloudinit/CloudConfig/cc_chef.py b/cloudinit/CloudConfig/cc_chef.py index 43927f63..1effba53 100644 --- a/cloudinit/CloudConfig/cc_chef.py +++ b/cloudinit/CloudConfig/cc_chef.py @@ -33,19 +33,26 @@ def handle(name,cfg,cloud,log,args): chef_cfg = cfg['chef'] # ensure the chef directories we use exist - mkdirs(['/etc/chef', '/var/log/chef', '/var/lib/chef', '/var/cache/chef', '/var/backups/chef', '/var/run/chef']) + mkdirs(['/etc/chef', '/var/log/chef', '/var/lib/chef', + '/var/cache/chef', '/var/backups/chef', '/var/run/chef']) - # set the validation cert - if chef_cfg.has_key('validation_key'): + # set the validation key based on the presence of either 'validation_key' + # or 'validation_cert'. In the case where both exist, 'validation_key' + # takes precedence + if chef_cfg.has_key('validation_key') or chef_cfg.has_key('validation_cert'): + validation_key = util.get_cfg_option_str(chef_cfg, 'validation_key', + chef_cfg['validation_cert']) with open('/etc/chef/validation.pem', 'w') as validation_key_fh: - validation_key_fh.write(chef_cfg['validation_key']) + validation_key_fh.write(validation_key) validation_name = chef_cfg.get('validation_name','chef-validator') # create the chef config from template util.render_to_file('chef_client.rb', '/etc/chef/client.rb', {'server_url': chef_cfg['server_url'], - 'node_name': chef_cfg['node_name'], - 'environment': chef_cfg['environment'], + 'node_name': util.get_cfg_option_str(chef_cfg, 'node_name', + cloud.datasource.get_instance_id()), + 'environment': util.get_cfg_option_str(chef_cfg, 'environment', + '_default'), 'validation_name': chef_cfg['validation_name']}) # set the firstboot json @@ -53,7 +60,8 @@ def handle(name,cfg,cloud,log,args): firstboot_json_fh.write("{\n") if chef_cfg.has_key('run_list'): firstboot_json_fh.write(" \"run_list\": [\n") - firstboot_json_fh.write(",\n".join([" \"%s\"" % runlist_item for runlist_item in chef_cfg['run_list']])) + firstboot_json_fh.write(",\n".join([" \"%s\"" % runlist_item + for runlist_item in chef_cfg['run_list']])) firstboot_json_fh.write("\n ]\n") firstboot_json_fh.write("}\n") @@ -74,12 +82,18 @@ def handle(name,cfg,cloud,log,args): def install_chef_from_gems(ruby_version, chef_version = None): cc.install_packages(ruby_packages[ruby_version]) - if not os.path.exists('/usr/bin/gem'): os.symlink('/usr/bin/gem%s' % ruby_version, '/usr/bin/gem') - if not os.path.exists('/usr/bin/ruby'): os.symlink('/usr/bin/ruby%s' % ruby_version, '/usr/bin/ruby') + if not os.path.exists('/usr/bin/gem'): + os.symlink('/usr/bin/gem%s' % ruby_version, '/usr/bin/gem') + if not os.path.exists('/usr/bin/ruby'): + os.symlink('/usr/bin/ruby%s' % ruby_version, '/usr/bin/ruby') if chef_version: - subprocess.check_call(['/usr/bin/gem','install','chef','-v %s' % chef_version, '--no-ri','--no-rdoc','--bindir','/usr/bin','-q']) + subprocess.check_call(['/usr/bin/gem','install','chef', + '-v %s' % chef_version, '--no-ri', + '--no-rdoc','--bindir','/usr/bin','-q']) else: - subprocess.check_call(['/usr/bin/gem','install','chef','--no-ri','--no-rdoc','--bindir','/usr/bin','-q']) + subprocess.check_call(['/usr/bin/gem','install','chef', + '--no-ri','--no-rdoc','--bindir', + '/usr/bin','-q']) def ensure_dir(d): if not os.path.exists(d): diff --git a/doc/examples/cloud-config-chef.txt b/doc/examples/cloud-config-chef.txt index 227bd3a3..a1dda4f1 100644 --- a/doc/examples/cloud-config-chef.txt +++ b/doc/examples/cloud-config-chef.txt @@ -9,16 +9,19 @@ apt_mirror: http://apt.opscode.com/ chef: - # If you want to install from rubygems: + + # Valid values are 'gems' and 'packages' install_type: "gems" # Chef settings server_url: "https://chef.yourorg.com:4000" # Node Name - node_name: "Your Node Name" + # Defaults to the instance-id if not present + node_name: "your-node-name" # Environment + # Defaults to '_default' if not present environment: "production" # Default validation name is chef-validator -- cgit v1.2.3 From 2e6b44be4a2c352a49910c437a830c27b0ad131c Mon Sep 17 00:00:00 2001 From: Mike Moulton Date: Tue, 13 Sep 2011 00:38:37 +0000 Subject: Bringing in proper json support for firstboot.json from lp:~avishai-ish-shalom/cloud-init/chef Bringing in 'initial_properties' support from lp:~avishai-ish-shalom/cloud-init/chef --- cloudinit/CloudConfig/cc_chef.py | 13 +++++++------ doc/examples/cloud-config-chef.txt | 7 +++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cloudinit/CloudConfig/cc_chef.py b/cloudinit/CloudConfig/cc_chef.py index 1effba53..807c3717 100644 --- a/cloudinit/CloudConfig/cc_chef.py +++ b/cloudinit/CloudConfig/cc_chef.py @@ -18,6 +18,7 @@ import os import pwd import socket import subprocess +import json import StringIO import ConfigParser import cloudinit.CloudConfig as cc @@ -57,13 +58,13 @@ def handle(name,cfg,cloud,log,args): # set the firstboot json with open('/etc/chef/firstboot.json', 'w') as firstboot_json_fh: - firstboot_json_fh.write("{\n") + initial_json = {} if chef_cfg.has_key('run_list'): - firstboot_json_fh.write(" \"run_list\": [\n") - firstboot_json_fh.write(",\n".join([" \"%s\"" % runlist_item - for runlist_item in chef_cfg['run_list']])) - firstboot_json_fh.write("\n ]\n") - firstboot_json_fh.write("}\n") + initial_json['run_list'] = chef_cfg['run_list'] + if chef_cfg.has_key('initial_attributes'): + initial_attributes = chef_cfg['initial_attributes'] + for k in initial_attributes.keys(): initial_json[k] = initial_attributes[k] + firstboot_json_fh.write(json.dumps(initial_json)) # If chef is not installed, we install chef based on 'install_type' if not os.path.isfile('/usr/bin/chef-client'): diff --git a/doc/examples/cloud-config-chef.txt b/doc/examples/cloud-config-chef.txt index a1dda4f1..cbaa3467 100644 --- a/doc/examples/cloud-config-chef.txt +++ b/doc/examples/cloud-config-chef.txt @@ -35,3 +35,10 @@ chef: run_list: - "recipe[apache2]" - "role[db]" + + # Specify a list of initial attributes used by the cookbooks + initial_attributes: + apache: + prefork: + maxclients: 100 + keepalive: "off" -- cgit v1.2.3