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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/CHANGELOG.md +5 -0
  4. data/README.md +79 -144
  5. data/Rakefile +0 -11
  6. data/lib/vra/catalog.rb +39 -8
  7. data/lib/vra/catalog_base.rb +62 -0
  8. data/lib/vra/catalog_item.rb +28 -74
  9. data/lib/vra/catalog_source.rb +116 -0
  10. data/lib/vra/catalog_type.rb +56 -0
  11. data/lib/vra/client.rb +62 -54
  12. data/lib/vra/deployment.rb +155 -0
  13. data/lib/vra/deployment_request.rb +117 -0
  14. data/lib/vra/{resources.rb → deployments.rb} +26 -17
  15. data/lib/vra/exceptions.rb +1 -1
  16. data/lib/vra/http.rb +11 -6
  17. data/lib/vra/request.rb +28 -36
  18. data/lib/vra/request_parameters.rb +12 -12
  19. data/lib/vra/resource.rb +32 -203
  20. data/lib/vra/version.rb +2 -2
  21. data/lib/vra.rb +15 -12
  22. data/spec/catalog_item_spec.rb +64 -222
  23. data/spec/catalog_source_spec.rb +178 -0
  24. data/spec/catalog_spec.rb +112 -72
  25. data/spec/catalog_type_spec.rb +114 -0
  26. data/spec/client_spec.rb +271 -226
  27. data/spec/deployment_request_spec.rb +192 -0
  28. data/spec/deployment_spec.rb +227 -0
  29. data/spec/deployments_spec.rb +80 -0
  30. data/spec/fixtures/resource/sample_catalog_item.json +18 -0
  31. data/spec/fixtures/resource/sample_catalog_item_2.json +18 -0
  32. data/spec/fixtures/resource/sample_catalog_source.json +20 -0
  33. data/spec/fixtures/resource/sample_catalog_type.json +49 -0
  34. data/spec/fixtures/resource/sample_dep_actions.json +58 -0
  35. data/spec/fixtures/resource/sample_dep_request.json +19 -0
  36. data/spec/fixtures/resource/sample_dep_resource.json +112 -0
  37. data/spec/fixtures/resource/sample_deployment.json +26 -0
  38. data/spec/fixtures/resource/sample_entitlements.json +25 -0
  39. data/spec/http_spec.rb +63 -61
  40. data/spec/request_spec.rb +62 -68
  41. data/spec/resource_spec.rb +71 -390
  42. data/spec/spec_helper.rb +10 -4
  43. data/vmware-vra.gemspec +0 -1
  44. metadata +40 -30
  45. data/.travis.yml +0 -14
  46. data/lib/vra/catalog_request.rb +0 -137
  47. data/lib/vra/requests.rb +0 -41
  48. data/spec/catalog_request_spec.rb +0 -268
  49. data/spec/requests_spec.rb +0 -60
  50. 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) 2015 Chef Software, Inc.
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 "ffi_yajl" unless defined?(FFI_Yajl)
21
- require "passwordmasker"
22
- require "vra/http"
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 = opts[:base_url]
30
- @username = opts[:username]
31
- @password = PasswordMasker.new(opts[:password])
32
- @tenant = opts[:tenant]
33
- @verify_ssl = opts.fetch(:verify_ssl, true)
34
- @bearer_token = PasswordMasker.new(nil)
35
- @page_size = opts.fetch(:page_size, 20)
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 resources(*args)
54
- Vra::Resources.new(self, *args)
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 bearer_token
63
- @bearer_token.value
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 bearer_token=(value)
67
- @bearer_token.value = value
74
+ def refresh_token=(value)
75
+ @refresh_token.value = value
68
76
  end
69
77
 
70
- def bearer_token_request_body
78
+ def token_params
71
79
  {
72
- "username" => @username,
73
- "password" => @password.value,
74
- "tenant" => @tenant,
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["Accept"] = "application/json"
81
- headers["Content-Type"] = "application/json"
82
- headers["Authorization"] = "Bearer #{@bearer_token.value}" unless @bearer_token.value.nil?
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
- generate_bearer_token unless authorized?
96
+ generate_access_token unless authorized?
88
97
 
89
- raise Vra::Exception::Unauthorized, "Unable to authorize against vRA" unless authorized?
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 @bearer_token.value.nil?
102
+ return false if @access_token.value.nil?
94
103
 
95
- response = http_head("/identity/api/tokens/#{@bearer_token.value}", :skip_auth)
96
- response.success_no_content?
104
+ response = http_head(ROLES_URL, :skip_auth)
105
+ response.success?
97
106
  end
98
107
 
99
- def generate_bearer_token
100
- @bearer_token.value = nil
108
+ def generate_access_token
109
+ @access_token.value = nil
101
110
  validate_client_options!
102
111
 
103
- response = http_post("/identity/api/tokens",
104
- FFI_Yajl::Encoder.encode(bearer_token_request_body),
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
- @bearer_token.value = FFI_Yajl::Parser.parse(response.body)["id"]
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 = 1
150
- base_path = path + "?limit=#{page_size}"
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}&page=#{page}")
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