kitchen-vcenter 1.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31833a2dfb60dba469a3c03aa8261cc4639760770cb33b913909950009e5603b
4
- data.tar.gz: c0c663f9b4ac33fdc505dab121ba33112d22b7cc9df59213a1aa1858c1191aa4
3
+ metadata.gz: 4830a5da83f0ac1eba8ce606f4151ff369058478452776699f45b52277bd4943
4
+ data.tar.gz: c7761ff930c8c78194dafe5c5ea7b55e4a27b1db992f4f1c678a66308cf75bb2
5
5
  SHA512:
6
- metadata.gz: 4c5ef3e005c6f281b651c197a46a1bb84d38c3261973d5dc909d1924afd398a8c4debc2746f0de3f84d5e2dcd294a3e0537fb8df4210733abd9e7eb94ff9a40c
7
- data.tar.gz: 66bc5bcb9263cbd8ab91757555f32daa26b0b2148c792ab1dd62613053bab7efdfa83673d6afbcc0e97621b393d7fb2f3339b853856f958d158f718cc16f43af
6
+ metadata.gz: 4986789d6c04264fcbf426176c3453427cf8a3f4b8cc951efe77a7b4d353b10aa20570c63f59b33294992f8a889b38b49454a25257ae6722a4431bb332272f4a
7
+ data.tar.gz: 3335539aeb36bd96b4e044c774501bee318ab1130a89cbb46fd319af83ee2d27952a9e8d232f3a1170b6baf196ee63cf6fd08bd952c920733d4993baffe8ea97
@@ -20,5 +20,5 @@
20
20
  # The main kitchen-vcenter module
21
21
  module KitchenVcenter
22
22
  # The version of this version of test-kitchen we assume enterprises want.
23
- VERSION = "1.5.0"
23
+ VERSION = "2.0.0"
24
24
  end
@@ -18,15 +18,8 @@
18
18
  #
19
19
 
20
20
  require "kitchen"
21
- require "rbvmomi"
22
- require "sso"
23
- require "base"
24
- require "lookup_service_helper"
25
- require "vapi"
26
- require "com/vmware/cis"
27
- require "com/vmware/cis/tagging"
28
- require "com/vmware/vcenter"
29
- require "com/vmware/vcenter/vm"
21
+ require "vsphere-automation-cis"
22
+ require "vsphere-automation-vcenter"
30
23
  require "support/clone_vm"
31
24
  require "securerandom"
32
25
  require "uri"
@@ -37,7 +30,7 @@ module Kitchen
37
30
  module Driver
38
31
  # Extends the Base class for vCenter
39
32
  class Vcenter < Kitchen::Driver::Base
40
- attr_accessor :connection_options, :ipaddress, :vapi_config, :session_svc, :session_id
33
+ attr_accessor :connection_options, :ipaddress, :api_client
41
34
 
42
35
  required_config :vcenter_username
43
36
  required_config :vcenter_password
@@ -53,7 +46,6 @@ module Kitchen
53
46
  default_config :resource_pool, nil
54
47
  default_config :clone_type, :full
55
48
  default_config :cluster, nil
56
- default_config :lookup_service_host, nil
57
49
  default_config :network_name, nil
58
50
  default_config :tags, nil
59
51
 
@@ -72,7 +64,6 @@ module Kitchen
72
64
  # @todo This does not allow to specify cluster AND pool yet
73
65
  unless config[:cluster].nil?
74
66
  cluster = get_cluster(config[:cluster])
75
- # @todo Check for active hosts, to avoid "A specified parameter was not correct: spec.pool"
76
67
  config[:resource_pool] = cluster.resource_pool
77
68
  else
78
69
  # Find the first resource pool on any cluster
@@ -111,30 +102,38 @@ module Kitchen
111
102
  }
112
103
 
113
104
  # Create an object from which the clone operation can be called
114
- clone_obj = Support::CloneVm.new(connection_options, options)
115
- state[:hostname] = clone_obj.clone
116
- state[:vm_name] = config[:vm_name]
105
+ new_vm = Support::CloneVm.new(connection_options, options)
106
+ new_vm.clone
107
+
108
+ state[:hostname] = new_vm.ip
109
+ state[:vm_name] = new_vm.name
117
110
 
118
111
  unless config[:tags].nil? || config[:tags].empty?
112
+ tag_api = VSphereAutomation::CIS::TaggingTagApi.new(api_client)
113
+ vm_tags = tag_api.list.value
114
+ raise format("No configured tags found on VCenter, but %s specified", config[:tags].to_s) if vm_tags.empty?
115
+
119
116
  valid_tags = {}
120
- vm_tags = Com::Vmware::Cis::Tagging::Tag.new(vapi_config)
121
- vm_tags.list.each do |uid|
122
- tag = vm_tags.get(uid)
123
- valid_tags[tag.name] = tag.id
117
+ vm_tags.each do |uid|
118
+ tag = tag_api.get(uid)
119
+
120
+ valid_tags[tag.value.name] = tag.value.id if tag.is_a? VSphereAutomation::CIS::CisTaggingTagResult
124
121
  end
125
122
 
126
123
  # Error out on undefined tags
127
124
  invalid = config[:tags] - valid_tags.keys
128
125
  raise format("Specified tag(s) %s not valid", invalid.join(",")) unless invalid.empty?
129
-
130
- tag_service = Com::Vmware::Cis::Tagging::TagAssociation.new(vapi_config)
131
-
132
- # calls needs a DynamicID object which we construct from type and mobID
133
- mobid = get_vm(config[:vm_name]).vm
134
- dynamic_id = Com::Vmware::Vapi::Std::DynamicID.new(type: "VirtualMachine", id: mobid)
135
-
126
+ tag_service = VSphereAutomation::CIS::TaggingTagAssociationApi.new(api_client)
136
127
  tag_ids = config[:tags].map { |name| valid_tags[name] }
137
- tag_service.attach_multiple_tags_to_object(dynamic_id, tag_ids)
128
+
129
+ request_body = {
130
+ object_id: {
131
+ id: get_vm(config[:vm_name]).vm,
132
+ type: "VirtualMachine",
133
+ },
134
+ tag_ids: tag_ids,
135
+ }
136
+ tag_service.attach_multiple_tags_to_object(request_body)
138
137
  end
