vmware-vra 2.7.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/CHANGELOG.md +5 -0
- data/README.md +79 -144
- data/Rakefile +0 -11
- data/lib/vra/catalog.rb +39 -8
- data/lib/vra/catalog_base.rb +62 -0
- data/lib/vra/catalog_item.rb +28 -74
- data/lib/vra/catalog_source.rb +116 -0
- data/lib/vra/catalog_type.rb +56 -0
- data/lib/vra/client.rb +62 -54
- data/lib/vra/deployment.rb +155 -0
- data/lib/vra/deployment_request.rb +117 -0
- data/lib/vra/{resources.rb → deployments.rb} +26 -17
- data/lib/vra/exceptions.rb +1 -1
- data/lib/vra/http.rb +11 -6
- data/lib/vra/request.rb +28 -36
- data/lib/vra/request_parameters.rb +12 -12
- data/lib/vra/resource.rb +32 -203
- data/lib/vra/version.rb +2 -2
- data/lib/vra.rb +15 -12
- data/spec/catalog_item_spec.rb +64 -222
- data/spec/catalog_source_spec.rb +178 -0
- data/spec/catalog_spec.rb +112 -72
- data/spec/catalog_type_spec.rb +114 -0
- data/spec/client_spec.rb +271 -226
- data/spec/deployment_request_spec.rb +192 -0
- data/spec/deployment_spec.rb +227 -0
- data/spec/deployments_spec.rb +80 -0
- data/spec/fixtures/resource/sample_catalog_item.json +18 -0
- data/spec/fixtures/resource/sample_catalog_item_2.json +18 -0
- data/spec/fixtures/resource/sample_catalog_source.json +20 -0
- data/spec/fixtures/resource/sample_catalog_type.json +49 -0
- data/spec/fixtures/resource/sample_dep_actions.json +58 -0
- data/spec/fixtures/resource/sample_dep_request.json +19 -0
- data/spec/fixtures/resource/sample_dep_resource.json +112 -0
- data/spec/fixtures/resource/sample_deployment.json +26 -0
- data/spec/fixtures/resource/sample_entitlements.json +25 -0
- data/spec/http_spec.rb +63 -61
- data/spec/request_spec.rb +62 -68
- data/spec/resource_spec.rb +71 -390
- data/spec/spec_helper.rb +10 -4
- data/vmware-vra.gemspec +0 -1
- metadata +40 -30
- data/.travis.yml +0 -14
- data/lib/vra/catalog_request.rb +0 -137
- data/lib/vra/requests.rb +0 -41
- data/spec/catalog_request_spec.rb +0 -268
- data/spec/requests_spec.rb +0 -60
- data/spec/resources_spec.rb +0 -71
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Author:: Ashique Saidalavi (<ashique.saidalavi@progress.com>)
|
4
|
+
# Copyright:: Copyright (c) 2022 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
|
+
require 'ffi_yajl' unless defined?(FFI_Yajl)
|
20
|
+
|
21
|
+
module Vra
|
22
|
+
# Class that represents the Catalog Source
|
23
|
+
class CatalogSource < Vra::CatalogBase
|
24
|
+
INDEX_URL = '/catalog/api/admin/sources'
|
25
|
+
|
26
|
+
# @param client [Vra::Client] - a vra client object
|
27
|
+
# @param opts [Hash] - Contains the either id of the catalog or the data hash
|
28
|
+
# Either one of id or data hash is required, must not supply both
|
29
|
+
def initialize(client, opts)
|
30
|
+
super
|
31
|
+
validate!
|
32
|
+
fetch_data
|
33
|
+
end
|
34
|
+
|
35
|
+
def name
|
36
|
+
data['name']
|
37
|
+
end
|
38
|
+
|
39
|
+
def catalog_type_id
|
40
|
+
data['typeId']
|
41
|
+
end
|
42
|
+
|
43
|
+
def catalog_type
|
44
|
+
@catalog_type ||= Vra::CatalogType.new(client, id: catalog_type_id)
|
45
|
+
end
|
46
|
+
|
47
|
+
def config
|
48
|
+
data['config']
|
49
|
+
end
|
50
|
+
|
51
|
+
def global?
|
52
|
+
data['global'] == true
|
53
|
+
end
|
54
|
+
|
55
|
+
def project_id
|
56
|
+
config['sourceProjectId']
|
57
|
+
end
|
58
|
+
|
59
|
+
def entitle!(opts = {})
|
60
|
+
super(opts.merge(type: 'CatalogSourceIdentifier'))
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
# Method to create a catalog source
|
65
|
+
def create(client, opts)
|
66
|
+
validate_create!(opts)
|
67
|
+
|
68
|
+
response = client.http_post(
|
69
|
+
'/catalog/api/admin/sources',
|
70
|
+
FFI_Yajl::Encoder.encode(create_params(opts)),
|
71
|
+
opts[:skip_auth] || false
|
72
|
+
)
|
73
|
+
|
74
|
+
return false unless response.success?
|
75
|
+
|
76
|
+
new(client, data: FFI_Yajl::Parser.parse(response.body))
|
77
|
+
end
|
78
|
+
|
79
|
+
def entitle!(client, id)
|
80
|
+
new(client, id: id).entitle!
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def validate_create!(opts)
|
86
|
+
%i[name catalog_type_id project_id].each do |arg|
|
87
|
+
raise ArgumentError, "#{arg} param is required to perform the create action" unless opts.key?(arg)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_params(opts)
|
92
|
+
{
|
93
|
+
'name': opts[:name],
|
94
|
+
'typeId': opts[:catalog_type_id],
|
95
|
+
'config': {
|
96
|
+
'sourceProjectId': opts[:project_id]
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def fetch_data
|
105
|
+
fetch_catalog_data && return if data.nil?
|
106
|
+
|
107
|
+
@id = data['id']
|
108
|
+
end
|
109
|
+
|
110
|
+
def fetch_catalog_data
|
111
|
+
@data = client.get_parsed("/catalog/api/admin/sources/#{id}")
|
112
|
+
rescue Vra::Exception::HTTPNotFound
|
113
|
+
raise Vra::Exception::NotFound, "catalog source ID #{id} does not exist"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Author:: Ashique Saidalavi (<ashique.saidalavi@progress.com>)
|
4
|
+
# Copyright:: Copyright (c) 2022 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
|
+
module Vra
|
20
|
+
# Class that represents the Catalog Type
|
21
|
+
class CatalogType < Vra::CatalogBase
|
22
|
+
INDEX_URL = '/catalog/api/types'
|
23
|
+
|
24
|
+
def initialize(client, opts = {})
|
25
|
+
super
|
26
|
+
validate!
|
27
|
+
fetch_data
|
28
|
+
end
|
29
|
+
|
30
|
+
def name
|
31
|
+
data['name']
|
32
|
+
end
|
33
|
+
|
34
|
+
def base_url
|
35
|
+
data['baseUri']
|
36
|
+
end
|
37
|
+
|
38
|
+
def config_schema
|
39
|
+
data['configSchema']
|
40
|
+
end
|
41
|
+
|
42
|
+
def icon_id
|
43
|
+
data['iconId']
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def fetch_data
|
49
|
+
@id = data['id'] and return unless data.nil?
|
50
|
+
|
51
|
+
@data = client.get_parsed("/catalog/api/types/#{id}")
|
52
|
+
rescue Vra::Exception::HTTPNotFound
|
53
|
+
raise Vra::Exception::NotFound, "catalog type ID #{id} does not exist"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/vra/client.rb
CHANGED
@@ -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)
|
4
|
+
# Copyright:: Copyright (c) 2022 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,22 +17,26 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
20
|
+
require 'ffi_yajl' unless defined?(FFI_Yajl)
|
21
|
+
require 'passwordmasker'
|
22
|
+
require 'vra/http'
|
23
23
|
|
24
24
|
module Vra
|
25
25
|
class Client
|
26
|
+
ACCESS_TOKEN_URL = '/csp/gateway/am/api/login?access_token'
|
27
|
+
ROLES_URL = '/csp/gateway/am/api/loggedin/user/orgs'
|
28
|
+
|
26
29
|
attr_accessor :page_size
|
27
30
|
|
28
31
|
def initialize(opts)
|
29
|
-
@base_url
|
30
|
-
@username
|
31
|
-
@password
|
32
|
-
@tenant
|
33
|
-
@verify_ssl
|
34
|
-
@
|
35
|
-
@
|
32
|
+
@base_url = opts[:base_url]
|
33
|
+
@username = opts[:username]
|
34
|
+
@password = PasswordMasker.new(opts[:password])
|
35
|
+
@tenant = opts[:tenant]
|
36
|
+
@verify_ssl = opts.fetch(:verify_ssl, true)
|
37
|
+
@refresh_token = PasswordMasker.new(nil)
|
38
|
+
@access_token = PasswordMasker.new(nil)
|
39
|
+
@page_size = opts.fetch(:page_size, 20)
|
36
40
|
|
37
41
|
validate_client_options!
|
38
42
|
end
|
@@ -43,15 +47,11 @@ module Vra
|
|
43
47
|
#
|
44
48
|
|
45
49
|
def catalog
|
46
|
-
Vra::Catalog.new(self)
|
47
|
-
end
|
48
|
-
|
49
|
-
def requests(*args)
|
50
|
-
Vra::Requests.new(self, *args)
|
50
|
+
@catalog ||= Vra::Catalog.new(self)
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
54
|
-
Vra::
|
53
|
+
def deployments
|
54
|
+
@deployments ||= Vra::Deployments.new(self)
|
55
55
|
end
|
56
56
|
|
57
57
|
#########################
|
@@ -59,55 +59,64 @@ module Vra
|
|
59
59
|
# client methods
|
60
60
|
#
|
61
61
|
|
62
|
-
def
|
63
|
-
@
|
62
|
+
def access_token
|
63
|
+
@access_token.value
|
64
|
+
end
|
65
|
+
|
66
|
+
def refresh_token
|
67
|
+
@refresh_token.value
|
68
|
+
end
|
69
|
+
|
70
|
+
def access_token=(value)
|
71
|
+
@access_token.value = value
|
64
72
|
end
|
65
73
|
|
66
|
-
def
|
67
|
-
@
|
74
|
+
def refresh_token=(value)
|
75
|
+
@refresh_token.value = value
|
68
76
|
end
|
69
77
|
|
70
|
-
def
|
78
|
+
def token_params
|
71
79
|
{
|
72
|
-
|
73
|
-
|
74
|
-
|
80
|
+
'username': @username,
|
81
|
+
'password': @password.value,
|
82
|
+
'tenant': @tenant
|
75
83
|
}
|
76
84
|
end
|
77
85
|
|
78
86
|
def request_headers
|
79
|
-
headers
|
80
|
-
headers[
|
81
|
-
headers[
|
82
|
-
headers[
|
87
|
+
headers = {}
|
88
|
+
headers['Accept'] = 'application/json'
|
89
|
+
headers['Content-Type'] = 'application/json'
|
90
|
+
headers['csp-auth-token'] = @access_token.value unless @access_token.value.nil?
|
91
|
+
|
83
92
|
headers
|
84
93
|
end
|
85
94
|
|
86
95
|
def authorize!
|
87
|
-
|
96
|
+
generate_access_token unless authorized?
|
88
97
|
|
89
|
-
raise Vra::Exception::Unauthorized,
|
98
|
+
raise Vra::Exception::Unauthorized, 'Unable to authorize against vRA' unless authorized?
|
90
99
|
end
|
91
100
|
|
92
101
|
def authorized?
|
93
|
-
return false if @
|
102
|
+
return false if @access_token.value.nil?
|
94
103
|
|
95
|
-
response = http_head(
|
96
|
-
response.
|
104
|
+
response = http_head(ROLES_URL, :skip_auth)
|
105
|
+
response.success?
|
97
106
|
end
|
98
107
|
|
99
|
-
def
|
100
|
-
@
|
108
|
+
def generate_access_token
|
109
|
+
@access_token.value = nil
|
101
110
|
validate_client_options!
|
102
111
|
|
103
|
-
response = http_post(
|
104
|
-
FFI_Yajl::Encoder.encode(
|
112
|
+
response = http_post(ACCESS_TOKEN_URL,
|
113
|
+
FFI_Yajl::Encoder.encode(token_params),
|
105
114
|
:skip_auth)
|
106
|
-
unless response.success_ok?
|
107
|
-
raise Vra::Exception::Unauthorized, "Unable to get bearer token: #{response.body}"
|
108
|
-
end
|
115
|
+
raise Vra::Exception::Unauthorized, "Unable to get the access token: #{response.body}" unless response.success_ok?
|
109
116
|
|
110
|
-
|
117
|
+
response_body = FFI_Yajl::Parser.parse(response.body)
|
118
|
+
@access_token.value = response_body['access_token']
|
119
|
+
@refresh_token.value = response_body['refresh_token']
|
111
120
|
end
|
112
121
|
|
113
122
|
def full_url(path)
|
@@ -140,22 +149,26 @@ module Vra
|
|
140
149
|
response.body
|
141
150
|
end
|
142
151
|
|
152
|
+
def http_delete(path, skip_auth = nil)
|
153
|
+
http_fetch(:delete, path, skip_auth)
|
154
|
+
end
|
155
|
+
|
143
156
|
def get_parsed(path)
|
144
157
|
FFI_Yajl::Parser.parse(http_get!(path))
|
145
158
|
end
|
146
159
|
|
147
|
-
def http_get_paginated_array!(path)
|
160
|
+
def http_get_paginated_array!(path, filter = nil)
|
148
161
|
items = []
|
149
|
-
page =
|
150
|
-
base_path = path + "
|
162
|
+
page = 0
|
163
|
+
base_path = path + "?$top=#{page_size}"
|
164
|
+
base_path += "&#{filter}" if filter
|
151
165
|
|
152
166
|
loop do
|
153
|
-
response = get_parsed("#{base_path}
|
167
|
+
response = get_parsed("#{base_path}&$skip=#{page * page_size}")
|
154
168
|
items += response["content"]
|
155
169
|
|
156
|
-
break if page >= response["metadata"]["totalPages"]
|
157
|
-
|
158
170
|
page += 1
|
171
|
+
break if page >= response["totalPages"]
|
159
172
|
end
|
160
173
|
|
161
174
|
if items.uniq!
|
@@ -219,10 +232,5 @@ module Vra
|
|
219
232
|
rescue URI::InvalidURIError
|
220
233
|
false
|
221
234
|
end
|
222
|
-
|
223
|
-
def fetch_subtenant_items(tenant, subtenant_name)
|
224
|
-
http_get("/identity/api/tenants/#{tenant}/subtenants?%24filter=name+eq+'#{subtenant_name}'")
|
225
|
-
end
|
226
|
-
|
227
235
|
end
|
228
236
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Author:: Ashique Saidalavi (<ashique.saidalavi@progress.com>)
|
4
|
+
# Copyright:: Copyright (c) 2022 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 "ffi_yajl" unless defined?(FFI_Yajl)
|
21
|
+
|
22
|
+
module Vra
|
23
|
+
# Class that represents the Deployment Object
|
24
|
+
class Deployment
|
25
|
+
INDEX_URL = '/deployment/api/deployments'
|
26
|
+
|
27
|
+
attr_reader :id
|
28
|
+
|
29
|
+
def initialize(client, opts = {})
|
30
|
+
@client = client
|
31
|
+
@id = opts[:id]
|
32
|
+
@data = opts[:data]
|
33
|
+
validate!
|
34
|
+
|
35
|
+
if @data.nil?
|
36
|
+
refresh
|
37
|
+
elsif @id.nil?
|
38
|
+
@id = @data['id']
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def name
|
43
|
+
@data['name']
|
44
|
+
end
|
45
|
+
|
46
|
+
def description
|
47
|
+
@data['description']
|
48
|
+
end
|
49
|
+
|
50
|
+
def org_id
|
51
|
+
@data['orgId']
|
52
|
+
end
|
53
|
+
|
54
|
+
def blueprint_id
|
55
|
+
@data['blueprintId']
|
56
|
+
end
|
57
|
+
|
58
|
+
def owner
|
59
|
+
@data['ownedBy']
|
60
|
+
end
|
61
|
+
|
62
|
+
def status
|
63
|
+
@data['status']
|
64
|
+
end
|
65
|
+
|
66
|
+
def successful?
|
67
|
+
status == 'CREATE_SUCCESSFUL'
|
68
|
+
end
|
69
|
+
|
70
|
+
def failed?
|
71
|
+
status == 'CREATE_FAILED'
|
72
|
+
end
|
73
|
+
|
74
|
+
def completed?
|
75
|
+
successful? || failed?
|
76
|
+
end
|
77
|
+
|
78
|
+
def actions
|
79
|
+
@actions = client.get_parsed("/deployment/api/deployments/#{id}/actions")
|
80
|
+
end
|
81
|
+
|
82
|
+
def action_id_by_name(action_name)
|
83
|
+
action = actions.find { |x| x['name'] == action_name}
|
84
|
+
return if action.nil?
|
85
|
+
|
86
|
+
action['id']
|
87
|
+
end
|
88
|
+
|
89
|
+
def resources
|
90
|
+
response = client.get_parsed("/deployment/api/deployments/#{id}/resources")
|
91
|
+
|
92
|
+
response['content'].map! { |x| Vra::Resource.new(client, id, data: x) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def resource_by_id(res_id)
|
96
|
+
Vra::Resource.new(client, id, id: res_id)
|
97
|
+
end
|
98
|
+
|
99
|
+
def requests
|
100
|
+
response = client.get_parsed("/deployment/api/deployments/#{id}/requests")
|
101
|
+
|
102
|
+
response['content'].map! { |x| Vra::Request.new(client, id, id: x['id'], data: x) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def refresh
|
106
|
+
@data = client.get_parsed("/deployment/api/deployments/#{id}")
|
107
|
+
rescue Vra::Exception::HTTPNotFound
|
108
|
+
raise Vra::Exception::NotFound, "deployment with ID #{id} does not exist"
|
109
|
+
end
|
110
|
+
|
111
|
+
def destroy(reason = '')
|
112
|
+
action_id = action_id_by_name('Delete')
|
113
|
+
raise Vra::Exception::NotFound, "No destroy action found for resource #{@id}" if action_id.nil?
|
114
|
+
|
115
|
+
submit_action_request(action_id, reason)
|
116
|
+
end
|
117
|
+
|
118
|
+
def power_off(reason = '')
|
119
|
+
action_id = action_id_by_name('PowerOff')
|
120
|
+
raise Vra::Exception::NotFound, "No power-off action found for resource #{@id}" if action_id.nil?
|
121
|
+
|
122
|
+
submit_action_request(action_id, reason)
|
123
|
+
end
|
124
|
+
|
125
|
+
def power_on(reason = nil)
|
126
|
+
action_id = action_id_by_name('PowerOn')
|
127
|
+
raise Vra::Exception::NotFound, "No power-on action found for resource #{@id}" if action_id.nil?
|
128
|
+
|
129
|
+
submit_action_request(action_id, reason)
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
attr_reader :client, :data
|
135
|
+
|
136
|
+
def validate!
|
137
|
+
raise ArgumentError, 'must supply id or data hash' if @id.nil? && @data.nil?
|
138
|
+
end
|
139
|
+
|
140
|
+
def submit_action_request(action_id, reason)
|
141
|
+
response = client.http_post!("/deployment/api/deployments/#{id}/requests",
|
142
|
+
FFI_Yajl::Encoder.encode(submit_action_payload(action_id, reason)))
|
143
|
+
|
144
|
+
Vra::Request.new(client, id, data: FFI_Yajl::Parser.parse(response))
|
145
|
+
end
|
146
|
+
|
147
|
+
def submit_action_payload(action_id, reason)
|
148
|
+
{
|
149
|
+
"actionId": action_id,
|
150
|
+
"inputs": {},
|
151
|
+
"reason": reason
|
152
|
+
}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Author:: Ashique Saidalavi (<ashique.saidalavi@progress.com>)
|
4
|
+
# Copyright:: Copyright (c) 2022 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
|
+
require 'ffi_yajl' unless defined?(FFI_Yajl)
|
20
|
+
|
21
|
+
# Overriding the hash object to add the deep_merge method
|
22
|
+
class ::Hash
|
23
|
+
def deep_merge(second)
|
24
|
+
merger = proc { |_key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
25
|
+
merge(second, &merger)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Vra
|
30
|
+
# class that handles the deployment request with catalog
|
31
|
+
class DeploymentRequest
|
32
|
+
attr_reader :catalog_id
|
33
|
+
attr_accessor :image_mapping, :name, :flavor_mapping,
|
34
|
+
:project_id, :version, :count
|
35
|
+
|
36
|
+
def initialize(client, catalog_id, opts = {})
|
37
|
+
@client = client
|
38
|
+
@catalog_id = catalog_id
|
39
|
+
@image_mapping = opts[:image_mapping]
|
40
|
+
@name = opts[:name]
|
41
|
+
@flavor_mapping = opts[:flavor_mapping]
|
42
|
+
@project_id = opts[:project_id]
|
43
|
+
@version = opts[:version]
|
44
|
+
@count = opts[:count] || 1
|
45
|
+
@additional_params = opts[:additional_params] || Vra::RequestParameters.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def submit
|
49
|
+
validate!
|
50
|
+
begin
|
51
|
+
response = send_request!
|
52
|
+
rescue Vra::Exception::HTTPError => e
|
53
|
+
raise Vra::Exception::RequestError, "Unable to submit request: #{e.message}, trace: #{e.errors.join(', ')}"
|
54
|
+
rescue StandardError => e
|
55
|
+
raise e, e.message
|
56
|
+
end
|
57
|
+
|
58
|
+
request_id = FFI_Yajl::Parser.parse(response)[0]['deploymentId']
|
59
|
+
Vra::Deployment.new(client, id: request_id)
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_parameter(key, type, value)
|
63
|
+
@additional_params.set(key, type, value)
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_parameters(key, value_data)
|
67
|
+
@additional_params.set_parameters(key, value_data)
|
68
|
+
end
|
69
|
+
|
70
|
+
def delete_parameter(key)
|
71
|
+
@additional_params.delete(key)
|
72
|
+
end
|
73
|
+
|
74
|
+
def parameters
|
75
|
+
@additional_params.to_vra
|
76
|
+
end
|
77
|
+
|
78
|
+
def hash_parameters
|
79
|
+
@additional_params.to_h
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
attr_reader :client
|
85
|
+
|
86
|
+
def validate!
|
87
|
+
missing_params = []
|
88
|
+
%i[image_mapping flavor_mapping name project_id version].each do |arg|
|
89
|
+
missing_params << arg if send(arg).nil?
|
90
|
+
end
|
91
|
+
|
92
|
+
return if missing_params.empty?
|
93
|
+
|
94
|
+
raise ArgumentError, "Unable to submit request, required param(s) missing => #{missing_params.join(', ')}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def send_request!
|
98
|
+
client.http_post!(
|
99
|
+
"/catalog/api/items/#{catalog_id}/request",
|
100
|
+
FFI_Yajl::Encoder.encode(request_payload)
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
def request_payload
|
105
|
+
{
|
106
|
+
'deploymentName': name,
|
107
|
+
'projectId': project_id,
|
108
|
+
'version': version,
|
109
|
+
'inputs': {
|
110
|
+
'count': count,
|
111
|
+
'image': image_mapping,
|
112
|
+
'flavor': flavor_mapping
|
113
|
+
}
|
114
|
+
}.deep_merge(parameters)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|