esxmagicwand 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 sgirones
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,41 @@
1
+ = EsxMagicWand
2
+
3
+ EsxMagicWand deploy VMs on ESXi hypervisors and starts a PXE installation
4
+
5
+ == Installation
6
+
7
+ $ gem install esxmagicwand
8
+
9
+ == Example
10
+
11
+ * Create a VM conf as following. Replace example values. File centos6_1.conf:
12
+
13
+ [dhcp-server]
14
+ ip=DHCP_SERVER_IP
15
+ port=7911
16
+
17
+ [esx-server]
18
+ ip=ESX_SERVER_IP
19
+ user=root
20
+ password=ROOT_PASSWORD
21
+ datastore=datastore1
22
+
23
+ [vm]
24
+ name=CentOS6
25
+ size=20000
26
+ cpu=1
27
+ memory=3000
28
+ os_type=centos64Guest
29
+
30
+ lease_name=centos6_test1
31
+ ip=192.168.20.2
32
+ mask=255.255.255.0
33
+ pxe_path=centos6/pxelinux.0
34
+
35
+ * Deploy
36
+
37
+ $ deploy_vm centos6_1.conf
38
+
39
+ * Undeploy
40
+
41
+ $ undeploy_vm centos6_1.conf
data/bin/deploy_vm ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'esx'
5
+ require 'esxmagicwand'
6
+ require 'clamp'
7
+ require 'parseconfig'
8
+
9
+ class BaseCommand < Clamp::Command
10
+ parameter "CONFIG_PATH", "Config file path"
11
+
12
+ def execute
13
+ c = ParseConfig.new(config_path)
14
+
15
+ begin
16
+
17
+ #Prepare MagicWand
18
+ puts 'Prepare MagicWand'
19
+ dhcp_host = DHCP::Server.new(c.params['dhcp-server']['ip'], c.params['dhcp-server']['port'])
20
+ esx_host = ESX::Host.connect(c.params['esx-server']['ip'], c.params['esx-server']['user'], c.params['esx-server']['password'])
21
+ magic_wand = VMWizard::MagicWand.new(esx_host, dhcp_host)
22
+
23
+ #Prepare VM definition
24
+ puts 'Prepare VM definition'
25
+ vm = VMWizard::VirtualMachine.new(
26
+ :name => c.params['vm']['name'],
27
+ :disk_size => c.params['vm']['size'],
28
+ :cpu => c.params['vm']['cpu'],
29
+ :ram => c.params['vm']['memory'],
30
+ :disk_type => c.params['vm']['disk_type'],
31
+ :guest => c.params['vm']['os_type']
32
+ )
33
+ datastore = c.params['esx-server']['datastore']
34
+
35
+ #Deploy VM
36
+ puts 'Start deployment'
37
+ deployed_vm = magic_wand.deploy(vm, datastore)
38
+
39
+ puts 'Powering ON'
40
+ deployed_vm.power_on
41
+
42
+ mac = ''
43
+ #Recover mac address
44
+ Net::SSH.start(c.params['esx-server']['ip'], c.params['esx-server']['user'], :password => c.params['esx-server']['password']) do |ssh|
45
+ mac = ssh.exec!("grep \"ethernet0.generatedAddress \" \"/vmfs/volumes/#{datastore}/#{vm.name}/#{vm.name}.vmx\"|cut -f3 -d\" \"").gsub('"','')
46
+ end
47
+
48
+ #Prepare lease definition
49
+ lease = DHCP::Lease.new(
50
+ :name => c.params['vm']['lease_name'],
51
+ :ip => c.params['vm']['ip'],
52
+ :mask => c.params['vm']['mask'],
53
+ :mac => mac,
54
+ :pxe_path => c.params['vm']['pxe_path'],
55
+ :hostname => c.params['vm']['hostname']
56
+ )
57
+
58
+ puts "Adding DHCP lease"
59
+ dhcp_host.del_lease lease
60
+ dhcp_host.add_lease lease
61
+
62
+ rescue Exception => e
63
+ puts e.message
64
+ exit 1
65
+ end
66
+ end
67
+ end
68
+
69
+ BaseCommand.run
data/bin/undeploy_vm ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'esx'
5
+ require 'esxmagicwand'
6
+ require 'clamp'
7
+ require 'parseconfig'
8
+
9
+ class BaseCommand < Clamp::Command
10
+ parameter "CONFIG_PATH", "Config file path"
11
+
12
+ def execute
13
+ c = ParseConfig.new(config_path)
14
+
15
+ begin
16
+ #Prepare MagicWand
17
+ puts 'Prepare MagicWand'
18
+ dhcp_host = DHCP::Server.new(c.params['dhcp-server']['ip'], c.params['dhcp-server']['port'])
19
+ esx_host = ESX::Host.connect(c.params['esx-server']['ip'], c.params['esx-server']['user'], c.params['esx-server']['password'])
20
+ magic_wand = VMWizard::MagicWand.new(esx_host, dhcp_host)
21
+
22
+ puts 'Start undeploy'
23
+ magic_wand.undeploy(c.params['vm']['name'])
24
+
25
+ #Prepare lease definition
26
+ lease = DHCP::Lease.new(
27
+ :name => c.params['vm']['lease_name'],
28
+ :ip => c.params['vm']['ip'],
29
+ :mask => c.params['vm']['mask']
30
+ )
31
+
32
+ puts "Removing DHCP lease"
33
+ dhcp_host.del_lease lease
34
+
35
+
36
+ rescue Exception => e
37
+ puts e.message
38
+ exit 1
39
+ end
40
+ end
41
+ end
42
+
43
+ BaseCommand.run
data/lib/dhcp.rb ADDED
@@ -0,0 +1,80 @@
1
+ module DHCP
2
+
3
+ class Server
4
+ attr_reader :address, :port
5
+
6
+ def initialize(address, port)
7
+ @address = address
8
+ @port = port
9
+ end
10
+
11
+ def add_lease(lease)
12
+ File.open('/tmp/add_pxe_lease','w') do |file|
13
+ file.puts "server #{@address}"
14
+ file.puts "server #{@port}"
15
+ file.puts "connect"
16
+ file.puts "new host"
17
+ file.puts "set name = \"#{lease.name}\""
18
+ file.puts "set hardware-address = #{lease.mac}"
19
+ file.puts "set hardware-type = 1"
20
+ file.puts "set ip-address = #{lease.ip}"
21
+ file.puts "set statements = \"#{lease.statements_string}\""
22
+ file.puts "create"
23
+ end
24
+
25
+ #execute!
26
+ `cat /tmp/add_pxe_lease | omshell`
27
+ `rm /tmp/add_pxe_lease`
28
+ end
29
+
30
+ def del_lease(lease)
31
+ File.open('/tmp/del_pxe_lease','w') do |file|
32
+ file.puts "server #{address}"
33
+ file.puts "server #{port}"
34
+ file.puts "connect"
35
+ file.puts "new host"
36
+ file.puts "set name = \"#{lease.name}\""
37
+ file.puts "open"
38
+ file.puts "remove"
39
+ end
40
+
41
+ #execute!
42
+ `cat /tmp/del_pxe_lease | omshell`
43
+ `rm /tmp/del_pxe_lease`
44
+ end
45
+ end
46
+
47
+ class Lease
48
+ attr_reader :name, :ip, :mask , :mac, :pxe_path, :hostname
49
+
50
+ def initialize(definition)
51
+ @name = definition[:name]
52
+ @ip = definition[:ip]
53
+ @mask = definition[:mask]
54
+ @mac = definition[:mac]
55
+ @pxe_path = definition[:pxe_path] if definition.include? :pxe_path
56
+ @hostname = definition[:hostname] if definition.include? :hostname
57
+ end
58
+
59
+ def statements_string
60
+ out = "option subnet-mask = #{ip2hex(@mask)};"
61
+ if @pxe_path
62
+ out += " filename = \\\"#{@pxe_path}\\\";"
63
+ end
64
+ if @hostname
65
+ out += " host-name = \\\"#{@hostname}\\\";"
66
+ end
67
+ return out
68
+ end
69
+
70
+ def ip2hex ip
71
+ ip.split(".").map{|i| "%02x" % i }.join(":")
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+
78
+
79
+
80
+
@@ -0,0 +1,61 @@
1
+ require File.join(File.dirname(__FILE__), 'dhcp.rb')
2
+
3
+ module VMWizard
4
+
5
+ class VirtualMachine
6
+ attr_reader :name, :disk_size, :cpu, :ram, :disk_type, :guest, :mac
7
+
8
+ def initialize(specs)
9
+ @name = specs[:name]
10
+ @disk_size = specs[:disk_size]
11
+ @cpu = specs[:cpu]
12
+ @ram = specs[:ram]
13
+ @mac = specs[:mac]
14
+ @disk_type = specs[:disk_type]
15
+ @guest = specs[:guest]
16
+ end
17
+ end
18
+
19
+ class MagicWand
20
+ attr_reader :esx_host, :dhcp_host
21
+
22
+ def initialize(esx_host, dhcp_host)
23
+ @esx_host = esx_host
24
+ @dhcp_host = dhcp_host
25
+ end
26
+
27
+ def deploy(vm, datastore)
28
+ vm = @esx_host.create_vm(
29
+ :vm_name => vm.name,
30
+ :datastore => datastore,
31
+ :disk_type => :thin,
32
+ :disk_size => vm.disk_size,
33
+ :memory => vm.ram,
34
+ :guest_id => vm.guest
35
+ )
36
+
37
+ return vm
38
+ end
39
+
40
+ def undeploy(vm_name)
41
+ vm = nil
42
+ esx_host.virtual_machines.each do |x|
43
+ if x.name == vm_name
44
+ vm = x
45
+ break
46
+ end
47
+ end
48
+
49
+ if not vm
50
+ raise "VM with name #{vm_name} not found"
51
+ end
52
+
53
+ if vm.power_state == "poweredOn"
54
+ vm.power_off
55
+ end
56
+
57
+ vm.destroy
58
+
59
+ end
60
+ end
61
+ end
metadata ADDED
@@ -0,0 +1,217 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: esxmagicwand
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - sgirones
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-12-29 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ requirement: &id001 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ hash: 3
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ version_requirements: *id001
31
+ name: shoulda
32
+ prerelease: false
33
+ type: :development
34
+ - !ruby/object:Gem::Dependency
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ hash: 23
41
+ segments:
42
+ - 1
43
+ - 0
44
+ - 0
45
+ version: 1.0.0
46
+ version_requirements: *id002
47
+ name: bundler
48
+ prerelease: false
49
+ type: :development
50
+ - !ruby/object:Gem::Dependency
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ hash: 7
57
+ segments:
58
+ - 1
59
+ - 6
60
+ - 4
61
+ version: 1.6.4
62
+ version_requirements: *id003
63
+ name: jeweler
64
+ prerelease: false
65
+ type: :development
66
+ - !ruby/object:Gem::Dependency
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ version_requirements: *id004
77
+ name: rcov
78
+ prerelease: false
79
+ type: :development
80
+ - !ruby/object:Gem::Dependency
81
+ requirement: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ version_requirements: *id005
91
+ name: rdoc
92
+ prerelease: false
93
+ type: :development
94
+ - !ruby/object:Gem::Dependency
95
+ requirement: &id006 !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 19
101
+ segments:
102
+ - 0
103
+ - 2
104
+ - 2
105
+ version: 0.2.2
106
+ version_requirements: *id006
107
+ name: esx
108
+ prerelease: false
109
+ type: :development
110
+ - !ruby/object:Gem::Dependency
111
+ requirement: &id007 !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ hash: 3
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ version_requirements: *id007
121
+ name: clamp
122
+ prerelease: false
123
+ type: :development
124
+ - !ruby/object:Gem::Dependency
125
+ requirement: &id008 !ruby/object:Gem::Requirement
126
+ none: false
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ hash: 3
131
+ segments:
132
+ - 0
133
+ version: "0"
134
+ version_requirements: *id008
135
+ name: parseconfig
136
+ prerelease: false
137
+ type: :development
138
+ - !ruby/object:Gem::Dependency
139
+ requirement: &id009 !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ hash: 3
145
+ segments:
146
+ - 0
147
+ version: "0"
148
+ version_requirements: *id009
149
+ name: esx
150
+ prerelease: false
151
+ type: :runtime
152
+ - !ruby/object:Gem::Dependency
153
+ requirement: &id010 !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ hash: 3
159
+ segments:
160
+ - 0
161
+ version: "0"
162
+ version_requirements: *id010
163
+ name: parseconfig
164
+ prerelease: false
165
+ type: :runtime
166
+ description: VM deploy on ESX using PXE as install method. Add dynamic leases to DHCP server through OMAPI
167
+ email: salvador.girones@abiquo.com
168
+ executables:
169
+ - deploy_vm
170
+ - undeploy_vm
171
+ extensions: []
172
+
173
+ extra_rdoc_files:
174
+ - LICENSE.txt
175
+ - README.rdoc
176
+ files:
177
+ - lib/dhcp.rb
178
+ - lib/esxmagicwand.rb
179
+ - LICENSE.txt
180
+ - README.rdoc
181
+ - bin/deploy_vm
182
+ - bin/undeploy_vm
183
+ homepage: http://github.com/sgirones/esxmagicwand
184
+ licenses:
185
+ - MIT
186
+ post_install_message:
187
+ rdoc_options: []
188
+
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ none: false
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ hash: 3
197
+ segments:
198
+ - 0
199
+ version: "0"
200
+ required_rubygems_version: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ">="
204
+ - !ruby/object:Gem::Version
205
+ hash: 3
206
+ segments:
207
+ - 0
208
+ version: "0"
209
+ requirements: []
210
+
211
+ rubyforge_project:
212
+ rubygems_version: 1.8.11
213
+ signing_key:
214
+ specification_version: 3
215
+ summary: VM deploy on ESX using PXE
216
+ test_files: []
217
+