fog 1.33.0 → 1.34.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/Rakefile +3 -0
  4. data/fog.gemspec +4 -4
  5. data/lib/fog/openstack/baremetal.rb +20 -82
  6. data/lib/fog/openstack/compute.rb +11 -34
  7. data/lib/fog/openstack/core.rb +37 -10
  8. data/lib/fog/openstack/identity.rb +33 -44
  9. data/lib/fog/openstack/identity_v2.rb +14 -84
  10. data/lib/fog/openstack/identity_v3.rb +4 -51
  11. data/lib/fog/openstack/image.rb +22 -83
  12. data/lib/fog/openstack/metering.rb +15 -76
  13. data/lib/fog/openstack/models/compute/server.rb +1 -1
  14. data/lib/fog/openstack/models/orchestration/events.rb +1 -0
  15. data/lib/fog/openstack/models/orchestration/resources.rb +1 -0
  16. data/lib/fog/openstack/models/orchestration/stack.rb +1 -1
  17. data/lib/fog/openstack/models/orchestration/stacks.rb +1 -0
  18. data/lib/fog/openstack/models/orchestration/templates.rb +1 -0
  19. data/lib/fog/openstack/network.rb +21 -21
  20. data/lib/fog/openstack/orchestration.rb +11 -91
  21. data/lib/fog/openstack/planning.rb +19 -81
  22. data/lib/fog/openstack/requests/compute/list_security_groups.rb +9 -1
  23. data/lib/fog/openstack/requests/network/add_router_interface.rb +12 -4
  24. data/lib/fog/openstack/requests/network/create_port.rb +14 -12
  25. data/lib/fog/openstack/requests/network/get_port.rb +4 -0
  26. data/lib/fog/openstack/requests/network/set_tenant.rb +1 -0
  27. data/lib/fog/openstack/storage.rb +18 -57
  28. data/lib/fog/openstack/volume.rb +17 -79
  29. data/lib/fog/rackspace/requests/storage/get_object_https_url.rb +13 -2
  30. data/lib/fog/vcloud_director/generators/compute/edge_gateway_service_configuration.rb +7 -6
  31. data/lib/fog/vcloud_director/models/compute/vm_customizations.rb +15 -0
  32. data/lib/fog/version.rb +1 -1
  33. data/lib/tasks/changelog_task.rb +1 -0
  34. data/spec/fog/openstack/volume_spec.rb +5 -0
  35. data/tests/compute/helper.rb +0 -6
  36. data/tests/openstack/requests/network/port_tests.rb +14 -12
  37. data/tests/rackspace/requests/storage/object_tests.rb +46 -4
  38. data/tests/vcloud_director/requests/compute/edge_gateway_tests.rb +2 -2
  39. metadata +11 -74
  40. data/lib/fog/bin/dynect.rb +0 -28
  41. data/tests/brightbox/compute/helper.rb +0 -1
  42. data/tests/brightbox/compute/schema.rb +0 -799
  43. data/tests/brightbox/compute_tests.rb +0 -101
  44. data/tests/brightbox/helper.rb +0 -1
  45. data/tests/brightbox/models/compute/account_tests.rb +0 -17
  46. data/tests/brightbox/models/compute/cloud_ip_tests.rb +0 -32
  47. data/tests/brightbox/models/compute/database_server_tests.rb +0 -78
  48. data/tests/brightbox/models/compute/database_snapshot_tests.rb +0 -26
  49. data/tests/brightbox/models/compute/database_type_tests.rb +0 -27
  50. data/tests/brightbox/models/compute/server_tests.rb +0 -19
  51. data/tests/brightbox/oauth2_tests.rb +0 -110
  52. data/tests/brightbox/requests/compute/account_tests.rb +0 -65
  53. data/tests/brightbox/requests/compute/api_client_tests.rb +0 -64
  54. data/tests/brightbox/requests/compute/application_test.rb +0 -63
  55. data/tests/brightbox/requests/compute/cloud_ip_tests.rb +0 -85
  56. data/tests/brightbox/requests/compute/collaboration_tests.rb +0 -39
  57. data/tests/brightbox/requests/compute/database_server_tests.rb +0 -54
  58. data/tests/brightbox/requests/compute/database_snapsnot_tests.rb +0 -47
  59. data/tests/brightbox/requests/compute/database_type_tests.rb +0 -17
  60. data/tests/brightbox/requests/compute/firewall_policy_tests.rb +0 -40
  61. data/tests/brightbox/requests/compute/firewall_rule_tests.rb +0 -43
  62. data/tests/brightbox/requests/compute/helper.rb +0 -41
  63. data/tests/brightbox/requests/compute/image_tests.rb +0 -60
  64. data/tests/brightbox/requests/compute/interface_tests.rb +0 -33
  65. data/tests/brightbox/requests/compute/load_balancer_tests.rb +0 -121
  66. data/tests/brightbox/requests/compute/server_group_tests.rb +0 -96
  67. data/tests/brightbox/requests/compute/server_tests.rb +0 -99
  68. data/tests/brightbox/requests/compute/server_type_tests.rb +0 -34
  69. data/tests/brightbox/requests/compute/user_collaboration_tests.rb +0 -67
  70. data/tests/brightbox/requests/compute/user_tests.rb +0 -38
  71. data/tests/brightbox/requests/compute/zone_tests.rb +0 -34
