knife-nodefu 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,4 +29,12 @@ module NodefuBase
29
29
  raise ServerRangeError if end_range.to_i < start_range.to_i
30
30
  return [base_name,start_range,end_range]
31
31
  end
32
+
33
+ def failed_nodes(servers)
34
+ servers.select {|k,v| v['chef_node'].nil? || !v['failure'].nil? }
35
+ end
36
+
37
+ def successful_nodes(servers)
38
+ servers.select {|k,v| !v['chef_node'].nil? && v['failure'].nil? }
39
+ end
32
40
  end
@@ -6,13 +6,17 @@ class NodefuCreate < Chef::Knife
6
6
  require 'fileutils'
7
7
  require 'yaml'
8
8
  require 'thread'
9
+ require 'fog'
9
10
  Chef::Knife::Ec2ServerCreate.load_deps
11
+ Chef::Knife::Ec2ServerDelete.load_deps
10
12
  end
11
13
 
12
14
  include NodefuBase
13
15
 
14
16
  banner "knife nodefu create <server><range> (OPTIONS)"
15
17
 
18
+ attr_reader :servers
19
+
16
20
  option :node_spec,
17
21
  :short => "-n <node_spec>",
18
22
  :long => "--node_spec <node_spec>",
@@ -31,26 +35,49 @@ class NodefuCreate < Chef::Knife
31
35
  :description => "yml definitions file",
32
36
  :default => nil
33
37
 
38
+ option :exit_on_fail,
39
+ :short => "-e",
40
+ :long => "--exit-on-fail",
41
+ :description => "Exit if one of the servers fails to come up",
42
+ :default => nil
43
+
44
+ option :destroy_on_fail,
45
+ :short => "-f",
46
+ :long => "--destroy-on-fail",
47
+ :description => "Terminate the ec2 instance on error",
48
+ :default => nil
49
+
50
+ def destroy_instances(servers)
51
+ ec2_delete = Ec2ServerDelete.new
52
+ servers.each_pair.with_index do |(k,v),i|
53
+ if v['server'].nil?
54
+ ui.msg("No server to delete for #{k}")
55
+ else
56
+ ec2_delete.name_args[i] = v['server'].id
57
+ end
58
+ end
59
+ ec2_delete.config[:yes] = true
60
+ ec2_delete.run
61
+ end
62
+
34
63
  def run
64
+ check_args(1)
35
65
  env = Chef::Config[:environment]
36
66
  definitions_file = config[:definitions_file].nil? ? Chef::Config[:nodefu_definitions_file] : config[:definitions_file]
37
67
  @yml_config = YAML.load_file definitions_file
38
68
 
39
- check_args(1)
40
- servers = name_args[0]
41
- base_name, start_range, end_range = parse_servers(servers)
69
+ base_name, start_range, end_range = parse_servers(name_args[0])
42
70
 
43
71
  #merge the current environment hash with the defaults
44
72
  merged_configuration = Chef::Mixin::DeepMerge.merge(@yml_config['default'],@yml_config['env'][env])
45
73
 
46
- domain = merged_configuration['domain']
47
-
48
74
  if (! config[:node_spec].nil?)
49
75
  node_spec_name = config[:node_spec]
50
76
  else
51
77
  node_spec_name = base_name
52
78
  end
53
79
 
80
+ domain = merged_configuration['domain']
54
81
  node_spec = merged_configuration['node_spec'][node_spec_name]
55
82
  vm_spec_name = node_spec['vm_spec']
56
83
  vm_spec = merged_configuration['vm_spec'][vm_spec_name]
@@ -67,27 +94,53 @@ class NodefuCreate < Chef::Knife
67
94
  config[:yes] ? user_response = 'yes' : user_response = ui.ask_question("Does this seem right to you? [y/n]").downcase
68
95
  abort("See ya!") unless (['yes','y',].include?(user_response))
69
96
 
70
- threads = []
97
+ threads = []
71
98
  for i in (start_range..end_range)
