esxmagicwand 0.1.0

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.
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
+