@@ -212,7 +212,7 @@ module Fog
212
212
  def security_groups
213
213
  requires :id
214
214
 
215
- groups = service.list_security_groups(id).body['security_groups']
215
+ groups = service.list_security_groups(:server_id => id).body['security_groups']
216
216
 
217
217
  groups.map do |group|
218
218
  Fog::Compute::OpenStack::SecurityGroup.new group.merge({:service => service})
@@ -1,3 +1,4 @@
1
+ require 'fog/openstack/models/collection'
1
2
  require 'fog/openstack/models/orchestration/event'
2
3
 
3
4
  module Fog
@@ -1,3 +1,4 @@
1
+ require 'fog/openstack/models/collection'
1
2
  require 'fog/openstack/models/orchestration/resource'
2
3
 
3
4
  module Fog
@@ -45,7 +45,7 @@ module Fog
45
45
  end
46
46
 
47
47
  def resources(options={})
48
- @resources ||= service.resources.all(self, options)
48
+ @resources ||= service.resources.all({:stack => self}.merge(options))
49
49
  end
50
50
 
51
51
  def events(options={})
@@ -1,3 +1,4 @@
1
+ require 'fog/openstack/models/collection'
1
2
  require 'fog/openstack/models/orchestration/stack'
2
3
 
3
4
  module Fog
@@ -1,3 +1,4 @@
1
+ require 'fog/openstack/models/collection'
1
2
  require 'fog/openstack/models/orchestration/template'
2
3
 
3
4
  module Fog
@@ -6,13 +6,15 @@ module Fog
6
6
  SUPPORTED_VERSIONS = /v2(\.0)*/
7
7
 
8
8
  requires :openstack_auth_url
9
- recognizes :openstack_auth_token, :openstack_management_url, :persistent,
10
- :openstack_service_type, :openstack_service_name, :openstack_tenant,
11
- :openstack_tenant_id,
12
- :openstack_api_key, :openstack_username, :openstack_endpoint_type,
9
+ recognizes :openstack_auth_token, :openstack_management_url,
10
+ :persistent, :openstack_service_type, :openstack_service_name,
11
+ :openstack_tenant, :openstack_tenant_id,
12
+ :openstack_api_key, :openstack_username, :openstack_identity_endpoint,
13
13
  :current_user, :current_tenant, :openstack_region,
14
- :openstack_project_name,
15
- :openstack_project_domain, :openstack_user_domain
14
+ :openstack_endpoint_type,
15
+ :openstack_project_name, :openstack_project_id,
16
+ :openstack_project_domain, :openstack_user_domain, :openstack_domain_name,
17
+ :openstack_project_domain_id, :openstack_user_domain_id, :openstack_domain_id
16
18
 
17
19
  ## MODELS
18
20
  #
@@ -228,31 +230,20 @@ module Fog
228
230
  include Fog::OpenStack::Core
229
231
 
230
232
  def initialize(options={})
231
-
232
233
  initialize_identity options
233
234
 
