knife-nodefu 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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