vm_shepherd 0.0.1 → 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.
@@ -0,0 +1,16 @@
1
+ require 'vm_shepherd/vsphere_manager'
2
+
3
+ module VmShepherd
4
+ RSpec.describe VsphereManager do
5
+ let(:host) { 'FAKE_VSPHERE_HOST' }
6
+ let(:username) { 'FAKE_USERNAME' }
7
+ let(:password) { 'FAKE_PASSWORD' }
8
+ let(:datacenter_name) { 'FAKE_DATACENTER_NAME' }
9
+
10
+ subject(:vsphere_manager) { VsphereManager.new(host, username, password, datacenter_name) }
11
+
12
+ it 'loads' do
13
+ expect { vsphere_manager }.not_to raise_error
14
+ end
15
+ end
16
+ end
data/vm_shepherd.gemspec CHANGED
@@ -18,11 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ['lib']
19
19
 
20
20
  spec.add_dependency 'aws-sdk-v1'
21
+ spec.add_dependency 'fog'
21
22
 
22
23
  spec.add_dependency 'ruby_vcloud_sdk', '~> 0.7.0'
23
24
 
24
25
  spec.add_dependency 'rbvmomi'
25
- spec.add_dependency 'vsphere_clients'
26
26
 
27
27
  spec.add_development_dependency 'rake', '~> 10.0'
28
28
  spec.add_development_dependency 'rspec', '~> 3.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vm_shepherd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ops Manager Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-02 00:00:00.000000000 Z
11
+ date: 2015-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-v1
@@ -25,35 +25,35 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: ruby_vcloud_sdk
28
+ name: fog
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.7.0
33
+ version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.7.0
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rbvmomi
42
+ name: ruby_vcloud_sdk
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.7.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.7.0
55
55
  - !ruby/object:Gem::Dependency
56
- name: vsphere_clients
56
+ name: rbvmomi
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -133,31 +133,30 @@ files:
133
133
  - ".rspec"
134
134
  - ".ruby-version"
135
135
  - Gemfile
136
+ - LICENSE.txt
136
137
  - README.md
137
138
  - Rakefile
138
139
  - ci/run_specs.sh
139
- - lib/vm_shepherd/ami_manager.rb
140
- - lib/vm_shepherd/ova_manager/base.rb
141
- - lib/vm_shepherd/ova_manager/deployer.rb
142
- - lib/vm_shepherd/ova_manager/destroyer.rb
143
- - lib/vm_shepherd/ova_manager/open_monkey_patch.rb
140
+ - lib/vm_shepherd.rb
141
+ - lib/vm_shepherd/aws_manager.rb
142
+ - lib/vm_shepherd/openstack_manager.rb
144
143
  - lib/vm_shepherd/shepherd.rb
145
- - lib/vm_shepherd/vapp_manager/deployer.rb
146
- - lib/vm_shepherd/vapp_manager/destroyer.rb
144
+ - lib/vm_shepherd/vcloud_manager.rb
147
145
  - lib/vm_shepherd/version.rb
146
+ - lib/vm_shepherd/vsphere_manager.rb
148
147
  - spec/fixtures/ova_manager/foo.ova
149
148
  - spec/fixtures/shepherd/aws.yml
149
+ - spec/fixtures/shepherd/openstack.yml
150
150
  - spec/fixtures/shepherd/unknown.yml
151
151
  - spec/fixtures/shepherd/vcloud.yml
152
152
  - spec/fixtures/shepherd/vsphere.yml
153
153
  - spec/spec_helper.rb
154
- - spec/vm_shepherd/ami_manager_spec.rb
155
- - spec/vm_shepherd/ova_manager/base_spec.rb
156
- - spec/vm_shepherd/ova_manager/deployer_spec.rb
157
- - spec/vm_shepherd/ova_manager/destroyer_spec.rb
154
+ - spec/support/patched_fog.rb
155
+ - spec/vm_shepherd/aws_manager_spec.rb
156
+ - spec/vm_shepherd/openstack_manager_spec.rb
158
157
  - spec/vm_shepherd/shepherd_spec.rb
159
- - spec/vm_shepherd/vapp_manager/deployer_spec.rb
160
- - spec/vm_shepherd/vapp_manager/destroyer_spec.rb
158
+ - spec/vm_shepherd/vcloud_manager_spec.rb
159
+ - spec/vm_shepherd/vsphere_manager_spec.rb
161
160
  - vm_shepherd.gemspec
