knife-voxel 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,184 @@
1
+ require 'chef/knife/voxel_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class VoxelVoxserversReimage < Knife
6
+ include Knife::VoxelBase
7
+
8
+ deps do
9
+ require 'chef/json_compat'
10
+ require 'chef/knife/bootstrap'
11
+ require 'hapi'
12
+ require 'readline'
13
+
14
+ Chef::Knife::Bootstrap.load_deps
15
+ end
16
+
17
+ banner "knife voxel voxservers reimage DEVICE_ID (options)"
18
+
19
+ option :swap_size,
20
+ :long => "--swap-size SIZE",
21
+ :description => "Swap Partition Size, in GB",
22
+ :default => 4
23
+
24
+ option :image_id,
25
+ :long => "--image-id IMAGE",
26
+ :description => "Image Id to Install",
27
+ :required => true
28
+
29
+ option :hostname,
30
+ :long => "--hostname NAME",
31
+ :description => "The server's hostname",
32
+ :required => true
33
+
34
+ option :chef_node_name,
35
+ :short => "-N NAME",
36
+ :long => "--node-name NAME",
37
+ :description => "The Chef node name for your new node"
38
+
39
+ option :ssh_user,
40
+ :short => "-x USERNAME",
41
+ :long => "--ssh-user USERNAME",
42
+ :description => "The ssh username; default is 'root'",
43
+ :default => "root"
44
+
45
+ option :ssh_password,
46
+ :short => "-P PASSWORD",
47
+ :long => "--ssh-password PASSWORD",
48
+ :description => "The ssh password"
49
+
50
+ option :identity_file,
51
+ :short => "-i IDENTITY_FILE",
52
+ :long => "--identity-file IDENTITY_FILE",
53
+ :description => "The SSH identity file used for authentication"
54
+
55
+ option :prerelease,
56
+ :long => "--prerelease",
57
+ :description => "Install the pre-release chef gems"
58
+
59
+ option :bootstrap_version,
60
+ :long => "--bootstrap-version VERSION",
61
+ :description => "The version of Chef to install",
62
+ :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
63
+
64
+ option :distro,
65
+ :short => "-d DISTRO",
66
+ :long => "--distro DISTRO",
67
+ :description => "Bootstrap a distro using a template; default is 'ubuntu10.04-gems'",
68
+ :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
69
+ :default => "ubuntu10.04-gems"
70
+
71
+ option :template_file,
72
+ :long => "--template-file TEMPLATE",
73
+ :description => "Full path to location of template to use",
74
+ :proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
75
+ :default => false
76
+
77
+ option :run_list,
78
+ :short => "-r RUN_LIST",
79
+ :long => "--run-list RUN_LIST",
80
+ :description => "Comma separated list of roles/recipes to apply",
81
+ :proc => lambda { |o| o.split(/[\s,]+/) },
82
+ :default => []
83
+
84
+ def bootstrap_for_node(device)
85
+ bootstrap = Chef::Knife::Bootstrap.new
86
+
87
+ bootstrap.name_args = [device['ipassignments']['ipassignment'].select { |i| i['type'] == 'frontend' }.first['content']]
88
+ bootstrap.config[:run_list] = config[:run_list]
89
+ bootstrap.config[:ssh_user] = config[:ssh_user] || "root"
90
+ bootstrap.config[:ssh_password] = device['accessmethods']['accessmethod'].select { |a| a['type'] == 'admin' }.first['password']
91
+ bootstrap.config[:identity_file] = config[:identity_file]
92
+ bootstrap.config[:chef_node_name] = config[:chef_node_name] || "d#{device['id']}"
93
+ bootstrap.config[:prerelease] = config[:prerelease]
94
+ bootstrap.config[:bootstrap_version] = config[:bootstrap_version]
95
+ bootstrap.config[:distro] = config[:distro]
96
+ bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
97
+ bootstrap.config[:template_file] = config[:template_file]
98
+ bootstrap.config[:environment] = config[:environment]
99
+ bootstrap
100
+ end
101
+
102
+ def tcp_test_ssh(hostname)
103
+ begin
104
+ tcp_socket = TCPSocket.new(hostname, 22)
105
+ readable = IO.select([tcp_socket], nil, nil, 5)
106
+ if readable
107
+ Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
108
+ yield
109
+ true
110
+ else
111
+ false
112
+ end
113
+ rescue Errno::ETIMEDOUT
114
+ false
115
+ rescue Errno::EPERM
116
+ false
117
+ rescue Errno::ECONNREFUSED
118
+ sleep 2
119
+ false
120
+ rescue Errno::EHOSTUNREACH
121
+ sleep 2
122
+ false
123
+ ensure
124
+ tcp_socket && tcp_socket.close
125
+ end
126
+ end
127
+
128
+ def run
129
+ $stdout.sync = true
130
+
131
+ unless @name_args.empty?
132
+ create = hapi.voxel_voxservers_reimage(
133
+ :device_id => @name_args.first,
134
+ :image_id => config[:image_id],
135
+ :hostname => config[:hostname],
136
+ :swap_space => config[:swap_size]
137
+ )
138
+
139
+ if create['stat'] == "fail"
140
+ ui.error(create['err']['msg'])
141
+ else
142
+ sleep 2
143
+
144
+ device = hapi.voxel_devices_list( :device_id => create['device']['id'], :verbosity => 'extended' )
145
+
146
+ if device['stat'] == "fail"
147
+ ui.error(device['err']['msg'])
148
+ else
149
+ device = device['devices']['device']
150
+
151
+ puts "#{ui.color("Device ID", :cyan)}: #{device['id']}"
152
+ puts "#{ui.color("Name", :cyan)}: #{device['label']}"
153
+ puts "#{ui.color("Image Id", :cyan)}: #{config[:image_id]}"
154
+ puts "#{ui.color("Facility", :cyan)}: #{device['location']['facility']['code']}"
155
+ puts "#{ui.color("Public IP Address", :cyan)}: #{device['ipassignments']['ipassignment'].select { |i| i['type'] == 'frontend' }.first['content']}"
156
+ puts "#{ui.color("Private IP Address", :cyan)}: #{device['ipassignments']['ipassignment'].select { |i| i['type'] == 'backend' }.first['content']}"
157
+ puts "#{ui.color("Root Password", :cyan)}: #{device['accessmethods']['accessmethod'].select { |a| a['type'] == 'admin' }.first['password']}"
158
+
159
+ status = hapi.voxel_voxservers_status( :device_id => device['id'], :verbosity => 'extended' )
160
+
161
+ while %w{ QUEUED IN_PROGRESS }.include?( status['devices']['device']['status'] ) do
162
+ print "."
163
+ status = hapi.voxel_voxservers_status( :device_id => device['id'], :verbosity => 'extended' )
164
+ sleep 10
165
+ end
166
+
167
+ print "\n#{ui.color("Waiting for sshd", :magenta)}"
168
+
169
+ print(".") until tcp_test_ssh(device['ipassignments']['ipassignment'].select { |i| i['type'] == 'frontend' }.first['content']) { sleep @initial_sleep_delay ||= 10; puts("done") }
170
+
171
+ bootstrap_for_node(device).run
172
+
173
+ puts "#{ui.color("Environment", :cyan)}: #{config[:environment] || '_default'}"
174
+ puts "#{ui.color("Run List", :cyan)}: #{config[:run_list].join(', ')}"
175
+ end
176
+ end
177
+ else
178
+ ui.error( "knife voxel voxservers reimage DEVICE_ID (options)" )
179
+ end
180
+ end
181
+
182
+ end
183
+ end
184
+ end
@@ -1,5 +1,5 @@
1
1
  module Knife
2
2
  module Voxel
3
- VERSION = "0.0.5"
3
+ VERSION = "0.0.6"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-voxel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
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: 2011-10-13 00:00:00.000000000Z
12
+ date: 2011-10-15 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: voxel-hapi
16
- requirement: &14538140 !ruby/object:Gem::Requirement
16
+ requirement: &10910840 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 1.1.10
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *14538140
24
+ version_requirements: *10910840
25
25
  description: Voxel hAPI Support for Chef's knife command
26
26
  email:
27
27
  - jwb@voxel.net
@@ -42,6 +42,7 @@ files:
42
42
  - lib/chef/knife/voxel_voxservers_create.rb
43
43
  - lib/chef/knife/voxel_voxservers_delete.rb
44
44
  - lib/chef/knife/voxel_voxservers_inventory_list.rb
45
+ - lib/chef/knife/voxel_voxservers_reimage.rb
45
46
  - lib/knife-voxel/version.rb
46
47
  homepage: http://api.voxel.net/
47
48
  licenses: []