139
138
  end
140
139
 
@@ -146,18 +145,20 @@ module Kitchen
146
145
 
147
146
  save_and_validate_parameters
148
147
  connect
148
+
149
149
  vm = get_vm(state[:vm_name])
150
+ unless vm.nil?
151
+ vm_api = VSphereAutomation::VCenter::VMApi.new(api_client)
150
152
 
151
- vm_obj = Com::Vmware::Vcenter::VM.new(vapi_config)
153
+ # shut the machine down if it is running
154
+ if vm.power_state == "POWERED_ON"
155
+ power = VSphereAutomation::VCenter::VmPowerApi.new(api_client)
156
+ power.stop(vm.vm)
157
+ end
152
158
 
153
- # shut the machine down if it is running
154
- if vm.power_state.value == "POWERED_ON"
155
- power = Com::Vmware::Vcenter::Vm::Power.new(vapi_config)
156
- power.stop(vm.vm)
159
+ # delete the vm
160
+ vm_api.delete(vm.vm)
157
161
  end
158
-
159
- # delete the vm
160
- vm_obj.delete(vm.vm)
161
162
  end
162
163
 
163
164
  private
@@ -195,22 +196,20 @@ module Kitchen
195
196
  #
196
197
  # @param [name] name is the name of the datacenter
197
198
  def datacenter_exists?(name)
198
- filter = Com::Vmware::Vcenter::Datacenter::FilterSpec.new(names: Set.new([name]))
199
- dc_obj = Com::Vmware::Vcenter::Datacenter.new(vapi_config)
200
- dc = dc_obj.list(filter)
199
+ dc_api = VSphereAutomation::VCenter::DatacenterApi.new(api_client)
200
+ dcs = dc_api.list({ filter_names: name }).value
201
201
 
202
- raise format("Unable to find data center: %s", name) if dc.empty?
202
+ raise format("Unable to find data center: %s", name) if dcs.empty?
203
203
  end
204
204
 
205
205
  # Checks if a network exists or not
206
206
  #
207
207
  # @param [name] name is the name of the Network
208
208
  def network_exists?(name)
209
- net_obj = Com::Vmware::Vcenter::Network.new(vapi_config)
210
- filter = Com::Vmware::Vcenter::Network::FilterSpec.new(names: Set.new([name]))
211
- net = net_obj.list(filter)
209
+ net_api = VSphereAutomation::VCenter::NetworkApi.new(api_client)
210
+ nets = net_api.list({ filter_names: name }).value
212
211
 
213
- raise format("Unable to find target network: %s", name) if net.empty?
212
+ raise format("Unable to find target network: %s", name) if nets.empty?
214
213
  end
215
214
 
216
215
  # Validates the host name of the server you can connect to
@@ -218,56 +217,58 @@ module Kitchen
218
217
  # @param [name] name is the name of the host
219
218
  def get_host(name)
220
219
  # create a host object to work with
221
- host_obj = Com::Vmware::Vcenter::Host.new(vapi_config)
220
+ host_api = VSphereAutomation::VCenter::HostApi.new(api_client)
222
221
 
223
222
  if name.nil?
224
- host = host_obj.list
223
+ hosts = host_api.list.value
225
224
  else
226
- filter = Com::Vmware::Vcenter::Host::FilterSpec.new(names: Set.new([name]))
227
- host = host_obj.list(filter)
225
+ hosts = host_api.list({ filter_names: name }).value
228
226
  end
229
227
 
230
- raise format("Unable to find target host: %s", name) if host.empty?
228
+ raise format("Unable to find target host: %s", name) if hosts.empty?
231
229
 
232
- host[0]
230
+ hosts.first
233
231
  end
234
232
 
235
233
  # Gets the folder you want to create the VM
236
234
  #
237
235
  # @param [name] name is the name of the folder
238
236
  def get_folder(name)
239
- # Create a filter to ensure that only the named folder is returned
240
- filter = Com::Vmware::Vcenter::Folder::FilterSpec.new(names: Set.new([name]))
241
- folder_obj = Com::Vmware::Vcenter::Folder.new(vapi_config)
242
- folder = folder_obj.list(filter)
237
+ folder_api = VSphereAutomation::VCenter::FolderApi.new(api_client)
238
+ folders = folder_api.list({ filter_names: name }).value
243
239
 
244
- raise format("Unable to find folder: %s", name) if folder.empty?
240
+ raise format("Unable to find folder: %s", name) if folders.empty?
245
241
 
246
- folder[0].folder
242
+ folders.first.folder
247
243
  end
248
244
 
249
245
  # Gets the name of the VM you are creating
250
246
  #
251
247
  # @param [name] name is the name of the VM
252
248
  def get_vm(name)
253
- filter = Com::Vmware::Vcenter::VM::FilterSpec.new(names: Set.new([name]))
254
- vm_obj = Com::Vmware::Vcenter::VM.new(vapi_config)
255
- vm_obj.list(filter)[0]
249
+ vm_api = VSphereAutomation::VCenter::VMApi.new(api_client)
250
+ vms = vm_api.list({ filter_names: name }).value
251
+
252
+ vms.first
256
253
  end
257
254
 
258
255
  # Gets the info of the cluster
259
256
  #
260
257
  # @param [name] name is the name of the Cluster
261
258
  def get_cluster(name)
262
- cl_obj = Com::Vmware::Vcenter::Cluster.new(vapi_config)
259
+ cluster_api = VSphereAutomation::VCenter::ClusterApi.new(api_client)
260
+ clusters = cluster_api.list({ filter_names: name }).value
263
261
 
264
- # @todo: Use Cluster::FilterSpec to only get the cluster which was asked
265
- # filter = Com::Vmware::Vcenter::Cluster::FilterSpec.new(clusters: Set.new(['...']))
266
- clusters = cl_obj.list.select { |cluster| cluster.name == name }
267
262
  raise format("Unable to find Cluster: %s", name) if clusters.empty?
268
263
 
