knife-vcenter 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/{LICENSE.txt → LICENSE} +0 -0
- data/lib/base.rb +8 -3
- data/lib/chef/knife/cloud/vcenter_service.rb +117 -81
- data/lib/chef/knife/cloud/vcenter_service_helpers.rb +15 -3
- data/lib/chef/knife/cloud/vcenter_service_options.rb +18 -17
- data/lib/chef/knife/vcenter_cluster_list.rb +19 -13
- data/lib/chef/knife/vcenter_datacenter_list.rb +19 -13
- data/lib/chef/knife/vcenter_host_list.rb +28 -19
- data/lib/chef/knife/vcenter_vm_clone.rb +39 -28
- data/lib/chef/knife/vcenter_vm_create.rb +26 -21
- data/lib/chef/knife/vcenter_vm_delete.rb +15 -10
- data/lib/chef/knife/vcenter_vm_list.rb +31 -21
- data/lib/chef/knife/vcenter_vm_show.rb +12 -13
- data/lib/knife-vcenter/version.rb +4 -2
- data/lib/lookup_service_helper.rb +421 -427
- data/lib/sso.rb +213 -218
- data/lib/support/clone_vm.rb +4 -4
- data/spec/spec_helper.rb +2 -2
- data/spec/unit/vcenter_vm_list_spec.rb +21 -22
- metadata +6 -58
- data/.github/ISSUE_TEMPLATE.md +0 -22
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -14
- data/.gitignore +0 -21
- data/.rubocop.yml +0 -18
- data/.travis.yml +0 -16
- data/CHANGELOG.md +0 -34
- data/Gemfile +0 -3
- data/README.md +0 -219
- data/Rakefile +0 -20
- data/knife-vcenter.gemspec +0 -37
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
4
|
-
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
|
4
|
+
# Copyright:: Copyright (c) 2017-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,31 +17,36 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
25
|
-
require
|
20
|
+
require "chef/knife"
|
21
|
+
require "chef/knife/cloud/server/delete_options"
|
22
|
+
require "chef/knife/cloud/server/delete_command"
|
23
|
+
require "chef/knife/cloud/vcenter_service"
|
24
|
+
require "chef/knife/cloud/vcenter_service_helpers"
|
25
|
+
require "chef/knife/cloud/vcenter_service_options"
|
26
26
|
|
27
27
|
class Chef
|
28
28
|
class Knife
|
29
29
|
class Cloud
|
30
|
+
# Extends the SeverDeleteCommand for specifically vCenter
|
30
31
|
class VcenterVmDelete < ServerDeleteCommand
|
31
32
|
include ServerDeleteOptions
|
32
33
|
include VcenterServiceOptions
|
33
34
|
include VcenterServiceHelpers
|
34
35
|
|
35
|
-
banner
|
36
|
+
banner "knife vcenter vm delete NAME [NAME] (options)"
|
36
37
|
|
37
38
|
# rubocop:disable Style/GuardClause
|
39
|
+
# Validates the parameters to make sure we're good.
|
40
|
+
#
|
38
41
|
def validate_params!
|
39
42
|
if @name_args.empty?
|
40
|
-
ui.error(
|
43
|
+
ui.error("You must supply the name of the virtual machine to delete.")
|
41
44
|
exit(1) if @name_args.empty?
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
48
|
+
# Executes the command against vCenter and the Chef Server
|
49
|
+
#
|
45
50
|
def execute_command
|
46
51
|
@name_args.each do |name|
|
47
52
|
service.delete_vm(name)
|
@@ -51,4 +56,4 @@ class Chef
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
end
|
54
|
-
end
|
59
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
4
|
-
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
|
4
|
+
# Copyright:: Copyright (c) 2017-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,50 +17,60 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
25
|
-
require
|
20
|
+
require "chef/knife"
|
21
|
+
require "chef/knife/cloud/server/list_command"
|
22
|
+
require "chef/knife/cloud/server/list_options"
|
23
|
+
require "chef/knife/cloud/vcenter_service"
|
24
|
+
require "chef/knife/cloud/vcenter_service_helpers"
|
25
|
+
require "chef/knife/cloud/vcenter_service_options"
|
26
26
|
|
27
27
|
class Chef
|
28
|
+
# The main knife class
|
28
29
|
class Knife
|
30
|
+
# The main cloud class from knife-cloud
|
29
31
|
class Cloud
|
32
|
+
# Extends the ServerListCommand for specific vCenter
|
30
33
|
class VcenterVmList < Chef::Knife::Cloud::ServerListCommand
|
31
34
|
include VcenterServiceHelpers
|
32
35
|
include VcenterServiceOptions
|
33
36
|
|
34
|
-
banner
|
37
|
+
banner "knife vcenter vm list"
|
35
38
|
|
39
|
+
# Sets up the columns for listing out and sorts by name
|
40
|
+
#
|
36
41
|
def before_exec_command
|
37
42
|
@columns_with_info = [
|
38
|
-
{ label:
|
39
|
-
{ label:
|
40
|
-
{ label:
|
41
|
-
{ label:
|
42
|
-
{ label:
|
43
|
+
{ label: "ID", key: "vm" },
|
44
|
+
{ label: "Name", key: "name" },
|
45
|
+
{ label: "Power State", key: "power_state", value_callback: method(:format_power_status) },
|
46
|
+
{ label: "CPU Count", key: "cpu_count" },
|
47
|
+
{ label: "RAM Size (MB)", key: "memory_size_MiB", value_callback: method(:format_memory_value) }
|
43
48
|
]
|
44
49
|
|
45
|
-
@sort_by_field =
|
50
|
+
@sort_by_field = "name"
|
46
51
|
end
|
47
52
|
|
53
|
+
# Sets the color for the different status of the machines
|
54
|
+
#
|
48
55
|
def format_power_status(status)
|
49
56
|
status_check = status.value
|
50
57
|
status_color = case status_check
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
when "POWERED_OFF"
|
59
|
+
:red
|
60
|
+
when "POWERED_ON"
|
61
|
+
:green
|
62
|
+
when "SUSPENDED"
|
63
|
+
:yellow
|
57
64
|
end
|
58
65
|
|
59
66
|
ui.color(status.value, status_color)
|
60
67
|
end
|
61
68
|
|
69
|
+
# Formats the memory value
|
70
|
+
#
|
71
|
+
# @param [Object] value takes the number and formats it how you need it to
|
62
72
|
def format_memory_value(value)
|
63
|
-
value.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse
|
73
|
+
value.to_s.reverse.gsub(/...(?=.)/, '\&,').reverse
|
64
74
|
end
|
65
75
|
end
|
66
76
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
4
|
-
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
|
4
|
+
# Copyright:: Copyright (c) 2017-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,32 +17,31 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
25
|
-
require
|
20
|
+
require "chef/knife"
|
21
|
+
require "chef/knife/cloud/server/show_options"
|
22
|
+
require "chef/knife/cloud/server/show_command"
|
23
|
+
require "chef/knife/cloud/vcenter_service"
|
24
|
+
require "chef/knife/cloud/vcenter_service_helpers"
|
25
|
+
require "chef/knife/cloud/vcenter_service_options"
|
26
26
|
|
27
27
|
class Chef
|
28
28
|
class Knife
|
29
29
|
class Cloud
|
30
|
+
# Extends the SeverShowCommand to do specific things for vCenter
|
30
31
|
class VcenterVmShow < ServerShowCommand
|
31
32
|
include ServerShowOptions
|
32
33
|
include VcenterServiceOptions
|
33
34
|
include VcenterServiceHelpers
|
34
35
|
|
35
|
-
banner
|
36
|
-
|
37
|
-
# rubocop:disable Style/GuardClause
|
36
|
+
banner "knife vcenter vm show NAME (options)"
|
38
37
|
def validate_params!
|
39
38
|
if @name_args.empty?
|
40
|
-
ui.error(
|
39
|
+
ui.error("You must supply the name of the virtual machine to display.")
|
41
40
|
exit(1) if @name_args.empty?
|
42
41
|
end
|
43
42
|
|
44
43
|
if @name_args.size > 1
|
45
|
-
ui.error(
|
44
|
+
ui.error("You may only supply one virtual machine name")
|
46
45
|
exit 1
|
47
46
|
end
|
48
47
|
|
@@ -51,4 +50,4 @@ class Chef
|
|
51
50
|
end
|
52
51
|
end
|
53
52
|
end
|
54
|
-
end
|
53
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
4
|
-
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
|
4
|
+
# Copyright:: Copyright (c) 2017-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,6 +17,8 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
+
# Provisions machines in vCenter
|
20
21
|
module KnifeVcenter
|
21
|
-
|
22
|
+
# The version of this amazing Gem, you should <3 it.
|
23
|
+
VERSION = "2.0.1"
|
22
24
|
end
|
@@ -1,463 +1,457 @@
|
|
1
1
|
# Copyright 2014-2017 VMware, Inc. All Rights Reserved.
|
2
2
|
# SPDX-License-Identifier: MIT
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
4
|
+
require "savon"
|
5
|
+
require "nokogiri"
|
6
|
+
require "base"
|
7
7
|
# require 'sample/framework/sample_base'
|
8
8
|
|
9
9
|
# Utility class that helps use the lookup service.
|
10
10
|
class LookupServiceHelper
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
#
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
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.empty?
|
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
|
+
|
66
|
+
result = find_vapi_urls
|
67
|
+
raise "VAPI URLs not found" unless result && !result.empty?
|
68
|
+
|
69
|
+
result[node_id]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Finds all the vim service endpoint URLs
|
73
|
+
# In a MxN setup where there are more than one management node;
|
74
|
+
# this method returns more than one URL
|
75
|
+
#
|
76
|
+
# @return [Hash] vim service endpoint URLs in a dictionary where
|
77
|
+
# the key is the node_id and the value is the service URL.
|
78
|
+
def find_vim_urls
|
79
|
+
find_service_url(product = "com.vmware.cis",
|
80
|
+
service = "vcenterserver",
|
81
|
+
endpoint = "com.vmware.vim",
|
82
|
+
protocol = "vmomi")
|
83
|
+
end
|
84
|
+
|
85
|
+
# Finds the vim service endpoint URL of a management node
|
86
|
+
#
|
87
|
+
# @param node_id [String] The UUID of the management node.
|
88
|
+
# @return [String] vim service endpoint URL of a management node or
|
89
|
+
# nil if no vim endpoint is found.
|
90
|
+
def find_vim_url(node_id)
|
91
|
+
raise "node_id is required" if node_id.nil?
|
92
|
+
|
93
|
+
result = find_vim_urls
|
94
|
+
raise "VIM URLs not found" unless result && !result.empty?
|
95
|
+
|
96
|
+
result[node_id]
|
97
|
+
end
|
98
|
+
|
99
|
+
# Finds all the spbm service endpoint URLs
|
100
|
+
# In a MxN setup where there are more than one management node;
|
101
|
+
# this method returns more than one URL
|
102
|
+
#
|
103
|
+
# @return [Hash] spbm service endpoint URLs in a dictionary where
|
104
|
+
# the key is the node_id and the value is the service URL.
|
105
|
+
def find_vim_pbm_urls
|
106
|
+
find_service_url(product = "com.vmware.vim.sms",
|
107
|
+
service = "sms",
|
108
|
+
endpoint = "com.vmware.vim.pbm",
|
109
|
+
protocol = "https")
|
110
|
+
end
|
111
|
+
|
112
|
+
# Finds the spbm service endpoint URL of a management node
|
113
|
+
#
|
114
|
+
# @param node_id [String] The UUID of the management node.
|
115
|
+
# @return [String] spbm service endpoint URL of a management node or
|
116
|
+
# nil if no spbm endpoint is found.
|
117
|
+
def find_vim_pbm_url(node_id)
|
118
|
+
raise "node_id is required" if node_id.nil?
|
119
|
+
|
120
|
+
result = find_vim_pbm_urls
|
121
|
+
raise "PBM URLs not found" unless result && !result.empty?
|
122
|
+
|
123
|
+
result[node_id]
|
124
|
+
end
|
125
|
+
|
126
|
+
# Get the management node id from the instance name
|
127
|
+
#
|
128
|
+
# @param instance_name [String] The instance name of the management node
|
129
|
+
# @return [String] The UUID of the management node or
|
130
|
+
# nil is no management node is found by the given instance name
|
131
|
+
def get_mgmt_node_id(instance_name)
|
132
|
+
raise "instance_name is required" if instance_name.nil?
|
133
|
+
result = find_mgmt_nodes()
|
134
|
+
raise "Management nodes not found" unless result && result.size > 0
|
135
|
+
result[instance_name]
|
136
|
+
end
|
137
|
+
|
138
|
+
def get_mgmt_node_instance_name(node_id)
|
139
|
+
raise "node_id is required" if node_id.nil?
|
140
|
+
|
141
|
+
result = find_mgmt_nodes
|
142
|
+
raise "Management nodes not found" unless result && !result.empty?
|
143
|
+
|
144
|
+
result.each { |k, v| return k if v == node_id }
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
|
148
|
+
# Finds the instance name and UUID of the management node for M1xN1 or
|
149
|
+
# when the PSC and management services all reside on a single node.
|
150
|
+
def get_default_mgmt_node
|
151
|
+
result = find_mgmt_nodes
|
152
|
+
raise "Management nodes not found" unless result && !result.empty?
|
153
|
+
|
154
|
+
# WHY: raise MultipleManagementNodeException.new if result.size > 1
|
155
|
+
[result.keys[0], result.values[0]]
|
156
|
+
end
|
157
|
+
|
158
|
+
# Finds all the management nodes
|
159
|
+
#
|
160
|
+
# @return [Hash] management node instance name and node id (UUID) in a dictionary.
|
161
|
+
def find_mgmt_nodes
|
162
|
+
# assert self.serviceRegistration is not None
|
163
|
+
list = List.new(client, "com.vmware.cis", "vcenterserver",
|
164
|
+
"vmomi", "com.vmware.vim")
|
165
|
+
|
166
|
+
list.invoke
|
167
|
+
list.get_instance_names
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
# Finds a service URL with the given attributes.
|
173
|
+
def find_service_url(product, service, endpoint, protocol)
|
174
|
+
# assert serviceRegistration is not None
|
175
|
+
list = List.new(client, product, service, protocol, endpoint)
|
176
|
+
|
177
|
+
list.invoke
|
178
|
+
list.get_service_endpoints
|
179
|
+
end
|
180
|
+
|
181
|
+
# Gets or creates the Savon client instance.
|
182
|
+
def client
|
183
|
+
@client ||= Savon.client do |globals|
|
184
|
+
# see: http://savonrb.com/version2/globals.html
|
185
|
+
globals.wsdl wsdl_url
|
186
|
+
globals.endpoint soap_url
|
187
|
+
|
188
|
+
globals.strip_namespaces false
|
189
|
+
globals.env_namespace :S
|
190
|
+
|
191
|
+
# set like this so https connection does not fail
|
192
|
+
# TODO: find an acceptable solution for production
|
193
|
+
globals.ssl_verify_mode :none
|
194
|
+
|
195
|
+
# dev/debug settings
|
196
|
+
# globals.pretty_print_xml ENV['DEBUG_SOAP']
|
197
|
+
# globals.log ENV['DEBUG_SOAP']
|
192
198
|
end
|
199
|
+
end
|
193
200
|
end
|
194
201
|
|
195
|
-
|
196
202
|
# @abstract Base class for invocable service calls.
|
197
203
|
class Invocable
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
204
|
+
attr_reader :operation, :client, :response
|
205
|
+
|
206
|
+
# Constructs a new instance.
|
207
|
+
# @param operation [Symbol] the operation name
|
208
|
+
# @param client [Savon::Client] the client
|
209
|
+
def initialize(operation, client)
|
210
|
+
@operation = operation
|
211
|
+
@client = client
|
212
|
+
end
|
213
|
+
|
214
|
+
# Invokes the service call represented by this type.
|
215
|
+
def invoke
|
216
|
+
request = request_xml.to_s
|
217
|
+
Base.log.debug(request)
|
218
|
+
@response = client.call(operation, xml: request)
|
219
|
+
Base.log.debug(response)
|
220
|
+
self # for chaining with new
|
221
|
+
end
|
222
|
+
|
223
|
+
# Builds the request XML content.
|
224
|
+
def request_xml
|
225
|
+
builder = Builder::XmlMarkup.new
|
226
|
+
builder.instruct!(:xml, encoding: "UTF-8")
|
227
|
+
|
228
|
+
builder.tag!("S:Envelope",
|
229
|
+
"xmlns:S" => "http://schemas.xmlsoap.org/soap/envelope/") do |envelope|
|
230
|
+
envelope.tag!("S:Body") do |body|
|
231
|
+
body_xml(body)
|
232
|
+
end
|
216
233
|
end
|
234
|
+
builder.target!
|
235
|
+
end
|
217
236
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
builder.tag!("S:Envelope",
|
224
|
-
"xmlns:S" => "http://schemas.xmlsoap.org/soap/envelope/") do |envelope|
|
225
|
-
envelope.tag!("S:Body") do |body|
|
226
|
-
body_xml(body)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
builder.target!
|
230
|
-
end
|
237
|
+
# Builds the body portion of the request XML content.
|
238
|
+
# Specific service operations must override this method.
|
239
|
+
def body_xml
|
240
|
+
raise "abstract method not implemented!"
|
241
|
+
end
|
231
242
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
raise 'abstract method not implemented!'
|
236
|
-
end
|
243
|
+
# Gets the response XML content.
|
244
|
+
def response_xml
|
245
|
+
raise "illegal state: response not set yet" if response.nil?
|
237
246
|
|
238
|
-
|
239
|
-
|
240
|
-
raise 'illegal state: response not set yet' if response.nil?
|
241
|
-
@response_xml ||= Nokogiri::XML(response.to_xml)
|
242
|
-
end
|
247
|
+
@response_xml ||= Nokogiri::XML(response.to_xml)
|
248
|
+
end
|
243
249
|
|
244
|
-
|
245
|
-
|
246
|
-
|
250
|
+
def response_hash
|
251
|
+
@response_hash ||= response.to_hash
|
252
|
+
end
|
247
253
|
end
|
248
254
|
|
249
255
|
# Encapsulates the list operation of the lookup service.
|
250
256
|
class List < Invocable
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
etype.tag!("type") do |t|
|
302
|
-
t << @endpoint
|
303
|
-
end
|
304
|
-
end
|
305
|
-
end
|
257
|
+
# Constructs a new instance.
|
258
|
+
def initialize(client, product, service, protocol, endpoint)
|
259
|
+
super(:list, client)
|
260
|
+
|
261
|
+
@product = product
|
262
|
+
@service = service
|
263
|
+
@protocol = protocol
|
264
|
+
@endpoint = endpoint
|
265
|
+
end
|
266
|
+
|
267
|
+
# <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
|
268
|
+
# <S:Body>
|
269
|
+
# <List xmlns="urn:lookup">
|
270
|
+
# <_this type="LookupServiceRegistration">ServiceRegistration</_this>
|
271
|
+
# <filterCriteria>
|
272
|
+
# <serviceType>
|
273
|
+
# <product>com.vmware.cis</product>
|
274
|
+
# <type>cs.identity</type>
|
275
|
+
# </serviceType>
|
276
|
+
# <endpointType>
|
277
|
+
# <protocol>wsTrust</protocol>
|
278
|
+
# <type>com.vmware.cis.cs.identity.sso</type>
|
279
|
+
# </endpointType>
|
280
|
+
# </filterCriteria>
|
281
|
+
# </List>
|
282
|
+
# </S:Body>
|
283
|
+
# </S:Envelope>
|
284
|
+
def body_xml(body)
|
285
|
+
body.tag!("List", "xmlns" => "urn:lookup") do |list|
|
286
|
+
# TODO: use the copy that was retrieved on startup?
|
287
|
+
list.tag!("_this",
|
288
|
+
"type" => "LookupServiceRegistration") do |this|
|
289
|
+
this << "ServiceRegistration"
|
290
|
+
end
|
291
|
+
list.tag!("filterCriteria") do |criteria|
|
292
|
+
criteria.tag!("serviceType") do |stype|
|
293
|
+
stype.tag!("product") do |p|
|
294
|
+
p << @product
|
295
|
+
end
|
296
|
+
stype.tag!("type") do |t|
|
297
|
+
t << @service
|
298
|
+
end
|
299
|
+
end
|
300
|
+
criteria.tag!("endpointType") do |etype|
|
301
|
+
etype.tag!("protocol") do |p|
|
302
|
+
p << @protocol
|
303
|
+
end
|
304
|
+
etype.tag!("type") do |t|
|
305
|
+
t << @endpoint
|
306
|
+
end
|
306
307
|
end
|
308
|
+
end
|
307
309
|
end
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
=
|
315
|
-
<ListResponse xmlns="urn:lookup">
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
</ListResponse>
|
346
|
-
=
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
result[node_id] = entry[:service_endpoints][:url]
|
354
|
-
}
|
355
|
-
Base.log.debug "List: result = #{result}"
|
356
|
-
return result
|
310
|
+
end
|
311
|
+
|
312
|
+
# Gets the service endpoint information from the response.
|
313
|
+
# Support for MxN.
|
314
|
+
# @return [Hash] a hash where the key is NodeId and the Value is a Service URL
|
315
|
+
def get_service_endpoints
|
316
|
+
result = {}
|
317
|
+
# <ListResponse xmlns="urn:lookup">
|
318
|
+
# <returnval>
|
319
|
+
# <serviceVersion>2.0</serviceVersion>
|
320
|
+
# <vendorNameResourceKey/>
|
321
|
+
# <vendorNameDefault/>
|
322
|
+
# <vendorProductInfoResourceKey/>
|
323
|
+
# <vendorProductInfoDefault/>
|
324
|
+
# <serviceEndpoints>
|
325
|
+
# <url>https://pa-rdinfra3-vm7-dhcp5583.eng.vmware.com/sts/STSService/vsphere.local</url>
|
326
|
+
# <endpointType>
|
327
|
+
# <protocol>wsTrust</protocol>
|
328
|
+
# <type>com.vmware.cis.cs.identity.sso</type>
|
329
|
+
# </endpointType>
|
330
|
+
# <sslTrust>
|
331
|
+
# ...
|
332
|
+
# </sslTrust>
|
333
|
+
# </serviceEndpoints>
|
334
|
+
# <serviceNameResourceKey/>
|
335
|
+
# <serviceNameDefault/>
|
336
|
+
# <serviceDescriptionResourceKey/>
|
337
|
+
# <serviceDescriptionDefault/>
|
338
|
+
# <ownerId>pa-rdinfra3-vm7-dhcp5583.eng.vmware.com@vsphere.local</ownerId>
|
339
|
+
# <serviceType>
|
340
|
+
# <product>com.vmware.cis</product>
|
341
|
+
# <type>cs.identity</type>
|
342
|
+
# </serviceType>
|
343
|
+
# <nodeId/>
|
344
|
+
# <serviceId>6a8a5058-5d3d-4d42-bb5e-383b91c8732e</serviceId>
|
345
|
+
# <siteId>default-first-site</siteId>
|
346
|
+
# </returnval>
|
347
|
+
# </ListResponse>
|
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]
|
357
355
|
end
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
Base.log.debug "List: result = #{result}"
|
394
|
-
return result
|
356
|
+
Base.log.debug "List: result = #{result}"
|
357
|
+
result
|
358
|
+
end
|
359
|
+
|
360
|
+
def get_instance_names
|
361
|
+
result = {}
|
362
|
+
# <serviceAttributes>
|
363
|
+
# <key>com.vmware.cis.cm.GroupInternalId</key>
|
364
|
+
# <value>com.vmware.vim.vcenter</value>
|
365
|
+
# </serviceAttributes>
|
366
|
+
# <serviceAttributes>
|
367
|
+
# <key>com.vmware.cis.cm.ControlScript</key>
|
368
|
+
# <value>vmware-vpxd.sh</value>
|
369
|
+
# </serviceAttributes>
|
370
|
+
# <serviceAttributes>
|
371
|
+
# <key>com.vmware.cis.cm.HostId</key>
|
372
|
+
# <value>906477a1-24c6-4d48-9e99-55ef962878f7</value>
|
373
|
+
# </serviceAttributes>
|
374
|
+
# <serviceAttributes>
|
375
|
+
# <key>com.vmware.vim.vcenter.instanceName</key>
|
376
|
+
# <value>pa-rdinfra3-vm7-dhcp5583.eng.vmware.com</value>
|
377
|
+
# </serviceAttributes>
|
378
|
+
Base.log.debug "List: response_hash = #{response_hash}"
|
379
|
+
return_val = response_hash[:list_response][:returnval]
|
380
|
+
return_val = [return_val] if return_val.is_a? Hash
|
381
|
+
return_val.each do |entry|
|
382
|
+
node_id = entry[:node_id]
|
383
|
+
# TODO: is it possible there be 0 or 1 attrs? if so, deal with it.
|
384
|
+
attrs = entry[:service_attributes]
|
385
|
+
Base.log.debug "List: attrs=#{attrs}"
|
386
|
+
attrs.each do |attr|
|
387
|
+
if attr[:key] == "com.vmware.vim.vcenter.instanceName"
|
388
|
+
result[attr[:value]] = node_id
|
389
|
+
end
|
390
|
+
end
|
395
391
|
end
|
392
|
+
Base.log.debug "List: result = #{result}"
|
393
|
+
result
|
394
|
+
end
|
396
395
|
end
|
397
396
|
|
398
397
|
# Encapsulates the RetrieveServiceContent operation of the lookup service.
|
399
398
|
class RetrieveServiceContent < Invocable
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
rsc.tag!("_this", "type" => "LookupServiceInstance") do |this|
|
418
|
-
this << "ServiceInstance"
|
419
|
-
end
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
=begin
|
424
|
-
...
|
425
|
-
<RetrieveServiceContentResponse xmlns="urn:lookup">
|
426
|
-
<returnval>
|
427
|
-
<lookupService type="LookupLookupService">lookupService</lookupService>
|
428
|
-
<serviceRegistration type="LookupServiceRegistration">ServiceRegistration</serviceRegistration>
|
429
|
-
<deploymentInformationService type="LookupDeploymentInformationService">deploymentInformationService</deploymentInformationService>
|
430
|
-
<l10n type="LookupL10n">l10n</l10n>
|
431
|
-
</returnval>
|
432
|
-
</RetrieveServiceContentResponse>
|
433
|
-
...
|
434
|
-
=end
|
435
|
-
def get_service_registration
|
436
|
-
Base.log.debug "RetrieveServiceContent: response_hash = #{response_hash}"
|
437
|
-
return_val = response_hash[:retrieve_service_content_response][:returnval]
|
438
|
-
result = return_val[:service_registration]
|
439
|
-
Base.log.debug "RetrieveServiceContent: result = #{result}"
|
440
|
-
result
|
399
|
+
# Constructs a new instance.
|
400
|
+
def initialize(client)
|
401
|
+
super(:retrieve_service_content, client)
|
402
|
+
end
|
403
|
+
|
404
|
+
# <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
|
405
|
+
# <S:Body>
|
406
|
+
# <RetrieveServiceContent xmlns="urn:lookup">
|
407
|
+
# <_this type="LookupServiceInstance">ServiceInstance</_this>
|
408
|
+
# </RetrieveServiceContent>
|
409
|
+
# </S:Body>
|
410
|
+
# </S:Envelope>
|
411
|
+
def body_xml(body)
|
412
|
+
body.tag!("RetrieveServiceContent", "xmlns" => "urn:lookup") do |rsc|
|
413
|
+
rsc.tag!("_this", "type" => "LookupServiceInstance") do |this|
|
414
|
+
this << "ServiceInstance"
|
415
|
+
end
|
441
416
|
end
|
417
|
+
end
|
418
|
+
|
419
|
+
# ...
|
420
|
+
# <RetrieveServiceContentResponse xmlns="urn:lookup">
|
421
|
+
# <returnval>
|
422
|
+
# <lookupService type="LookupLookupService">lookupService</lookupService>
|
423
|
+
# <serviceRegistration type="LookupServiceRegistration">ServiceRegistration</serviceRegistration>
|
424
|
+
# <deploymentInformationService type="LookupDeploymentInformationService">deploymentInformationService</deploymentInformationService>
|
425
|
+
# <l10n type="LookupL10n">l10n</l10n>
|
426
|
+
# </returnval>
|
427
|
+
# </RetrieveServiceContentResponse>
|
428
|
+
# ...
|
429
|
+
def get_service_registration
|
430
|
+
Base.log.debug "RetrieveServiceContent: response_hash = #{response_hash}"
|
431
|
+
return_val = response_hash[:retrieve_service_content_response][:returnval]
|
432
|
+
result = return_val[:service_registration]
|
433
|
+
Base.log.debug "RetrieveServiceContent: result = #{result}"
|
434
|
+
result
|
435
|
+
end
|
442
436
|
end
|
443
437
|
|
444
|
-
class MultipleManagementNodeException <
|
438
|
+
class MultipleManagementNodeException < RuntimeError
|
445
439
|
end
|
446
440
|
|
447
441
|
# main: quick self tester
|
448
|
-
if
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
442
|
+
if $PROGRAM_NAME == __FILE__
|
443
|
+
Base.log.level = Logger::DEBUG if ENV["DEBUG"]
|
444
|
+
sample = SelfTestSample.new
|
445
|
+
sample.ls_ip = ARGV[0] || "10.67.245.207"
|
446
|
+
# MXN: sample.ls_ip = '10.160.42.83'
|
447
|
+
# MXN: sample.ls_ip = '10.160.35.191'
|
448
|
+
# MAYBE: sample.main() # for arg parsing
|
449
|
+
ls_helper = LookupServiceHelper.new(sample)
|
450
|
+
ls_helper.connect
|
451
|
+
puts "***************************************"
|
452
|
+
puts "SSO URL: #{ls_helper.find_sso_url}"
|
453
|
+
puts "VAPI URL: #{ls_helper.find_vapi_urls}"
|
454
|
+
puts "VIM URL: #{ls_helper.find_vim_urls}"
|
455
|
+
puts "PBM URL: #{ls_helper.find_vim_pbm_urls}"
|
456
|
+
puts "Mgmt Nodes: #{ls_helper.find_mgmt_nodes}"
|
463
457
|
end
|