234
- @openstack_service_type = options[:openstack_service_type] || ['network']
235
- @openstack_service_name = options[:openstack_service_name]
235
+ @openstack_service_type = options[:openstack_service_type] || ['network']
236
+ @openstack_service_name = options[:openstack_service_name]
236
237
 
237
- @connection_options = options[:connection_options] || {}
238
+ @connection_options = options[:connection_options] || {}
238
239
 
239
240
  authenticate
240
-
241
- @path.sub!(/\/$/, '')
242
- unless @path.match(SUPPORTED_VERSIONS)
243
- @path = "/" + Fog::OpenStack.get_supported_version(SUPPORTED_VERSIONS,
244
- @openstack_management_uri,
245
- @auth_token,
246
- @connection_options)
247
- end
241
+ set_api_path
248
242
 
249
243
  @persistent = options[:persistent] || false
250
244
  @connection = Fog::Core::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
251
245
  end
252
246
 
253
- def reload
254
- @connection.reset
255
- end
256
247
 
257
248
  def request(params)
258
249
  begin
@@ -286,6 +277,15 @@ module Fog
286
277
  response
287
278
  end
288
279
 
280
+ def set_api_path
281
+ @path.sub!(/\/$/, '')
282
+ unless @path.match(SUPPORTED_VERSIONS)
283
+ @path = "/" + Fog::OpenStack.get_supported_version(SUPPORTED_VERSIONS,
284
+ @openstack_management_uri,
285
+ @auth_token,
286
+ @connection_options)
287
+ end
288
+ end
289
289
  end
290
290
  end
291
291
  end
@@ -6,10 +6,13 @@ module Fog
6
6
  requires :openstack_auth_url
7
7
  recognizes :openstack_auth_token, :openstack_management_url,
8
8
  :persistent, :openstack_service_type, :openstack_service_name,
9
- :openstack_tenant,
9
+ :openstack_tenant, :openstack_tenant_id,
10
10
  :openstack_api_key, :openstack_username, :openstack_identity_endpoint,
11
11
  :current_user, :current_tenant, :openstack_region,
12
- :openstack_endpoint_type
12
+ :openstack_endpoint_type,
13
+ :openstack_project_name, :openstack_project_id,
14
+ :openstack_project_domain, :openstack_user_domain, :openstack_domain_name,
15
+ :openstack_project_domain_id, :openstack_user_domain_id, :openstack_domain_id
13
16
 
14
17
  model_path 'fog/openstack/models/orchestration'
15
18
  model :stack
@@ -124,40 +127,17 @@ module Fog
124
127
  end
125
128
 
126
129
  class Real
127
- attr_reader :auth_token
128
- attr_reader :auth_token_expiration
129
- attr_reader :current_user
130
- attr_reader :current_tenant
130
+ include Fog::OpenStack::Core
131
131
 
132
132
  def initialize(options={})
133
- @openstack_auth_token = options[:openstack_auth_token]
134
- @auth_token = options[:openstack_auth_token]
135
- @openstack_identity_public_endpoint = options[:openstack_identity_endpoint]
136
-
137
- unless @auth_token
138
- missing_credentials = Array.new
139
- @openstack_api_key = options[:openstack_api_key]
140
- @openstack_username = options[:openstack_username]
141
-
142
- missing_credentials << :openstack_api_key unless @openstack_api_key
143
- missing_credentials << :openstack_username unless @openstack_username
144
- raise ArgumentError, "Missing required arguments: #{missing_credentials.join(', ')}" unless missing_credentials.empty?
145
- end
133
+ initialize_identity options
146
134
 
147
- @openstack_tenant = options[:openstack_tenant]
148
- @openstack_auth_uri = URI.parse(options[:openstack_auth_url])
149
- @openstack_management_url = options[:openstack_management_url]
150
- @openstack_must_reauthenticate = false
151
- @openstack_service_type = options[:openstack_service_type] || ['orchestration']
152
- @openstack_service_name = options[:openstack_service_name]
153
135
  @openstack_identity_service_type = options[:openstack_identity_service_type] || 'identity'
154
- @openstack_endpoint_type = options[:openstack_endpoint_type] || 'publicURL'
155
- @openstack_region = options[:openstack_region]
156
136
 
157
- @connection_options = options[:connection_options] || {}
137
+ @openstack_service_type = options[:openstack_service_type] || ['orchestration']
138
+ @openstack_service_name = options[:openstack_service_name]
158
139
 