269
- cluster_id = clusters[0].cluster
270
- cl_obj.get(cluster_id)
264
+ cluster_id = clusters.first.cluster
265
+
266
+ host_api = VSphereAutomation::VCenter::HostApi.new(api_client)
267
+ hosts = host_api.list({ filter_clusters: cluster_id, connection_states: "CONNECTED" }).value
268
+
269
+ raise format("Unable to find active host in cluster %s", name) if hosts.empty?
270
+
271
+ cluster_api.get(cluster_id).value
271
272
  end
272
273
 
273
274
  # Gets the name of the resource pool
@@ -276,92 +277,47 @@ module Kitchen
276
277
  # @param [name] name is the name of the ResourcePool
277
278
  def get_resource_pool(name)
278
279
  # Create a resource pool object
279
- rp_obj = Com::Vmware::Vcenter::ResourcePool.new(vapi_config)
280
+ rp_api = VSphereAutomation::VCenter::ResourcePoolApi.new(api_client)
280
281
 
281
282
  # If no name has been set, use the first resource pool that can be found,
282
283
  # otherwise try to find by given name
283
284
  if name.nil?
284
285
  # Remove default pool for first pass (<= 1.2.1 behaviour to pick first user-defined pool found)
285
- resource_pool = rp_obj.list.delete_if { |pool| pool.name == "Resources" }
286
- debug("Search of all resource pools found: " + resource_pool.map { |pool| pool.name }.to_s)
286
+ resource_pools = rp_api.list.value.delete_if { |pool| pool.name == "Resources" }
287
+ debug("Search of all resource pools found: " + resource_pools.map { |pool| pool.name }.to_s)
287
288
 
288
289
  # Revert to default pool, if no user-defined pool found (> 1.2.1 behaviour)
289
290
  # (This one might not be found under some circumstances by the statement above)
290
- return get_resource_pool("Resources") if resource_pool.empty?
291
+ return get_resource_pool("Resources") if resource_pools.empty?
291
292
  else
292
- # create a filter to find the named resource pool
293
- filter = Com::Vmware::Vcenter::ResourcePool::FilterSpec.new(names: Set.new([name]))
294
- resource_pool = rp_obj.list(filter)
295
- debug("Search for resource pools found: " + resource_pool.map { |pool| pool.name }.to_s)
293
+ resource_pools = rp_api.list({ filter_names: name }).value
294
+ debug("Search for resource pools found: " + resource_pools.map { |pool| pool.name }.to_s)
296
295
  end
297
296
 
298
- raise format("Unable to find Resource Pool: %s", name) if resource_pool.empty?
297
+ raise format("Unable to find Resource Pool: %s", name) if resource_pools.empty?
299
298
 
300
- resource_pool[0].resource_pool
301
- end
302
-
303
- # Get location of lookup service
304
- def lookup_service_host
305
- # Allow manual overrides
306
- return config[:lookup_service_host] unless config[:lookup_service_host].nil?
307
-
308
- # Retrieve SSO service via RbVmomi, which is always co-located with the Lookup Service.
309
- vim = RbVmomi::VIM.connect @connection_options
310
- vim_settings = vim.serviceContent.setting.setting
311
- sso_url = vim_settings.select { |o| o.key == "config.vpxd.sso.sts.uri" }&.first&.value
312
-
313
- # Configuration fallback, if no SSO URL found for some reason
314
- ls_host = sso_url.nil? ? config[:vcenter_host] : URI.parse(sso_url).host
315
- debug("Using Lookup Service at: " + ls_host)
316
-
317
- ls_host
318
- end
319
-
320
- # Get vCenter FQDN
321
- def vcenter_host
322
- # Retrieve SSO service via RbVmomi, which is always co-located with the Lookup Service.
323
- vim = RbVmomi::VIM.connect @connection_options
324
- vim_settings = vim.serviceContent.setting.setting
325
-
326
- vim_settings.select { |o| o.key == "VirtualCenter.FQDN" }.first.value
299
+ resource_pools.first.resource_pool
327
300
  end
328
301
 
329
302
  # The main connect method
330
303
  #
331
304
  def connect
332
- # Configure the connection to vCenter
333
- lookup_service_helper = LookupServiceHelper.new(lookup_service_host)
334
- vapi_urls = lookup_service_helper.find_vapi_urls
335
- debug("Found vAPI endpoints: [" + vapi_urls.to_s + "]")
336
-
337
- vim_urls = lookup_service_helper.find_vim_urls
338
- debug("Found VIM endpoints: [" + vim_urls.to_s + "]")
339
-
340
- node_id = vim_urls.select { |id, url| url.include? vcenter_host }.keys.first
341
- debug("NodeID of vCenter " + config[:vcenter_host] + " is " + node_id.to_s)
342
-
343
- vapi_url = lookup_service_helper.find_vapi_url(node_id)
344
- debug("vAPI Endpoint for vCenter is " + vapi_url)
345
-
346
- # Create the VAPI config object
347
- ssl_options = {}
348
- ssl_options[:verify] = config[:vcenter_disable_ssl_verify] ? :none : :peer
349
- @vapi_config = VAPI::Bindings::VapiConfig.new(vapi_url, ssl_options)
350
-
351
- # get the SSO url
352
- sso_url = lookup_service_helper.find_sso_url
353
- sso = SSO::Connection.new(sso_url).login(config[:vcenter_username], config[:vcenter_password])
354
- token = sso.request_bearer_token
355
- vapi_config.set_security_context(
356
- VAPI::Security.create_saml_bearer_security_context(token.to_s)
357
- )
358
-
359
- # Login and get the session information
360
- @session_svc = Com::Vmware::Cis::Session.new(vapi_config)
361
- @session_id = session_svc.create
362
- vapi_config.set_security_context(
363
- VAPI::Security.create_session_security_context(session_id)
364
- )
305
+ configuration = VSphereAutomation::Configuration.new.tap do |c|
306
+ c.host = config[:vcenter_host]
307
+ c.username = config[:vcenter_username]
308
+ c.password = config[:vcenter_password]
309
+ c.scheme = "https"
310
+ c.verify_ssl = config[:vcenter_disable_ssl_verify] ? false : true
311
+ c.verify_ssl_host = config[:vcenter_disable_ssl_verify] ? false : true
312
+ end
313
+
314
+ @api_client = VSphereAutomation::ApiClient.new(configuration)
315
+ api_client.default_headers["Authorization"] = configuration.basic_auth_token
316
+
317
+ session_api = VSphereAutomation::CIS::SessionApi.new(api_client)
318
+ session_id = session_api.create("").value
319
+
320
+ api_client.default_headers["vmware-api-session-id"] = session_id
365
321
  end
