From 6fe997c3e5cfdf89087daf8b265730ec681c96c3 Mon Sep 17 00:00:00 2001 From: jtimberman Date: Thu, 14 Jun 2012 14:22:24 -0600 Subject: [PATCH 01/12] YAML wildcards should be quoted * Quote the "*" wildcard used in the examples and README. * Rescue the YAML exception. --- README.md | 6 +++--- bin/spiceweasel | 6 +++++- example.yml | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4bf59f6..d5bf871 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ data bags: - bob - chuck - data: - - * + - "*" - passwords: - secret secret_key - mysql @@ -225,7 +225,7 @@ knife role from file webserver.rb Data Bags --------- -The `data bags` section of the manifest currently creates the data bags listed with `knife data bag create FOO` where `FOO` is the name of the data bag. Individual items may be added to the data bag as part of a JSON or YAML sequence, the assumption is made that they `.json` files and in the proper `data_bags/FOO` directory. You may also pass a wildcard as an entry to load all matching data bags (ie. `*`). Encrypted data bags are supported by listing `secret filename` as the first item (where `filename` is the secret key to be used). Validation is done to ensure the JSON is properly formatted, the id matches and any secret keys are in the correct locations. Assuming the presence of `dataA.json` and `dataB.json` in the `data_bags/data` directory, the YAML snippet +The `data bags` section of the manifest currently creates the data bags listed with `knife data bag create FOO` where `FOO` is the name of the data bag. Individual items may be added to the data bag as part of a JSON or YAML sequence, the assumption is made that they `.json` files and in the proper `data_bags/FOO` directory. You may also pass a wildcard as an entry to load all matching data bags (ie. `"*"`). Encrypted data bags are supported by listing `secret filename` as the first item (where `filename` is the secret key to be used). Validation is done to ensure the JSON is properly formatted, the id matches and any secret keys are in the correct locations. Assuming the presence of `dataA.json` and `dataB.json` in the `data_bags/data` directory, the YAML snippet ``` yaml data bags: @@ -234,7 +234,7 @@ data bags: - bob - chuck - data: - - * + - "*" - passwords: - secret secret_key - mysql diff --git a/bin/spiceweasel b/bin/spiceweasel index d17ed03..fe4bd28 100755 --- a/bin/spiceweasel +++ b/bin/spiceweasel @@ -66,9 +66,13 @@ else STDERR.puts "ERROR: Unknown file type, please use a file ending with either '.json' or '.yml'." exit(-1) end + rescue Psych::SyntaxError => e + STDERR.puts e.message + STDERR.puts "ERROR: Parsing error in #{file}." + exit(-1) rescue JSON::ParserError => e STDERR.puts e.message - STDERR.puts "ERROR: Parsing error in the infrastructure file provided." + STDERR.puts "ERROR: Parsing error in #{file}." exit(-1) rescue Exception STDERR.puts "ERROR: No infrastructure .json or .yml file provided." diff --git a/example.yml b/example.yml index 2402a4d..efbb594 100644 --- a/example.yml +++ b/example.yml @@ -18,7 +18,7 @@ data bags: - bob - chuck - data: - - * + - "*" - passwords: - secret secret_key - mysql From bcbbc92576b2e45376aec2f97d71726872411fdb Mon Sep 17 00:00:00 2001 From: Chris Griego Date: Wed, 13 Jun 2012 19:35:30 -0500 Subject: [PATCH 02/12] Don't add empty strings to the cookbook dependency list --- lib/spiceweasel/cookbook_list.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/spiceweasel/cookbook_list.rb b/lib/spiceweasel/cookbook_list.rb index 0ba6381..31c31c2 100644 --- a/lib/spiceweasel/cookbook_list.rb +++ b/lib/spiceweasel/cookbook_list.rb @@ -67,13 +67,12 @@ def validateMetadata(cookbook,version) deps.each do |dependency| STDOUT.puts "DEBUG: cookbook #{cookbook} metadata dependency: #{dependency}" if DEBUG line = dependency.split() - cbdep = '' if line[1] =~ /^"/ #ignore variables and versions cbdep = line[1].gsub(/"/,'') cbdep.gsub!(/\,/,'') if cbdep.end_with?(',') + STDOUT.puts "DEBUG: cookbook #{cookbook} metadata depends: #{cbdep}" if DEBUG + @dependencies << cbdep end - STDOUT.puts "DEBUG: cookbook #{cookbook} metadata depends: #{cbdep}" if DEBUG - @dependencies << cbdep end return @cookbook end From 928ead7d2f3bcc4811d3e81879e9c270bda72062 Mon Sep 17 00:00:00 2001 From: ndowns Date: Wed, 18 Jul 2012 10:53:42 -0700 Subject: [PATCH 03/12] Bug fixes and adjusting printing of some debug strings. - Chased down a bug that was causing the --extractyaml and --extractjson commands to output a data_bags section that was not complete. This issue was due to modification of the lists that are passed down to the data bag parsing class. Fixed by creating a "deep copy" (using Marshal) of the inputs structure and passing references to that copy. This keeps the original inputs intact. - Removed all occurences of the hash key "data bags" (with a space). Changed them all to "data_bags". I don't like spaces in hash keys if I can help it. - Changed some debugging to add spaces between printed items. --- .gitignore | 1 + README.md | 8 ++++---- bin/spiceweasel | 20 +++++++++++++------- example.json | 2 +- example.yml | 2 +- examples/php-quick-start.yml | 2 +- lib/spiceweasel/directory_extractor.rb | 6 +++--- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 4040c6c..65637f2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .bundle Gemfile.lock pkg/* +.*.*~ diff --git a/README.md b/README.md index d5bf871..66a71d3 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ roles: - iisserver: - monitoring: - webserver: -data bags: +data_bags: - users: - alice - bob @@ -98,7 +98,7 @@ From the `example.json`: {"monitoring":[]}, {"webserver":[]} ], - "data bags": + "data_bags": [ {"users": [ @@ -225,10 +225,10 @@ knife role from file webserver.rb Data Bags --------- -The `data bags` section of the manifest currently creates the data bags listed with `knife data bag create FOO` where `FOO` is the name of the data bag. Individual items may be added to the data bag as part of a JSON or YAML sequence, the assumption is made that they `.json` files and in the proper `data_bags/FOO` directory. You may also pass a wildcard as an entry to load all matching data bags (ie. `"*"`). Encrypted data bags are supported by listing `secret filename` as the first item (where `filename` is the secret key to be used). Validation is done to ensure the JSON is properly formatted, the id matches and any secret keys are in the correct locations. Assuming the presence of `dataA.json` and `dataB.json` in the `data_bags/data` directory, the YAML snippet +The `data_bags` section of the manifest currently creates the data bags listed with `knife data bag create FOO` where `FOO` is the name of the data bag. Individual items may be added to the data bag as part of a JSON or YAML sequence, the assumption is made that they `.json` files and in the proper `data_bags/FOO` directory. You may also pass a wildcard as an entry to load all matching data bags (ie. `"*"`). Encrypted data bags are supported by listing `secret filename` as the first item (where `filename` is the secret key to be used). Validation is done to ensure the JSON is properly formatted, the id matches and any secret keys are in the correct locations. Assuming the presence of `dataA.json` and `dataB.json` in the `data_bags/data` directory, the YAML snippet ``` yaml -data bags: +data_bags: - users: - alice - bob diff --git a/bin/spiceweasel b/bin/spiceweasel index fe4bd28..fda9966 100755 --- a/bin/spiceweasel +++ b/bin/spiceweasel @@ -18,8 +18,10 @@ # limitations under the License. # +require 'rubygems' require 'json' require 'yaml' +require 'pp' require 'spiceweasel' @@ -40,7 +42,7 @@ begin rescue OptionParser::InvalidOption => e STDERR.puts e.message puts cli.opt_parser.to_s - exit(-1) +n exit(-1) end if cli.config[:knifeconfig] @@ -53,7 +55,7 @@ end if EXTRACTLOCAL || EXTRACTJSON || EXTRACTYAML input = Spiceweasel::DirectoryExtractor.parse_objects - STDOUT.puts "DEBUG: extract input: #{input}" if DEBUG + STDOUT.puts "DEBUG: extract input: #{PP.pp(input)}" if DEBUG else begin file = ARGV.last @@ -85,11 +87,15 @@ end create = String.new() delete = String.new() -cookbook_list = Spiceweasel::CookbookList.new(input['cookbooks'], options) -environment_list = Spiceweasel::EnvironmentList.new(input['environments'], cookbook_list, options) -role_list = Spiceweasel::RoleList.new(input['roles'], environment_list, cookbook_list, options) -data_bag_list = Spiceweasel::DataBagList.new(input['data bags'], options) -node_list = Spiceweasel::NodeList.new(input['nodes'], cookbook_list, environment_list, role_list, options) +# This is a total hack to ensure the original input data structure does +# not get modified. (Deep copy) +input_copy = Marshal.load(Marshal.dump(input)) + +cookbook_list = Spiceweasel::CookbookList.new(input_copy['cookbooks'], options) +environment_list = Spiceweasel::EnvironmentList.new(input_copy['environments'], cookbook_list, options) +role_list = Spiceweasel::RoleList.new(input_copy['roles'], environment_list, cookbook_list, options) +data_bag_list = Spiceweasel::DataBagList.new(input_copy['data_bags'].dup, options) +node_list = Spiceweasel::NodeList.new(input_copy['nodes'], cookbook_list, environment_list, role_list, options) create += cookbook_list.create create += environment_list.create diff --git a/example.json b/example.json index a889efd..d6c2041 100644 --- a/example.json +++ b/example.json @@ -22,7 +22,7 @@ {"monitoring":[]}, {"webserver":[]} ], - "data bags": + "data_bags": [ {"users": [ diff --git a/example.yml b/example.yml index efbb594..3894410 100644 --- a/example.yml +++ b/example.yml @@ -12,7 +12,7 @@ roles: - iisserver: - monitoring: - webserver: -data bags: +data_bags: - users: - alice - bob diff --git a/examples/php-quick-start.yml b/examples/php-quick-start.yml index 75e4fa2..15a81a3 100644 --- a/examples/php-quick-start.yml +++ b/examples/php-quick-start.yml @@ -59,7 +59,7 @@ roles: - mediawiki: - mediawiki_load_balancer: -data bags: +data_bags: - apps: - mediawiki diff --git a/lib/spiceweasel/directory_extractor.rb b/lib/spiceweasel/directory_extractor.rb index 4614e13..38492e6 100644 --- a/lib/spiceweasel/directory_extractor.rb +++ b/lib/spiceweasel/directory_extractor.rb @@ -20,7 +20,7 @@ class Spiceweasel::DirectoryExtractor def self.parse_objects - objects = {"cookbooks" => nil, "roles" => nil, "environments" => nil, "data bags" => nil, "nodes" => nil} + objects = {"cookbooks" => nil, "roles" => nil, "environments" => nil, "data_bags" => nil, "nodes" => nil} # COOKBOOKS cookbooks = [] Dir.glob("cookbooks/*").each do |cookbook_full_path| @@ -63,7 +63,7 @@ def self.parse_objects end if File.directory?(data_bag_full_path) data_bags << {data_bag => data_bag_items} unless data_bag_items.empty? end - objects["data bags"] = data_bags unless data_bags.empty? + objects["data_bags"] = data_bags unless data_bags.empty? # NODES # TODO: Cant use this yet as node_list.rb doesnt support node from file syntax but expects the node info to be part of the objects passed in # nodes = [] @@ -111,7 +111,7 @@ def self.order_cookbooks_by_dependency(cookbooks) sorted_cookbooks.push(remainders).flatten! else deps = unsorted_cookbooks.collect {|x| x['dependencies'].collect {|x| x['cookbook']} - sorted_cookbooks} - STDERR.puts "ERROR: Dependencies not satisfied or circular dependencies in cookbook(s): #{remainders} depend(s) on #{deps}" + STDERR.puts "ERROR: Dependencies not satisfied or circular dependencies in cookbook(s): #{remainders.join(' ')} depend(s) on #{deps.join(' ')}" exit(-1) end end From 9df4ba2f8ee402413b2ccb35d92c538340d46c27 Mon Sep 17 00:00:00 2001 From: ndowns Date: Wed, 18 Jul 2012 23:21:26 -0700 Subject: [PATCH 04/12] Redesigned how the yaml and json node peices are used. - The node yaml/json format has been extended to allow for a more human friendly format. - Parallel options removed. - Added pre-chef-10 knife command format. (How roles were passed had to be updated) TODO: Documentation needs to be updated. --- bin/spiceweasel | 4 +-- lib/spiceweasel/cli.rb | 6 ++-- lib/spiceweasel/node_list.rb | 69 ++++++++++++++++-------------------- 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/bin/spiceweasel b/bin/spiceweasel index fda9966..cb29403 100755 --- a/bin/spiceweasel +++ b/bin/spiceweasel @@ -33,7 +33,7 @@ begin cli = Spiceweasel::CLI.new cli.parse_options DEBUG = cli.config[:debug] - PARALLEL = cli.config[:parallel] + CHEF_PRE_10 = cli.config[:chef_pre_10] SITEINSTALL = cli.config[:siteinstall] NOVALIDATION = cli.config[:novalidation] EXTRACTLOCAL = cli.config[:extractlocal] @@ -94,7 +94,7 @@ input_copy = Marshal.load(Marshal.dump(input)) cookbook_list = Spiceweasel::CookbookList.new(input_copy['cookbooks'], options) environment_list = Spiceweasel::EnvironmentList.new(input_copy['environments'], cookbook_list, options) role_list = Spiceweasel::RoleList.new(input_copy['roles'], environment_list, cookbook_list, options) -data_bag_list = Spiceweasel::DataBagList.new(input_copy['data_bags'].dup, options) +data_bag_list = Spiceweasel::DataBagList.new(input_copy['data_bags'], options) node_list = Spiceweasel::NodeList.new(input_copy['nodes'], cookbook_list, environment_list, role_list, options) create += cookbook_list.create diff --git a/lib/spiceweasel/cli.rb b/lib/spiceweasel/cli.rb index c545a4d..3accb41 100644 --- a/lib/spiceweasel/cli.rb +++ b/lib/spiceweasel/cli.rb @@ -58,9 +58,9 @@ class Spiceweasel::CLI :description => "Disable validation", :boolean => true - option :parallel, - :long => "--parallel", - :description => "Use the GNU 'parallel' command to parallelize 'knife VENDOR server create' commands that are not order-dependent", + option :chef_pre_10, + :long => "--chef-pre-10", + :description => "Print knife commands using syntax for pre chef 10 versions of knife", :boolean => true option :rebuild, diff --git a/lib/spiceweasel/node_list.rb b/lib/spiceweasel/node_list.rb index 8b98cdf..507ccd1 100644 --- a/lib/spiceweasel/node_list.rb +++ b/lib/spiceweasel/node_list.rb @@ -3,55 +3,48 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) @create = @delete = '' if nodes nodes.each do |node| - nname = node.keys[0] + nname = node["name"] STDOUT.puts "DEBUG: node: '#{nname}'" if DEBUG - #convert spaces to commas, drop multiple commas - run_list = node[nname][0].gsub(/ /,',').gsub(/,+/,',') + + run_list = node["run_list"] STDOUT.puts "DEBUG: node: 'node[nname]' run_list: '#{run_list}'" if DEBUG validateRunList(nname, run_list, cookbooks, roles) unless NOVALIDATION - noptions = node[nname][1] + + noptions = node["options"] STDOUT.puts "DEBUG: node: 'node[nname]' options: '#{noptions}'" if DEBUG validateOptions(nname, noptions, environments) unless NOVALIDATION + #provider support - if nname.start_with?("bluebox ","clodo ","cs ","ec2 ","gandi ","hp ","openstack ","rackspace ","slicehost ","terremark ","voxel ") - provider = nname.split() - count = 1 - if (provider.length == 2) - count = provider[1] - end - if PARALLEL - @create += "seq #{count} | parallel -j 0 -v \"" - @create += "knife #{provider[0]}#{options['knife_options']} server create #{noptions}" - if run_list.length > 0 - @create += " -r '#{run_list}'\"\n" - end - else - count.to_i.times do - @create += "knife #{provider[0]}#{options['knife_options']} server create #{noptions}" + provider = node["type"] + count = node["count"] || 1 + count.to_i.times do |num| + nodename = "%s-%02d" % [nname, num + 1] + if ["bluebox","clodo","cs","ec2","gandi","hp","openstack","rackspace","slicehost","terremark","voxel"].include?(provider) + if CHEF_PRE_10 + @create += "knife #{provider}#{options['knife_options']} server create #{run_list} #{noptions} -N \'#{nodename}\'\n" + else + @create += "knife #{provider}#{options['knife_options']} server create -r #{run_list} #{noptions} -N \'#{nodename}\'\n" + end + @delete += "knife #{provider} server delete -y \'#{nodename}\'\n" + elsif provider == "windows" #windows node bootstrap support + #TODO Fix this section + nodeline = nname.split() + provider = nodeline.shift.split('_') #split on 'windows_ssh' etc + nodeline.each do |server| + @create += "knife bootstrap #{provider[0]} #{provider[1]}#{options['knife_options']} #{server} #{noptions}\n" if run_list.length > 0 @create += " -r '#{run_list}'\n" end + @delete += "knife node#{options['knife_options']} delete #{server} -y\n" end - end - @delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n" - elsif nname.start_with?("windows") #windows node bootstrap support - nodeline = nname.split() - provider = nodeline.shift.split('_') #split on 'windows_ssh' etc - nodeline.each do |server| - @create += "knife bootstrap #{provider[0]} #{provider[1]}#{options['knife_options']} #{server} #{noptions}" - if run_list.length > 0 - @create += " -r '#{run_list}'\n" - end - @delete += "knife node#{options['knife_options']} delete #{server} -y\n" - end - @delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n" - else #node bootstrap support - nname.split.each do |server| - @create += "knife bootstrap#{options['knife_options']} #{server} #{noptions}" - if run_list.length > 0 - @create += " -r '#{run_list}'\n" + @delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n" + else #node bootstrap support + if CHEF_PRE_10 + @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' #{run_list} #{noptions} -N \'#{nodename}\'\n" + else + @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' -r #{run_list} #{noptions} -N \'#{nodename}\'\n" end - @delete += "knife node#{options['knife_options']} delete #{server} -y\n" + @delete += "knife node#{options['knife_options']} delete \'#{nodename}\' -y\n" end end end From 6df0ba49035b1a78633d9c95fbafe10e6769aa87 Mon Sep 17 00:00:00 2001 From: ndowns Date: Wed, 18 Jul 2012 23:38:58 -0700 Subject: [PATCH 05/12] Begin documentation update. - changed the way the chef 10 role string is generated. - Documentation update started. --- README.md | 74 +++++++++++------------------------- example.yml | 26 ++++--------- lib/spiceweasel/node_list.rb | 4 +- 3 files changed, 32 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 66a71d3..8d71cbc 100644 --- a/README.md +++ b/README.md @@ -49,26 +49,17 @@ data_bags: - mysql - rabbitmq nodes: -- serverA: - - role[base] - - -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -- serverB serverC: - - role[base] - - -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -E production -- ec2 3: - - role[webserver] recipe[mysql::client] - - -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -- rackspace 3: - - recipe[mysql],role[monitoring] - - --image 49 --flavor 2 -- windows_winrm winboxA: - - role[base],role[iisserver] - - -x Administrator -P 'super_secret_password' -- windows_ssh winboxB winboxC: - - role[base],role[iisserver] - - -x Administrator -P 'super_secret_password' + - name: mysql-server + count: 3 + type: ec2 + run_list: role[mysql] recipe[hello] + options: -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large + - name: http + run_list: role[apache2] + options: -i '~/.ssh/key.pem' -x myuser ``` + JSON ---- From the `example.json`: @@ -258,48 +249,27 @@ knife data bag from file passwords rabbitmq.json --secret-file secret_key Nodes ----- -The `nodes` section of the manifest bootstraps a node for each entry where the entry is a hostname or provider and count. A shortcut syntax for bulk-creating nodes with various providers where the line starts with the provider and ends with the number of nodes to be provisioned. Windows nodes need to specify either `windows_winrm` or `windows_ssh` depending on the protocol used, followed by the name of the node(s). Each node requires 2 items after it in a sequence. You may also use the `--parallel` flag from the command line, allowing provider commands to run simultaneously for faster deployment. - -The first item after the node is the run_list and the second are the CLI options used. The run_list may be space or comma-delimited. Validation is performed on the run_list components to ensure that only cookbooks and roles listed in the manifest are used. Validation on the options ensures that any Environments referenced are also listed. You may specify multiple nodes to have the same configuration by listing them separated by a space. The example YAML snippet +The `nodes` section of the manifest bootstraps a node for each entry where the entry is a hostname or provider. Windows nodes need to specify either `windows_winrm` or `windows_ssh` depending on the protocol used, followed by the name of the node(s). Each node requires 2 items after it in a sequence. ``` yaml nodes: -- serverA: - - role[base] - - -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -- serverB serverC: - - role[base] - - -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -E production -- ec2 3: - - role[webserver] recipe[mysql::client] - - -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -- rackspace 3: - - recipe[mysql],role[monitoring] - - --image 49 --flavor 2 -- windows_winrm winboxA: - - role[base],role[iisserver] - - -x Administrator -P 'super_secret_password' -- windows_ssh winboxB winboxC: - - role[base],role[iisserver] - - -x Administrator -P 'super_secret_password' + - name: mysql-server + count: 3 + type: ec2 + run_list: role[mysql] recipe[hello] + options: -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large + - name: http + run_list: role[apache2] + options: -i '~/.ssh/key.pem' -x myuser ``` produces the knife commands ``` -knife bootstrap serverA -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -r 'role[base]' -knife bootstrap serverB -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -E production -r 'role[base]' -knife bootstrap serverC -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -E production -r 'role[base]' -knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -r 'role[webserver],recipe[mysql::client]' -knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -r 'role[webserver],recipe[mysql::client]' -knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -r 'role[webserver],recipe[mysql::client]' -knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -r 'role[webserver],recipe[mysql::client]' -knife rackspace server create --image 49 --flavor 2 -r 'recipe[mysql],role[monitoring]' -knife rackspace server create --image 49 --flavor 2 -r 'recipe[mysql],role[monitoring]' -knife rackspace server create --image 49 --flavor 2 -r 'recipe[mysql],role[monitoring]' -knife bootstrap windows winrm winboxA -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]' -knife bootstrap windows ssh winboxB -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]' -knife bootstrap windows ssh winboxC -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]' +knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-01' +knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-02' +knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-03' +knife bootstrap 'http-01' -r role[apache2] -i '~/.ssh/key.pem' -x myuser -N 'http-01' ``` Extract diff --git a/example.yml b/example.yml index 3894410..6e8fb16 100644 --- a/example.yml +++ b/example.yml @@ -24,21 +24,11 @@ data_bags: - mysql - rabbitmq nodes: -- serverA: - - role[base] - - -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -- serverB serverC: - - role[base] - - -i ~/.ssh/mray.pem -x user --sudo -d ubuntu10.04-gems -E production -- ec2 4: - - role[webserver] recipe[mysql::client] - - -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -- rackspace 3: - - recipe[mysql],role[monitoring] - - --image 49 --flavor 2 -- windows_winrm winboxA: - - role[base],role[iisserver] - - -x Administrator -P 'super_secret_password' -- windows_ssh winboxB winboxC: - - role[base],role[iisserver] - - -x Administrator -P 'super_secret_password' + - name: mysql-server + count: 3 + type: ec2 + run_list: role[mysql] recipe[hello] + options: -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large + - name: http + run_list: role[apache2] + options: -i '~/.ssh/key.pem' -x myuser diff --git a/lib/spiceweasel/node_list.rb b/lib/spiceweasel/node_list.rb index 507ccd1..b490166 100644 --- a/lib/spiceweasel/node_list.rb +++ b/lib/spiceweasel/node_list.rb @@ -23,7 +23,7 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) if CHEF_PRE_10 @create += "knife #{provider}#{options['knife_options']} server create #{run_list} #{noptions} -N \'#{nodename}\'\n" else - @create += "knife #{provider}#{options['knife_options']} server create -r #{run_list} #{noptions} -N \'#{nodename}\'\n" + @create += "knife #{provider}#{options['knife_options']} server create -r #{run_list.gsub(' ', ',')} #{noptions} -N \'#{nodename}\'\n" end @delete += "knife #{provider} server delete -y \'#{nodename}\'\n" elsif provider == "windows" #windows node bootstrap support @@ -42,7 +42,7 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) if CHEF_PRE_10 @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' #{run_list} #{noptions} -N \'#{nodename}\'\n" else - @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' -r #{run_list} #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' -r #{run_list.gsub(' ', ',')} #{noptions} -N \'#{nodename}\'\n" end @delete += "knife node#{options['knife_options']} delete \'#{nodename}\' -y\n" end From 12027241edb742e67a275ea2b0af109d6354eeef Mon Sep 17 00:00:00 2001 From: Nick Downs Date: Thu, 19 Jul 2012 21:49:39 -0700 Subject: [PATCH 06/12] run_list now required to be a list. - In order to clean up support for chef-pre-10 knife strings, the run_list should be in the config as a list from now on. --- README.md | 10 +++++++--- example.yml | 6 ++++-- lib/spiceweasel/node_list.rb | 8 ++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8d71cbc..c3360f2 100644 --- a/README.md +++ b/README.md @@ -52,10 +52,12 @@ nodes: - name: mysql-server count: 3 type: ec2 - run_list: role[mysql] recipe[hello] + run_list: + - role[mysql] + - recipe[hello] options: -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large - name: http - run_list: role[apache2] + run_list: ["role[apache2]"] options: -i '~/.ssh/key.pem' -x myuser ``` @@ -256,7 +258,9 @@ nodes: - name: mysql-server count: 3 type: ec2 - run_list: role[mysql] recipe[hello] + run_list: + - role[mysql] + - recipe[hello] options: -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large - name: http run_list: role[apache2] diff --git a/example.yml b/example.yml index 6e8fb16..793421d 100644 --- a/example.yml +++ b/example.yml @@ -27,8 +27,10 @@ nodes: - name: mysql-server count: 3 type: ec2 - run_list: role[mysql] recipe[hello] + run_list: + - "role[mysql]" + - "recipe[hello]" options: -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large - name: http - run_list: role[apache2] + run_list: ["role[apache2]"] options: -i '~/.ssh/key.pem' -x myuser diff --git a/lib/spiceweasel/node_list.rb b/lib/spiceweasel/node_list.rb index b490166..5258162 100644 --- a/lib/spiceweasel/node_list.rb +++ b/lib/spiceweasel/node_list.rb @@ -21,9 +21,9 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) nodename = "%s-%02d" % [nname, num + 1] if ["bluebox","clodo","cs","ec2","gandi","hp","openstack","rackspace","slicehost","terremark","voxel"].include?(provider) if CHEF_PRE_10 - @create += "knife #{provider}#{options['knife_options']} server create #{run_list} #{noptions} -N \'#{nodename}\'\n" + @create += "knife #{provider}#{options['knife_options']} server create \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" else - @create += "knife #{provider}#{options['knife_options']} server create -r #{run_list.gsub(' ', ',')} #{noptions} -N \'#{nodename}\'\n" + @create += "knife #{provider}#{options['knife_options']} server create -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" end @delete += "knife #{provider} server delete -y \'#{nodename}\'\n" elsif provider == "windows" #windows node bootstrap support @@ -40,9 +40,9 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) @delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n" else #node bootstrap support if CHEF_PRE_10 - @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' #{run_list} #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" else - @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' -r #{run_list.gsub(' ', ',')} #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" end @delete += "knife node#{options['knife_options']} delete \'#{nodename}\' -y\n" end From b18f9e900614595581a74174ec820a1320b9f896 Mon Sep 17 00:00:00 2001 From: Nick Downs Date: Sun, 22 Jul 2012 01:06:24 -0700 Subject: [PATCH 07/12] Updates to support bootstrap by IP with updated Documentation. - The "host" directive has been added which will allow setting the bootstrap target to an IP or hostname different from the "name" directive. - Updated README with documentation on my yaml/json data structure changes and requirements. --- README.md | 43 ++++++++++++++++++++++++++++++++---- lib/spiceweasel/node_list.rb | 5 +++-- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c3360f2..fa1c69a 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,41 @@ knife data bag from file passwords rabbitmq.json --secret-file secret_key Nodes ----- -The `nodes` section of the manifest bootstraps a node for each entry where the entry is a hostname or provider. Windows nodes need to specify either `windows_winrm` or `windows_ssh` depending on the protocol used, followed by the name of the node(s). Each node requires 2 items after it in a sequence. +The `nodes` section of the manifest bootstraps a node for each entry where the entry is a hostname or provider. + +Use the following list of directives to control the format of the knife command: +* name: + The -N option is passed to every knife command. Currently this isn't configurable so this option is required for the knife command to be generated correctly. + This directive is also used for bootstrap knife commands if the host directive isn't configured. + + Note: The node name is generated with a -## at the end of it. For example, the string "mysql" will actually be turned into mysql-01. This is to allow a number + of servers to be generated using the count directive. It ensures that the node names are different (as required by chef). In the future there will be a + way to disable this behavior. + +* host: + + Hostname or IP of the host to be bootstrapped. This directive is only used for nodes that do not use the "type" directive. It is usefull for boxes that are + not in DNS but need to be bootstrapped. It defaults to the "name" directive if it is not set. + +* count: + Generate of this type of server. This allows you to generate multiple servers of the same type (same run_list and knife options) without having to + configure number of nodes in the config file. + +* type: + Supported types: "bluebox","clodo","cs","ec2","gandi","hp","openstack","rackspace","slicehost","terremark","voxel" + + Type is used to declare which knife plugin to use for server create commands. If type is left blank, bootstrap commands are generated instead of cloud + specific commands. See the example second to see how type affects command generation. + +* run_list: ["role[]", "recipe[]"] + + A list of roles or recipes to add to the run list for this host. This directive has to be a valid yaml to json LIST type. + +* options: + + Additional command line options to be passed to the knife command. + +Windows support is currently untested (and is probably broken). ``` yaml nodes: @@ -263,7 +297,8 @@ nodes: - recipe[hello] options: -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large - name: http - run_list: role[apache2] + host: 192.168.1.10 + run_list: ["role[apache2]"] options: -i '~/.ssh/key.pem' -x myuser ``` @@ -273,7 +308,7 @@ produces the knife commands knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-01' knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-02' knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-03' -knife bootstrap 'http-01' -r role[apache2] -i '~/.ssh/key.pem' -x myuser -N 'http-01' +knife bootstrap '192.168.1.10' -r role[apache2] -i '~/.ssh/key.pem' -x myuser -N 'http-01' ``` Extract @@ -366,7 +401,7 @@ Use the 'install' command with 'knife cookbook site' instead of the default 'dow ------------ Print the version of spiceweasel currently installed. -License and Author +Original License and Author ================== Author: Matt Ray diff --git a/lib/spiceweasel/node_list.rb b/lib/spiceweasel/node_list.rb index 5258162..32b0e4c 100644 --- a/lib/spiceweasel/node_list.rb +++ b/lib/spiceweasel/node_list.rb @@ -19,6 +19,7 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) count = node["count"] || 1 count.to_i.times do |num| nodename = "%s-%02d" % [nname, num + 1] + host = node["host"] || nodename if ["bluebox","clodo","cs","ec2","gandi","hp","openstack","rackspace","slicehost","terremark","voxel"].include?(provider) if CHEF_PRE_10 @create += "knife #{provider}#{options['knife_options']} server create \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" @@ -40,9 +41,9 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) @delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n" else #node bootstrap support if CHEF_PRE_10 - @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{host}\' \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" else - @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{host}\' -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" end @delete += "knife node#{options['knife_options']} delete \'#{nodename}\' -y\n" end From eab29ff275960d7dcf735645563bfc4777ca144c Mon Sep 17 00:00:00 2001 From: nickryand Date: Sun, 22 Jul 2012 01:12:45 -0700 Subject: [PATCH 08/12] Updates to support bootstrap by IP with updated Documentation. - The "host" directive has been added which will allow setting the bootstrap target to an IP or hostname different from the "name" directive. - Updated README with documentation on my yaml/json data structure changes and requirements. --- README.md | 43 ++++++++++++++++++++++++++++++++---- lib/spiceweasel/node_list.rb | 5 +++-- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c3360f2..fa1c69a 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,41 @@ knife data bag from file passwords rabbitmq.json --secret-file secret_key Nodes ----- -The `nodes` section of the manifest bootstraps a node for each entry where the entry is a hostname or provider. Windows nodes need to specify either `windows_winrm` or `windows_ssh` depending on the protocol used, followed by the name of the node(s). Each node requires 2 items after it in a sequence. +The `nodes` section of the manifest bootstraps a node for each entry where the entry is a hostname or provider. + +Use the following list of directives to control the format of the knife command: +* name: + The -N option is passed to every knife command. Currently this isn't configurable so this option is required for the knife command to be generated correctly. + This directive is also used for bootstrap knife commands if the host directive isn't configured. + + Note: The node name is generated with a -## at the end of it. For example, the string "mysql" will actually be turned into mysql-01. This is to allow a number + of servers to be generated using the count directive. It ensures that the node names are different (as required by chef). In the future there will be a + way to disable this behavior. + +* host: + + Hostname or IP of the host to be bootstrapped. This directive is only used for nodes that do not use the "type" directive. It is usefull for boxes that are + not in DNS but need to be bootstrapped. It defaults to the "name" directive if it is not set. + +* count: + Generate of this type of server. This allows you to generate multiple servers of the same type (same run_list and knife options) without having to + configure number of nodes in the config file. + +* type: + Supported types: "bluebox","clodo","cs","ec2","gandi","hp","openstack","rackspace","slicehost","terremark","voxel" + + Type is used to declare which knife plugin to use for server create commands. If type is left blank, bootstrap commands are generated instead of cloud + specific commands. See the example second to see how type affects command generation. + +* run_list: ["role[]", "recipe[]"] + + A list of roles or recipes to add to the run list for this host. This directive has to be a valid yaml to json LIST type. + +* options: + + Additional command line options to be passed to the knife command. + +Windows support is currently untested (and is probably broken). ``` yaml nodes: @@ -263,7 +297,8 @@ nodes: - recipe[hello] options: -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large - name: http - run_list: role[apache2] + host: 192.168.1.10 + run_list: ["role[apache2]"] options: -i '~/.ssh/key.pem' -x myuser ``` @@ -273,7 +308,7 @@ produces the knife commands knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-01' knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-02' knife ec2 server create -r role[mysql],recipe[hello] -S 'key-pair' -i '~/.ssh/key.pem' -x ubuntu -G inside-db -I ami-123fsdf1 -f m1.large -N 'mysql-server-03' -knife bootstrap 'http-01' -r role[apache2] -i '~/.ssh/key.pem' -x myuser -N 'http-01' +knife bootstrap '192.168.1.10' -r role[apache2] -i '~/.ssh/key.pem' -x myuser -N 'http-01' ``` Extract @@ -366,7 +401,7 @@ Use the 'install' command with 'knife cookbook site' instead of the default 'dow ------------ Print the version of spiceweasel currently installed. -License and Author +Original License and Author ================== Author: Matt Ray diff --git a/lib/spiceweasel/node_list.rb b/lib/spiceweasel/node_list.rb index 5258162..32b0e4c 100644 --- a/lib/spiceweasel/node_list.rb +++ b/lib/spiceweasel/node_list.rb @@ -19,6 +19,7 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) count = node["count"] || 1 count.to_i.times do |num| nodename = "%s-%02d" % [nname, num + 1] + host = node["host"] || nodename if ["bluebox","clodo","cs","ec2","gandi","hp","openstack","rackspace","slicehost","terremark","voxel"].include?(provider) if CHEF_PRE_10 @create += "knife #{provider}#{options['knife_options']} server create \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" @@ -40,9 +41,9 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) @delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n" else #node bootstrap support if CHEF_PRE_10 - @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{host}\' \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" else - @create += "knife bootstrap#{options['knife_options']} \'#{nodename}\' -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{host}\' -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" end @delete += "knife node#{options['knife_options']} delete \'#{nodename}\' -y\n" end From 6f9ee5b72bc91dbd6968743b9d8c30213ad60ea2 Mon Sep 17 00:00:00 2001 From: Keith Thornhill Date: Mon, 15 Oct 2012 19:08:10 -0700 Subject: [PATCH 09/12] provide cli option to skip generating a numbered nodename --- bin/spiceweasel | 1 + lib/spiceweasel/cli.rb | 4 ++++ lib/spiceweasel/node_list.rb | 9 +++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/bin/spiceweasel b/bin/spiceweasel index cb29403..b68bd67 100755 --- a/bin/spiceweasel +++ b/bin/spiceweasel @@ -39,6 +39,7 @@ begin EXTRACTLOCAL = cli.config[:extractlocal] EXTRACTYAML = cli.config[:extractyaml] EXTRACTJSON = cli.config[:extractjson] + SKIP_NODENAME = cli.config[:skip_nodename] rescue OptionParser::InvalidOption => e STDERR.puts e.message puts cli.opt_parser.to_s diff --git a/lib/spiceweasel/cli.rb b/lib/spiceweasel/cli.rb index 3accb41..7e712aa 100644 --- a/lib/spiceweasel/cli.rb +++ b/lib/spiceweasel/cli.rb @@ -82,4 +82,8 @@ class Spiceweasel::CLI :proc => lambda {|v| puts "Spiceweasel: #{Spiceweasel::VERSION}" }, :exit => 0 + option :skip_nodename, + :long => '--skip_nodename', + :boolean => true + end diff --git a/lib/spiceweasel/node_list.rb b/lib/spiceweasel/node_list.rb index 32b0e4c..c56fea9 100644 --- a/lib/spiceweasel/node_list.rb +++ b/lib/spiceweasel/node_list.rb @@ -22,9 +22,14 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) host = node["host"] || nodename if ["bluebox","clodo","cs","ec2","gandi","hp","openstack","rackspace","slicehost","terremark","voxel"].include?(provider) if CHEF_PRE_10 - @create += "knife #{provider}#{options['knife_options']} server create \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" + @create += "knife #{provider}#{options['knife_options']} server create \'#{run_list.join("' '")}\' #{noptions}" else - @create += "knife #{provider}#{options['knife_options']} server create -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" + @create += "knife #{provider}#{options['knife_options']} server create -r \'#{run_list.join(',')}\' #{noptions}" + end + if noptions["-N"] or SKIP_NODENAME + @create += "\n" + else + @create += " -N \'#{nodename}\'\n" end @delete += "knife #{provider} server delete -y \'#{nodename}\'\n" elsif provider == "windows" #windows node bootstrap support From 435e5fd61b19942c1ffa4be08fb5f60cddf2feb3 Mon Sep 17 00:00:00 2001 From: Nick Downs Date: Thu, 18 Oct 2012 23:25:33 -0700 Subject: [PATCH 10/12] Changes to validation, group and disabled delete support for nodes. - Validation is now an option. It doesn't do it by default. - Added support for sec groups. You don't have to put them in the options section. The script will do that for you. - Grafted in the {{n}} support for node names from the main project. - Added an "availability_zone" directive to node sections to support distributing nodes across AZ's. - Added support to alternate AZ's when generating nodes of the same type. - Disabled delete command generation for the time being. It needs work. --- bin/spiceweasel | 2 +- lib/spiceweasel/cli.rb | 8 +++--- lib/spiceweasel/node_list.rb | 47 ++++++++++++++++++++++++++---------- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/bin/spiceweasel b/bin/spiceweasel index cb29403..b15caa7 100755 --- a/bin/spiceweasel +++ b/bin/spiceweasel @@ -35,7 +35,7 @@ begin DEBUG = cli.config[:debug] CHEF_PRE_10 = cli.config[:chef_pre_10] SITEINSTALL = cli.config[:siteinstall] - NOVALIDATION = cli.config[:novalidation] + VALIDATION = cli.config[:validation] EXTRACTLOCAL = cli.config[:extractlocal] EXTRACTYAML = cli.config[:extractyaml] EXTRACTJSON = cli.config[:extractjson] diff --git a/lib/spiceweasel/cli.rb b/lib/spiceweasel/cli.rb index 3accb41..79a0d29 100644 --- a/lib/spiceweasel/cli.rb +++ b/lib/spiceweasel/cli.rb @@ -53,10 +53,10 @@ class Spiceweasel::CLI :long => "--knifeconfig CONFIG", :description => "Specify the knife.rb configuration file" - option :novalidation, - :long => "--novalidation", - :description => "Disable validation", - :boolean => true + option :validation, + :long => "--validation", + :description => "Enable validation", + :boolean => false option :chef_pre_10, :long => "--chef-pre-10", diff --git a/lib/spiceweasel/node_list.rb b/lib/spiceweasel/node_list.rb index 32b0e4c..ba06dab 100644 --- a/lib/spiceweasel/node_list.rb +++ b/lib/spiceweasel/node_list.rb @@ -8,25 +8,40 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) run_list = node["run_list"] STDOUT.puts "DEBUG: node: 'node[nname]' run_list: '#{run_list}'" if DEBUG - validateRunList(nname, run_list, cookbooks, roles) unless NOVALIDATION + validateRunList(nname, run_list, cookbooks, roles) if VALIDATION - noptions = node["options"] + # If were an array, join together to make a string. This allows for yaml + # anchor and alias usage within the config file. + noptions = node["options"].kind_of?(Array) ? node["options"].join(' ') : \ + node["options"] STDOUT.puts "DEBUG: node: 'node[nname]' options: '#{noptions}'" if DEBUG - validateOptions(nname, noptions, environments) unless NOVALIDATION + validateOptions(nname, noptions, environments) if VALIDATION - #provider support + #provider supportp provider = node["type"] count = node["count"] || 1 count.to_i.times do |num| - nodename = "%s-%02d" % [nname, num + 1] - host = node["host"] || nodename + host = node["host"] if ["bluebox","clodo","cs","ec2","gandi","hp","openstack","rackspace","slicehost","terremark","voxel"].include?(provider) if CHEF_PRE_10 - @create += "knife #{provider}#{options['knife_options']} server create \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" + @create << "knife #{provider}#{options['knife_options']} server create \'#{run_list.join("' '")}\' #{noptions}".gsub(/\{\{n\}\}/, "%02d" % (num + 1)) else - @create += "knife #{provider}#{options['knife_options']} server create -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" + @create << "knife #{provider}#{options['knife_options']} server create -r \'#{run_list.join(',')}\' #{noptions}".gsub(/\{\{n\}\}/, "%02d" % (num + 1)) end - @delete += "knife #{provider} server delete -y \'#{nodename}\'\n" + + # Rotate around the configured AZ's. + if node.key?("availability_zones") + az_num = num % node["availability_zones"].length + @create += "-Z #{node['availability_zones'][az_num]}" + end + + if node.key?("groups") + @create += " -g #{node['groups'].join(',')}" + end + + @create << "\n" + + #@delete += "knife #{provider} server delete -y \'#{host}\'\n" elsif provider == "windows" #windows node bootstrap support #TODO Fix this section nodeline = nname.split() @@ -38,14 +53,20 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) end @delete += "knife node#{options['knife_options']} delete #{server} -y\n" end - @delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n" + #@delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n" else #node bootstrap support if CHEF_PRE_10 - @create += "knife bootstrap#{options['knife_options']} \'#{host}\' \'#{run_list.join("' '")}\' #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{host}\' \'#{run_list.join("' '")}\' #{noptions}".gsub(/\{\{n\}\}/, "%02d" % (num + 1)) else - @create += "knife bootstrap#{options['knife_options']} \'#{host}\' -r \'#{run_list.join(',')}\' #{noptions} -N \'#{nodename}\'\n" + @create += "knife bootstrap#{options['knife_options']} \'#{host}\' -r \'#{run_list.join(',')}\' #{noptions}".gsub(/\{\{n\}\}/, "%02d" % (num + 1)) + end + #@delete += "knife node#{options['knife_options']} delete \'#{nodename}\' -y\n" + + if node.key?("groups") + @create += " -g #{node['groups'].join(',')}" end - @delete += "knife node#{options['knife_options']} delete \'#{nodename}\' -y\n" + + @create << "\n" end end end From b5756ba3b045faf628095cba9d031ade8aca8841 Mon Sep 17 00:00:00 2001 From: Nick Downs Date: Sat, 17 Nov 2012 01:15:48 -0800 Subject: [PATCH 11/12] Fixed security group parameter to -G for chef-pre-10 mode. --- lib/spiceweasel/node_list.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/spiceweasel/node_list.rb b/lib/spiceweasel/node_list.rb index ba06dab..4ae1cc4 100644 --- a/lib/spiceweasel/node_list.rb +++ b/lib/spiceweasel/node_list.rb @@ -36,7 +36,11 @@ def initialize(nodes, cookbooks, environments, roles, options = {}) end if node.key?("groups") + if CHEF_PRE_10 + @create += " -G #{node['groups'].join(',')}" + else @create += " -g #{node['groups'].join(',')}" + end end @create << "\n" From b2dac810129b34e2f374100bccf6635cf104ecc3 Mon Sep 17 00:00:00 2001 From: I-Ming Chen Date: Wed, 18 Jun 2014 13:12:38 -0700 Subject: [PATCH 12/12] Added better error output for Exception catch all error. --- bin/spiceweasel | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/spiceweasel b/bin/spiceweasel index a9143ab..0a164bf 100755 --- a/bin/spiceweasel +++ b/bin/spiceweasel @@ -77,7 +77,8 @@ else STDERR.puts e.message STDERR.puts "ERROR: Parsing error in #{file}." exit(-1) - rescue Exception + rescue Exception => e + STDERR.puts e.message STDERR.puts "ERROR: No infrastructure .json or .yml file provided." puts cli.opt_parser.to_s exit(-1)