vm_shepherd 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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