366
322
  end
367
323
  end
@@ -2,10 +2,11 @@ require "rbvmomi"
2
2
 
3
3
  class Support
4
4
  class CloneVm
5
- attr_reader :vim, :options
5
+ attr_reader :vim, :options, :vm, :name, :path
6
6
 
7
7
  def initialize(conn_opts, options)
8
8
  @options = options
9
+ @name = options[:name]
9
10
 
10
11
  # Connect to vSphere
11
12
  @vim ||= RbVmomi::VIM.connect conn_opts
@@ -83,7 +84,7 @@ class Support
83
84
  # @todo not working yet
84
85
  # relocate_spec.folder = dest_folder
85
86
  clone_spec = RbVmomi::VIM.VirtualMachineInstantCloneSpec(location: relocate_spec,
86
- name: options[:name])
87
+ name: name)
87
88
 
88
89
  task = src_vm.InstantClone_Task(spec: clone_spec)
89
90
  else
@@ -91,24 +92,27 @@ class Support
91
92
  powerOn: options[:poweron],
92
93
  template: false)
93
94
 
94
- task = src_vm.CloneVM_Task(spec: clone_spec, folder: dest_folder, name: options[:name])
95
+ task = src_vm.CloneVM_Task(spec: clone_spec, folder: dest_folder, name: name)
95
96
  end
96
97
  task.wait_for_completion
97
98
 
98
99
  # get the IP address of the machine for bootstrapping
99
100
  # machine name is based on the path, e.g. that includes the folder
100
- name = options[:folder].nil? ? options[:name] : format("%s/%s", options[:folder][:name], options[:name])
101
- new_vm = dc.find_vm(name)
101
+ @path = options[:folder].nil? ? name : format("%s/%s", options[:folder][:name], name)
102
+ @vm = dc.find_vm(path)
102
103
 
103
- if new_vm.nil?
104
- puts format("Unable to find machine: %s", name)
104
+ if vm.nil?
105
+ puts format("Unable to find machine: %s", path)
105
106
  else
106
107
  puts "Waiting for network interfaces to become available..."
107
- sleep 2 while new_vm.guest.net.empty? || !new_vm.guest.ipAddress
108
- new_vm.guest.net[0].ipConfig.ipAddress.detect do |addr|
109
- addr.origin != "linklayer"
110
- end.ipAddress
108
+ sleep 2 while vm.guest.net.empty? || !vm.guest.ipAddress
111
109
  end
112
110
  end
111
+
112
+ def ip
113
+ vm.guest.net[0].ipConfig.ipAddress.detect do |addr|
114
+ addr.origin != "linklayer"
115
+ end.ipAddress
116
+ end
113
117
  end
114
118
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-vcenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-12 00:00:00.000000000 Z
11
+ date: 2019-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbvmomi
@@ -58,28 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '6.6'
61
+ version: '0.1'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '6.6'
68
+ version: '0.1'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bundler
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '1.7'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '1.7'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -102,11 +102,8 @@ extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
104
  - LICENSE
105
- - lib/base.rb
106
105
  - lib/kitchen-vcenter/version.rb
107
106
  - lib/kitchen/driver/vcenter.rb
108
- - lib/lookup_service_helper.rb
109
- - lib/sso.rb
110
107
  - lib/support/clone_vm.rb
111
108
  homepage: https://github.com/chef/kitchen-vcenter
112
109
  licenses:
@@ -127,8 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
124
  - !ruby/object:Gem::Version
128
125
  version: '0'
129
126
  requirements: []
130
- rubyforge_project:
131
- rubygems_version: 2.7.6
127
+ rubygems_version: 3.0.2
132
128
  signing_key:
133
129
  specification_version: 4
134
130
  summary: Test Kitchen driver for VMare vCenter