162
161
  homepage: ''
163
162
  licenses: []
@@ -185,14 +184,14 @@ summary: A tool for booting and tearing down Ops Manager VMs on various Infrastr
185
184
  test_files:
186
185
  - spec/fixtures/ova_manager/foo.ova
187
186
  - spec/fixtures/shepherd/aws.yml
187
+ - spec/fixtures/shepherd/openstack.yml
188
188
  - spec/fixtures/shepherd/unknown.yml
189
189
  - spec/fixtures/shepherd/vcloud.yml
190
190
  - spec/fixtures/shepherd/vsphere.yml
191
191
  - spec/spec_helper.rb
192
- - spec/vm_shepherd/ami_manager_spec.rb
193
- - spec/vm_shepherd/ova_manager/base_spec.rb
194
- - spec/vm_shepherd/ova_manager/deployer_spec.rb
195
- - spec/vm_shepherd/ova_manager/destroyer_spec.rb
192
+ - spec/support/patched_fog.rb
193
+ - spec/vm_shepherd/aws_manager_spec.rb
194
+ - spec/vm_shepherd/openstack_manager_spec.rb
196
195
  - spec/vm_shepherd/shepherd_spec.rb
197
- - spec/vm_shepherd/vapp_manager/deployer_spec.rb
198
- - spec/vm_shepherd/vapp_manager/destroyer_spec.rb
196
+ - spec/vm_shepherd/vcloud_manager_spec.rb
197
+ - spec/vm_shepherd/vsphere_manager_spec.rb
@@ -1,31 +0,0 @@
1
- require 'rbvmomi'
2
-
3
- module VmShepherd
4
- module OvaManager
5
- class Base
6
- attr_reader :vcenter
7
-
8
- def initialize(vcenter)
9
- @vcenter = vcenter
10
- end
11
-
12
- def find_datacenter(name)
13
- match = connection.searchIndex.FindByInventoryPath(inventoryPath: name)
14
- return unless match and match.is_a?(RbVmomi::VIM::Datacenter)
15
- match
16
- end
17
-
18
- private
19
-
20
- def connection
21
- @connection ||= RbVmomi::VIM.connect(
22
- host: @vcenter.fetch(:host),
23
- user: @vcenter.fetch(:user),
24
- password: @vcenter.fetch(:password),
25
- ssl: true,
26
- insecure: true,
27
- )
28
- end
29
- end
30
- end
31
- end
@@ -1,202 +0,0 @@
1
- require 'tmpdir'
2
- require 'fileutils'
3
- require 'rbvmomi'
4
- require 'rbvmomi/utils/deploy'
5
- require 'vsphere_clients'
6
- require 'vm_shepherd/ova_manager/base'
7
- require 'vm_shepherd/ova_manager/open_monkey_patch'
8
-
9
- module VmShepherd
10
- module OvaManager
11
- class Deployer < Base
12
- attr_reader :location
13
-
14
- def initialize(vcenter, location)
15
- super(vcenter)
16
- @location = location
17
- raise 'Target folder must be set' unless @location[:folder]
18
- end
19
-
20
- def deploy(name_prefix, ova_path, ova_config)
21
- ova_path = File.expand_path(ova_path.strip)
22
- check_vm_status(ova_config)
23
-
24
- tmp_dir = untar_vbox_ova(ova_path)
25
- ovf_path = obtain_ovf_path(tmp_dir)
26
-
27
- deployer = build_deployer(@location)
28
- template = deploy_ovf_template(name_prefix, deployer, ovf_path)
29
- vm = create_vm_from_template(deployer, template)
30
-
31
- reconfigure_vm(vm, ova_config)
32
- power_on_vm(vm)
33
- ensure
34
- FileUtils.remove_entry_secure(tmp_dir, force: true)
35
- end
36
-
37
- private
38
-
39
- def check_vm_status(ova_config)
40
- log('Checking for existing VM') do # Bad idea to redeploy VM over existing running VM
41
- ip = ova_config[:external_ip] || ova_config[:ip]
42
- port = ova_config[:external_port] || 443
43
- raise "VM exists at #{ip}" if system("nc -z -w 5 #{ip} #{port}")
44
- end
45
- end
46
-
47
- def untar_vbox_ova(ova_path)
48
- log("Untarring #{ova_path}") do
49
- Dir.mktmpdir.tap do |dir|
50
- system_or_exit("cd #{dir} && tar xfv '#{ova_path}'")
51
- end
52
- end
53
- end
54
-
55
- def obtain_ovf_path(dir)
56
- raise 'Failed to find ovf' unless (file_path = Dir["#{dir}/*.ovf"].first)
57
- "file://#{file_path}"
58
- end
59
-
60
- def deploy_ovf_template(name_prefix, deployer, ovf_path)
61
- log('Uploading template') do
62
- deployer.upload_ovf_as_template(
63
- ovf_path,
64
- Time.new.strftime("#{name_prefix}-%F-%H-%M"),
65
- run_without_interruptions: true,
66
- )
67
- end
68
- end
69
-
70
- def create_vm_from_template(deployer, template)
71
- log('Cloning template') do
72
- deployer.linked_clone(template, "#{template.name}-vm", {
73
- :numCPUs => 2,
74
- :memoryMB => 2048,
75
- })
76
- end
77
- end
78
-
79
- def reconfigure_vm(vm, ova_config)
80
- ip_configuration = {
81
- 'ip0' => ova_config[:ip],
82
- 'netmask0' => ova_config[:netmask],
83
- 'gateway' => ova_config[:gateway],
84
- 'DNS' => ova_config[:dns],
85
- 'ntp_servers' => ova_config[:ntp_servers],
86
- }
87
-
88
- log("Reconfiguring VM using #{ip_configuration.inspect}") do
89
- property_specs = []
90
-
91
- # Order of ip configuration keys must match
92
- # order of OVF template properties.
93
- ip_configuration.each_with_index do |(key, value), i|
94
- property_specs << RbVmomi::VIM::VAppPropertySpec.new.tap do |spec|
95
- spec.operation = 'edit'
96
- spec.info = RbVmomi::VIM::VAppPropertyInfo.new.tap do |p|
97
- p.key = i
98
- p.label = key
99
- p.value = value
100
- end
101
- end
102
- end
103
-
104
- property_specs << RbVmomi::VIM::VAppPropertySpec.new.tap do |spec|
105
- spec.operation = 'edit'
106
- spec.info = RbVmomi::VIM::VAppPropertyInfo.new.tap do |p|
107
- p.key = ip_configuration.length
108
- p.label = 'admin_password'
109
- p.value = ova_config[:vm_password]
110
- end
111
- end
112
-
113
- vm_config_spec = RbVmomi::VIM::VmConfigSpec.new
114
- vm_config_spec.ovfEnvironmentTransport = ['com.vmware.guestInfo']
115
- vm_config_spec.property = property_specs
116
-
117
- vmachine_spec = RbVmomi::VIM::VirtualMachineConfigSpec.new
118
- vmachine_spec.vAppConfig = vm_config_spec
119
- vm.ReconfigVM_Task(spec: vmachine_spec).wait_for_completion
120
- end
121
- end
122
-
123
- def power_on_vm(vm)
124
- log('Powering on VM') do
125
- vm.PowerOnVM_Task.wait_for_completion
126
- wait_for('VM IP') { vm.guest_ip }
127
- end
128
- end
129
-
130
- def build_deployer(location)
131
- unless (datacenter = find_datacenter(location[:datacenter]))
132
- raise "Failed to find datacenter '#{location[:datacenter]}'"
133
- end
134
-
135
- unless (cluster = datacenter.find_compute_resource(location[:cluster]))
136
- raise "Failed to find cluster '#{location[:cluster]}'"
137
- end
138
-
139
- unless (datastore = datacenter.find_datastore(location[:datastore]))
140
- raise "Failed to find datastore '#{location[:datastore]}'"
141
- end
142
-
143
- unless (network = datacenter.networkFolder.traverse(location[:network]))
144
- raise "Failed to find network '#{location[:network]}'"
145
- end
146
-
147
- resource_pool_name = location[:resource_pool] || location[:resource_pool_name]
148
- unless (resource_pool = find_resource_pool(cluster, resource_pool_name))
149
- raise "Failed to find resource pool '#{resource_pool_name}'"
150
- end
151
-
152
- target_folder = datacenter.vmFolder.traverse(location[:folder], RbVmomi::VIM::Folder, true)
153
-
154
- VsphereClients::CachedOvfDeployer.new(
155
- logged_connection,
156
- network,
157
- cluster,
158
- resource_pool,
159
- target_folder, # template
160
- target_folder, # vm
161
- datastore,
162
- )
163
- end
164
-
165
- def find_resource_pool(cluster, resource_pool_name)
166
- if resource_pool_name
167
- cluster.resourcePool.resourcePool.find { |rp| rp.name == resource_pool_name }
168
- else
169
- cluster.resourcePool
170
- end
171
- end
172
-
173
- def logged_connection
174
- log("connecting to #{@vcenter[:user]}@#{@vcenter[:host]}") { connection }
175
- end
176
-
177
- def log(title, &blk)
178
- puts "--- Running: #{title} @ #{DateTime.now}"
179
- blk.call
180
- end
181
-
182
- def system_or_exit(*args)
183
- puts "--- Running: #{args} @ #{DateTime.now}"
184
- system(*args) || fail('FAILED')
185
- end
186
-
187
- def wait_for(title, &blk)
188
- Timeout.timeout(7*60) do
189
- until (value = blk.call)
190
- puts '--- Waiting for 30 secs'
191
- sleep 30
192
- end
193
- puts "--- Value obtained for #{title} is #{value}"
194
- value
195
- end
196
- rescue Timeout::Error
197
- puts "--- Timed out waiting for #{title}"
198
- raise
199
- end
200
- end
201
- end
202
- end
@@ -1,29 +0,0 @@
1
- require 'rbvmomi'
2
- require 'logger'
3
- require 'vsphere_clients/vm_folder_client'
4
- require 'vm_shepherd/ova_manager/base'
5
-
6
- module VmShepherd
7
- module OvaManager
8
- class Destroyer < Base
9
- def initialize(datacenter_name, vcenter)
10
- @datacenter_name = datacenter_name
11
- @vcenter = vcenter
12
- end
13
-
14
- def clean_folder(folder_name)
15
- vm_folder_client.delete_folder(folder_name)
16
- vm_folder_client.create_folder(folder_name)
17
- end
18
-
19
- private
20
-
21
- def vm_folder_client
22
- @vm_folder_client ||= VsphereClients::VmFolderClient.new(
23
- find_datacenter(@datacenter_name),
24
- Logger.new(STDERR)
25
- )
26
- end
27
- end
28
- end
29
- end
@@ -1,14 +0,0 @@
1
- # open is used by RbvMomi when trying to upload OVA file.
2
- # It does not support local file upload without following patch.
3
- module Kernel
4
- private
5
- alias open_without_file open
6
- class << self
7
- alias open_without_file open
8
- end
9
-
10
- def open(name, *rest, &blk)
11
- name = name[7..-1] if name.start_with?('file://')
12
- open_without_file(name, *rest, &blk)
13
- end
14
- end
@@ -1,151 +0,0 @@
1
- require 'tmpdir'
2
- require 'fileutils'
3
- require 'ruby_vcloud_sdk'
4
-
5
- module VmShepherd
6
- module VappManager
7
- class Deployer
8
- def initialize(login_info, location, logger)
9
- @login_info = login_info
10
- @location = location
11
- @logger = logger
12
- raise 'VDC must be set' unless @location[:vdc]
13
- raise 'Catalog must be set' unless @location[:catalog]
14
- raise 'Network must be set' unless @location[:network]
15
- end
16
-
17
- def deploy(vapp_template_tar_path, vapp_config)
18
- tmpdir = Dir.mktmpdir
19
-
20
- check_vapp_status(vapp_config)
21
-
22
- untar_vapp_template_tar(File.expand_path(vapp_template_tar_path), tmpdir)
23
-
24
- vapp = deploy_vapp(tmpdir, vapp_config)
25
- reconfigure_vm(vapp, vapp_config)
26
- vapp.power_on
27
- ensure
28
- FileUtils.remove_entry_secure(tmpdir, force: true)
29
- end
30
-
31
- private
32
-
33
- def check_vapp_status(vapp_config)
34
- log('Checking for existing VM') do
35
- ip = vapp_config[:ip]
36
- raise "VM exists at #{ip}" if system("ping -c 5 #{ip}")
37
- end
38
- end
39
-
40
- def untar_vapp_template_tar(vapp_template_tar_path, dir)
41
- log("Untarring #{vapp_template_tar_path}") do
42
- system_or_exit("cd #{dir} && tar xfv '#{vapp_template_tar_path}'")
43
- end
44
- end
45
-
46
- def client
47
- @client ||= VCloudSdk::Client.new(
48
- @login_info[:url],
49
- "#{@login_info[:user]}@#{@login_info[:organization]}",
50
- @login_info[:password],
51
- {},
52
- @logger,
53
- )
54
- end
55
-
56
- def deploy_vapp(ovf_dir, vapp_config)
57
- # setup the catalog
58
- client.delete_catalog_by_name(@location[:catalog]) if client.catalog_exists?(@location[:catalog])
59
- catalog = client.create_catalog(@location[:catalog])
60
-
61
- # upload template and instantiate vapp
62
- catalog.upload_vapp_template(@location[:vdc], vapp_config[:name], ovf_dir)
63
-
64
- # instantiate template
65
- network_config = VCloudSdk::NetworkConfig.new(@location[:network], 'Network 1')
66
- catalog.instantiate_vapp_template(
67
- vapp_config[:name], @location[:vdc], vapp_config[:name], nil, nil, network_config)
68
- rescue => e
69
- @logger.error(e.http_body) if e.respond_to?(:http_body)
70
- raise e
71
- end
72
-
73
- def reconfigure_vm(vapp, vapp_config)
74
- vm = vapp.find_vm_by_name(vapp_config[:name])
75
- vm.product_section_properties = build_properties(vapp_config)
76
- vm
77
- end
78
-
79
- def build_properties(vapp_config)
80
- [
81
- {
82
- 'type' => 'string',
83
- 'key' => 'gateway',
84
- 'value' => vapp_config[:gateway],
85
- 'password' => 'false',
86
- 'userConfigurable' => 'true',
87
- 'Label' => 'Default Gateway',
88
- 'Description' => 'The default gateway address for the VM network. Leave blank if DHCP is desired.'
89
- },
90
- {
91
- 'type' => 'string',
92
- 'key' => 'DNS',
93
- 'value' => vapp_config[:dns],
94
- 'password' => 'false',
95
- 'userConfigurable' => 'true',
96
- 'Label' => 'DNS',
97
- 'Description' => 'The domain name servers for the VM (comma separated). Leave blank if DHCP is desired.',
98
- },
99
- {
100
- 'type' => 'string',
101
- 'key' => 'ntp_servers',
102
- 'value' => vapp_config[:ntp],
103
- 'password' => 'false',
104
- 'userConfigurable' => 'true',
105
- 'Label' => 'NTP Servers',
106
- 'Description' => 'Comma-delimited list of NTP servers'
107
- },
108
- {
109
- 'type' => 'string',
110
- 'key' => 'admin_password',
111
- 'value' => 'tempest',
112
- 'password' => 'true',
113
- 'userConfigurable' => 'true',
114
- 'Label' => 'Admin Password',
115
- 'Description' => 'This password is used to SSH into the VM. The username is "tempest".',
116
- },
117
- {
118
- 'type' => 'string',
119
- 'key' => 'ip0',
120
- 'value' => vapp_config[:ip],
121
- 'password' => 'false',
122
- 'userConfigurable' => 'true',
123
- 'Label' => 'IP Address',
124
- 'Description' => 'The IP address for the VM. Leave blank if DHCP is desired.',
125
- },
126
- {
127
- 'type' => 'string',
128
- 'key' => 'netmask0',
129
- 'value' => vapp_config[:netmask],
130
- 'password' => 'false',
131
- 'userConfigurable' => 'true',
132
- 'Label' => 'Netmask',
133
- 'Description' => 'The netmask for the VM network. Leave blank if DHCP is desired.'
134
- }
135
- ]
136
- end
137
-
138
- def log(title, &blk)
139
- @logger.debug "--- Begin: #{title.inspect} @ #{DateTime.now}"
140
- blk.call
141
- @logger.debug "--- End: #{title.inspect} @ #{DateTime.now}"
142
- end
143
-
144
- def system_or_exit(command)
145
- log(command) do
146
- system(command) || raise("Error executing: #{command.inspect}")
147
- end
148
- end
149
- end
150
- end
151
- end