knife-proxmox 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +155 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +14 -0
- data/LICENSE +201 -0
- data/README +127 -0
- data/TODO +7 -0
- data/knife-proxmox-0.0.11.gem +0 -0
- data/knife-proxmox.gemspec +22 -0
- data/lib/chef/knife/connection.rb +34 -0
- data/lib/chef/knife/proxmox_base.rb +251 -0
- data/lib/chef/knife/proxmox_server_create.rb +234 -0
- data/lib/chef/knife/proxmox_server_destroy.rb +63 -0
- data/lib/chef/knife/proxmox_server_list.rb +43 -0
- data/lib/chef/knife/proxmox_server_start.rb +27 -0
- data/lib/chef/knife/proxmox_server_stop.rb +28 -0
- data/lib/chef/knife/proxmox_template_available.rb +31 -0
- data/lib/chef/knife/proxmox_template_list.rb +36 -0
- data/lib/chef/knife/server.rb +0 -0
- data/lib/chef/knife/template.rb +0 -0
- data/lib/knife-proxmox/version.rb +6 -0
- metadata +124 -0
data/TODO
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Description Resource Path Location Type
|
2
|
+
FIXME: storage = local debería ser tambien un parametro configurable proxmox_template_list.rb /knife-proxmox/lib/chef line 53 Studio Task
|
3
|
+
TODO: Create a good gem using this tutorial http://guides.rubygems.org/make-your-own-gem/#writing-tests
|
4
|
+
TODO: All inputs MUST be checked and errors MUST be catched.
|
5
|
+
TODO: Testing of everything
|
6
|
+
TODO: change ticket.gsub for CGI.escape(str) proxmox_server_create.rb /knife-proxmox/lib/chef line 110 Studio Task
|
7
|
+
TODO: parameters for openvz should be in other object proxmox_server_create.rb /knife-proxmox/lib/chef line 55 Studio Task
|
Binary file
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "knife-proxmox/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "knife-proxmox"
|
7
|
+
s.version = Knife::Proxmox::VERSION
|
8
|
+
s.has_rdoc = false
|
9
|
+
s.authors = ["Jorge Moratilla", "Sergio Galvan"]
|
10
|
+
s.email = ["jorge@moratilla.com","sergalma@gmail.com"]
|
11
|
+
s.homepage = "http://wiki.opscode.com/display/chef"
|
12
|
+
s.summary = "ProxmoxVE Support for Chef's Knife Command"
|
13
|
+
s.description = s.summary
|
14
|
+
s.extra_rdoc_files = ["README", "LICENSE","TODO","CHANGELOG" ]
|
15
|
+
|
16
|
+
s.files = Dir['lib/**/*.rb'] + Dir['./*']
|
17
|
+
s.add_dependency "chef", ">= 0.10.10"
|
18
|
+
s.add_dependency "rest-client", ">=1.6.7"
|
19
|
+
s.add_dependency "json", ">=1.5.4"
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# This class should be a singleton with all the logic to use proxmox
|
2
|
+
|
3
|
+
class Connection
|
4
|
+
|
5
|
+
@site = nil
|
6
|
+
@auth_params = nil
|
7
|
+
@servers = {}
|
8
|
+
@templates = {}
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
@site = RestClient::Resource.new(Chef::Config[:knife][:pve_cluster_url])
|
12
|
+
@auth_params ||= begin
|
13
|
+
ticket = nil
|
14
|
+
csrf_prevention_token = nil
|
15
|
+
@site['access/ticket'].post :username=>Chef::Config[:knife][:pve_user_name],
|
16
|
+
:realm=>Chef::Config[:knife][:pve_user_realm],
|
17
|
+
:password=>Chef::Config[:knife][:pve_user_password] do |response, request, result, &block|
|
18
|
+
if response.code == 200 then
|
19
|
+
data = JSON.parse(response.body)
|
20
|
+
ticket = data['data']['ticket']
|
21
|
+
csrf_prevention_token = data['data']['CSRFPreventionToken']
|
22
|
+
if !ticket.nil? then
|
23
|
+
token = 'PVEAuthCookie=' + ticket.gsub!(/:/,'%3A').gsub!(/=/,'%3D')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
{:CSRFPreventionToken => csrf_prevention_token, :cookie => token}
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
#TODO: Testing of everything
|
3
|
+
#TODO: All inputs MUST be checked and errors MUST be catched.
|
4
|
+
class Chef
|
5
|
+
class Knife
|
6
|
+
module ProxmoxBase
|
7
|
+
|
8
|
+
def self.included(includer)
|
9
|
+
includer.class_eval do
|
10
|
+
|
11
|
+
deps do
|
12
|
+
require 'rubygems'
|
13
|
+
require 'rest_client'
|
14
|
+
require 'json'
|
15
|
+
require 'chef/json_compat'
|
16
|
+
require 'cgi'
|
17
|
+
require 'chef/log'
|
18
|
+
require 'set'
|
19
|
+
require 'net/ssh/multi'
|
20
|
+
require 'chef/api_client'
|
21
|
+
require 'chef/node'
|
22
|
+
end
|
23
|
+
|
24
|
+
# options
|
25
|
+
option :pve_cluster_url,
|
26
|
+
:short => "-U URL",
|
27
|
+
:long => "--pve_cluster_url URL",
|
28
|
+
:description => "Your URL to access Proxmox VE server/cluster",
|
29
|
+
:proc => Proc.new {|url| Chef::Config[:knife][:pve_cluster_url] = url }
|
30
|
+
|
31
|
+
option :pve_user_name,
|
32
|
+
:short => "-u username",
|
33
|
+
:long => "--username username",
|
34
|
+
:description => "Your username in Proxmox VE",
|
35
|
+
:proc => Proc.new {|username| Chef::Config[:knife][:pve_user_name] = username }
|
36
|
+
|
37
|
+
option :pve_user_password,
|
38
|
+
:short => "-p password",
|
39
|
+
:long => "--password password",
|
40
|
+
:description => "Your password in Proxmox VE",
|
41
|
+
:proc => Proc.new {|password| Chef::Config[:knife][:pve_user_password] = password }
|
42
|
+
|
43
|
+
option :pve_user_realm,
|
44
|
+
:short => "-r realm",
|
45
|
+
:long => "--realm realm",
|
46
|
+
:description => "Your realm of Authentication in Proxmox VE",
|
47
|
+
:proc => Proc.new {|realm| Chef::Config[:knife][:pve_user_realm] = realm }
|
48
|
+
|
49
|
+
option :pve_node_name,
|
50
|
+
:short => "-n node",
|
51
|
+
:long => "--node nodename",
|
52
|
+
:description => "Proxmox VE server name where you will actuate",
|
53
|
+
:proc => Proc.new {|node| Chef::Config[:knife][:pve_node_name] = node }
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Checks that the parameter provided is defined in knife.rb
|
59
|
+
def check_global_parameter(value)
|
60
|
+
if (Chef::Config[:knife][value].nil? or Chef::Config[:knife][value].empty?) then
|
61
|
+
ui.error "knife[:#{value.to_s}] is empty, define a value for it and try again"
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
Chef::Log.debug("knife[:#{value}] = " + Chef::Config[:knife][value])
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_config_parameter(value)
|
68
|
+
if (config[value].nil? or config[value].empty?) then
|
69
|
+
ui.error "--#{value} is empty, define a value for it and try again"
|
70
|
+
exit 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Establishes the connection with proxmox server
|
75
|
+
def connection
|
76
|
+
# First, let's check we have all info needed to connect to pve
|
77
|
+
[:pve_cluster_url, :pve_node_name, :pve_user_name, :pve_user_password, :pve_user_realm].each do |value|
|
78
|
+
check_global_parameter(value)
|
79
|
+
end
|
80
|
+
|
81
|
+
@connection ||= RestClient::Resource.new(Chef::Config[:knife][:pve_cluster_url])
|
82
|
+
@auth_params ||= begin
|
83
|
+
token = nil
|
84
|
+
csrf_prevention_token = nil
|
85
|
+
@connection['access/ticket'].post :username=>Chef::Config[:knife][:pve_user_name],
|
86
|
+
:realm=>Chef::Config[:knife][:pve_user_realm],
|
87
|
+
:password=>Chef::Config[:knife][:pve_user_password] do |response, request, result, &block|
|
88
|
+
if response.code == 200 then
|
89
|
+
data = JSON.parse(response.body)
|
90
|
+
ticket = data['data']['ticket']
|
91
|
+
csrf_prevention_token = data['data']['CSRFPreventionToken']
|
92
|
+
if !ticket.nil? then
|
93
|
+
token = 'PVEAuthCookie=' + ticket.gsub!(/:/,'%3A').gsub!(/=/,'%3D')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
{:CSRFPreventionToken => csrf_prevention_token, :cookie => token}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# new_vmid: calculates a new vmid from the highest existing vmid
|
102
|
+
def new_vmid
|
103
|
+
vmid ||= @connection['cluster/resources?type=vm'].get @auth_params do |response, request, result, &block|
|
104
|
+
data = JSON.parse(response.body)['data']
|
105
|
+
vmids = Set[]
|
106
|
+
data.each {|entry|
|
107
|
+
vmids.add entry['vmid']
|
108
|
+
}
|
109
|
+
(vmids.max + 1).to_s
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# locate_config_value: find a value in arguments or default chef config properties
|
114
|
+
def locate_config_value(key)
|
115
|
+
key = key.to_sym
|
116
|
+
Chef::Config[:knife][key] || config[key]
|
117
|
+
end
|
118
|
+
|
119
|
+
# template_number_to_name: converts the id from the template list to the real name in the storage
|
120
|
+
# of the node
|
121
|
+
def template_number_to_name(number,storage)
|
122
|
+
template_list = []
|
123
|
+
#TODO: esta parte hay que sacarla a un modulo comun de acceso a templates
|
124
|
+
@connection["nodes/#{Chef::Config[:knife][:pve_node_name]}/storage/#{storage}/content"].get @auth_params do |response, request, result, &block|
|
125
|
+
JSON.parse(response.body)['data'].each { |entry|
|
126
|
+
if entry['content'] == 'vztmpl' then
|
127
|
+
template_list << entry['volid']
|
128
|
+
end
|
129
|
+
}
|
130
|
+
end
|
131
|
+
return CGI.escape(template_list[number.to_i])
|
132
|
+
end
|
133
|
+
|
134
|
+
# server_name_to_vmid: Use the name of the server to get the vmid
|
135
|
+
def server_name_to_vmid(name)
|
136
|
+
@connection['cluster/resources?type=vm'].get @auth_params do |response, request, result, &block|
|
137
|
+
data = JSON.parse(response.body)['data']
|
138
|
+
data.each {|entry|
|
139
|
+
return entry['vmid'] if entry['name'].to_s.match(name)
|
140
|
+
}
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# vmid_to_node: Specify the vmid and get the node in which is
|
145
|
+
def vmid_to_node(vmid)
|
146
|
+
@connection['cluster/resources?type=vm'].get @auth_params do |response, request, result, &block|
|
147
|
+
data = JSON.parse(response.body)['data']
|
148
|
+
data.each {|entry|
|
149
|
+
return entry['node'] if entry['vmid'].to_s.match(vmid.to_s)
|
150
|
+
}
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def action_response(action,response)
|
155
|
+
result = nil
|
156
|
+
taskid = nil
|
157
|
+
begin
|
158
|
+
if (response.code == 200) then
|
159
|
+
result = "OK"
|
160
|
+
else
|
161
|
+
result = "NOK: error code = " + response.code.to_s
|
162
|
+
end
|
163
|
+
taskid = JSON.parse(response.body)['data']
|
164
|
+
waitfor(taskid)
|
165
|
+
Chef::Log.debug("Action: #{action}, Result: #{result}\n")
|
166
|
+
rescue Exception => msg
|
167
|
+
result = "An exception ocurred. Use -VV to show it"
|
168
|
+
Chef::Log.debug("Action: #{action}, Result: #{msg}\n")
|
169
|
+
end
|
170
|
+
ui.msg(result)
|
171
|
+
end
|
172
|
+
|
173
|
+
# waitfor end of the task, need the taskid and the timeout
|
174
|
+
def waitfor(taskid, timeout=60)
|
175
|
+
taskstatus = nil
|
176
|
+
while taskstatus.nil? and timeout>= 0 do
|
177
|
+
print "."
|
178
|
+
@connection["nodes/#{Chef::Config[:knife][:pve_node_name]}/tasks/#{taskid}/status"].get @auth_params do |response, request, result, &block|
|
179
|
+
taskstatus = (JSON.parse(response.body)['data']['status'] == "stopped")?true:nil
|
180
|
+
end
|
181
|
+
timeout-=1
|
182
|
+
sleep(1)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def server_start(vmid)
|
187
|
+
node = vmid_to_node(vmid)
|
188
|
+
ui.msg("Starting VM #{vmid} on node #{node}....")
|
189
|
+
@connection["nodes/#{node}/openvz/#{vmid}/status/start"].post "", @auth_params do |response, request, result, &block|
|
190
|
+
# take the response and extract the taskid
|
191
|
+
action_response("server start",response)
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
# server_stop: Stops the server
|
197
|
+
def server_stop(vmid)
|
198
|
+
node = vmid_to_node(vmid)
|
199
|
+
ui.msg("Stopping VM #{vmid} on node #{node}...")
|
200
|
+
@connection["nodes/#{node}/openvz/#{vmid}/status/stop"].post "", @auth_params do |response, request, result, &block|
|
201
|
+
# take the response and extract the taskid
|
202
|
+
action_response("server stop",response)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def server_create(vmid,vm_definition)
|
207
|
+
ui.msg("Creating VM #{vmid}...")
|
208
|
+
@connection["nodes/#{Chef::Config[:knife][:pve_node_name]}/openvz"].post "#{vm_definition}", @auth_params do |response, request, result, &block|
|
209
|
+
action_response("server create",response)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# server_get_address: Returns the IP Address of the machine to chef
|
214
|
+
# field is a string, and if it doesn't exist, it will return nil
|
215
|
+
def server_get_data(vmid,field)
|
216
|
+
node = vmid_to_node(vmid)
|
217
|
+
@connection["nodes/#{node}/openvz/#{vmid}/status/current"].get @auth_params do |response, request, result, &block|
|
218
|
+
#action_response("server get data",response)
|
219
|
+
data = JSON.parse(response.body)['data'][field]
|
220
|
+
end
|
221
|
+
end
|
222
|
+
# server_destroy: Destroys the server
|
223
|
+
def server_destroy(vmid)
|
224
|
+
node = vmid_to_node(vmid)
|
225
|
+
ui.msg("Destroying VM #{vmid} on node #{node}...")
|
226
|
+
@connection["nodes/#{node}/openvz/#{vmid}"].delete @auth_params do |response, request, result, &block|
|
227
|
+
action_response("server destroy",response)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# Extracted from Chef::Knife.delete_object, because it has a
|
232
|
+
# confirmation step built in... By specifying the '--purge'
|
233
|
+
# flag (and also explicitly confirming the server destruction!)
|
234
|
+
# the user is already making their intent known. It is not
|
235
|
+
# necessary to make them confirm two more times.
|
236
|
+
def destroy_item(klass, name, type_name)
|
237
|
+
begin
|
238
|
+
object = klass.load(name)
|
239
|
+
object.destroy
|
240
|
+
ui.warn("Deleted #{type_name} #{name}")
|
241
|
+
rescue Net::HTTPServerException
|
242
|
+
ui.warn("Could not find a #{type_name} named #{name} to delete!")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
|
248
|
+
|
249
|
+
end # module
|
250
|
+
end # class
|
251
|
+
end # class
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'chef/knife/proxmox_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class ProxmoxServerCreate < Knife
|
6
|
+
|
7
|
+
include Knife::ProxmoxBase
|
8
|
+
|
9
|
+
deps do
|
10
|
+
require 'readline'
|
11
|
+
require 'chef/json_compat'
|
12
|
+
require 'chef/knife/bootstrap'
|
13
|
+
Chef::Knife::Bootstrap.load_deps
|
14
|
+
end
|
15
|
+
|
16
|
+
banner "knife proxmox server create (options)"
|
17
|
+
|
18
|
+
# TODO: parameters for openvz should be in other object
|
19
|
+
option :vm_hostname,
|
20
|
+
:short => "-H hostname",
|
21
|
+
:long => "--hostname hostname",
|
22
|
+
:description => "VM instance hostname"
|
23
|
+
|
24
|
+
option :vm_cpus,
|
25
|
+
:short => "-C CPUs",
|
26
|
+
:long => "--cpus number",
|
27
|
+
:description => "Number of cpus of the VM instance"
|
28
|
+
|
29
|
+
option :vm_memory,
|
30
|
+
:short => "-M MB",
|
31
|
+
:long => "--mem MB",
|
32
|
+
:description => "Memory in MB"
|
33
|
+
|
34
|
+
option :vm_swap,
|
35
|
+
:short => "-SW",
|
36
|
+
:long => "--swap MB",
|
37
|
+
:description => "Memory in MB for swap"
|
38
|
+
|
39
|
+
option :vm_vmid,
|
40
|
+
:short => "-I id",
|
41
|
+
:long => "--vmid id",
|
42
|
+
:description => "Id for the VM"
|
43
|
+
|
44
|
+
option :vm_disk,
|
45
|
+
:short => "-D disk",
|
46
|
+
:long => "--disk GB",
|
47
|
+
:description => "Disk space in GB"
|
48
|
+
|
49
|
+
option :vm_storage,
|
50
|
+
:short => "-ST name",
|
51
|
+
:long => "--storage name",
|
52
|
+
:description => "Name of the storage where to reserve space"
|
53
|
+
|
54
|
+
option :vm_password,
|
55
|
+
:short => "-P password",
|
56
|
+
:long => "--vm_pass password",
|
57
|
+
:description => "root password for VM (openvz only)",
|
58
|
+
:default => "proxmox"
|
59
|
+
|
60
|
+
option :vm_netif,
|
61
|
+
:short => "-N netif",
|
62
|
+
:long => "--netif netif_specification",
|
63
|
+
:description => "description of the network interface (experimental)"
|
64
|
+
|
65
|
+
option :vm_template,
|
66
|
+
:short => "-T number",
|
67
|
+
:long => "--template number",
|
68
|
+
:description => "id of the template"
|
69
|
+
|
70
|
+
option :vm_ipaddress,
|
71
|
+
:short => "-ip ipaddress",
|
72
|
+
:long => "--ipaddress IP Address",
|
73
|
+
:description => "force guest to use venet interface with this ip address"
|
74
|
+
|
75
|
+
option :bootstrap,
|
76
|
+
:long => "--[no-]bootstrap",
|
77
|
+
:description => "Bootstrap the server, enable by default",
|
78
|
+
:boolean => true,
|
79
|
+
:default => true
|
80
|
+
|
81
|
+
option :bootstrap_version,
|
82
|
+
:long => "--bootstrap-version VERSION",
|
83
|
+
:description => "The version of Chef to install",
|
84
|
+
:proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
|
85
|
+
|
86
|
+
option :distro,
|
87
|
+
:short => "-d DISTRO",
|
88
|
+
:long => "--distro DISTRO",
|
89
|
+
:description => "Bootstrap a distro using a template; default is 'chef-full'",
|
90
|
+
:proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
|
91
|
+
:default => "chef-full"
|
92
|
+
|
93
|
+
option :template_file,
|
94
|
+
:long => "--template-file TEMPLATE",
|
95
|
+
:description => "Full path to location of template to use",
|
96
|
+
:proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
|
97
|
+
:default => false
|
98
|
+
|
99
|
+
option :run_list,
|
100
|
+
:short => "-r RUN_LIST",
|
101
|
+
:long => "--run-list RUN_LIST",
|
102
|
+
:description => "Comma separated list of roles/recipes to apply",
|
103
|
+
:proc => lambda { |o| o.split(/[\s,]+/) },
|
104
|
+
:default => []
|
105
|
+
|
106
|
+
option :first_boot_attributes,
|
107
|
+
:short => "-j JSON_ATTRIBS",
|
108
|
+
:long => "--json-attributes",
|
109
|
+
:description => "A JSON string to be added to the first run of chef-client",
|
110
|
+
:proc => lambda { |o| JSON.parse(o) },
|
111
|
+
:default => {}
|
112
|
+
|
113
|
+
option :identity_file,
|
114
|
+
:short => "-i IDENTITY_FILE",
|
115
|
+
:long => "--identity-file IDENTITY_FILE",
|
116
|
+
:description => "The SSH identity file used for authentication"
|
117
|
+
|
118
|
+
option :host_key_verify,
|
119
|
+
:long => "--[no-]host-key-verify",
|
120
|
+
:description => "Verify host key, enabled by default",
|
121
|
+
:boolean => true,
|
122
|
+
:default => true
|
123
|
+
|
124
|
+
option :environment,
|
125
|
+
:short=> "-e environment",
|
126
|
+
:long => "--environment environment",
|
127
|
+
:description => "Chef environment",
|
128
|
+
:proc => Proc.new {|env| Chef::Config[:knife][:environment] = env },
|
129
|
+
:default => '_default'
|
130
|
+
|
131
|
+
def run
|
132
|
+
# Needed
|
133
|
+
connection
|
134
|
+
|
135
|
+
vm_id = config[:vm_vmid] || new_vmid
|
136
|
+
vm_hostname = config[:vm_hostname] || 'proxmox'
|
137
|
+
vm_storage = config[:vm_storage] || 'local'
|
138
|
+
vm_password = config[:vm_password] || 'pve123'
|
139
|
+
vm_cpus = config[:vm_cpus] || 1
|
140
|
+
vm_memory = config[:vm_memory] || 512
|
141
|
+
vm_disk = config[:vm_disk] || 4
|
142
|
+
vm_swap = config[:vm_swap] || 512
|
143
|
+
vm_ipaddress= config[:vm_ipaddress]|| nil
|
144
|
+
vm_netif = config[:vm_netif] || 'ifname%3Deth0%2Cbridge%3Dvmbr0'
|
145
|
+
vm_template = template_number_to_name(config[:vm_template],vm_storage) || 'local%3Avztmpl%2Fubuntu-11.10-x86_64-jorge2-.tar.gz'
|
146
|
+
|
147
|
+
vm_definition = "vmid=#{vm_id}&hostname=#{vm_hostname}&storage=#{vm_storage}&password=#{vm_password}&ostemplate=#{vm_template}&memory=#{vm_memory}&swap=#{vm_swap}&disk=#{vm_disk}&cpus=#{vm_cpus}"
|
148
|
+
|
149
|
+
# Add ip_address parameter to vm_definition if it's provided by CLI
|
150
|
+
if (config[:vm_ipaddress]) then
|
151
|
+
vm_definition += "&ip_address=" + vm_ipaddress
|
152
|
+
elsif (config[:vm_netif] || vm_netif) then
|
153
|
+
vm_definition += "&netif=" + vm_netif
|
154
|
+
end
|
155
|
+
|
156
|
+
Chef::Log.debug(vm_definition)
|
157
|
+
|
158
|
+
server_create(vm_id,vm_definition)
|
159
|
+
ui.msg("Preparing the server to start")
|
160
|
+
sleep(5)
|
161
|
+
server_start(vm_id)
|
162
|
+
sleep(5)
|
163
|
+
|
164
|
+
# which IP address to bootstrap
|
165
|
+
bootstrap_ip_address = server_get_data(vm_id,'ip')
|
166
|
+
ui.msg("New Server #{vm_id} has IP Address: #{server_get_data(vm_id,'ip')}")
|
167
|
+
|
168
|
+
if bootstrap_ip_address.nil?
|
169
|
+
ui.error("No IP address available for bootstrapping.")
|
170
|
+
exit 1
|
171
|
+
end
|
172
|
+
|
173
|
+
print(".") until tcp_test_ssh(bootstrap_ip_address) {
|
174
|
+
sleep @initial_sleep_delay ||= 10
|
175
|
+
puts("done")
|
176
|
+
}
|
177
|
+
|
178
|
+
# bootstrapping the node
|
179
|
+
if config[:bootstrap]
|
180
|
+
bootstrap_for_node(bootstrap_ip_address).run
|
181
|
+
else
|
182
|
+
ui.msg("Skipping bootstrap of the server because --no-bootstrap used as argument.")
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
def tcp_test_ssh(hostname)
|
188
|
+
tcp_socket = TCPSocket.new(hostname, 22)
|
189
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
190
|
+
if readable
|
191
|
+
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
|
192
|
+
yield
|
193
|
+
true
|
194
|
+
else
|
195
|
+
false
|
196
|
+
end
|
197
|
+
rescue Errno::ETIMEDOUT
|
198
|
+
false
|
199
|
+
rescue Errno::EPERM
|
200
|
+
false
|
201
|
+
rescue Errno::ECONNREFUSED
|
202
|
+
sleep 2
|
203
|
+
false
|
204
|
+
rescue Errno::EHOSTUNREACH
|
205
|
+
sleep 2
|
206
|
+
false
|
207
|
+
ensure
|
208
|
+
tcp_socket && tcp_socket.close
|
209
|
+
end
|
210
|
+
|
211
|
+
def bootstrap_for_node(bootstrap_ip_address)
|
212
|
+
bootstrap = Chef::Knife::Bootstrap.new
|
213
|
+
bootstrap.name_args = [bootstrap_ip_address]
|
214
|
+
bootstrap.config[:run_list] = config[:run_list]
|
215
|
+
bootstrap.config[:environment] = locate_config_value(:environment)
|
216
|
+
# bootstrap.config[:first_boot_attributes] = config[:first_boot_attributes]
|
217
|
+
bootstrap.config[:ssh_user] = "root"
|
218
|
+
bootstrap.config[:ssh_password] = config[:vm_password]
|
219
|
+
# bootstrap.config[:identity_file] = config[:identity_file]
|
220
|
+
# bootstrap.config[:host_key_verify] = config[:host_key_verify]
|
221
|
+
bootstrap.config[:chef_node_name] = config[:vm_hostname]
|
222
|
+
# bootstrap.config[:prerelease] = config[:prerelease]
|
223
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
224
|
+
bootstrap.config[:distro] = locate_config_value(:distro)
|
225
|
+
# bootstrap will run as root...sudo (by default) also messes up Ohai on CentOS boxes
|
226
|
+
# bootstrap.config[:use_sudo] = false
|
227
|
+
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
228
|
+
|
229
|
+
pp bootstrap.config
|
230
|
+
bootstrap
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|