data/lib/base.rb DELETED
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # Author:: Chef Partner Engineering (<partnereng@chef.io>)
4
- # Copyright:: Copyright (c) 2017 Chef Software, Inc.
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
- #
19
-
20
- require "logger"
21
-
22
- module Base
23
- attr_accessor :log
24
-
25
- def self.log
26
- @log ||= init_logger
27
- end
28
-
29
- def self.init_logger
30
- log = Logger.new(STDOUT)
31
- log.progname = "Knife VCenter"
32
- log.level = Logger::INFO
33
- log
34
- end
35
- end
@@ -1,464 +0,0 @@
1
- # Copyright 2014-2017 VMware, Inc. All Rights Reserved.
2
- # SPDX-License-Identifier: MIT
3
-
4
- require "savon"
5
- require "nokogiri"
6
- require "base"
7
- # require 'sample/framework/sample_base'
8
-
9
- # Utility class that helps use the lookup service.
10
- class LookupServiceHelper
11
- attr_reader :sample, :wsdl_url, :soap_url
12
- attr_reader :serviceRegistration
13
-
14
- # Constructs a new instance.
15
- # @param [Object] host the associated sample, which provides access
16
- # to the configuration properties of the sample
17
- def initialize(host)
18
- @soap_url = format("https://%s/lookupservice/sdk", host)
19
- @wsdl_url = format("https://%s/lookupservice/wsdl/lookup.wsdl", host)
20
- end
21
-
22
- # Connects to the lookup service.
23
- def connect
24
- rsc = RetrieveServiceContent.new(client).invoke
25
- @serviceRegistration = rsc.get_service_registration
26
- Base.log.info "service registration = #{serviceRegistration}"
27
- end
28
-
29
- # Finds the SSO service URL.
30
- # In a MxN setup where there are more than one PSC nodes;
31
- # This method returns the first SSO service endpoint URL
32
- # as returned by the lookup service.
33
- #
34
- # @return [String] SSO Service endpoint URL.
35
- def find_sso_url
36
- result = find_service_url(product = "com.vmware.cis",
37
- service = "cs.identity",
38
- endpoint = "com.vmware.cis.cs.identity.sso",
39
- protocol = "wsTrust")
40
- raise "SSO URL not found" unless result && result.size > 0
41
-
42
- result.values[0]
43
- end
44
-
45
- # Finds all the vAPI service endpoint URLs.
46
- # In a MxN setup where there are more than one management node;
47
- # this method returns more than one URL
48
- #
49
- # @return [Hash] vapi service endpoint URLs in a dictionary
50
- # where the key is the node_id and the value is the service URL.
51
- def find_vapi_urls
52
- find_service_url(product = "com.vmware.cis",
53
- service = "cs.vapi",
54
- endpoint = "com.vmware.vapi.endpoint",
55
- protocol = "vapi.json.https.public")
56
- end
57
-
58
- # Finds the vapi service endpoint URL of a management node.
59
- #
60
- # @param node_id [String] The UUID of the management node.
61
- # @return [String] vapi service endpoint URL of a management node or
62
- # nil if no vapi endpoint is found.
63
- def find_vapi_url(node_id)
64
- raise "node_id is required" if node_id.nil?
65
- result = find_vapi_urls()
66
- raise "VAPI URLs not found" unless result && result.size > 0
67
- result[node_id]
68
- end
69
-
70
- # Finds all the vim service endpoint URLs
71
- # In a MxN setup where there are more than one management node;
72
- # this method returns more than one URL
73
- #
74
- # @return [Hash] vim service endpoint URLs in a dictionary where
75
- # the key is the node_id and the value is the service URL.
76
- def find_vim_urls
77
- find_service_url(product = "com.vmware.cis",
78
- service = "vcenterserver",
79
- endpoint = "com.vmware.vim",
80
- protocol = "vmomi")
81
- end
82
-
83
- # Finds the vim service endpoint URL of a management node
84
- #
85
- # @param node_id [String] The UUID of the management node.
86
- # @return [String] vim service endpoint URL of a management node or
87
- # nil if no vim endpoint is found.
88
- def find_vim_url(node_id)
89
- raise "node_id is required" if node_id.nil?
90
- result = find_vim_urls()
91
- raise "VIM URLs not found" unless result && result.size > 0
92
- result[node_id]
93
- end
94
-
95
- # Finds all the spbm service endpoint URLs
96
- # In a MxN setup where there are more than one management node;
97
- # this method returns more than one URL
98
- #
99
- # @return [Hash] spbm service endpoint URLs in a dictionary where
100
- # the key is the node_id and the value is the service URL.
101
- def find_vim_pbm_urls
102
- find_service_url(product = "com.vmware.vim.sms",
103
- service = "sms",
104
- endpoint = "com.vmware.vim.pbm",
105
- protocol = "https")
106
- end
107
-
108
- # Finds the spbm service endpoint URL of a management node
109
- #
110
- # @param node_id [String] The UUID of the management node.
111
- # @return [String] spbm service endpoint URL of a management node or
112
- # nil if no spbm endpoint is found.
113
- def find_vim_pbm_url(node_id)
114
- raise "node_id is required" if node_id.nil?
115
- result = find_vim_pbm_urls()
116
- raise "PBM URLs not found" unless result && result.size > 0
117
- result[node_id]
118
- end
119
-
120
- # Get the management node id from the instance name
121
- #
122
- # @param instance_name [String] The instance name of the management node
123
- # @return [String] The UUID of the management node or
124
- # nil is no management node is found by the given instance name
125
- def get_mgmt_node_id(instance_name)
126
- raise "instance_name is required" if instance_name.nil?
127
-
128
- result = find_mgmt_nodes
129
- raise "Management nodes not found" unless result && !result.empty?
130
-
131
- result[instance_name]
132
- end
133
-
134
- def get_mgmt_node_instance_name(node_id)
135
- raise "node_id is required" if node_id.nil?
136
-
137
- result = find_mgmt_nodes
138
- raise "Management nodes not found" unless result && !result.empty?
139
-
140
- result.each { |k, v| return k if v == node_id }
141
- nil
142
- end
143
-
144
- # Finds the instance name and UUID of the management node for M1xN1 or
145
- # when the PSC and management services all reside on a single node.
146
- def get_default_mgmt_node
147
- result = find_mgmt_nodes
148
- raise "Management nodes not found" unless result && !result.empty?
149
-
150
- # WHY: raise MultipleManagementNodeException.new if result.size > 1
151
- [result.keys[0], result.values[0]]
152
- end
153
-
154
- # Finds all the management nodes
155
- #
156
- # @return [Hash] management node instance name and node id (UUID) in a dictionary.
157
- def find_mgmt_nodes
158
- # assert self.serviceRegistration is not None
159
- list = List.new(client, "com.vmware.cis", "vcenterserver",
160
- "vmomi", "com.vmware.vim")
161
-
162
- list.invoke
163
- list.get_instance_names
164
- end
165
-
166
- private
167
-
168
- # Finds a service URL with the given attributes.
169
- def find_service_url(product, service, endpoint, protocol)
170
- # assert serviceRegistration is not None
171
- list = List.new(client, product, service, protocol, endpoint)
172
-
173
- list.invoke
174
- list.get_service_endpoints
175
- end
176
-
177
- # Gets or creates the Savon client instance.
178
- def client
179
- @client ||= Savon.client do |globals|
180
- # see: http://savonrb.com/version2/globals.html
181
- globals.wsdl wsdl_url
182
- globals.endpoint soap_url
183
-
184
- globals.strip_namespaces false
185
- globals.env_namespace :S
186
-
187
- # set like this so https connection does not fail
188
- # TODO: find an acceptable solution for production
189
- globals.ssl_verify_mode :none
190
-
191
- # dev/debug settings
192
- # globals.pretty_print_xml ENV['DEBUG_SOAP']
193
- # globals.log ENV['DEBUG_SOAP']
194
- end
195
- end
196
- end
197
-
198
- # @abstract Base class for invocable service calls.
199
- class Invocable
200
- attr_reader :operation, :client, :response
201
-
202
- # Constructs a new instance.
203
- # @param operation [Symbol] the operation name
204
- # @param client [Savon::Client] the client
205
- def initialize(operation, client)
206
- @operation = operation
207
- @client = client
208
- end
209
-
210
- # Invokes the service call represented by this type.
211
- def invoke
212
- request = request_xml.to_s
213
- Base.log.debug(request)
214
- @response = client.call(operation, xml: request)
215
- Base.log.debug(response)
216
- self # for chaining with new
217
- end
218
-
219
- # Builds the request XML content.
220
- def request_xml
221
- builder = Builder::XmlMarkup.new
222
- builder.instruct!(:xml, encoding: "UTF-8")
223
-
224
- builder.tag!("S:Envelope",
225
- "xmlns:S" => "http://schemas.xmlsoap.org/soap/envelope/") do |envelope|
226
- envelope.tag!("S:Body") do |body|
227
- body_xml(body)
228
- end
229
- end
230
- builder.target!
231
- end
232
-
233
- # Builds the body portion of the request XML content.
234
- # Specific service operations must override this method.
235
- def body_xml
236
- raise "abstract method not implemented!"
237
- end
238
-
239
- # Gets the response XML content.
240
- def response_xml
241
- raise "illegal state: response not set yet" if response.nil?
242
-
243
- @response_xml ||= Nokogiri::XML(response.to_xml)
244
- end
245
-
246
- def response_hash
247
- @response_hash ||= response.to_hash
248
- end
249
- end
250
-
251
- # Encapsulates the list operation of the lookup service.
252
- class List < Invocable
253
- # Constructs a new instance.
254
- def initialize(client, product, service, protocol, endpoint)
255
- super(:list, client)
256
-
257
- @product = product
258
- @service = service
259
- @protocol = protocol
260
- @endpoint = endpoint
261
- end
262
-
263
- =begin
264
- <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
265
- <S:Body>
266
- <List xmlns="urn:lookup">
267
- <_this type="LookupServiceRegistration">ServiceRegistration</_this>
268
- <filterCriteria>
269
- <serviceType>
270
- <product>com.vmware.cis</product>
271
- <type>cs.identity</type>
272
- </serviceType>
273
- <endpointType>
274
- <protocol>wsTrust</protocol>
275
- <type>com.vmware.cis.cs.identity.sso</type>
276
- </endpointType>
277
- </filterCriteria>
278
- </List>
279
- </S:Body>
280
- </S:Envelope>
281
- =end
282
- def body_xml(body)
283
- body.tag!("List", "xmlns" => "urn:lookup") do |list|
284
- # TODO: use the copy that was retrieved on startup?
285
- list.tag!("_this",
286
- "type" => "LookupServiceRegistration") do |this|
287
- this << "ServiceRegistration"
288
- end
289
- list.tag!("filterCriteria") do |criteria|
290
- criteria.tag!("serviceType") do |stype|
291
- stype.tag!("product") do |p|
292
- p << @product
293
- end
294
- stype.tag!("type") do |t|
295
- t << @service
296
- end
297
- end
298
- criteria.tag!("endpointType") do |etype|
299
- etype.tag!("protocol") do |p|
300
- p << @protocol
301
- end
302
- etype.tag!("type") do |t|
303
- t << @endpoint
304
- end
305
- end
306
- end
307
- end
308
- end
309
-
310
- # Gets the service endpoint information from the response.
311
- # Support for MxN.
312
- # @return [Hash] a hash where the key is NodeId and the Value is a Service URL
313
- def get_service_endpoints
314
- result = {}
315
- =begin
316
- <ListResponse xmlns="urn:lookup">
317
- <returnval>
318
- <serviceVersion>2.0</serviceVersion>
319
- <vendorNameResourceKey/>
320
- <vendorNameDefault/>
321
- <vendorProductInfoResourceKey/>
322
- <vendorProductInfoDefault/>
323
- <serviceEndpoints>
324
- <url>https://pa-rdinfra3-vm7-dhcp5583.eng.vmware.com/sts/STSService/vsphere.local</url>
325
- <endpointType>
326
- <protocol>wsTrust</protocol>
327
- <type>com.vmware.cis.cs.identity.sso</type>
328
- </endpointType>
329
- <sslTrust>
330
- ...
331
- </sslTrust>
332
- </serviceEndpoints>
333
- <serviceNameResourceKey/>
334
- <serviceNameDefault/>
335
- <serviceDescriptionResourceKey/>
336
- <serviceDescriptionDefault/>
337
- <ownerId>pa-rdinfra3-vm7-dhcp5583.eng.vmware.com@vsphere.local</ownerId>
338
- <serviceType>
339
- <product>com.vmware.cis</product>
340
- <type>cs.identity</type>
341
- </serviceType>
342
- <nodeId/>
343
- <serviceId>6a8a5058-5d3d-4d42-bb5e-383b91c8732e</serviceId>
344
- <siteId>default-first-site</siteId>
345
- </returnval>
346
- </ListResponse>
347
- =end
348
- Base.log.debug "List: response_hash = #{response_hash}"
349
- return_val = response_hash[:list_response][:returnval]
350
- return_val = [return_val] if return_val.is_a? Hash
351
- return_val.each do |entry|
352
- # FYI: the node_id is sometimes null, so use the service_id in this case
353
- node_id = entry[:node_id] || entry[:service_id]
354
- result[node_id] = entry[:service_endpoints][:url]
355
- end
356
- Base.log.debug "List: result = #{result}"
357
- result
358
- end
359
-
360
- def get_instance_names
361
- result = {}
362
- =begin
363
- <serviceAttributes>
364
- <key>com.vmware.cis.cm.GroupInternalId</key>
365
- <value>com.vmware.vim.vcenter</value>
366
- </serviceAttributes>
367
- <serviceAttributes>
368
- <key>com.vmware.cis.cm.ControlScript</key>
369
- <value>vmware-vpxd.sh</value>
370
- </serviceAttributes>
371
- <serviceAttributes>
372
- <key>com.vmware.cis.cm.HostId</key>
373
- <value>906477a1-24c6-4d48-9e99-55ef962878f7</value>
374
- </serviceAttributes>
375
- <serviceAttributes>
376
- <key>com.vmware.vim.vcenter.instanceName</key>
377
- <value>pa-rdinfra3-vm7-dhcp5583.eng.vmware.com</value>
378
- </serviceAttributes>
379
- =end
380
- Base.log.debug "List: response_hash = #{response_hash}"
381
- return_val = response_hash[:list_response][:returnval]
382
- return_val = [return_val] if return_val.is_a? Hash
383
- return_val.each do |entry|
384
- node_id = entry[:node_id]
385
- # TODO: is it possible there be 0 or 1 attrs? if so, deal with it.
386
- attrs = entry[:service_attributes]
387
- Base.log.debug "List: attrs=#{attrs}"
388
- attrs.each do |attr|
389
- if attr[:key] == "com.vmware.vim.vcenter.instanceName"
390
- result[attr[:value]] = node_id
391
- end
392
- end
393
- end
394
- Base.log.debug "List: result = #{result}"
395
- result
396
- end
397
- end
398
-
399
- # Encapsulates the RetrieveServiceContent operation of the lookup service.
400
- class RetrieveServiceContent < Invocable
401
-
402
- # Constructs a new instance.
403
- def initialize(client)
404
- super(:retrieve_service_content, client)
405
- end
406
-
407
- =begin
408
- <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
409
- <S:Body>
410
- <RetrieveServiceContent xmlns="urn:lookup">
411
- <_this type="LookupServiceInstance">ServiceInstance</_this>
412
- </RetrieveServiceContent>
413
- </S:Body>
414
- </S:Envelope>
415
- =end
416
- def body_xml(body)
417
- body.tag!("RetrieveServiceContent", "xmlns" => "urn:lookup") do |rsc|
418
- rsc.tag!("_this", "type" => "LookupServiceInstance") do |this|
419
- this << "ServiceInstance"
420
- end
421
- end
422
- end
423
-
424
- =begin
425
- ...
426
- <RetrieveServiceContentResponse xmlns="urn:lookup">
427
- <returnval>
428
- <lookupService type="LookupLookupService">lookupService</lookupService>
429
- <serviceRegistration type="LookupServiceRegistration">ServiceRegistration</serviceRegistration>
430
- <deploymentInformationService type="LookupDeploymentInformationService">deploymentInformationService</deploymentInformationService>
431
- <l10n type="LookupL10n">l10n</l10n>
432
- </returnval>
433
- </RetrieveServiceContentResponse>
434
- ...
435
- =end
436
- def get_service_registration
437
- Base.log.debug "RetrieveServiceContent: response_hash = #{response_hash}"
438
- return_val = response_hash[:retrieve_service_content_response][:returnval]
439
- result = return_val[:service_registration]
440
- Base.log.debug "RetrieveServiceContent: result = #{result}"
441
- result
442
- end
443
- end
444
-
445
- class MultipleManagementNodeException < RuntimeError
446
- end
447
-
448
- # main: quick self tester
449
- if __FILE__ == $0
450
- Base.log.level = Logger::DEBUG if ENV["DEBUG"]
451
- sample = SelfTestSample.new
452
- sample.ls_ip = ARGV[0] || "10.67.245.207"
453
- # MXN: sample.ls_ip = '10.160.42.83'
454
- # MXN: sample.ls_ip = '10.160.35.191'
455
- # MAYBE: sample.main() # for arg parsing
456
- ls_helper = LookupServiceHelper.new(sample)
457
- ls_helper.connect
458
- puts "***************************************"
459
- puts "SSO URL: #{ls_helper.find_sso_url}"
460
- puts "VAPI URL: #{ls_helper.find_vapi_urls}"
461
- puts "VIM URL: #{ls_helper.find_vim_urls}"
462
- puts "PBM URL: #{ls_helper.find_vim_pbm_urls}"
463
- puts "Mgmt Nodes: #{ls_helper.find_mgmt_nodes}"
464
- end
data/lib/sso.rb DELETED
@@ -1,268 +0,0 @@
1
- # Copyright 2014-2017 VMware, Inc. All Rights Reserved.
2
- # SPDX-License-Identifier: MIT
3
-
4
- require "savon"
5
- require "nokogiri"
6
- require "date"
7
- require "securerandom"
8
-
9
- # A little utility library for VMware SSO.
10
- # For now, this is not a general purpose library that covers all
11
- # the interfaces of the SSO service.
12
- # Specifically, the support is limited to the following:
13
- # * request bearer token.
14
- module SSO
15
- # The XML date format.
16
- DATE_FORMAT = "%FT%T.%LZ".freeze
17
-
18
- # The XML namespaces that are required: SOAP, WSDL, et al.
19
- NAMESPACES = {
20
- "xmlns:S" => "http://schemas.xmlsoap.org/soap/envelope/",
21
- "xmlns:wst" => "http://docs.oasis-open.org/ws-sx/ws-trust/200512",
22
- "xmlns:u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
23
- "xmlns:x" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
24
- }.freeze
25
-
26
- # Provides the connection details for the SSO service.
27
- class Connection
28
- attr_accessor :sso_url, :wsdl_url, :username, :password
29
-
30
- # Creates a new instance.
31
- def initialize(sso_url, wsdl_url = nil)
32
- self.sso_url = sso_url
33
- self.wsdl_url = wsdl_url || "#{sso_url}?wsdl"
34
- end
35
-
36
- # Login with the given credentials.
37
- # Note: this does not invoke a login action, but rather stores the
38
- # credentials for use later.
39
- def login(username, password)
40
- self.username = username
41
- self.password = password
42
- self # enable builder pattern
43
- end
44
-
45
- # Gets (or creates) the Savon client instance.
46
- def client
47
- # construct and init the client proxy
48
- @client ||= Savon.client do |globals|
49
- # see: http://savonrb.com/version2/globals.html
50
- globals.wsdl wsdl_url
51
- globals.endpoint sso_url
52
-
53
- globals.strip_namespaces false
54
- globals.env_namespace :S
55
-
56
- # set like this so https connection does not fail
57
- # TODO: find an acceptable solution for production
58
- globals.ssl_verify_mode :none
59
-
60
- # dev/debug settings
61
- # globals.pretty_print_xml ENV['DEBUG_SOAP']
62
- # globals.log ENV['DEBUG_SOAP']
63
- end
64
- end
65
-
66
- # Invokes the request bearer token operation.
67
- # @return [SamlToken]
68
- def request_bearer_token
69
- rst = RequestSecurityToken.new(client, username, password)
70
- rst.invoke
71
- rst.saml_token
72
- end
73
- end
74
-
75
- # @abstract Base class for invocable service calls.
76
- class SoapInvocable
77
- attr_reader :operation, :client, :response
78
-
79
- # Constructs a new instance.
80
- # @param operation [Symbol] the SOAP operation name (in Symbol form)
81
- # @param client [Savon::Client] the client
82
- def initialize(operation, client)
83
- @operation = operation
84
- @client = client
85
- end
86
-
87
- # Invokes the service call represented by this type.
88
- def invoke
89
- request = request_xml.to_s
90
- puts "request = #{request}" if ENV["DEBUG"]
91
- @response = client.call(operation, xml: request)
92
- puts "response = #{response}" if ENV["DEBUG"]
93
- self # for chaining with new
94
- end
95
-
96
- # Builds the request XML content.
97
- def request_xml
98
- builder = Builder::XmlMarkup.new
99
- builder.instruct!(:xml, encoding: "UTF-8")
100
-
101
- builder.tag!("S:Envelope", NAMESPACES) do |envelope|
102
- if has_header?
103
- envelope.tag!("S:Header") do |header|
104
- header_xml(header)
105
- end
106
- end
107
- envelope.tag!("S:Body") do |body|
108
- body_xml(body)
109
- end
110
- end
111
- builder.target!
112
- end
113
-
114
- def has_header?
115
- true
116
- end
117
-
118
- # Builds the header portion of the SOAP request.
119
- # Specific service operations must override this method.
120
- def header_xml(_header)
121
- raise "abstract method not implemented!"
122
- end
123
-
124
- # Builds the body portion of the SOAP request.
125
- # Specific service operations must override this method.
126
- def body_xml(_body)
127
- raise "abstract method not implemented!"
128
- end
129
-
130
- # Gets the response XML content.
131
- def response_xml
132
- raise "illegal state: response not set yet" if response.nil?
133
-
134
- @response_xml ||= Nokogiri::XML(response.to_xml)
135
- end
136
-
137
- def response_hash
138
- @response_hash ||= response.to_hash
139
- end
140
- end
141
-
142
- # Encapsulates an issue operation that requests a security token
143
- # from the SSO service.
144
- class RequestSecurityToken < SoapInvocable
145
-
146
- attr_accessor :request_type, :delegatable
147
-
148
- # Constructs a new instance.
149
- def initialize(client, username, password, hours = 2)
150
- super(:issue, client)
151
-
152
- @username = username
153
- @password = password
154
- @hours = hours
155
-
156
- # TODO: these things should be configurable, so we can get
157
- # non-delegatable tokens, HoK tokens, etc.
158
- @request_type = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue"
159
- @delegatable = true
160
- end
161
-
162
- def now
163
- @now ||= Time.now.utc.to_datetime
164
- end
165
-
166
- def created
167
- @created ||= now.strftime(DATE_FORMAT)
168
- end
169
-
170
- def future
171
- @future ||= now + (2 / 24.0) # days (for DateTime math)
172
- end
173
-
174
- def expires
175
- @expires ||= future.strftime(DATE_FORMAT)
176
- end
177
-
178
- # Builds the header XML for the SOAP request.
179
- def header_xml(header)
180
- id = "uuid-" + SecureRandom.uuid
181
-
182
- # header.tag!("x:Security", "x:mustUnderstand" => "1") do |security|
183
- header.tag!("x:Security") do |security|
184
- security.tag!("u:Timestamp", "u:Id" => "_0") do |timestamp|
185
- timestamp.tag!("u:Created") do |element|
186
- element << created
187
- end
188
- timestamp.tag!("u:Expires") do |element|
189
- element << expires
190
- end
191
- end
192
-
193
- security.tag!("x:UsernameToken", "u:Id" => id) do |utoken|
194
- utoken.tag!("x:Username") do |element|
195
- element << @username
196
- end
197
- utoken.tag!("x:Password") do |element|
198
- element << @password
199
- end
200
- end
201
- end
202
- end
203
-
204
- # Builds the body XML for the SOAP request.
205
- def body_xml(body)
206
- body.tag!("wst:RequestSecurityToken") do |rst|
207
- rst.tag!("wst:RequestType") do |element|
208
- element << request_type
209
- end
210
- rst.tag!("wst:Delegatable") do |element|
211
- element << delegatable.to_s
212
- end
213
- =begin
214
- #TODO: we don't seem to need this, but I'm leaving this
215
- #here for now as a reminder.
216
- rst.tag!("wst:Lifetime") do |lifetime|
217
- lifetime.tag!("u:Created") do |element|
218
- element << created
219
- end
220
- lifetime.tag!("u:Expires") do |element|
221
- element << expires
222
- end
223
- end
224
- =end
225
- end
226
- end
227
-
228
- # Gets the saml_token from the SOAP response body.
229
- # @return [SamlToken] the requested SAML token
230
- def saml_token
231
- assertion = response_xml.at_xpath("//saml2:Assertion",
232
- "saml2" => "urn:oasis:names:tc:SAML:2.0:assertion")
233
- SamlToken.new(assertion)
234
- end
235
- end
236
-
237
- # Holds a SAML token.
238
- class SamlToken
239
- attr_reader :xml
240
-
241
- # Creates a new instance.
242
- def initialize(xml)
243
- @xml = xml
244
- end
245
-
246
- # TODO: add some getters for interesting content
247
-
248
- def to_s
249
- esc_token = xml.to_xml(indent: 0, encoding: "UTF-8")
250
- esc_token = esc_token.delete("\n")
251
- esc_token
252
- end
253
- end
254
- end
255
-
256
- # main: quick self tester
257
- if __FILE__ == $0
258
- cloudvm_ip = ARGV[0]
259
- cloudvm_ip ||= "10.20.17.0"
260
- # cloudvm_ip ||= "10.67.245.207"
261
- sso_url = "https://#{cloudvm_ip}/sts/STSService/vsphere.local"
262
- wsdl_url = "#{sso_url}?wsdl"
263
- sso = SSO::Connection.new(sso_url, wsdl_url)
264
- # sso.login("administrator@vsphere.local", "Admin!23")
265
- sso.login("root", "vmware")
266
- token = sso.request_bearer_token
267
- puts token.to_s
268
- end