159
- @current_user = options[:current_user]
160
- @current_tenant = options[:current_tenant]
140
+ @connection_options = options[:connection_options] || {}
161
141
 
162
142
  authenticate
163
143
 
@@ -165,21 +145,6 @@ module Fog
165
145
  @connection = Fog::Core::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
166
146
  end
167
147
 
168
- def credentials
169
- { :provider => 'openstack',
170
- :openstack_auth_url => @openstack_auth_uri.to_s,
171
- :openstack_auth_token => @auth_token,
172
- :openstack_management_url => @openstack_management_url,
173
- :openstack_identity_endpoint => @openstack_identity_public_endpoint,
174
- :openstack_region => @openstack_region,
175
- :current_user => @current_user,
176
- :current_tenant => @current_tenant }
177
- end
178
-
179
- def reload
180
- @connection.reset
181
- end
182
-
183
148
  def request(params)
184
149
  begin
185
150
  response = @connection.request(params.merge({
@@ -190,7 +155,7 @@ module Fog
190
155
  'X-Auth-User' => @openstack_username,
191
156
  'X-Auth-Key' => @openstack_api_key
192
157
  }.merge!(params[:headers] || {}),
193
- :path => "#{@path}/#{@tenant_id}/#{params[:path]}",
158
+ :path => "#{@path}/#{params[:path]}",
194
159
  :query => params[:query]
195
160
  }))
196
161
  rescue Excon::Errors::Unauthorized => error
@@ -219,51 +184,6 @@ module Fog
219
184
 
220
185
  private
221
186
 
222
- def authenticate
223
- if !@openstack_management_url || @openstack_must_reauthenticate
224
- options = {
225
- :openstack_api_key => @openstack_api_key,
226
- :openstack_username => @openstack_username,
227
- :openstack_auth_token => @openstack_must_reauthenticate ? nil : @auth_token,
228
- :openstack_auth_uri => @openstack_auth_uri,
229
- :openstack_region => @openstack_region,
230
- :openstack_tenant => @openstack_tenant,
231
- :openstack_service_type => @openstack_service_type,
232
- :openstack_service_name => @openstack_service_name,
233
- :openstack_identity_service_type => @openstack_identity_service_type,
234
- :openstack_endpoint_type => @openstack_endpoint_type
235
- }
236
-
237
- credentials = Fog::OpenStack.authenticate(options, @connection_options)
238
-
239
- @current_user = credentials[:user]
240
- @current_tenant = credentials[:tenant]
241
-
242
- @openstack_must_reauthenticate = false
243
- @auth_token = credentials[:token]
244
- @auth_token_expiration = credentials[:expires]
245
- @openstack_management_url = credentials[:server_management_url]
246
- @openstack_identity_public_endpoint = credentials[:identity_public_endpoint]
247
- end
248
-
249
- uri = URI.parse(@openstack_management_url)
250
- @host = uri.host
251
- @path, @tenant_id = uri.path.scan(/(\/.*)\/(.*)/).flatten
252
-
253
- @path.sub!(/\/$/, '')
254
-
255
- @port = uri.port
256
- @scheme = uri.scheme
257
-
258
- # Not all implementations have identity service in the catalog
259
- if @openstack_identity_public_endpoint || @openstack_management_url
260
- @identity_connection = Fog::Core::Connection.new(
261
- @openstack_identity_public_endpoint || @openstack_management_url,
262
- false, @connection_options)
263
- end
264
-
265
- true
266
- end
267
187
  end
268
188
  end
269
189
  end
@@ -6,10 +6,15 @@ module Fog
6
6
  SUPPORTED_VERSIONS = /v2/
7
7
 
8
8
  requires :openstack_auth_url
9
- recognizes :openstack_auth_token, :openstack_management_url, :persistent,
10
- :openstack_service_type, :openstack_service_name, :openstack_tenant,
11
- :openstack_api_key, :openstack_username,
12
- :current_user, :current_tenant, :openstack_endpoint_type, :openstack_region
9
+ recognizes :openstack_auth_token, :openstack_management_url,
10
+ :persistent, :openstack_service_type, :openstack_service_name,
11
+ :openstack_tenant, :openstack_tenant_id,
12
+ :openstack_api_key, :openstack_username, :openstack_identity_endpoint,
13
+ :current_user, :current_tenant, :openstack_region,
14
+ :openstack_endpoint_type,
15
+ :openstack_project_name, :openstack_project_id,
16
+ :openstack_project_domain, :openstack_user_domain, :openstack_domain_name,
17
+ :openstack_project_domain_id, :openstack_user_domain_id, :openstack_domain_id
13
18
 