72
- threads << Thread.new(i) do |id|
73
- ec2_create = Ec2ServerCreate.new
74
- node_name = "#{base_name}#{id}"
75
-
76
- #A handeful of the Ec2ServerCreate command line options use a :proc field so I have to
77
- #populate those by hand instead of simply passing a value to its config entry
78
- Chef::Config[:knife][:aws_ssh_key_id] = vm_spec['ssh_key']
79
- Chef::Config[:knife][:image] = vm_spec['ami']
80
- Chef::Config[:knife][:region] = vm_spec['region']
81
- ec2_create.config[:chef_node_name] = "#{node_name}.#{env}.#{domain}"
82
- ec2_create.config[:run_list] = node_spec['run_list']
83
- ec2_create.config[:flavor] = vm_spec['type']
84
- ec2_create.config[:security_groups] = (generate_security_groups(node_name,env) + aux_groups).split(',')
85
- ec2_create.config[:ssh_user] = vm_spec['user']
86
- ec2_create.config[:availability_zone] = vm_spec['az']
87
- ec2_create.config[:distro] = vm_spec['bootstrap']
88
- ec2_create.run
89
- end
99
+ ec2_server_request = Ec2ServerCreate.new
100
+ node_name = "#{base_name}#{i}"
101
+ full_node_name = "#{base_name}#{i}.#{env}.#{domain}"
102
+ #A handfull of the Ec2ServerCreate command line options use a :proc field so I have to
103
+ #populate those by hand instead of simply passing a value to its config entry
104
+ Chef::Config[:knife][:aws_ssh_key_id] = vm_spec['ssh_key']
105
+ Chef::Config[:knife][:image] = vm_spec['ami']
106
+ Chef::Config[:knife][:region] = vm_spec['region']
107
+ ec2_server_request.config[:chef_node_name] = full_node_name
108
+ ec2_server_request.config[:run_list] = node_spec['run_list']
109
+ ec2_server_request.config[:flavor] = vm_spec['type']
110
+ ec2_server_request.config[:security_groups] = (generate_security_groups(node_name,env) + aux_groups).split(',')
111
+ ec2_server_request.config[:ssh_user] = vm_spec['user']
112
+ ec2_server_request.config[:availability_zone] = vm_spec['az']
113
+ ec2_server_request.config[:distro] = vm_spec['bootstrap']
114
+ threads << Thread.new(full_node_name,ec2_server_request) do |full_node_name,request|
115
+ e = nil
116
+ begin
117
+ request.run
118
+ rescue => e
119
+ config[:exit_on_fail] ? raise(e) : puts("#{full_node_name}: #{e.message}")
120
+ end
121
+ [full_node_name, { 'server' => request.server, 'failure' => e, 'chef_node' => nil} ]
122
+ end
90
123
  end
91
124
  threads.each(&:join)
125
+
126
+ #Build a servers hash with the node names as they key from the object returned by the threads
127
+ @servers = threads.inject({}) {|hash,t| hash[t.value[0]] = t.value[1]; hash}
128
+
129
+ query = Chef::Search::Query.new
130
+ query.search('node',"name:#{base_name}*#{env}*") do |n|
131
+ @servers[n.name]['chef_node'] = n
132
+ end
133
+
134
+ ui.msg('')
135
+ ui.msg(ui.color('Failed Nodes:',:red))
136
+ failed = failed_nodes(@servers).each_pair { |k,v| ui.msg("#{k}: #{v['failure']}") }
137
+
138
+ ui.msg(ui.color('Successful Nodes:',:green))
139
+ successful = successful_nodes(@servers).each_pair { |k,v| ui.msg("#{k}: #{v['id']}, #{v['dns_name']}") }
140
+
141
+ if config[:destroy_on_fail]
142
+ ui.msg(ui.color("Destroying failed nodes:",:red))
143
+ destroy_instances(failed)
144
+ end
92
145
  end
93
146
  end
