deltacloud-core 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/config.ru +19 -1
- data/deltacloud.rb +20 -1
- data/lib/deltacloud/backend_capability.rb +18 -0
- data/lib/deltacloud/base_driver.rb +1 -1
- data/lib/deltacloud/base_driver/base_driver.rb +3 -0
- data/lib/deltacloud/drivers/azure/azure_driver.rb +32 -1
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +17 -11
- data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +18 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +0 -1
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +20 -5
- data/lib/deltacloud/drivers/mock/mock_driver.rb +1 -1
- data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +1 -1
- data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +28 -1
- data/lib/deltacloud/hardware_profile.rb +17 -0
- data/lib/deltacloud/helpers.rb +18 -0
- data/lib/deltacloud/helpers/application_helper.rb +2 -2
- data/lib/deltacloud/helpers/blob_stream.rb +5 -1
- data/lib/deltacloud/helpers/conversion_helper.rb +1 -2
- data/lib/deltacloud/helpers/hardware_profiles_helper.rb +17 -0
- data/lib/deltacloud/method_serializer.rb +1 -1
- data/lib/deltacloud/models/base_model.rb +1 -1
- data/lib/deltacloud/models/blob.rb +3 -1
- data/lib/deltacloud/models/bucket.rb +2 -1
- data/lib/deltacloud/models/image.rb +3 -2
- data/lib/deltacloud/models/instance.rb +1 -2
- data/lib/deltacloud/models/instance_profile.rb +2 -1
- data/lib/deltacloud/models/key.rb +2 -1
- data/lib/deltacloud/models/load_balancer.rb +1 -1
- data/lib/deltacloud/models/realm.rb +1 -1
- data/lib/deltacloud/models/storage_snapshot.rb +1 -1
- data/lib/deltacloud/models/storage_volume.rb +1 -1
- data/lib/deltacloud/state_machine.rb +17 -0
- data/lib/deltacloud/validation.rb +18 -0
- data/lib/drivers.rb +69 -43
- data/lib/sinatra/lazy_auth.rb +1 -1
- data/lib/sinatra/rabbit.rb +4 -4
- data/lib/sinatra/rack_driver_select.rb +21 -0
- data/server.rb +44 -15
- data/views/api/drivers.xml.haml +6 -0
- data/views/api/show.html.haml +2 -2
- data/views/api/show.xml.haml +1 -1
- data/views/buckets/index.html.haml +2 -1
- data/views/buckets/show.html.haml +4 -3
- data/views/errors/backend_error.xml.haml +1 -1
- data/views/images/index.xml.haml +5 -1
- data/views/keys/show.xml.haml +2 -0
- data/views/layout.html.haml +1 -1
- data/views/realms/index.html.haml +4 -7
- metadata +35 -34
- data/lib/deltacloud/drivers/gogrid/test.rb +0 -13
data/config.ru
CHANGED
@@ -1,7 +1,25 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009,2010 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
9
|
+
# License. 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, WITHOUT
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
16
|
+
# License for the specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
|
1
19
|
require 'rubygems'
|
2
|
-
require 'sinatra'
|
3
20
|
|
4
21
|
$:.unshift File.join(File.dirname(__FILE__), '.')
|
5
22
|
|
6
23
|
require 'server.rb'
|
24
|
+
|
7
25
|
run Sinatra::Application
|
data/deltacloud.rb
CHANGED
@@ -1,6 +1,25 @@
|
|
1
|
-
#
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009,2010 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
9
|
+
# License. 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, WITHOUT
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
16
|
+
# License for the specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
|
2
19
|
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
3
20
|
|
21
|
+
require 'drivers'
|
22
|
+
|
4
23
|
require 'deltacloud/base_driver'
|
5
24
|
require 'deltacloud/hardware_profile'
|
6
25
|
require 'deltacloud/state_machine'
|
@@ -1,3 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009, 2010 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
9
|
+
# License. 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, WITHOUT
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
16
|
+
# License for the specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
|
1
19
|
module Deltacloud::BackendCapability
|
2
20
|
|
3
21
|
class Failure < StandardError
|
@@ -256,6 +256,9 @@ module Deltacloud
|
|
256
256
|
catched_exceptions_list[:glob].each do |ex|
|
257
257
|
raise Deltacloud::BackendError.new(502, e.class.to_s, e.message, e.backtrace) if e.class.name =~ ex
|
258
258
|
end
|
259
|
+
puts "======= UNHANDLED EXCEPTION ============"
|
260
|
+
puts e.inspect
|
261
|
+
puts "========================================"
|
259
262
|
raise e
|
260
263
|
end
|
261
264
|
end
|
@@ -17,8 +17,9 @@
|
|
17
17
|
# under the License.
|
18
18
|
|
19
19
|
#Windows Azure (WAZ) gem at http://github.com/johnnyhalife/waz-storage
|
20
|
-
require 'waz-blobs'
|
21
20
|
require 'deltacloud/base_driver'
|
21
|
+
require 'waz-blobs'
|
22
|
+
|
22
23
|
module Deltacloud
|
23
24
|
module Drivers
|
24
25
|
module Azure
|
@@ -46,6 +47,9 @@ class AzureDriver < Deltacloud::BaseDriver
|
|
46
47
|
# Create bucket
|
47
48
|
#--
|
48
49
|
def create_bucket(credentials, name, opts)
|
50
|
+
#for whatever reason, bucket names MUST be lowercase...
|
51
|
+
#http://msdn.microsoft.com/en-us/library/dd135715.aspx
|
52
|
+
name.downcase!
|
49
53
|
bucket = nil
|
50
54
|
azure_connect(credentials)
|
51
55
|
safely do
|
@@ -87,6 +91,33 @@ class AzureDriver < Deltacloud::BaseDriver
|
|
87
91
|
yield WAZ::Blobs::Container.find(bucket_id)[blob_id].value
|
88
92
|
end
|
89
93
|
|
94
|
+
#--
|
95
|
+
# Create Blob
|
96
|
+
#--
|
97
|
+
def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)
|
98
|
+
azure_connect(credentials)
|
99
|
+
#get a handle to the bucket in order to put there
|
100
|
+
the_bucket = WAZ::Blobs::Container.find(bucket_id)
|
101
|
+
the_bucket.store(blob_id, blob_data[:tempfile], blob_data[:type])
|
102
|
+
Blob.new( { :id => blob_id,
|
103
|
+
:bucket => bucket_id,
|
104
|
+
:content_lengh => blob_data[:tempfile].length,
|
105
|
+
:content_type => blob_data[:type],
|
106
|
+
:last_modified => ''
|
107
|
+
} )
|
108
|
+
end
|
109
|
+
|
110
|
+
#--
|
111
|
+
# Delete Blob
|
112
|
+
#--
|
113
|
+
def delete_blob(credentials, bucket_id, blob_id, opts=nil)
|
114
|
+
azure_connect(credentials)
|
115
|
+
#get a handle to bucket and blob, and destroy!
|
116
|
+
the_bucket = WAZ::Blobs::Container.find(bucket_id)
|
117
|
+
the_blob = the_bucket[blob_id]
|
118
|
+
the_blob.destroy!
|
119
|
+
end
|
120
|
+
|
90
121
|
private
|
91
122
|
|
92
123
|
def azure_connect(credentials)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2009 Red Hat, Inc.
|
2
|
+
# Copyright (C) 2009, 2010 Red Hat, Inc.
|
3
3
|
#
|
4
4
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
5
|
# contributor license agreements. See the NOTICE file distributed with
|
@@ -296,7 +296,7 @@ class EC2Driver < Deltacloud::BaseDriver
|
|
296
296
|
safely do
|
297
297
|
keypairs.keySet.item.each do |keypair|
|
298
298
|
result << convert_key(keypair)
|
299
|
-
end
|
299
|
+
end if keypairs.keySet
|
300
300
|
end
|
301
301
|
result
|
302
302
|
end
|
@@ -398,8 +398,10 @@ class EC2Driver < Deltacloud::BaseDriver
|
|
398
398
|
#--
|
399
399
|
def blob_data(credentials, bucket_id, blob_id, opts)
|
400
400
|
s3_client = s3_client(credentials)
|
401
|
-
|
402
|
-
|
401
|
+
safely do
|
402
|
+
s3_client.interface.get(bucket_id, blob_id) do |chunk|
|
403
|
+
yield chunk
|
404
|
+
end
|
403
405
|
end
|
404
406
|
end
|
405
407
|
|
@@ -410,15 +412,17 @@ class EC2Driver < Deltacloud::BaseDriver
|
|
410
412
|
s3_client = s3_client(credentials)
|
411
413
|
#data is a construct with the temporary file created by server @.tempfile
|
412
414
|
#also file[:type] will give us the content-type
|
413
|
-
|
414
|
-
|
415
|
-
|
415
|
+
safely do
|
416
|
+
res = s3_client.interface.put(bucket_id, blob_id, data[:tempfile], {"Content-Type" => data[:type]})
|
417
|
+
#create a new Blob object and return that
|
418
|
+
Blob.new( { :id => blob_id,
|
416
419
|
:bucket => bucket_id,
|
417
|
-
:content_length => data
|
420
|
+
:content_length => data[:tempfile].length,
|
418
421
|
:content_type => data[:type],
|
419
422
|
:last_modified => ''
|
420
423
|
}
|
421
424
|
)
|
425
|
+
end
|
422
426
|
end
|
423
427
|
|
424
428
|
#--
|
@@ -426,7 +430,9 @@ class EC2Driver < Deltacloud::BaseDriver
|
|
426
430
|
#--
|
427
431
|
def delete_blob(credentials, bucket_id, blob_id, opts=nil)
|
428
432
|
s3_client = s3_client(credentials)
|
429
|
-
|
433
|
+
safely do
|
434
|
+
s3_client.interface.delete(bucket_id, blob_id)
|
435
|
+
end
|
430
436
|
end
|
431
437
|
|
432
438
|
def load_balancer(credentials, opts={})
|
@@ -656,8 +662,8 @@ class EC2Driver < Deltacloud::BaseDriver
|
|
656
662
|
def catched_exceptions_list
|
657
663
|
{
|
658
664
|
:auth => [ AWS::AuthFailure ],
|
659
|
-
:error => [],
|
660
|
-
:glob => [
|
665
|
+
:error => [ RightAws::AwsError ],
|
666
|
+
:glob => [ /.*AWS::(\w+)/ ]
|
661
667
|
}
|
662
668
|
end
|
663
669
|
|
@@ -1,3 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009,2010 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
9
|
+
# License. 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, WITHOUT
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
16
|
+
# License for the specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
|
1
19
|
module RightAws
|
2
20
|
class MockEc2
|
3
21
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2009 Red Hat, Inc.
|
2
|
+
# Copyright (C) 2009, 2010 Red Hat, Inc.
|
3
3
|
#
|
4
4
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
5
|
# contributor license agreements. See the NOTICE file distributed with
|
@@ -37,10 +37,24 @@ class GogridDriver < Deltacloud::BaseDriver
|
|
37
37
|
|
38
38
|
feature :instances, :authentication_password
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
def hardware_profiles(credentials, opts={})
|
41
|
+
client = new_client(credentials)
|
42
|
+
safely do
|
43
|
+
server_types = client.request('common/lookup/list', { 'lookup' => 'server.type' })
|
44
|
+
server_rams = client.request('common/lookup/list', { 'lookup' => 'server.ram' })
|
45
|
+
@hardware_profiles = []
|
46
|
+
server_types['list'].each do |type|
|
47
|
+
memory_values = server_rams['list'].collect do |r|
|
48
|
+
r['name'] =~ /MB$/ ? r['name'].gsub(/MB$/, '').to_i : (r['name'].gsub(/(\w{2})$/, '')).to_i*1024
|
49
|
+
end
|
50
|
+
@hardware_profiles << ::Deltacloud::HardwareProfile.new(type['name'].tr(' ', '-').downcase) do
|
51
|
+
cpu 2
|
52
|
+
memory memory_values
|
53
|
+
storage 25
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
@hardware_profiles
|
44
58
|
end
|
45
59
|
|
46
60
|
def supported_collections
|
@@ -361,6 +375,7 @@ class GogridDriver < Deltacloud::BaseDriver
|
|
361
375
|
:description=> convert_description(gg_image),
|
362
376
|
:owner_id=>gg_image['owner']['name'],
|
363
377
|
:architecture=>convert_arch(gg_image['description']),
|
378
|
+
:state => gg_image['state']['name'].upcase
|
364
379
|
} )
|
365
380
|
end
|
366
381
|
|
@@ -228,6 +228,33 @@ class RackspaceDriver < Deltacloud::BaseDriver
|
|
228
228
|
end
|
229
229
|
end
|
230
230
|
|
231
|
+
#--
|
232
|
+
# Create Blob
|
233
|
+
#--
|
234
|
+
def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)
|
235
|
+
cf = cloudfiles_client(credentials)
|
236
|
+
#must first create the object using cloudfiles_client.create_object
|
237
|
+
#then can write using object.write(data)
|
238
|
+
object = cf.container(bucket_id).create_object(blob_id)
|
239
|
+
#blob_data is a construct with data in .tempfile and content-type in {:type}
|
240
|
+
res = object.write(blob_data[:tempfile], {'Content-Type' => blob_data[:type]})
|
241
|
+
Blob.new( { :id => object.name,
|
242
|
+
:bucket => object.container.name,
|
243
|
+
:content_length => blob_data[:tempfile].length,
|
244
|
+
:content_type => blob_data[:type],
|
245
|
+
:last_modified => ''
|
246
|
+
}
|
247
|
+
)
|
248
|
+
end
|
249
|
+
|
250
|
+
#--
|
251
|
+
# Delete Blob
|
252
|
+
#--
|
253
|
+
def delete_blob(credentials, bucket_id, blob_id, opts=nil)
|
254
|
+
cf = cloudfiles_client(credentials)
|
255
|
+
cf.container(bucket_id).delete_object(blob_id)
|
256
|
+
end
|
257
|
+
|
231
258
|
private
|
232
259
|
|
233
260
|
def convert_srv_to_instance(srv)
|
@@ -271,7 +298,7 @@ private
|
|
271
298
|
|
272
299
|
def cloudfiles_client(credentials)
|
273
300
|
safely do
|
274
|
-
CloudFiles::Connection.new(credentials.user, credentials.password)
|
301
|
+
CloudFiles::Connection.new(:username => credentials.user, :api_key => credentials.password)
|
275
302
|
end
|
276
303
|
end
|
277
304
|
|
@@ -1,3 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009,2010 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
9
|
+
# License. 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, WITHOUT
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
16
|
+
# License for the specific language governing permissions and limitations
|
17
|
+
# under the License.
|
1
18
|
|
2
19
|
module Deltacloud
|
3
20
|
class HardwareProfile
|
data/lib/deltacloud/helpers.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009,2010 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
9
|
+
# License. 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, WITHOUT
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
16
|
+
# License for the specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
|
1
19
|
require 'deltacloud/helpers/application_helper'
|
2
20
|
require 'deltacloud/helpers/conversion_helper'
|
3
21
|
require 'deltacloud/helpers/hardware_profiles_helper'
|
@@ -1,5 +1,4 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (C) 2009 Red Hat, Inc.
|
1
|
+
# Copyright (C) 2009, 2010 Red Hat, Inc.
|
3
2
|
#
|
4
3
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
5
4
|
# contributor license agreements. See the NOTICE file distributed with
|
@@ -17,6 +16,7 @@
|
|
17
16
|
# under the License.
|
18
17
|
|
19
18
|
# Methods added to this helper will be available to all templates in the application.
|
19
|
+
|
20
20
|
module ApplicationHelper
|
21
21
|
|
22
22
|
def bread_crumb
|
@@ -28,7 +28,11 @@ begin
|
|
28
28
|
#the client guess and if they can't they SHOULD default to
|
29
29
|
#'application/octet-stream' anyway as per:
|
30
30
|
#http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
|
31
|
-
EM.next_tick { env['async.callback'].call [200, {
|
31
|
+
EM.next_tick { env['async.callback'].call [200, {
|
32
|
+
'Content-Type' => "#{params['content_type']}",
|
33
|
+
'Content-Disposition' => params["content_disposition"],
|
34
|
+
'Content-Length' => "#{params['content_length']}"}, body]
|
35
|
+
}
|
32
36
|
#call the driver from here. the driver method yields for every chunk of blob it receives. We then
|
33
37
|
#use body.call to write that chunk as received.
|
34
38
|
driver.blob_data(credentials, params[:bucket], params[:blob], params) {|chunk| body.call ["#{chunk}"]} #close blob_data block
|
@@ -1,3 +1,20 @@
|
|
1
|
+
# Copyright (C) 2009, 2010 Red Hat, Inc.
|
2
|
+
#
|
3
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
4
|
+
# contributor license agreements. See the NOTICE file distributed with
|
5
|
+
# this work for additional information regarding copyright ownership. The
|
6
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance with the
|
8
|
+
# License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
|
1
18
|
module HardwareProfilesHelper
|
2
19
|
|
3
20
|
def format_hardware_property(prop)
|