14
19
  ## MODELS
15
20
  #
@@ -89,55 +94,27 @@ module Fog
89
94
  end
90
95
 
91
96
  class Real
92
- attr_reader :current_user
93
- attr_reader :current_tenant
97
+ include Fog::OpenStack::Core
94
98
 
95
99
  def initialize(options={})
96
- @openstack_auth_token = options[:openstack_auth_token]
100
+ initialize_identity options
97
101
 
98
- unless @openstack_auth_token
99
- missing_credentials = Array.new
100
- @openstack_api_key = options[:openstack_api_key]
101
- @openstack_username = options[:openstack_username]
102
+ @openstack_service_type = options[:openstack_service_type] || ['management'] # currently Tuskar is configured as 'management' service in Keystone
103
+ @openstack_service_name = options[:openstack_service_name]
104
+ @openstack_endpoint_type = options[:openstack_endpoint_type] || 'adminURL'
102
105
 
103
- missing_credentials << :openstack_api_key unless @openstack_api_key
104
- missing_credentials << :openstack_username unless @openstack_username
105
- raise ArgumentError, "Missing required arguments: #{missing_credentials.join(', ')}" unless missing_credentials.empty?
106
- end
107
-
108
- @openstack_tenant = options[:openstack_tenant]
109
- @openstack_auth_uri = URI.parse(options[:openstack_auth_url])
110
- @openstack_management_url = options[:openstack_management_url]
111
- @openstack_must_reauthenticate = false
112
- @openstack_service_type = options[:openstack_service_type] || ['management'] # currently Tuskar is configured as 'management' service in Keystone
113
- @openstack_service_name = options[:openstack_service_name]
114
- @openstack_endpoint_type = options[:openstack_endpoint_type] || 'adminURL'
115
- @openstack_region = options[:openstack_region]
116
-
117
- @connection_options = options[:connection_options] || {}
118
-
119
- @current_user = options[:current_user]
120
- @current_tenant = options[:current_tenant]
106
+ @connection_options = options[:connection_options] || {}
121
107
 
122
108
  authenticate
123
109
 
110
+ unless @path.match(SUPPORTED_VERSIONS)
111
+ @path = "/v2"
112
+ end
113
+
124
114
  @persistent = options[:persistent] || false
125
115
  @connection = Fog::Core::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
126
116
  end
127
117
 
128
- def credentials
129
- { :provider => 'openstack',
130
- :openstack_auth_url => @openstack_auth_uri.to_s,
131
- :openstack_auth_token => @auth_token,
132
- :openstack_management_url => @openstack_management_url,
133
- :current_user => @current_user,
134
- :current_tenant => @current_tenant }
135
- end
136
-
137
- def reload
138
- @connection.reset
139
- end
140
-
141
118
  def request(params)
142
119
  begin