@@ -7,13 +7,14 @@ class NodefuDestroy < Chef::Knife
7
7
  require 'chef/api_client'
8
8
  require 'chef/node'
9
9
  require 'chef/json_compat'
10
+ require 'chef/search/query'
10
11
  require 'thread'
11
12
  Chef::Knife::Ec2ServerDelete.load_deps
12
13
  end
13
14
 
14
15
  include NodefuBase
15
16
 
16
- banner "knife nodefu destroy <name>|<name>[range]"
17
+ banner "knife nodefu destroy QUERY (options)"
17
18
 
18
19
  option :yes,
19
20
  :short => "-y",
@@ -41,13 +42,13 @@ class NodefuDestroy < Chef::Knife
41
42
 
42
43
  def run
43
44
  check_args(1)
44
- matcher = /#{name_args[0]}/
45
45
 
46
- all_clients = Chef::ApiClient.list(true)
47
- all_nodes = Chef::Node.list
48
-
49
- nodes_to_delete = all_nodes.inject({}) { |nodes, (k,v)| nodes[k] = Chef::Node.load(k) if k =~ matcher; nodes }
50
- clients_to_delete = all_clients.inject({}) { |clients, (k, v)| clients[k] = v if k =~ matcher; clients }
46
+ nodes_to_delete, clients_to_delete = {},{}
47
+ query = Chef::Search::Query.new
48
+ query.search('node',name_args[0]) do |node|
49
+ nodes_to_delete[node.name] = node
50
+ clients_to_delete[node.name] = Chef::ApiClient.load(node.name)
51
+ end
51
52
 
52
53
  #Display all the items that will be removed
53
54
  if config[:skip_clients]
@@ -68,9 +69,9 @@ class NodefuDestroy < Chef::Knife
68
69
  ui.msg("#{ui.color('Skipping instances...',:cyan)}")
69
70
  else
70
71
  ui.msg("#{ui.color('EC2 instances to be terminated:',:red)}")
71
- nodes_to_delete.each do |node|
72
- instance_id = node[1]['ec2']['instance_id']
73
- ui.msg("#{ui.color(node[0],:magenta)}: #{instance_id}")
72
+ nodes_to_delete.each_pair do |name,node|
73
+ instance_id = node['ec2']['instance_id']
74
+ ui.msg("#{ui.color(name,:magenta)}: #{instance_id}")
74
75
  end
75
76
  end
76
77
 
@@ -80,14 +81,11 @@ class NodefuDestroy < Chef::Knife
80
81
  unless config[:skip_instances]
81
82
  threads = []
82
83
  #Delete the ec2 server
83
- for i in nodes_to_delete
84
- threads << Thread.new(i) do |node|
84
+ nodes_to_delete.each_pair do |name,node|
85
85
  ec2_delete = Ec2ServerDelete.new
86
- instance_id = node[1]['ec2']['instance_id']
87
- ec2_delete.name_args[0] = instance_id
86
+ ec2_delete.name_args[0] = node['ec2']['instance_id']
88
87
  ec2_delete.config[:yes] = true
89
- ec2_delete.run
90
- end
88
+ threads << Thread.new(node) { |node| ec2_delete.run }
91
89
  end
92
90
  threads.each(&:join)
93
91
  end
@@ -1,6 +1,6 @@
1
1
  module Knife
2
2
  module Nodefu
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  MAJOR, MINOR, TINY = VERSION.split(',')
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-nodefu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-16 00:00:00.000000000Z
12
+ date: 2012-05-24 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: knife-ec2
16
- requirement: &70111068734520 !ruby/object:Gem::Requirement
16
+ requirement: &70184212905400 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70111068734520
24
+ version_requirements: *70184212905400
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: chef
27
- requirement: &70111068734020 !ruby/object:Gem::Requirement
27
+ requirement: &70184212904900 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0.10'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70111068734020
35
+ version_requirements: *70184212904900
36
36
  description: A knife plugin for simple node creation automation
37
37
  email:
38
38
  - brian.bianco@gmail.com