bosh_vsphere_cpi 1.1868.0 → 1.1975.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cloud/vsphere/client.rb +3 -3
- data/lib/cloud/vsphere/cloud.rb +31 -110
- data/lib/cloud/vsphere/cluster_config.rb +15 -0
- data/lib/cloud/vsphere/config.rb +140 -198
- data/lib/cloud/vsphere/fixed_cluster_placer.rb +17 -0
- data/lib/cloud/vsphere/resources.rb +20 -22
- data/lib/cloud/vsphere/resources/cluster.rb +98 -125
- data/lib/cloud/vsphere/resources/datacenter.rb +51 -61
- data/lib/cloud/vsphere/resources/datastore.rb +1 -3
- data/lib/cloud/vsphere/resources/folder.rb +41 -41
- data/lib/cloud/vsphere/resources/resource_pool.rb +6 -6
- data/lib/cloud/vsphere/resources/scorer.rb +2 -2
- data/lib/cloud/vsphere/version.rb +1 -1
- data/lib/cloud/vsphere/vm_creator.rb +116 -0
- data/lib/cloud/vsphere/vm_creator_builder.rb +17 -0
- metadata +12 -8
data/lib/cloud/vsphere/client.rb
CHANGED
@@ -10,7 +10,7 @@ module VSphereCloud
|
|
10
10
|
class NotLoggedInException < StandardError; end
|
11
11
|
|
12
12
|
attr_accessor :service_content
|
13
|
-
attr_accessor :
|
13
|
+
attr_accessor :soap_stub
|
14
14
|
attr_accessor :service_instance
|
15
15
|
|
16
16
|
def initialize(host, options = {})
|
@@ -26,9 +26,9 @@ module VSphereCloud
|
|
26
26
|
http_client.connect_timeout = 4
|
27
27
|
http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
28
28
|
|
29
|
-
@
|
29
|
+
@soap_stub = Soap::StubAdapter.new(host, "vim.version.version6", http_client)
|
30
30
|
|
31
|
-
@service_instance = Vim::ServiceInstance.new("ServiceInstance",
|
31
|
+
@service_instance = Vim::ServiceInstance.new("ServiceInstance", soap_stub)
|
32
32
|
@service_content = service_instance.content
|
33
33
|
@metrics_cache = {}
|
34
34
|
@lock = Mutex.new
|
data/lib/cloud/vsphere/cloud.rb
CHANGED
@@ -16,6 +16,8 @@ require 'cloud/vsphere/resources/scorer'
|
|
16
16
|
require 'cloud/vsphere/resources/util'
|
17
17
|
require 'cloud/vsphere/models/disk'
|
18
18
|
require 'cloud/vsphere/path_finder'
|
19
|
+
require 'cloud/vsphere/vm_creator_builder'
|
20
|
+
require 'cloud/vsphere/fixed_cluster_placer'
|
19
21
|
|
20
22
|
module VSphereCloud
|
21
23
|
|
@@ -28,12 +30,12 @@ module VSphereCloud
|
|
28
30
|
attr_accessor :client
|
29
31
|
|
30
32
|
def initialize(options)
|
31
|
-
Config.
|
33
|
+
@config = Config.build(options)
|
32
34
|
|
33
|
-
@logger =
|
34
|
-
@client =
|
35
|
-
@rest_client =
|
36
|
-
@resources = Resources.new
|
35
|
+
@logger = config.logger
|
36
|
+
@client = config.client
|
37
|
+
@rest_client = config.rest_client
|
38
|
+
@resources = Resources.new(config)
|
37
39
|
|
38
40
|
# Global lock
|
39
41
|
@lock = Mutex.new
|
@@ -163,108 +165,10 @@ module VSphereCloud
|
|
163
165
|
client.find_by_inventory_path([dc.name, 'vm', dc.template_folder.name, name])
|
164
166
|
end
|
165
167
|
|
166
|
-
def create_vm(agent_id, stemcell,
|
168
|
+
def create_vm(agent_id, stemcell, cloud_properties, networks, disk_locality = nil, environment = nil)
|
167
169
|
with_thread_name("create_vm(#{agent_id}, ...)") do
|
168
|
-
|
169
|
-
|
170
|
-
cpu = resource_pool['cpu']
|
171
|
-
|
172
|
-
# Make sure number of cores is a power of 2. kb.vmware.com/kb/2003484
|
173
|
-
if cpu & cpu - 1 != 0
|
174
|
-
raise "Number of vCPUs: #{cpu} is not a power of 2."
|
175
|
-
end
|
176
|
-
|
177
|
-
stemcell_vm = stemcell_vm(stemcell)
|
178
|
-
raise "Could not find stemcell: #{stemcell}" if stemcell_vm.nil?
|
179
|
-
|
180
|
-
stemcell_size =
|
181
|
-
client.get_property(stemcell_vm, Vim::VirtualMachine, 'summary.storage.committed', ensure_all: true)
|
182
|
-
stemcell_size /= 1024 * 1024
|
183
|
-
|
184
|
-
disks = disk_spec(disk_locality)
|
185
|
-
# need to include swap and linked clone log
|
186
|
-
ephemeral = disk + memory + stemcell_size
|
187
|
-
cluster, datastore = @resources.place(memory, ephemeral, disks)
|
188
|
-
|
189
|
-
name = "vm-#{generate_unique_name}"
|
190
|
-
@logger.info("Creating vm: #{name} on #{cluster.mob} stored in #{datastore.mob}")
|
191
|
-
|
192
|
-
replicated_stemcell_vm = replicate_stemcell(cluster, datastore, stemcell)
|
193
|
-
replicated_stemcell_properties = client.get_properties(replicated_stemcell_vm, Vim::VirtualMachine,
|
194
|
-
['config.hardware.device', 'snapshot'],
|
195
|
-
ensure_all: true)
|
196
|
-
|
197
|
-
devices = replicated_stemcell_properties['config.hardware.device']
|
198
|
-
snapshot = replicated_stemcell_properties['snapshot']
|
199
|
-
|
200
|
-
config = Vim::Vm::ConfigSpec.new(memory_mb: memory, num_cpus: cpu)
|
201
|
-
config.device_change = []
|
202
|
-
|
203
|
-
system_disk = devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualDisk) }
|
204
|
-
pci_controller = devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualPCIController) }
|
205
|
-
|
206
|
-
file_name = "[#{datastore.name}] #{name}/ephemeral_disk.vmdk"
|
207
|
-
ephemeral_disk_config =
|
208
|
-
create_disk_config_spec(datastore.mob, file_name, system_disk.controller_key, disk, create: true)
|
209
|
-
config.device_change << ephemeral_disk_config
|
210
|
-
|
211
|
-
dvs_index = {}
|
212
|
-
networks.each_value do |network|
|
213
|
-
v_network_name = network['cloud_properties']['name']
|
214
|
-
network_mob = client.find_by_inventory_path([cluster.datacenter.name, 'network', v_network_name])
|
215
|
-
nic_config = create_nic_config_spec(v_network_name, network_mob, pci_controller.key, dvs_index)
|
216
|
-
config.device_change << nic_config
|
217
|
-
end
|
218
|
-
|
219
|
-
nics = devices.select { |device| device.kind_of?(Vim::Vm::Device::VirtualEthernetCard) }
|
220
|
-
nics.each do |nic|
|
221
|
-
nic_config = create_delete_device_spec(nic)
|
222
|
-
config.device_change << nic_config
|
223
|
-
end
|
224
|
-
|
225
|
-
fix_device_unit_numbers(devices, config.device_change)
|
226
|
-
|
227
|
-
@logger.info("Cloning vm: #{replicated_stemcell_vm} to #{name}")
|
228
|
-
|
229
|
-
task = clone_vm(replicated_stemcell_vm,
|
230
|
-
name,
|
231
|
-
cluster.datacenter.vm_folder.mob,
|
232
|
-
cluster.resource_pool.mob,
|
233
|
-
datastore: datastore.mob, linked: true, snapshot: snapshot.current_snapshot, config: config)
|
234
|
-
vm = client.wait_for_task(task)
|
235
|
-
|
236
|
-
begin
|
237
|
-
upload_file(cluster.datacenter.name, datastore.name, "#{name}/env.iso", '')
|
238
|
-
|
239
|
-
vm_properties = client.get_properties(vm, Vim::VirtualMachine, ['config.hardware.device'], ensure_all: true)
|
240
|
-
devices = vm_properties['config.hardware.device']
|
241
|
-
|
242
|
-
# Configure the ENV CDROM
|
243
|
-
config = Vim::Vm::ConfigSpec.new
|
244
|
-
config.device_change = []
|
245
|
-
file_name = "[#{datastore.name}] #{name}/env.iso"
|
246
|
-
cdrom_change = configure_env_cdrom(datastore.mob, devices, file_name)
|
247
|
-
config.device_change << cdrom_change
|
248
|
-
client.reconfig_vm(vm, config)
|
249
|
-
|
250
|
-
network_env = generate_network_env(devices, networks, dvs_index)
|
251
|
-
disk_env = generate_disk_env(system_disk, ephemeral_disk_config.device)
|
252
|
-
env = generate_agent_env(name, vm, agent_id, network_env, disk_env)
|
253
|
-
env['env'] = environment
|
254
|
-
@logger.info("Setting VM env: #{env.pretty_inspect}")
|
255
|
-
|
256
|
-
location =
|
257
|
-
get_vm_location(vm, datacenter: cluster.datacenter.name, datastore: datastore.name, vm: name)
|
258
|
-
set_agent_env(vm, location, env)
|
259
|
-
|
260
|
-
@logger.info("Powering on VM: #{vm} (#{name})")
|
261
|
-
client.power_on_vm(cluster.datacenter.mob, vm)
|
262
|
-
rescue => e
|
263
|
-
@logger.info("#{e} - #{e.backtrace.join("\n")}")
|
264
|
-
delete_vm(name)
|
265
|
-
raise e
|
266
|
-
end
|
267
|
-
name
|
170
|
+
VmCreatorBuilder.new.build(choose_placer(cloud_properties), cloud_properties, @client, @logger, self).
|
171
|
+
create(agent_id, stemcell, networks, disk_locality, environment)
|
268
172
|
end
|
269
173
|
end
|
270
174
|
|
@@ -541,7 +445,7 @@ module VSphereCloud
|
|
541
445
|
destination_path = "[#{persistent_datastore.name}] #{datacenter_disk_path}/#{disk.uuid}"
|
542
446
|
@logger.info("Moving #{disk.datacenter}/#{source_path} to #{datacenter_name}/#{destination_path}")
|
543
447
|
|
544
|
-
if
|
448
|
+
if config.copy_disks
|
545
449
|
client.copy_disk(source_datacenter, source_path, datacenter, destination_path)
|
546
450
|
@logger.info('Copied disk successfully')
|
547
451
|
else
|
@@ -790,7 +694,7 @@ module VSphereCloud
|
|
790
694
|
env['agent_id'] = agent_id
|
791
695
|
env['networks'] = networking_env
|
792
696
|
env['disks'] = disk_env
|
793
|
-
env.merge!(
|
697
|
+
env.merge!(config.agent)
|
794
698
|
env
|
795
699
|
end
|
796
700
|
|
@@ -906,7 +810,7 @@ module VSphereCloud
|
|
906
810
|
def fetch_file(datacenter_name, datastore_name, path)
|
907
811
|
retry_block do
|
908
812
|
url =
|
909
|
-
"https://#{
|
813
|
+
"https://#{config.vcenter_host}/folder/#{path}?dcPath=#{URI.escape(datacenter_name)}&dsName=#{URI.escape(datastore_name)}"
|
910
814
|
|
911
815
|
response = @rest_client.get(url)
|
912
816
|
|
@@ -923,7 +827,7 @@ module VSphereCloud
|
|
923
827
|
def upload_file(datacenter_name, datastore_name, path, contents)
|
924
828
|
retry_block do
|
925
829
|
url =
|
926
|
-
"https://#{
|
830
|
+
"https://#{config.vcenter_host}/folder/#{path}?dcPath=#{URI.escape(datacenter_name)}&dsName=#{URI.escape(datastore_name)}"
|
927
831
|
response = @rest_client.put(url,
|
928
832
|
contents,
|
929
833
|
{ 'Content-Type' => 'application/octet-stream', 'Content-Length' => contents.length })
|
@@ -1143,5 +1047,22 @@ module VSphereCloud
|
|
1143
1047
|
|
1144
1048
|
vms
|
1145
1049
|
end
|
1050
|
+
|
1051
|
+
private
|
1052
|
+
|
1053
|
+
def choose_placer(cloud_properties)
|
1054
|
+
datacenter_spec = cloud_properties.fetch('datacenters', []).first
|
1055
|
+
cluster_spec = datacenter_spec.fetch('clusters', []).first if datacenter_spec
|
1056
|
+
placer = FixedClusterPlacer.new(find_cluster(cluster_spec)) unless cluster_spec.nil?
|
1057
|
+
|
1058
|
+
placer.nil? ? @resources : placer
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
def find_cluster(cluster_spec)
|
1062
|
+
datacenter = Resources::Datacenter.new(config)
|
1063
|
+
datacenter.clusters[cluster_spec.keys.first]
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
attr_reader :config
|
1146
1067
|
end
|
1147
1068
|
end
|
data/lib/cloud/vsphere/config.rb
CHANGED
@@ -1,250 +1,192 @@
|
|
1
|
-
|
1
|
+
require 'cloud/vsphere/cluster_config'
|
2
2
|
|
3
3
|
module VSphereCloud
|
4
|
-
|
5
|
-
# vSphere CPI Config
|
6
4
|
class Config
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
"agent" => dict(String, Object), # passthrough to the agent
|
12
|
-
optional("cpi_log") => String,
|
13
|
-
optional("soap_log") => String,
|
14
|
-
optional("mem_overcommit_ratio") => Numeric,
|
15
|
-
optional("copy_disks") => bool,
|
16
|
-
"vcenters" => [{
|
17
|
-
"host" => String,
|
18
|
-
"user" => String,
|
19
|
-
"password" => String,
|
20
|
-
"datacenters" => [{
|
21
|
-
"name" => String,
|
22
|
-
"vm_folder" => String,
|
23
|
-
"template_folder" => String,
|
24
|
-
optional("use_sub_folder") => bool,
|
25
|
-
"disk_path" => String,
|
26
|
-
"datastore_pattern" => String,
|
27
|
-
"persistent_datastore_pattern" => String,
|
28
|
-
optional("allow_mixed_datastores") => bool,
|
29
|
-
"clusters" => [enum(String,
|
30
|
-
dict(String, {"resource_pool" => String}))]
|
31
|
-
}]
|
32
|
-
}]
|
33
|
-
}
|
5
|
+
def self.build(config_hash)
|
6
|
+
config = new(config_hash)
|
7
|
+
config.validate
|
8
|
+
config
|
34
9
|
end
|
35
10
|
|
36
|
-
|
37
|
-
|
11
|
+
def initialize(config_hash)
|
12
|
+
@config = config_hash
|
13
|
+
@vcenter_host = nil
|
14
|
+
@vcenter_user = nil
|
15
|
+
@vcenter_password = nil
|
16
|
+
@rest_client = nil
|
17
|
+
@default_overcommit_ratio = 1.0
|
38
18
|
|
39
|
-
|
40
|
-
|
41
|
-
attr_accessor :host
|
19
|
+
@is_validated = false
|
20
|
+
end
|
42
21
|
|
43
|
-
|
44
|
-
|
45
|
-
attr_accessor :user
|
22
|
+
def validate
|
23
|
+
return true if @is_validated
|
46
24
|
|
47
|
-
|
48
|
-
|
49
|
-
|
25
|
+
unless config['vcenters'].size == 1
|
26
|
+
raise 'vSphere CPI only supports a single vCenter'
|
27
|
+
end
|
50
28
|
|
51
|
-
|
52
|
-
|
53
|
-
|
29
|
+
unless config['vcenters'].first['datacenters'].size ==1
|
30
|
+
raise 'vSphere CPI only supports a single datacenter'
|
31
|
+
end
|
54
32
|
|
55
|
-
|
56
|
-
#
|
57
|
-
# @param [Hash] config parsed YAML.
|
58
|
-
def initialize(config)
|
59
|
-
@host = config["host"]
|
60
|
-
@user = config["user"]
|
61
|
-
@password = config["password"]
|
62
|
-
@datacenters = {}
|
33
|
+
validate_schema
|
63
34
|
|
64
|
-
|
65
|
-
|
66
|
-
end
|
35
|
+
@is_validated = true
|
36
|
+
end
|
67
37
|
|
68
|
-
|
69
|
-
|
70
|
-
@datacenters[dc_config.name] = dc_config
|
71
|
-
end
|
72
|
-
end
|
38
|
+
def logger
|
39
|
+
@logger ||= Bosh::Clouds::Config.logger
|
73
40
|
end
|
74
41
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
42
|
+
def client
|
43
|
+
unless @client
|
44
|
+
@client = Client.new("https://#{vcenter['host']}/sdk/vimService", {
|
45
|
+
'soap_log' => config['soap_log'] || config['cpi_log']
|
46
|
+
})
|
80
47
|
|
81
|
-
|
82
|
-
|
83
|
-
attr_accessor :template
|
48
|
+
@client.login(vcenter['user'], vcenter['password'], 'en')
|
49
|
+
end
|
84
50
|
|
85
|
-
|
86
|
-
# @return [true, false] boolean indicating shared folders, so an
|
87
|
-
# additional namespace should be used.
|
88
|
-
attr_accessor :shared
|
51
|
+
@client
|
89
52
|
end
|
90
53
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
attr_accessor :ephemeral_pattern
|
97
|
-
|
98
|
-
# @!attribute persistent_pattern
|
99
|
-
# @return [Regexp] regexp pattern for persistent datastores.
|
100
|
-
attr_accessor :persistent_pattern
|
54
|
+
def rest_client
|
55
|
+
unless @rest_client
|
56
|
+
@rest_client = HTTPClient.new
|
57
|
+
@rest_client.send_timeout = 14400 # 4 hours, for stemcell uploads
|
58
|
+
@rest_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
101
59
|
|
102
|
-
|
103
|
-
|
104
|
-
|
60
|
+
# HACK: read the session from the SOAP client so we don't leak sessions
|
61
|
+
# when using the REST client
|
62
|
+
cookie_str = client.soap_stub.cookie
|
63
|
+
@rest_client.cookie_manager.parse(cookie_str, URI.parse("https://#{vcenter_host}"))
|
64
|
+
end
|
105
65
|
|
106
|
-
|
107
|
-
# @return [true, false] boolean indicating whether persistent and
|
108
|
-
# ephemeral datastores can overlap..
|
109
|
-
attr_accessor :allow_mixed
|
66
|
+
@rest_client
|
110
67
|
end
|
111
68
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
# @!attribute name
|
116
|
-
# @return [String] datacenter name.
|
117
|
-
attr_accessor :name
|
69
|
+
def mem_overcommit
|
70
|
+
config.fetch('mem_overcommit_ratio', @default_overcommit_ratio)
|
71
|
+
end
|
118
72
|
|
119
|
-
|
120
|
-
|
121
|
-
|
73
|
+
def copy_disks
|
74
|
+
!!config['copy_disks']
|
75
|
+
end
|
122
76
|
|
123
|
-
|
124
|
-
|
125
|
-
|
77
|
+
def agent
|
78
|
+
config['agent']
|
79
|
+
end
|
126
80
|
|
127
|
-
|
128
|
-
|
129
|
-
|
81
|
+
def vcenter_host
|
82
|
+
vcenter['host']
|
83
|
+
end
|
130
84
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
def initialize(config)
|
135
|
-
@name = config["name"]
|
85
|
+
def vcenter_user
|
86
|
+
vcenter['user']
|
87
|
+
end
|
136
88
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
@folders.shared = !!config["use_sub_folder"]
|
89
|
+
def vcenter_password
|
90
|
+
vcenter['password']
|
91
|
+
end
|
141
92
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
config["persistent_datastore_pattern"])
|
146
|
-
@datastores.disk_path = config["disk_path"]
|
147
|
-
@datastores.allow_mixed = !!config["allow_mixed_datastores"]
|
93
|
+
def datacenter_name
|
94
|
+
vcenter_datacenter['name']
|
95
|
+
end
|
148
96
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
@clusters[cluster_config.name] = cluster_config
|
153
|
-
end
|
97
|
+
def datacenter_vm_folder
|
98
|
+
vcenter_datacenter['vm_folder']
|
99
|
+
end
|
154
100
|
|
155
|
-
|
156
|
-
|
157
|
-
end
|
158
|
-
end
|
101
|
+
def datacenter_template_folder
|
102
|
+
vcenter_datacenter['template_folder']
|
159
103
|
end
|
160
104
|
|
161
|
-
|
162
|
-
|
105
|
+
def datacenter_disk_path
|
106
|
+
vcenter_datacenter['disk_path']
|
107
|
+
end
|
163
108
|
|
164
|
-
|
165
|
-
|
166
|
-
|
109
|
+
def datacenter_datastore_pattern
|
110
|
+
Regexp.new(vcenter_datacenter['datastore_pattern'])
|
111
|
+
end
|
167
112
|
|
168
|
-
|
169
|
-
|
170
|
-
|
113
|
+
def datacenter_persistent_datastore_pattern
|
114
|
+
Regexp.new(vcenter_datacenter['persistent_datastore_pattern'])
|
115
|
+
end
|
171
116
|
|
172
|
-
|
173
|
-
|
174
|
-
# @param [Hash] config parsed YAML.
|
175
|
-
def initialize(config)
|
176
|
-
case config
|
177
|
-
when String
|
178
|
-
@name = config
|
179
|
-
else
|
180
|
-
@name = config.keys.first
|
181
|
-
@resource_pool = config[@name]["resource_pool"]
|
182
|
-
end
|
183
|
-
end
|
117
|
+
def datacenter_clusters
|
118
|
+
@cluster_objs ||= cluster_objs
|
184
119
|
end
|
185
120
|
|
186
|
-
|
121
|
+
def datacenter_allow_mixed_datastores
|
122
|
+
!!vcenter_datacenter['allow_mixed_datastores']
|
123
|
+
end
|
187
124
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
:agent,
|
193
|
-
:copy_disks,
|
194
|
-
:vcenter,
|
195
|
-
:mem_overcommit,
|
196
|
-
]
|
125
|
+
def datacenter_use_sub_folder
|
126
|
+
datacenter_clusters.any? { |_, cluster| cluster.resource_pool } ||
|
127
|
+
!!vcenter_datacenter['use_sub_folder']
|
128
|
+
end
|
197
129
|
|
198
|
-
|
199
|
-
attr_accessor option
|
200
|
-
end
|
130
|
+
private
|
201
131
|
|
202
|
-
|
203
|
-
#
|
204
|
-
# Used by unit tests.
|
205
|
-
# @return [void]
|
206
|
-
def clear
|
207
|
-
CONFIG_OPTIONS.each do |option|
|
208
|
-
self.instance_variable_set("@#{option}".to_sym, nil)
|
209
|
-
end
|
210
|
-
end
|
132
|
+
attr_reader :config
|
211
133
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
def configure(config)
|
216
|
-
@logger = Bosh::Clouds::Config.logger
|
217
|
-
@schema.validate(config)
|
218
|
-
@agent = config["agent"]
|
134
|
+
def is_validated?
|
135
|
+
raise 'Configuration has not been validated' unless @is_validated
|
136
|
+
end
|
219
137
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
@vcenter = VCenterConfig.new(config["vcenters"].first)
|
138
|
+
def vcenter
|
139
|
+
config['vcenters'].first
|
140
|
+
end
|
224
141
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
@client.login(@vcenter.user, @vcenter.password, "en")
|
142
|
+
def vcenter_datacenter
|
143
|
+
vcenter['datacenters'].first
|
144
|
+
end
|
229
145
|
|
230
|
-
|
231
|
-
|
232
|
-
|
146
|
+
def validate_schema
|
147
|
+
# Membrane schema for the provided config.
|
148
|
+
schema = Membrane::SchemaParser.parse do
|
149
|
+
{
|
150
|
+
'agent' => dict(String, Object), # passthrough to the agent
|
151
|
+
optional('cpi_log') => String,
|
152
|
+
optional('soap_log') => String,
|
153
|
+
optional('mem_overcommit_ratio') => Numeric,
|
154
|
+
optional('copy_disks') => bool,
|
155
|
+
'vcenters' => [{
|
156
|
+
'host' => String,
|
157
|
+
'user' => String,
|
158
|
+
'password' => String,
|
159
|
+
'datacenters' => [{
|
160
|
+
'name' => String,
|
161
|
+
'vm_folder' => String,
|
162
|
+
'template_folder' => String,
|
163
|
+
optional('use_sub_folder') => bool,
|
164
|
+
'disk_path' => String,
|
165
|
+
'datastore_pattern' => String,
|
166
|
+
'persistent_datastore_pattern' => String,
|
167
|
+
optional('allow_mixed_datastores') => bool,
|
168
|
+
'clusters' => [enum(String,
|
169
|
+
dict(String, { 'resource_pool' => String }))]
|
170
|
+
}]
|
171
|
+
}]
|
172
|
+
}
|
173
|
+
end
|
233
174
|
|
234
|
-
|
235
|
-
|
236
|
-
cookie_str = @client.stub.cookie
|
237
|
-
@rest_client.cookie_manager.parse(
|
238
|
-
cookie_str, URI.parse("https://#{@vcenter.host}"))
|
175
|
+
schema.validate(config)
|
176
|
+
end
|
239
177
|
|
240
|
-
|
241
|
-
|
178
|
+
def cluster_objs
|
179
|
+
cluster_objs = {}
|
180
|
+
vcenter_datacenter['clusters'].each do |cluster|
|
181
|
+
if cluster.is_a?(Hash)
|
182
|
+
name = cluster.keys.first
|
183
|
+
cluster_objs[name] = ClusterConfig.new(name, cluster[name])
|
242
184
|
else
|
243
|
-
|
185
|
+
cluster_objs[cluster] = ClusterConfig.new(cluster, {})
|
244
186
|
end
|
245
|
-
|
246
|
-
@copy_disks = !!config["copy_disks"]
|
247
187
|
end
|
188
|
+
cluster_objs
|
248
189
|
end
|
249
190
|
end
|
191
|
+
|
250
192
|
end
|