143
120
  response = @connection.request(params.merge({
@@ -171,44 +148,6 @@ module Fog
171
148
 
172
149
  private
173
150
 
174
- def authenticate
175
- if !@openstack_management_url || @openstack_must_reauthenticate
176
- options = {
177
- :openstack_tenant => @openstack_tenant,
178
- :openstack_api_key => @openstack_api_key,
179
- :openstack_username => @openstack_username,
180
- :openstack_auth_uri => @openstack_auth_uri,
181
- :openstack_region => @openstack_region,
182
- :openstack_auth_token => @openstack_must_reauthenticate ? nil : @openstack_auth_token,
183
- :openstack_service_type => @openstack_service_type,
184
- :openstack_service_name => @openstack_service_name,
185
- :openstack_endpoint_type => @openstack_endpoint_type
186
- }
187
-
188
- credentials = Fog::OpenStack.authenticate(options, @connection_options)
189
-
190
- @current_user = credentials[:user]
191
- @current_tenant = credentials[:tenant]
192
-
193
- @openstack_must_reauthenticate = false
194
- @auth_token = credentials[:token]
195
- @openstack_management_url = credentials[:server_management_url]
196
- uri = URI.parse(@openstack_management_url)
197
- else
198
- @auth_token = @openstack_auth_token
199
- uri = URI.parse(@openstack_management_url)
200
- end
201
-
202
- @host = uri.host
203
- @path = uri.path
204
- @path.sub!(/\/$/, '')
205
- unless @path.match(SUPPORTED_VERSIONS)
206
- @path = "/v2"
207
- end
208
- @port = uri.port
209
- @scheme = uri.scheme
210
- true
211
- end
212
151
  end
213
152
  end
214
153
 
@@ -232,4 +171,3 @@ module Fog
232
171
  end
233
172
  end
234
173
  end
235
-
@@ -29,7 +29,15 @@ module Fog
29
29
  end
30
30
 
31
31
  class Mock
32
- def list_security_groups(server_id = nil)
32
+ def list_security_groups(options = {})
33
+ if options.is_a?(Hash)
34
+ server_id = options.delete(:server_id)
35
+ query = options
36
+ else
37
+ server_id = options
38
+ query = {}
39
+ end
40
+
33
41
  security_groups = self.data[:security_groups].values
34
42
 
35
43
  groups = if server_id then
@@ -2,10 +2,18 @@ module Fog
2
2
  module Network
3
3
  class OpenStack
4
4
  class Real
5
- def add_router_interface(router_id, subnet_id, options = {})
6
- data = {
7
- 'subnet_id' => subnet_id,
8
- }
5
+ def add_router_interface(router_id, subnet_id_or_options)
6
+
7
+ if(subnet_id_or_options.is_a? String)
8
+ data = {
9
+ 'subnet_id' => subnet_id_or_options,
10
+ }
11
+ elsif subnet_id_or_options.is_a? Hash
12
+ data = subnet_id_or_options
13
+ else
14
+ raise ArgumentError,'Please pass a subnet id or hash {subnet_id:xxx,port_id:xxx}'
15
+ end
16
+
9
17
 
10
18
  request(
11
19
  :body => Fog::JSON.encode(data),
@@ -10,7 +10,8 @@ module Fog
10
10
  }
11
11
 
12
12
  vanilla_options = [:name, :fixed_ips, :mac_address, :admin_state_up,
13
- :device_owner, :device_id, :tenant_id, :security_groups]
13
+ :device_owner, :device_id, :tenant_id, :security_groups,
14
+ :allowed_address_pairs]
14
15
  vanilla_options.reject{ |o| options[o].nil? }.each do |key|
15
16
  data['port'][key] = options[key]
16
17
  end
@@ -29,17 +30,18 @@ module Fog
29
30
  response = Excon::Response.new
30
31
  response.status = 201
31
32
  data = {
32
- 'id' => Fog::Mock.random_numbers(6).to_s,
33
- 'name' => options[:name],
34
- 'network_id' => network_id,
35
- 'fixed_ips' => options[:fixed_ips],
36
- 'mac_address' => options[:mac_address],
37
- 'status' => 'ACTIVE',
38
- 'admin_state_up' => options[:admin_state_up],
39
- 'device_owner' => options[:device_owner],
40
- 'device_id' => options[:device_id],
41
- 'tenant_id' => options[:tenant_id],
42
- 'security_groups' => options[:security_groups],
33
+ 'id' => Fog::Mock.random_numbers(6).to_s,
34
+ 'name' => options[:name],
35
+ 'network_id' => network_id,
36
+ 'fixed_ips' => options[:fixed_ips],
37
+ 'mac_address' => options[:mac_address],
38
+ 'status' => 'ACTIVE',
39
+ 'admin_state_up' => options[:admin_state_up],
40
+ 'device_owner' => options[:device_owner],
41
+ 'device_id' => options[:device_id],
42
+ 'tenant_id' => options[:tenant_id],
43
+ 'security_groups' => options[:security_groups],
44
+ 'allowed_address_pairs' => options[:allowed_address_pairs],
43
45
  }
44
46
  self.data[:ports][data['id']] = data
45
47
  response.body = { 'port' => data }