vmonkey 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +120 -0
- data/Rakefile +5 -0
- data/lib/vmonkey.rb +29 -0
- data/lib/vmonkey/version.rb +3 -0
- data/lib/vmonkey/vim/Datacenter.rb +34 -0
- data/lib/vmonkey/vim/Folder.rb +9 -0
- data/lib/vmonkey/vim/VirtualApp.rb +16 -0
- data/lib/vmonkey/vim/VirtualMachine.rb +178 -0
- data/lib/vmonkey/vim/vim.rb +63 -0
- data/spec/datacenter_spec.rb +31 -0
- data/spec/folder_spec.rb +13 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/vapp_spec.rb +14 -0
- data/spec/vim_spec.rb +77 -0
- data/spec/virtualmachine_spec.rb +211 -0
- data/spec/vmonkey_spec.rb +12 -0
- data/vmonkey.gemspec +27 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c80f0a833b6907731b9809f68d81af87f3886cd0
|
4
|
+
data.tar.gz: 40ca2aa1adb647c8fc244834e46a6411b26775ec
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0c785b37bee04305d7151a99d707364895ef5021ebfd405830d8c9d7eab47e54aa96997502274887e91842399b35a48d8ba2b2ceb3e988df790c4f77554d630f
|
7
|
+
data.tar.gz: f48409e63777562785d8c9c14c8f4b756bf5fb0d8fef9e478d5b181a1255c233910851b5e7dec29b620dc94b42d28944fe68a50c0e16f9edb9a46799a35b98cd
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
.vmonkey
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 TODO: Write your name
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# VMonkey
|
2
|
+
|
3
|
+
VMonkey is a cheeky little feller who wants so very badly to make interacintg with vSphere more enjoyable. Let VMonkey fetch your VMs, clone your templates, set your properties, and more. VMonkey tinkers around in the uglier parts of the vSphere API so you don't have to. Enjoy!
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'vmonkey'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install vmonkey
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### $HOME/.vmonkey (optional)
|
22
|
+
|
23
|
+
```yml
|
24
|
+
host: vsphere.host.name
|
25
|
+
user: vsphere_user
|
26
|
+
password: monkey!
|
27
|
+
insecure: false #or true
|
28
|
+
ssl: true #or false
|
29
|
+
datacenter: your_dc_name
|
30
|
+
cluster: your_cluster_or_compute_resource_name
|
31
|
+
```
|
32
|
+
|
33
|
+
### initial connection
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# use connect opts from $HOME/.vmonkey
|
37
|
+
monkey = VMonkey.connect
|
38
|
+
```
|
39
|
+
|
40
|
+
or
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# use your own connect opts
|
44
|
+
monkey = VMonkey.connect opts_hash
|
45
|
+
```
|
46
|
+
|
47
|
+
### what is VMonkey
|
48
|
+
|
49
|
+
VMonkey.connect simply returns an instance of RbVmomi::VIM with added utility methods. The utility methods operate within the datacenter and cluster specified by the connection options.
|
50
|
+
|
51
|
+
|
52
|
+
### VMonkey finds stuff
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
monkey.folder '/path/to/my/folder' # returns a Folder or nil
|
56
|
+
monkey.folder! '/path/to/my/folder' # returns a Folder or raises an error
|
57
|
+
|
58
|
+
monkey.vm '/path/to/my/vm' # returns a VirtualMachine or nil
|
59
|
+
monkey.vm! '/path/to/my/vm' # returns a VirtualMachine or raises an error
|
60
|
+
|
61
|
+
monkey.vapp '/path/to/my/vapp' # returns a VirtualApp or nil
|
62
|
+
monkey.vapp! '/path/to/my/vapp' # returns a VirtualApp or raises an error
|
63
|
+
```
|
64
|
+
|
65
|
+
### VMonkey puts his glitter on VirtualMachine instances
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
vm.annotation
|
69
|
+
vm.annotation = 'VMonkey is hot'
|
70
|
+
|
71
|
+
vm.move_to '/path/to/some_folder/clone_name' # moves the VM or raises if the destination exists
|
72
|
+
vm.move_to! '/path/to/some_folder/clone_name' # moves the VM, overwrting the detinsation VM if necessary
|
73
|
+
|
74
|
+
vm.clone_to '/path/to/some_folder/clone_name' # clones the VM to a Folder
|
75
|
+
vm.clone_to '/path/to/some_vapp/clone_name' # clones the VM to a VirtualApp
|
76
|
+
|
77
|
+
vm.property :foo # returns the value of a vApp property, or nil
|
78
|
+
vm.property! :foo # returns the value of a vApp property, or raises an error
|
79
|
+
vm.property :foo, 'bar' # set the value of a vApp property
|
80
|
+
|
81
|
+
vm.port_ready? 22 # true if the VM is listening a TCP port
|
82
|
+
vm.wait_for_port 22 # blocks until the port_ready? is true
|
83
|
+
|
84
|
+
vm.start # power on if needed
|
85
|
+
vm.stop # guest shutdown and power off
|
86
|
+
vm.destroy # deletes the VM from the inventory, no need to power off first
|
87
|
+
```
|
88
|
+
|
89
|
+
### VMonkey gives some love to other types, too
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
datacenter.find_pool # returns the default datacenter ResourcePool
|
93
|
+
datacenter.find_pool '/path/to/cluster' # returns the cluster's default ResourcePool
|
94
|
+
datacenter.find_pool '/path/to/vapp' # returns the vApp, since it's already a ResourcePool
|
95
|
+
|
96
|
+
vapp.find_vm 'vm_name' # returns a VM of the given name, or nil
|
97
|
+
```
|
98
|
+
|
99
|
+
### VMonkey earns his keep
|
100
|
+
|
101
|
+
Before:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
config = [annotation: 'This makes VMonkey sad.']
|
105
|
+
spec = RbVmomi::VIM.VirtualMachineConfigSpec(config)
|
106
|
+
vm.ReconfigVM_Task(spec: spec).wait_for_completion
|
107
|
+
```
|
108
|
+
|
109
|
+
After:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
vm.annotation = 'VMonkey is so easy!'
|
113
|
+
```
|
114
|
+
|
115
|
+
## Contributing
|
116
|
+
|
117
|
+
1. Fork it ( https://github.com/[my-github-username]/vmonkey )
|
118
|
+
2. Setup your test environment (`bundle exec rake spec` and follow the test setup instructions)
|
119
|
+
3. Hack
|
120
|
+
4. Pull request ( be sure to include updated specs )
|
data/Rakefile
ADDED
data/lib/vmonkey.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rbvmomi'
|
2
|
+
require_relative 'vmonkey/version'
|
3
|
+
require_relative 'vmonkey/vim/vim'
|
4
|
+
|
5
|
+
monkey_vim = File.join(File.dirname(__FILE__), 'vmonkey', 'vim')
|
6
|
+
RbVmomi::VIM.add_extension_dir monkey_vim
|
7
|
+
|
8
|
+
module VMonkey
|
9
|
+
def self.connect(opts = nil)
|
10
|
+
RbVmomi::VIM.monkey_connect(opts)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class String
|
15
|
+
def parent
|
16
|
+
p = self.split('/')[0...-1].join('/')
|
17
|
+
p == '' ? '/' : p
|
18
|
+
end
|
19
|
+
|
20
|
+
def basename
|
21
|
+
p = self.split('/').last
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class RbVmomi::BasicTypes::ManagedObject
|
26
|
+
def monkey
|
27
|
+
_connection
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class RbVmomi::VIM::Datacenter
|
2
|
+
|
3
|
+
## modified from knife-vsphere / base_vsphere_command.rb
|
4
|
+
def find_pool(pool_path = '/')
|
5
|
+
parent = self.hostFolder
|
6
|
+
|
7
|
+
pool_path.split('/').each do |path_element|
|
8
|
+
next if path_element == ''
|
9
|
+
|
10
|
+
case parent
|
11
|
+
when RbVmomi::VIM::Folder
|
12
|
+
chilln = parent.childEntity
|
13
|
+
when RbVmomi::VIM::ClusterComputeResource, RbVmomi::VIM::ComputeResource
|
14
|
+
chilln = parent.resourcePool.resourcePool
|
15
|
+
when RbVmomi::VIM::ResourcePool
|
16
|
+
chilln = parent.resourcePool
|
17
|
+
else
|
18
|
+
parent = nil
|
19
|
+
break
|
20
|
+
end
|
21
|
+
|
22
|
+
parent = chilln.find { |f| f.name == path_element }
|
23
|
+
end
|
24
|
+
|
25
|
+
unless parent.is_a?(RbVmomi::VIM::ResourcePool)
|
26
|
+
if parent.respond_to?(:resourcePool)
|
27
|
+
parent = parent.resourcePool
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
parent
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
class RbVmomi::VIM::VirtualMachine
|
2
|
+
|
3
|
+
def destroy
|
4
|
+
self.PowerOffVM_Task.wait_for_completion unless runtime.powerState == 'poweredOff'
|
5
|
+
self.Destroy_Task.wait_for_completion
|
6
|
+
end
|
7
|
+
|
8
|
+
def clone_to(path, opts = {})
|
9
|
+
dest = monkey.get(path.parent)
|
10
|
+
unless dest.is_a? RbVmomi::VIM::Folder or dest.is_a? RbVmomi::VIM::VirtualApp
|
11
|
+
raise "Cannot clone_to [#{dest.pretty_path}] - destination must specify a Folder or VirtualApp"
|
12
|
+
end
|
13
|
+
|
14
|
+
params = _clone_params(path.basename, dest, opts)
|
15
|
+
|
16
|
+
self.CloneVM_Task(params).wait_for_completion
|
17
|
+
end
|
18
|
+
|
19
|
+
def annotation
|
20
|
+
config.annotation
|
21
|
+
end
|
22
|
+
|
23
|
+
def annotation=(value)
|
24
|
+
ReconfigVM_Task(spec: RbVmomi::VIM.VirtualMachineConfigSpec(annotation: value)).wait_for_completion
|
25
|
+
end
|
26
|
+
|
27
|
+
def property(*args)
|
28
|
+
case args.size
|
29
|
+
when 1
|
30
|
+
read_property(*args)
|
31
|
+
when 2
|
32
|
+
set_property(*args)
|
33
|
+
else
|
34
|
+
raise ArgumentError.new("wrong number of arguments (#{args.size} for 1 or 2)")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def property!(name)
|
39
|
+
read_property(name) || raise("vApp Property not found. [#{name}]")
|
40
|
+
end
|
41
|
+
|
42
|
+
def move_to(path)
|
43
|
+
monkey.vm(path) && raise("VirtualMachine already exists. [#{path}]")
|
44
|
+
rename = name != path.basename
|
45
|
+
|
46
|
+
to_folder = monkey.folder! path.parent
|
47
|
+
reparent = parent != to_folder
|
48
|
+
|
49
|
+
if reparent
|
50
|
+
Rename_Task(newName: "#{path.basename}-tmp").wait_for_completion if rename
|
51
|
+
to_folder.MoveIntoFolder_Task(list: [self]).wait_for_completion
|
52
|
+
Rename_Task(newName: path.basename).wait_for_completion if rename
|
53
|
+
else
|
54
|
+
Rename_Task(newName: path.basename).wait_for_completion
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
unless self.method_defined? :guest_ip
|
59
|
+
## backported from rbvmomi 1.8 for rbvmomi 1.5 support
|
60
|
+
def guest_ip
|
61
|
+
g = self.guest
|
62
|
+
if g.ipAddress && (g.toolsStatus == "toolsOk" || g.toolsStatus == "toolsOld")
|
63
|
+
g.ipAddress
|
64
|
+
else
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def move_to!(path)
|
71
|
+
dest_vm = monkey.vm(path)
|
72
|
+
dest_vm.destroy if dest_vm
|
73
|
+
|
74
|
+
move_to(path)
|
75
|
+
end
|
76
|
+
|
77
|
+
def port_ready?(port)
|
78
|
+
ip = guest_ip or return false
|
79
|
+
tcp_socket = TCPSocket.new(ip, port)
|
80
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
81
|
+
if readable
|
82
|
+
true
|
83
|
+
else
|
84
|
+
false
|
85
|
+
end
|
86
|
+
rescue Errno::ETIMEDOUT, Errno::EPERM, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH
|
87
|
+
false
|
88
|
+
ensure
|
89
|
+
tcp_socket && tcp_socket.close
|
90
|
+
end
|
91
|
+
|
92
|
+
def wait_for_port(port)
|
93
|
+
sleep 2 until port_ready?(port)
|
94
|
+
end
|
95
|
+
|
96
|
+
def stop
|
97
|
+
return if runtime.powerState == 'poweredOff'
|
98
|
+
ShutdownGuest
|
99
|
+
sleep 2 until runtime.powerState == 'poweredOff'
|
100
|
+
rescue
|
101
|
+
PowerOffVM_Task().wait_for_completion unless runtime.powerState == 'poweredOff'
|
102
|
+
end
|
103
|
+
|
104
|
+
def start
|
105
|
+
PowerOnVM_Task().wait_for_completion unless runtime.powerState == 'poweredOn'
|
106
|
+
end
|
107
|
+
|
108
|
+
def find_property(name)
|
109
|
+
config.vAppConfig.property.find { |p| p.props[:id] == name.to_s }
|
110
|
+
end
|
111
|
+
|
112
|
+
def read_property(name)
|
113
|
+
p = find_property(name)
|
114
|
+
p.nil? ? nil : p[:value]
|
115
|
+
end
|
116
|
+
|
117
|
+
def set_property(name, value)
|
118
|
+
if config.vAppConfig && config.vAppConfig.property
|
119
|
+
existing_property = find_property(name)
|
120
|
+
end
|
121
|
+
|
122
|
+
if existing_property
|
123
|
+
operation = 'edit'
|
124
|
+
property_key = existing_property.props[:key]
|
125
|
+
else
|
126
|
+
operation = 'add'
|
127
|
+
property_key = name.object_id
|
128
|
+
end
|
129
|
+
|
130
|
+
vm_config_spec = RbVmomi::VIM.VirtualMachineConfigSpec(
|
131
|
+
vAppConfig: RbVmomi::VIM.VmConfigSpec(
|
132
|
+
property: [
|
133
|
+
RbVmomi::VIM.VAppPropertySpec(
|
134
|
+
operation: operation,
|
135
|
+
info: {
|
136
|
+
key: property_key,
|
137
|
+
id: name.to_s,
|
138
|
+
type: 'string',
|
139
|
+
userConfigurable: true,
|
140
|
+
value: value
|
141
|
+
})]))
|
142
|
+
|
143
|
+
if config.vAppConfig.nil? || config.vAppConfig.ovfEnvironmentTransport.empty?
|
144
|
+
vm_config_spec[:vAppConfig][:ovfEnvironmentTransport] = ['com.vmware.guestInfo']
|
145
|
+
end
|
146
|
+
|
147
|
+
ReconfigVM_Task( spec: vm_config_spec ).wait_for_completion
|
148
|
+
end
|
149
|
+
|
150
|
+
def _clone_params(vm_name, dest, opts)
|
151
|
+
{
|
152
|
+
name: vm_name,
|
153
|
+
folder: dest.vm_folder,
|
154
|
+
spec: _clone_spec(dest, opts)
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
def _clone_spec(dest, opts)
|
159
|
+
opts[:config] ||= {}
|
160
|
+
|
161
|
+
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
162
|
+
location: RbVmomi::VIM.VirtualMachineRelocateSpec(pool: dest.vm_pool),
|
163
|
+
powerOn: false,
|
164
|
+
template: false
|
165
|
+
)
|
166
|
+
|
167
|
+
clone_spec.config = RbVmomi::VIM.VirtualMachineConfigSpec(deviceChange: Array.new)
|
168
|
+
|
169
|
+
clone_spec.customization = monkey.customization_spec(opts[:customization_spec])
|
170
|
+
clone_spec.config.annotation = opts[:config][:annotation]
|
171
|
+
clone_spec.config.numCPUs = opts[:config][:num_cpus]
|
172
|
+
clone_spec.config.memoryMB = opts[:config][:memory_mb]
|
173
|
+
|
174
|
+
clone_spec
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module RbVmomi
|
4
|
+
class VIM
|
5
|
+
|
6
|
+
attr_accessor :dc
|
7
|
+
attr_accessor :cluster
|
8
|
+
attr_accessor :opts
|
9
|
+
|
10
|
+
def self.monkey_connect(opts = nil)
|
11
|
+
opts ||= self.read_yml_opts
|
12
|
+
vim = self.connect(opts)
|
13
|
+
vim.opts = opts
|
14
|
+
vim.dc = vim.serviceInstance.find_datacenter(vim.opts[:datacenter]) or raise "Datacenter not found [#{vim.opts[:datacenter]}]"
|
15
|
+
vim.cluster = vim.dc.find_compute_resource(vim.opts[:cluster]) or raise "Cluster not found [#{vim.opts[:cluster]}]"
|
16
|
+
|
17
|
+
vim
|
18
|
+
end
|
19
|
+
|
20
|
+
def folder(path)
|
21
|
+
dc.vmFolder.traverse path, RbVmomi::VIM::Folder
|
22
|
+
end
|
23
|
+
|
24
|
+
def folder!(path)
|
25
|
+
folder(path) || raise("Folder not found. [#{path}]")
|
26
|
+
end
|
27
|
+
|
28
|
+
def vm(path)
|
29
|
+
dc.vmFolder.traverse path, RbVmomi::VIM::VirtualMachine
|
30
|
+
end
|
31
|
+
|
32
|
+
def vm!(path)
|
33
|
+
vm(path) || raise("VirtualMachine not found. [#{path}]")
|
34
|
+
end
|
35
|
+
|
36
|
+
def vapp(path)
|
37
|
+
dc.vmFolder.traverse path, RbVmomi::VIM::VirtualApp
|
38
|
+
end
|
39
|
+
|
40
|
+
def vapp!(path)
|
41
|
+
vapp(path) || raise("VirtualApp not found. [#{path}]")
|
42
|
+
end
|
43
|
+
|
44
|
+
def get(path)
|
45
|
+
dc.vmFolder.traverse path
|
46
|
+
end
|
47
|
+
|
48
|
+
def customization_spec(spec_name)
|
49
|
+
return nil if spec_name.nil?
|
50
|
+
serviceContent.customizationSpecManager.GetCustomizationSpec(name: spec_name).spec
|
51
|
+
rescue
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def self.read_yml_opts
|
58
|
+
yml_path = File.expand_path( ENV['VMONKEY_YML'] || File.join(ENV['HOME'], '.vmonkey') )
|
59
|
+
YAML::load_file(yml_path).inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe RbVmomi::VIM::Datacenter do
|
4
|
+
before :all do
|
5
|
+
@monkey = VMonkey.connect
|
6
|
+
@cluster_path = "/#{@monkey.opts[:cluster]}"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#find_pool' do
|
10
|
+
context 'with no params' do
|
11
|
+
subject { @pool ||= VMonkey.connect.dc.find_pool }
|
12
|
+
|
13
|
+
it { should_not be_nil }
|
14
|
+
its(:name) { should == 'host' }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with cluster path' do
|
18
|
+
subject { @pool ||= VMonkey.connect.dc.find_pool @cluster_path }
|
19
|
+
|
20
|
+
it { should_not be_nil }
|
21
|
+
its(:name) { should == 'Resources' }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with vApp path' do
|
25
|
+
subject { @pool ||= VMonkey.connect.dc.find_pool VM_SPEC_OPTS[:vapp_pool_path] }
|
26
|
+
|
27
|
+
it { should_not be_nil }
|
28
|
+
its(:name) { should == VM_SPEC_OPTS[:vapp_pool_path].split('/').last }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/spec/folder_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe RbVmomi::VIM::Folder do
|
4
|
+
before :all do
|
5
|
+
@monkey ||= VMonkey.connect
|
6
|
+
@folder ||= @monkey.folder VM_SPEC_OPTS[:working_folder]
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#vm_pool' do
|
10
|
+
subject { @folder.vm_pool }
|
11
|
+
it { should_not be_nil }
|
12
|
+
end
|
13
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../lib/vmonkey'
|
2
|
+
|
3
|
+
instructions = "
|
4
|
+
For the integration tests to run, you need:
|
5
|
+
- On the machine running the specs:
|
6
|
+
+ #{ENV['VMONKEY_YML']} (see below)
|
7
|
+
|
8
|
+
- On your vSphere system
|
9
|
+
+ A VM or Template from which VMs will be cloned (:template_path)
|
10
|
+
(Clones of this VM must listen on TCP port 22 on bootup)
|
11
|
+
+ A working Folder into which VMs will be cloned (:working_folder)
|
12
|
+
+ A working Folder into which VM will be moved (:working_folder2)
|
13
|
+
+ An empty vApp into which cloned VMs will be placed (:vapp_path)
|
14
|
+
+ A Customization Spec which will be applied to cloned VMs (:customization_spec)
|
15
|
+
|
16
|
+
Place the following in #{ENV['VMONKEY_YML']}
|
17
|
+
host: host_name_or_ip_address
|
18
|
+
user: user_name
|
19
|
+
password: password
|
20
|
+
insecure: true
|
21
|
+
ssl: true
|
22
|
+
datacenter: datacenter_name
|
23
|
+
cluster: cluster_name
|
24
|
+
spec:
|
25
|
+
:template_path: /path/to/a/vm_or_template
|
26
|
+
:working_folder: /path/to/a/folder
|
27
|
+
:working_folder2: /path/to/another/folder
|
28
|
+
:vapp_pool_path: /cluster_name/monkey_vapp
|
29
|
+
:vapp_path: /path/to/a/vapp
|
30
|
+
:customization_spec: name-of-a-cust-spec
|
31
|
+
"
|
32
|
+
|
33
|
+
raise instructions unless File.exists? ENV['VMONKEY_YML']
|
34
|
+
|
35
|
+
monkey = VMonkey.connect
|
36
|
+
VM_SPEC_OPTS = monkey.opts[:spec]
|
37
|
+
raise instructions unless monkey.folder VM_SPEC_OPTS[:working_folder]
|
38
|
+
raise instructions unless monkey.folder VM_SPEC_OPTS[:working_folder2]
|
39
|
+
raise instructions unless monkey.vm VM_SPEC_OPTS[:template_path]
|
40
|
+
raise instructions unless monkey.vapp VM_SPEC_OPTS[:vapp_path]
|
41
|
+
raise instructions unless monkey.dc.find_pool VM_SPEC_OPTS[:vapp_pool_path]
|
42
|
+
raise instructions unless monkey.customization_spec VM_SPEC_OPTS[:customization_spec]
|
43
|
+
|
44
|
+
RSpec.configure do |config|
|
45
|
+
config.color_enabled = true
|
46
|
+
config.tty = true
|
47
|
+
config.formatter = :documentation
|
48
|
+
end
|
data/spec/vapp_spec.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe RbVmomi::VIM::Folder do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@monkey ||= VMonkey.connect
|
7
|
+
@vapp ||= @monkey.vapp VM_SPEC_OPTS[:vapp_path]
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#vm_pool' do
|
11
|
+
subject { @vapp.vm_pool }
|
12
|
+
it { should_not be_nil }
|
13
|
+
end
|
14
|
+
end
|
data/spec/vim_spec.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe RbVmomi::VIM do
|
4
|
+
before :all do
|
5
|
+
@monkey ||= VMonkey.connect
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '#folder' do
|
9
|
+
subject { @folder ||= @monkey.folder VM_SPEC_OPTS[:working_folder] }
|
10
|
+
|
11
|
+
it { should_not be_nil }
|
12
|
+
its(:name) { should == VM_SPEC_OPTS[:working_folder].split('/').last }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#folder!' do
|
16
|
+
it 'should raise a RuntimeError given a path to a non-existent folder' do
|
17
|
+
expect { @monkey.folder! '/xyzzy' }.to raise_error RuntimeError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#vm' do
|
22
|
+
subject { @vm ||= @monkey.vm VM_SPEC_OPTS[:template_path] }
|
23
|
+
|
24
|
+
it { should_not be_nil }
|
25
|
+
its(:name) { should == VM_SPEC_OPTS[:template_path].split('/').last }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#vm!' do
|
29
|
+
it 'should raise a RuntimeError given a path to a non-existent vm' do
|
30
|
+
expect { @monkey.vm! '/xyzzy' }.to raise_error RuntimeError
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#vapp' do
|
35
|
+
subject { @vapp ||= @monkey.vapp VM_SPEC_OPTS[:vapp_path] }
|
36
|
+
|
37
|
+
it { should_not be_nil }
|
38
|
+
its(:name) { should == VM_SPEC_OPTS[:vapp_path].split('/').last }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#vapp!' do
|
42
|
+
it 'should raise a RuntimeError given a path to a non-existent vapp' do
|
43
|
+
expect { @monkey.vapp! '/xyzzy' }.to raise_error RuntimeError
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#get' do
|
48
|
+
context 'given a path to a real object' do
|
49
|
+
subject { @get ||= @monkey.get VM_SPEC_OPTS[:working_folder] }
|
50
|
+
|
51
|
+
it { should_not be_nil }
|
52
|
+
its(:name) { should == VM_SPEC_OPTS[:working_folder].split('/').last }
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'given a path to a non-existent object' do
|
56
|
+
subject { @get_nil ||= @monkey.get '/xyzzy' }
|
57
|
+
|
58
|
+
it { should be_nil }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#customization_spec' do
|
63
|
+
context 'given an existing customization spec' do
|
64
|
+
subject { @cspec ||= @monkey.customization_spec VM_SPEC_OPTS[:customization_spec] }
|
65
|
+
|
66
|
+
it { should_not be_nil }
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'given a non-existing customization spec' do
|
70
|
+
subject { @cspec ||= @monkey.customization_spec 'xyzzy' }
|
71
|
+
|
72
|
+
it { should be_nil }
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe RbVmomi::VIM::VirtualMachine do
|
4
|
+
before :all do
|
5
|
+
@monkey ||= VMonkey.connect
|
6
|
+
@template = @monkey.vm VM_SPEC_OPTS[:template_path]
|
7
|
+
@vm_path = "#{VM_SPEC_OPTS[:working_folder]}/vmonkey_spec"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#_clone_params' do
|
11
|
+
context 'with Folder destination' do
|
12
|
+
subject { @params ||= @template._clone_params(@vm_path.basename, @monkey.get(@vm_path.parent), {}) }
|
13
|
+
|
14
|
+
it { expect(subject[:name]).to eq @vm_path.basename }
|
15
|
+
it { expect(subject[:folder].name).to eq @vm_path.parent.basename }
|
16
|
+
it { expect(subject[:spec].powerOn).to eq false }
|
17
|
+
it { expect(subject[:spec].template).to eq false }
|
18
|
+
it { expect(subject[:spec].location.pool.name).to eq 'Resources' }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with vApp destination' do
|
22
|
+
subject { @params ||= @template._clone_params(@vm_path.basename, @monkey.vapp(VM_SPEC_OPTS[:vapp_path]), {}) }
|
23
|
+
|
24
|
+
it { expect(subject[:name]).to eq @vm_path.basename }
|
25
|
+
it { expect(subject[:folder].name).to eq VM_SPEC_OPTS[:vapp_path].parent.basename }
|
26
|
+
it { expect(subject[:spec].powerOn).to eq false }
|
27
|
+
it { expect(subject[:spec].template).to eq false }
|
28
|
+
it { expect(subject[:spec].location.pool.name).to eq VM_SPEC_OPTS[:vapp_path].basename }
|
29
|
+
|
30
|
+
it { expect(subject[:spec].customization).to be_nil }
|
31
|
+
it { expect(subject[:spec].config.annotation).to be_nil }
|
32
|
+
it { expect(subject[:spec].config.numCPUs).to be_nil }
|
33
|
+
it { expect(subject[:spec].config.memoryMB).to be_nil }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with config' do
|
37
|
+
subject do
|
38
|
+
@params ||=
|
39
|
+
@template._clone_params(
|
40
|
+
@vm_path.basename,
|
41
|
+
@monkey.get(@vm_path.parent),
|
42
|
+
customization_spec: VM_SPEC_OPTS[:customization_spec],
|
43
|
+
config: {
|
44
|
+
annotation: 'an annotation',
|
45
|
+
num_cpus: 3,
|
46
|
+
memory_mb: 1024
|
47
|
+
})
|
48
|
+
end
|
49
|
+
|
50
|
+
it { expect(subject[:spec].customization).to_not be_nil }
|
51
|
+
it { expect(subject[:spec].config.annotation).to eq 'an annotation' }
|
52
|
+
it { expect(subject[:spec].config.numCPUs).to eq 3 }
|
53
|
+
it { expect(subject[:spec].config.memoryMB).to eq 1024 }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'with a cloned VM' do
|
58
|
+
before(:all) { @spec_vm = @template.clone_to @vm_path }
|
59
|
+
after(:all) { @spec_vm.destroy }
|
60
|
+
|
61
|
+
describe '#clone' do
|
62
|
+
context 'to a Folder' do
|
63
|
+
subject { @monkey.vm @vm_path }
|
64
|
+
it { should_not be_nil }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#annotation=' do
|
69
|
+
it 'sets the annotation' do
|
70
|
+
@spec_vm.annotation = 'xyzzy'
|
71
|
+
expect(@spec_vm.annotation).to eq 'xyzzy'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#property' do
|
76
|
+
before(:all) do
|
77
|
+
@spec_vm.property :prop, 'xyzzy'
|
78
|
+
@spec_vm.property :prop2, 'abc123'
|
79
|
+
@spec_vm.property :prop2, 'abc456'
|
80
|
+
end
|
81
|
+
|
82
|
+
it { expect(@spec_vm.property :prop).to eq 'xyzzy' }
|
83
|
+
it { expect(@spec_vm.property :prop2).to eq 'abc456' }
|
84
|
+
it { expect(@spec_vm.property :xyzzy).to be_nil }
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#property!' do
|
88
|
+
it 'should raise a RuntimeError given a path to a non-existent property' do
|
89
|
+
expect { @spec_vm.property! :xyzzy }.to raise_error RuntimeError
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#move_to' do
|
94
|
+
it 'should raise a RuntimeError when given a path of an existing VM' do
|
95
|
+
expect { @spec_vm.move_to @vm_path }.to raise_error RuntimeError
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should move a vm to a new name in the same folder' do
|
99
|
+
parent = @spec_vm.parent
|
100
|
+
|
101
|
+
@spec_vm.move_to "#{@vm_path}-moved"
|
102
|
+
expect(@spec_vm.name).to eq "#{@vm_path.basename}-moved"
|
103
|
+
expect(@spec_vm.parent).to eq parent
|
104
|
+
|
105
|
+
@spec_vm.move_to @vm_path
|
106
|
+
expect(@spec_vm.name).to eq @vm_path.basename
|
107
|
+
expect(@spec_vm.parent).to eq parent
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should move a vm to the same name in a new folder' do
|
111
|
+
from_folder = @spec_vm.parent
|
112
|
+
from_name = @spec_vm.name
|
113
|
+
to_path = "#{VM_SPEC_OPTS[:working_folder2]}/#{@vm_path.basename}"
|
114
|
+
to_folder = @monkey.folder VM_SPEC_OPTS[:working_folder2]
|
115
|
+
|
116
|
+
@spec_vm.move_to to_path
|
117
|
+
expect(@spec_vm.name).to eq from_name
|
118
|
+
expect(@spec_vm.parent).to eq to_folder
|
119
|
+
|
120
|
+
@spec_vm.move_to @vm_path
|
121
|
+
expect(@spec_vm.name).to eq from_name
|
122
|
+
expect(@spec_vm.parent).to eq from_folder
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should move a vm to a new name in a new folder' do
|
126
|
+
from_folder = @spec_vm.parent
|
127
|
+
from_name = @spec_vm.name
|
128
|
+
to_name = "#{@vm_path.basename}-different"
|
129
|
+
to_path = "#{VM_SPEC_OPTS[:working_folder2]}/#{to_name}"
|
130
|
+
to_folder = @monkey.folder VM_SPEC_OPTS[:working_folder2]
|
131
|
+
|
132
|
+
@spec_vm.move_to to_path
|
133
|
+
expect(@spec_vm.name).to eq to_name
|
134
|
+
expect(@spec_vm.parent).to eq to_folder
|
135
|
+
|
136
|
+
@spec_vm.move_to @vm_path
|
137
|
+
expect(@spec_vm.name).to eq from_name
|
138
|
+
expect(@spec_vm.parent).to eq from_folder
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '#move_to!' do
|
143
|
+
before(:all) do
|
144
|
+
@other_path = "#{@vm_path}-other"
|
145
|
+
@other_vm = @spec_vm.clone_to @other_path
|
146
|
+
end
|
147
|
+
|
148
|
+
after(:all) do
|
149
|
+
other_vm = @monkey.vm @other_path
|
150
|
+
other_vm.destroy if other_vm
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should overwrite a VM when given a path of an existing VM' do
|
154
|
+
@spec_vm.move_to! @other_path
|
155
|
+
expect(@monkey.vm @other_path).to_not be_nil
|
156
|
+
|
157
|
+
@spec_vm.move_to @vm_path
|
158
|
+
expect(@monkey.vm @other_path).to be_nil
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#stop' do
|
163
|
+
it 'should return successfully when the VM is already powered off' do
|
164
|
+
expect { @spec_vm.stop }.to_not raise_error
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#port_ready?' do
|
169
|
+
it 'should be false when the VM is powered off' do
|
170
|
+
expect( @spec_vm.port_ready? 22 ).to be_false
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'that has had #start called' do
|
175
|
+
before(:all) { @spec_vm.start }
|
176
|
+
|
177
|
+
describe '#port_ready?' do
|
178
|
+
it 'should be false immediately following start' do
|
179
|
+
expect(@spec_vm.port_ready? 22).to be_false
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'should be true after wait_for_port' do
|
183
|
+
@spec_vm.wait_for_port 22
|
184
|
+
expect(@spec_vm.port_ready? 22).to be_true
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
after(:all) { @spec_vm.stop }
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '#clone' do
|
194
|
+
context 'to a vApp' do
|
195
|
+
before :all do
|
196
|
+
@vm_name_in_vapp = "#{@vm_path.basename}-vapp"
|
197
|
+
@template.clone_to "#{VM_SPEC_OPTS[:vapp_path]}/#{@vm_name_in_vapp}"
|
198
|
+
@spec_vapp = @monkey.vapp VM_SPEC_OPTS[:vapp_path]
|
199
|
+
end
|
200
|
+
|
201
|
+
subject { @spec_vapp.find_vm @vm_name_in_vapp }
|
202
|
+
|
203
|
+
it { should_not be_nil }
|
204
|
+
|
205
|
+
after :all do
|
206
|
+
(@spec_vapp.find_vm @vm_name_in_vapp).destroy
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
data/vmonkey.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'vmonkey/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'vmonkey'
|
8
|
+
spec.version = Vmonkey::VERSION
|
9
|
+
spec.authors = ['Brian Dupras', 'Dave Smith']
|
10
|
+
spec.email = ['brian@duprasville.com', 'dsmith@rallydev.com']
|
11
|
+
spec.summary = %q{ simple to use vsphere methods }
|
12
|
+
spec.description = %q{ simple to use vsphere methods }
|
13
|
+
spec.homepage = 'https://github.com/something/vmonkey'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'nokogiri', '= 1.5.5' #until vmware/rbvmomi issue #32 is fixed
|
22
|
+
spec.add_dependency 'rbvmomi', '~> 1.5'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'rspec'
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vmonkey
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Dupras
|
8
|
+
- Dave Smith
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-06-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 1.5.5
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.5.5
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rbvmomi
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.5'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.5'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: bundler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1.6'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.6'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rake
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
description: ' simple to use vsphere methods '
|
85
|
+
email:
|
86
|
+
- brian@duprasville.com
|
87
|
+
- dsmith@rallydev.com
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- .gitignore
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- lib/vmonkey.rb
|
98
|
+
- lib/vmonkey/version.rb
|
99
|
+
- lib/vmonkey/vim/Datacenter.rb
|
100
|
+
- lib/vmonkey/vim/Folder.rb
|
101
|
+
- lib/vmonkey/vim/VirtualApp.rb
|
102
|
+
- lib/vmonkey/vim/VirtualMachine.rb
|
103
|
+
- lib/vmonkey/vim/vim.rb
|
104
|
+
- spec/datacenter_spec.rb
|
105
|
+
- spec/folder_spec.rb
|
106
|
+
- spec/spec_helper.rb
|
107
|
+
- spec/vapp_spec.rb
|
108
|
+
- spec/vim_spec.rb
|
109
|
+
- spec/virtualmachine_spec.rb
|
110
|
+
- spec/vmonkey_spec.rb
|
111
|
+
- vmonkey.gemspec
|
112
|
+
homepage: https://github.com/something/vmonkey
|
113
|
+
licenses:
|
114
|
+
- MIT
|
115
|
+
metadata: {}
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 2.1.11
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: simple to use vsphere methods
|
136
|
+
test_files:
|
137
|
+
- spec/datacenter_spec.rb
|
138
|
+
- spec/folder_spec.rb
|
139
|
+
- spec/spec_helper.rb
|
140
|
+
- spec/vapp_spec.rb
|
141
|
+
- spec/vim_spec.rb
|
142
|
+
- spec/virtualmachine_spec.rb
|
143
|
+
- spec/vmonkey_spec.rb
|