occi 3.0.0.beta.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/Gemfile +3 -26
  2. data/Gemfile.lock +43 -35
  3. data/README.md +40 -4
  4. data/bin/occi +67 -64
  5. data/ext/mkrf_conf.rb +25 -0
  6. data/features/cassettes/Create_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml +186 -0
  7. data/features/cassettes/Delete_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml +186 -0
  8. data/features/cassettes/Discovery_Interface/Retrieving_all_OCCI_Categories_supported_by_the_OCCI_Server/_http_http___141_5_99_69__application_json_200_.yml +173 -0
  9. data/features/cassettes/Discovery_Interface/Retrieving_all_OCCI_Categories_supported_by_the_OCCI_Server/_http_http___141_5_99_69__text_plain_200_.yml +325 -0
  10. data/features/cassettes/Discovery_Interface/Retrieving_all_OCCI_Categories_supported_by_the_OCCI_Server/_http_http___141_5_99_69__text_plain_200_action_.yml +186 -0
  11. data/features/cassettes/Miscellaneous_operation_on_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml +186 -0
  12. data/features/cassettes/Read_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml +186 -0
  13. data/features/cassettes/Update_an_OCCI_Resource/_http_http___141_5_99_69__text_plain_201_.yml +186 -0
  14. data/features/occi/core/create/create.feature +3 -2
  15. data/features/occi/core/delete/delete.feature +6 -2
  16. data/features/occi/core/discovery_interface/discovery_interface.feature +4 -2
  17. data/features/occi/core/miscellaneous/miscellaneous.feature +6 -2
  18. data/features/occi/core/read/read.feature +6 -2
  19. data/features/occi/core/update/update.feature +6 -2
  20. data/features/occi/infrastructure/create/create.feature +6 -2
  21. data/features/support/env.rb +13 -1
  22. data/lib/occi/api/client/client_http.rb +914 -820
  23. data/lib/occi/api/client/http/net_http_fix.rb +7 -36
  24. data/lib/occi/api/dsl.rb +32 -2
  25. data/lib/occi/bin/occi_opts.rb +15 -1
  26. data/lib/occi/collection.rb +26 -15
  27. data/lib/occi/core/categories.rb +9 -1
  28. data/lib/occi/core/category.rb +20 -11
  29. data/lib/occi/core/link.rb +4 -5
  30. data/lib/occi/model.rb +2 -2
  31. data/lib/occi/parser.rb +51 -49
  32. data/lib/occi/version.rb +1 -1
  33. data/occi.gemspec +16 -3
  34. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/creates_a_new_compute_resource.yml +222 -0
  35. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/creates_a_new_network_resource.yml +222 -0
  36. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/creates_a_new_storage_resource.yml +222 -0
  37. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/deletes_a_compute_resource.yml +222 -0
  38. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/deletes_a_network_resource.yml +222 -0
  39. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/deletes_a_storage_resource.yml +222 -0
  40. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/deploys_an_instance_based_on_OVF_OVA_file.yml +222 -0
  41. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/describes_all_available_mixins.yml +222 -0
  42. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/describes_compute_resources.yml +324 -0
  43. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/describes_network_resources.yml +326 -0
  44. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/describes_os_tpl_mixins.yml +222 -0
  45. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/describes_resource_tpl_mixins.yml +222 -0
  46. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/describes_storage_resources.yml +386 -0
  47. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/establishes_connection.yml +222 -0
  48. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/instantiates_a_compute_resource_using_type_identifier.yml +222 -0
  49. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/instantiates_a_compute_resource_using_type_name.yml +222 -0
  50. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/instantiates_a_network_resource_using_type_identifier.yml +222 -0
  51. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/instantiates_a_network_resource_using_type_name.yml +222 -0
  52. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/instantiates_a_storage_resource_using_type_identifier.yml +222 -0
  53. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/instantiates_a_storage_resource_using_type_name.yml +222 -0
  54. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_entity_type_identifiers.yml +222 -0
  55. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_entity_types.yml +222 -0
  56. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_link_type_identifiers.yml +222 -0
  57. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_link_types.yml +222 -0
  58. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_mixin_type_identifiers.yml +222 -0
  59. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_mixin_types.yml +222 -0
  60. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_mixins.yml +222 -0
  61. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_resource_type_identifiers.yml +222 -0
  62. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_all_available_resource_types.yml +222 -0
  63. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_compute_resources.yml +264 -0
  64. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_network_resources.yml +264 -0
  65. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_os_tpl_mixins.yml +222 -0
  66. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_resource_tpl_mixins.yml +222 -0
  67. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/lists_storage_resources.yml +266 -0
  68. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/refreshes_its_model.yml +397 -0
  69. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/triggers_an_action_on_a_compute_resource.yml +222 -0
  70. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/triggers_an_action_on_a_network_resource.yml +222 -0
  71. data/spec/cassettes/Occi_Api_Client_ClientHttp/using_media_type_text_plain/triggers_an_action_on_a_storage_resource.yml +222 -0
  72. data/spec/occi/api/client/client_amqp_spec.rb +10 -2
  73. data/spec/occi/api/client/client_http_spec.rb +111 -117
  74. data/spec/occi/api/dsl_spec.rb +22 -0
  75. data/spec/occi/collection_spec.rb +11 -2
  76. data/spec/occi/core/resource_spec.rb +1 -1
  77. data/spec/occi/infrastructure/compute_spec.rb +3 -3
  78. data/spec/occi/log_spec.rb +1 -1
  79. data/spec/occi/model_spec.rb +4 -8
  80. data/spec/occi/parser_spec.rb +4 -4
  81. data/spec/spec_helper.rb +3 -2
  82. metadata +264 -12
  83. data/spec/cassettes/client_http_text_plain.yml +0 -1066
  84. data/spec/occi/api/client/client_http_0.5_spec.rb +0 -292
@@ -1,9 +1,9 @@
1
-
2
1
  Feature:
3
2
  In order to create an OCCI Resource on the OCCI Server
4
3
  As an OCCI Client
5
4
  I want to get an success report of the create operation and receive the URI of the new Resource by the OCCI Server
6
5
 
6
+ @vcr_record
7
7
  Scenario Outline: Create an OCCI Resource
8
8
  Given endpoint : <endpoint>
9
9
  And transfer_protocol : <protocol>
@@ -12,6 +12,7 @@ Feature:
12
12
  When the Client makes a create request
13
13
  Then the Client should have the response code <response_code>
14
14
 
15
+ @vcr_record
15
16
  Scenarios:
16
17
  | protocol | endpoint | accept_type | response_code |
17
- | http | http://141.5.99.69/ | text/plain | 201 |
18
+ | http | http://141.5.99.69/ | text/plain | 201 |
@@ -1,7 +1,10 @@
1
1
  Feature:
2
- ...
2
+ In order to delete an OCCI Resource on the OCCI Server
3
+ As an OCCI Client
4
+ I want to get an success report of the delete operation
3
5
 
4
- Scenario Outline: ...
6
+ @vcr_record
7
+ Scenario Outline: Delete an OCCI Resource
5
8
  Given endpoint : <endpoint>
6
9
  And transfer_protocol : <protocol>
7
10
  And accept type : <accept_type>
@@ -9,6 +12,7 @@ Feature:
9
12
  When the Client makes a delete request
10
13
  Then the Client should have the response code <response_code>
11
14
 
15
+ @vcr_record
12
16
  Scenarios:
13
17
  | protocol | endpoint | accept_type | response_code |
14
18
  | http | http://141.5.99.69/ | text/plain | 201 |
@@ -5,6 +5,7 @@ Feature: Discovery Interface
5
5
  As an OCCI Client
6
6
  I want to receive all OCCI Categories supported by the OCCI Server
7
7
 
8
+ @vcr_record
8
9
  Scenario Outline: Retrieving all OCCI Categories supported by the OCCI Server
9
10
  Given endpoint : <endpoint>
10
11
  And transfer_protocol : <protocol>
@@ -15,12 +16,13 @@ Feature: Discovery Interface
15
16
  Then the Client should have the response code <response_code>
16
17
  And OCCI Client should display the OCCI Categories received from the OCCI Server
17
18
 
19
+ @vcr_record
18
20
  Scenarios:
19
21
  | protocol | endpoint | accept_type | response_code | category_filter |
20
22
  | http | http://141.5.99.69/ | application/json | 200 | |
21
- | http | http://141.5.99.69/ | text/occi | 200 | |
23
+ #| http | http://141.5.99.69/ | text/occi | 200 | |
22
24
  | http | http://141.5.99.69/ | text/plain | 200 | |
23
- | http | http://46.231.128.85:8086/| text/occi | 200 | |
25
+ #| http | http://46.231.128.85:8086/| text/occi | 200 | |
24
26
  | http | http://141.5.99.69/ | text/plain | 200 | action |
25
27
 
26
28
  #Scenario: Retrieving the OCCI Categories with an OCCI Category filter from the OCCI Server
@@ -1,7 +1,10 @@
1
1
  Feature:
2
- ...
2
+ In order to manipulate an OCCI Resource on the OCCI Server
3
+ As an OCCI Client
4
+ I want to get an success report of the miscellaneous operation
3
5
 
4
- Scenario Outline: ...
6
+ @vcr_record
7
+ Scenario Outline: Miscellaneous operation on an OCCI Resource
5
8
  Given endpoint : <endpoint>
6
9
  And transfer_protocol : <protocol>
7
10
  And accept type : <accept_type>
@@ -9,6 +12,7 @@ Feature:
9
12
  When the Client makes a miscellaneous request
10
13
  Then the Client should have the response code <response_code>
11
14
 
15
+ @vcr_record
12
16
  Scenarios:
13
17
  | protocol | endpoint | accept_type | response_code |
14
18
  | http | http://141.5.99.69/ | text/plain | 201 |
@@ -1,7 +1,10 @@
1
1
  Feature:
2
- ...
2
+ In order to read an OCCI Resource on the OCCI Server
3
+ As an OCCI Client
4
+ I want to get an success report of the read operation and receive Resource data from the OCCI Server
3
5
 
4
- Scenario Outline: ...
6
+ @vcr_record
7
+ Scenario Outline: Read an OCCI Resource
5
8
  Given endpoint : <endpoint>
6
9
  And transfer_protocol : <protocol>
7
10
  And accept type : <accept_type>
@@ -9,6 +12,7 @@ Feature:
9
12
  When the Client makes a read request
10
13
  Then the Client should have the response code <response_code>
11
14
 
15
+ @vcr_record
12
16
  Scenarios:
13
17
  | protocol | endpoint | accept_type | response_code |
14
18
  | http | http://141.5.99.69/ | text/plain | 201 |
@@ -1,7 +1,10 @@
1
1
  Feature:
2
- ...
2
+ In order to update an OCCI Resource on the OCCI Server
3
+ As an OCCI Client
4
+ I want to get an success report of the update operation
3
5
 
4
- Scenario Outline: ...
6
+ @vcr_record
7
+ Scenario Outline: Update an OCCI Resource
5
8
  Given endpoint : <endpoint>
6
9
  And transfer_protocol : <protocol>
7
10
  And accept type : <accept_type>
@@ -9,6 +12,7 @@ Feature:
9
12
  When the Client makes an update request
10
13
  Then the Client should have the response code <response_code>
11
14
 
15
+ @vcr_record
12
16
  Scenarios:
13
17
  | protocol | endpoint | accept_type | response_code |
14
18
  | http | http://141.5.99.69/ | text/plain | 201 |
@@ -1,7 +1,10 @@
1
1
  Feature:
2
- ...
2
+ In order to create an OCCI Resource on the OCCI Server
3
+ As an OCCI Client
4
+ I want to get an success report of the create operation and receive the URI of the new Resource by the OCCI Server
3
5
 
4
- Scenario Outline: ...
6
+ @vcr_record
7
+ Scenario Outline: Create an OCCI Resource
5
8
  Given endpoint : <endpoint>
6
9
  And transfer_protocol : <protocol>
7
10
  And accept type : <accept_type>
@@ -9,6 +12,7 @@ Feature:
9
12
  When the Client makes a create request
10
13
  Then the Client should have the response code <response_code>
11
14
 
15
+ @vcr_record
12
16
  Scenarios:
13
17
  | protocol | endpoint | accept_type | response_code |
14
18
  | http | http://141.5.99.69/ | text/plain | 201 |
@@ -1,4 +1,16 @@
1
1
  $:.unshift(File.dirname(__FILE__) + '/../../lib')
2
2
 
3
3
  require 'rubygems'
4
- require 'occi'
4
+ require 'occi'
5
+
6
+ require 'vcr'
7
+
8
+ VCR.configure do |c|
9
+ c.hook_into :webmock
10
+ c.cassette_library_dir = 'features/cassettes'
11
+ end
12
+
13
+ VCR.cucumber_tags do |t|
14
+ t.tags '@vcr_ignore', :record => :none
15
+ t.tag '@vcr_record', {:use_scenario_name => true, :record => :new_episodes}
16
+ end
@@ -7,916 +7,1010 @@ module Occi
7
7
  module Api
8
8
  module Client
9
9
 
10
- class ClientHttp
11
-
12
- # HTTParty for raw HTTP requests
13
- include HTTParty
14
-
15
- # TODO: uncomment the following line as JSON is properly implemented in OpenStack
16
- # headers 'Accept' => 'application/occi+json,text/plain;q=0.8,text/occi;q=0.2'
17
- headers 'Accept' => 'text/plain,text/occi;q=0.2'
18
-
19
- # a few attributes which should be visible outside the client
20
- attr_reader :endpoint
21
- attr_reader :auth_options
22
- attr_accessor :media_type
23
- attr_reader :connected
24
- attr_accessor :model
25
- attr_reader :logger
26
- attr_reader :last_response
27
-
28
- # hash mapping HTTP response codes to human-readable messages
29
- HTTP_CODES = {
30
- "100" => "Continue",
31
- "101" => "Switching Protocols",
32
- "200" => "OK",
33
- "201" => "Created",
34
- "202" => "Accepted",
35
- "203" => "Non-Authoritative Information",
36
- "204" => "No Content",
37
- "205" => "Reset Content",
38
- "206" => "Partial Content",
39
- "300" => "Multiple Choices",
40
- "301" => "Moved Permanently",
41
- "302" => "Found",
42
- "303" => "See Other",
43
- "304" => "Not Modified",
44
- "305" => "Use Proxy",
45
- "307" => "Temporary Redirect",
46
- "400" => "Bad Request",
47
- "401" => "Unauthorized",
48
- "402" => "Payment Required",
49
- "403" => "Forbidden",
50
- "404" => "Not Found",
51
- "405" => "Method Not Allowed",
52
- "406" => "Not Acceptable",
53
- "407" => "Proxy Authentication Required",
54
- "408" => "Request Time-out",
55
- "409" => "Conflict",
56
- "410" => "Gone",
57
- "411" => "Length Required",
58
- "412" => "Precondition Failed",
59
- "413" => "Request Entity Too Large",
60
- "414" => "Request-URI Too Large",
61
- "415" => "Unsupported Media Type",
62
- "416" => "Requested range not satisfiable",
63
- "417" => "Expectation Failed",
64
- "500" => "Internal Server Error",
65
- "501" => "Not Implemented",
66
- "502" => "Bad Gateway",
67
- "503" => "Service Unavailable",
68
- "504" => "Gateway Time-out",
69
- "505" => "HTTP Version not supported"
70
- }
71
-
72
- # Initializes client data structures and retrieves OCCI model
73
- # from the server.
74
- #
75
- # @example
76
- # Occi::Api::Client::ClientHttp.new # => #<Occi::Api::Client::ClientHttp>
77
- #
78
- # @param [String] endpoint URI
79
- # @param [Hash] auth options in a hash
80
- # @param [Hash] logging options in a hash
81
- # @param [Boolean] enable autoconnect
82
- # @param [String] media type identifier
83
- # @return [Occi::Api::Client::ClientHttp] client instance
84
- def initialize(endpoint = "http://localhost:3000/", auth_options = { :type => "none" },
85
- log_options = { :out => STDERR, :level => Occi::Log::WARN, :logger => nil },
86
- auto_connect = true, media_type = nil)
87
- # set Occi::Log
88
- set_logger log_options
89
-
90
- # pass auth options to HTTParty
91
- change_auth auth_options
92
-
93
- # check the validity and canonize the endpoint URI
94
- prepare_endpoint endpoint
95
-
96
- # get accepted media types from HTTParty
97
- set_media_type
98
-
99
- # force media_type if provided
100
- if media_type
101
- self.class.headers 'Accept' => media_type
102
- @media_type = media_type
103
- end
104
-
105
- Occi::Log.debug("Media Type: #{@media_type}")
106
- Occi::Log.debug("Headers: #{self.class.headers}")
107
-
108
- # get model information from the endpoint
109
- # and create Occi::Model instance
110
- set_model
111
-
112
- # auto-connect?
113
- @connected = auto_connect
114
- end
10
+ class ClientHttp
11
+
12
+ # HTTParty for raw HTTP requests
13
+ include HTTParty
14
+
15
+ # TODO: uncomment the following line as JSON is properly implemented in OpenStack
16
+ # headers 'Accept' => 'application/occi+json,text/plain;q=0.8,text/occi;q=0.2'
17
+ headers 'Accept' => 'text/plain,text/occi;q=0.2'
18
+
19
+ # a few attributes which should be visible outside the client
20
+ attr_reader :endpoint
21
+ attr_reader :auth_options
22
+ attr_accessor :media_type
23
+ attr_reader :connected
24
+ attr_accessor :model
25
+ attr_reader :logger
26
+ attr_reader :last_response
27
+
28
+ # hash mapping HTTP response codes to human-readable messages
29
+ HTTP_CODES = {
30
+ "100" => "Continue",
31
+ "101" => "Switching Protocols",
32
+ "200" => "OK",
33
+ "201" => "Created",
34
+ "202" => "Accepted",
35
+ "203" => "Non-Authoritative Information",
36
+ "204" => "No Content",
37
+ "205" => "Reset Content",
38
+ "206" => "Partial Content",
39
+ "300" => "Multiple Choices",
40
+ "301" => "Moved Permanently",
41
+ "302" => "Found",
42
+ "303" => "See Other",
43
+ "304" => "Not Modified",
44
+ "305" => "Use Proxy",
45
+ "307" => "Temporary Redirect",
46
+ "400" => "Bad Request",
47
+ "401" => "Unauthorized",
48
+ "402" => "Payment Required",
49
+ "403" => "Forbidden",
50
+ "404" => "Not Found",
51
+ "405" => "Method Not Allowed",
52
+ "406" => "Not Acceptable",
53
+ "407" => "Proxy Authentication Required",
54
+ "408" => "Request Time-out",
55
+ "409" => "Conflict",
56
+ "410" => "Gone",
57
+ "411" => "Length Required",
58
+ "412" => "Precondition Failed",
59
+ "413" => "Request Entity Too Large",
60
+ "414" => "Request-URI Too Large",
61
+ "415" => "Unsupported Media Type",
62
+ "416" => "Requested range not satisfiable",
63
+ "417" => "Expectation Failed",
64
+ "500" => "Internal Server Error",
65
+ "501" => "Not Implemented",
66
+ "502" => "Bad Gateway",
67
+ "503" => "Service Unavailable",
68
+ "504" => "Gateway Time-out",
69
+ "505" => "HTTP Version not supported"
70
+ }
71
+
72
+ # Initializes client data structures and retrieves OCCI model
73
+ # from the server.
74
+ #
75
+ # @example
76
+ # Occi::Api::Client::ClientHttp.new # => #<Occi::Api::Client::ClientHttp>
77
+ #
78
+ # @param [String] endpoint URI
79
+ # @param [Hash] auth options in a hash
80
+ # @param [Hash] logging options in a hash
81
+ # @param [Boolean] enable autoconnect
82
+ # @param [String] media type identifier
83
+ # @return [Occi::Api::Client::ClientHttp] client instance
84
+ def initialize(endpoint = "http://localhost:3000/", auth_options = {:type => "none"},
85
+ log_options = {:out => STDERR, :level => Occi::Log::WARN, :logger => nil},
86
+ auto_connect = true, media_type = nil)
87
+ # set Occi::Log
88
+ set_logger log_options
89
+
90
+ # pass auth options to HTTParty
91
+ change_auth auth_options
92
+
93
+ # check the validity and canonize the endpoint URI
94
+ prepare_endpoint endpoint
95
+
96
+ # get accepted media types from HTTParty
97
+ set_media_type
98
+
99
+ # force media_type if provided
100
+ if media_type
101
+ self.class.headers 'Accept' => media_type
102
+ @media_type = media_type
103
+ end
104
+
105
+ Occi::Log.debug("Media Type: #{@media_type}")
106
+ Occi::Log.debug("Headers: #{self.class.headers}")
115
107
 
116
- # Creates a new resource instance, resource should be specified
117
- # by its name or identifier.
118
- #
119
- # @example
120
- # client.get_resource "compute" # => Occi::Core::Resource
121
- # client.get_resource "storage" # => Occi::Core::Resource
122
- # client.get_resource "http://schemas.ogf.org/occi/infrastructure#network"
123
- # # => Occi::Core::Resource
124
- #
125
- # @param [String] resource name or resource identifier
126
- # @return [Occi::Core::Resource] new resource instance
127
- def get_resource(resource_type)
128
-
129
- Occi::Log.debug("Instantiating #{resource_type} ...")
130
-
131
- if @model.get_by_id resource_type
132
- # we got a resource type identifier
133
- Occi::Core::Resource.new resource_type
134
- elsif @model.kinds.select { |kind| kind.term == resource_type }.any?
135
- # we got a resource type name
136
- Occi::Core::Resource.new @model.kinds.select {
137
- |kind| kind.term == resource_type
138
- }.first.type_identifier
139
- else
140
- raise "Unknown resource type! [#{resource_type}]"
108
+ # get model information from the endpoint
109
+ # and create Occi::Model instance
110
+ set_model
111
+
112
+ # auto-connect?
113
+ @connected = auto_connect
141
114
  end
142
115
 
143
- end
116
+ # Creates a new resource instance, resource should be specified
117
+ # by its name or identifier.
118
+ #
119
+ # @example
120
+ # client.get_resource "compute" # => Occi::Core::Resource
121
+ # client.get_resource "storage" # => Occi::Core::Resource
122
+ # client.get_resource "http://schemas.ogf.org/occi/infrastructure#network"
123
+ # # => Occi::Core::Resource
124
+ #
125
+ # @param [String] resource name or resource identifier
126
+ # @return [Occi::Core::Resource] new resource instance
127
+ def get_resource(resource_type)
128
+
129
+ Occi::Log.debug("Instantiating #{resource_type} ...")
130
+
131
+ if @model.get_by_id resource_type
132
+ # we got a resource type identifier
133
+ Occi::Core::Resource.new resource_type
134
+ elsif @model.kinds.select { |kind| kind.term == resource_type }.any?
135
+ # we got a resource type name
136
+ Occi::Core::Resource.new @model.kinds.select {
137
+ |kind| kind.term == resource_type
138
+ }.first.type_identifier
139
+ else
140
+ raise "Unknown resource type! [#{resource_type}]"
141
+ end
144
142
 
145
- # Retrieves all available resource types.
146
- #
147
- # @example
148
- # client.get_resource_types # => [ "compute", "storage", "network" ]
149
- #
150
- # @return [Array<String>] list of available resource types in a human-readable format
151
- def get_resource_types
152
- Occi::Log.debug("Getting resource types ...")
153
- @model.kinds.collect { |kind| kind.term }
154
- end
143
+ end
155
144
 
156
- # Retrieves all available resource type identifiers.
157
- #
158
- # @example
159
- # client.get_resource_type_identifiers
160
- # # => [ "http://schemas.ogf.org/occi/infrastructure#compute",
161
- # # "http://schemas.ogf.org/occi/infrastructure#storage",
162
- # # "http://schemas.ogf.org/occi/infrastructure#network" ]
163
- #
164
- # @return [Array<String>] list of available resource types in a Occi ID format
165
- def get_resource_type_identifiers
166
- Occi::Log.debug("Getting resource identifiers ...")
167
- @model.kinds.collect { |kind| kind.type_identifier }
168
- end
145
+ # Retrieves all entity type identifiers related to a given type identifier
146
+ #
147
+ # @example
148
+ # client.get_entity_type_identifiers_related_to 'network'
149
+ # # => [ "http://schemas.ogf.org/occi/infrastructure#network",
150
+ # # "http://schemas.ogf.org/occi/infrastructure#ipnetwork" ]
151
+ #
152
+ # @param [String] type_identifier
153
+ # @return [Array<String>] list of available entity type identifiers related to given type identifier in a human-readable format
154
+ def get_entity_types_related_to(type_identifier)
155
+ Occi::Log.debug("Getting entity type identifiers related to #{type_identifier}")
156
+ collection = @model.get type_identifier
157
+ collection.kinds.collect { |kind| kind.type_identifier }
158
+ end
159
+
160
+ # Retrieves all available entity types.
161
+ #
162
+ # @example
163
+ # client.get_entity_types # => [ "entity", "resource", "link" ]
164
+ #
165
+ # @return [Array<String>] list of available entity types in a human-readable format
166
+ def get_entity_types
167
+ Occi::Log.debug("Getting entity types ...")
168
+ @model.kinds.collect { |kind| kind.term }
169
+ end
170
+
171
+ # Retrieves all available entity type identifiers.
172
+ #
173
+ # @example
174
+ # client.get_entity_type_identifiers
175
+ # # => [ "http://schemas.ogf.org/occi/core#entity",
176
+ # # "http://schemas.ogf.org/occi/core#resource",
177
+ # # "http://schemas.ogf.org/occi/core#link" ]
178
+ #
179
+ # @return [Array<String>] list of available entity types in a OCCI ID format
180
+ def get_entity_type_identifiers
181
+ get_entity_types_related_to Occi::Core::Entity.kind.type_identifier
182
+ end
183
+
184
+ # Retrieves all available resource types.
185
+ #
186
+ # @example
187
+ # client.get_resource_types # => [ "compute", "storage", "network" ]
188
+ #
189
+ # @return [Array<String>] list of available resource types in a human-readable format
190
+ def get_resource_types
191
+ Occi::Log.debug("Getting resource types ...")
192
+ collection = @model.get Occi::Core::Resource.kind
193
+ collection.kinds.collect { |kind| kind.term }
194
+ end
195
+
196
+ # Retrieves all available resource type identifiers.
197
+ #
198
+ # @example
199
+ # client.get_resource_type_identifiers
200
+ # # => [ "http://schemas.ogf.org/occi/infrastructure#compute",
201
+ # # "http://schemas.ogf.org/occi/infrastructure#storage",
202
+ # # "http://schemas.ogf.org/occi/infrastructure#network" ]
203
+ #
204
+ # @return [Array<String>] list of available resource types in a Occi ID format
205
+ def get_resource_type_identifiers
206
+ get_entity_types_related_to Occi::Core::Resource.kind.type_identifier
207
+
208
+ end
209
+
210
+ # Retrieves all available link types.
211
+ #
212
+ # @example
213
+ # client.get_link_types # => [ "storagelink", "networkinterface" ]
214
+ #
215
+ # @return [Array<String>] list of available link types in a human-readable format
216
+ def get_link_types
217
+ Occi::Log.debug("Getting link types ...")
218
+ collection = @model.get Occi::Core::Link.kind
219
+ collection.kinds.collect { |kind| kind.term }
220
+ end
169
221
 
170
- # Looks up a mixin using its name and, optionally, a type as well.
171
- # Will return mixin's full location (a link) or a description.
172
- #
173
- # @example
174
- # client.find_mixin "debian6"
175
- # # => "http://my.occi.service/occi/infrastructure/os_tpl#debian6"
176
- # client.find_mixin "debian6", "os_tpl"
177
- # # => "http://my.occi.service/occi/infrastructure/os_tpl#debian6"
178
- # client.find_mixin "large", "resource_tpl"
179
- # # => "http://my.occi.service/occi/infrastructure/resource_tpl#large"
180
- # client.find_mixin "debian6", "resource_tpl" # => nil
181
- #
182
- # @param [String] name of the mixin
183
- # @param [String] type of the mixin
184
- # @param [Boolean] should we describe the mixin or return its link?
185
- # @return [String, Occi::Collection, nil] link, mixin description or nothing found
186
- def find_mixin(name, type = nil, describe = false)
187
-
188
- Occi::Log.debug("Looking for mixin #{name} + #{type} + #{describe}")
189
-
190
- # is type valid?
191
- if type
192
- raise "Unknown mixin type! [#{type}]" unless @mixins.has_key? type.to_sym
193
- end
194
-
195
- # TODO: extend this code to support multiple matches and regex filters
196
- # should we look for links or descriptions?
197
- if describe
198
- # we are looking for descriptions
222
+ # Retrieves all available link type identifiers.
223
+ #
224
+ # @example
225
+ # client.get_link_type_identifiers
226
+ # # => [ "http://schemas.ogf.org/occi/infrastructure#storagelink",
227
+ # # "http://schemas.ogf.org/occi/infrastructure#networkinterface" ]
228
+ #
229
+ # @return [Array<String>] list of available link types in a OCCI ID format
230
+ def get_link_type_identifiers
231
+ get_entity_types_related_to Occi::Core::Link.kind.type_identifier
232
+ end
233
+
234
+ # Looks up a mixin using its name and, optionally, a type as well.
235
+ # Will return mixin's full location (a link) or a description.
236
+ #
237
+ # @example
238
+ # client.find_mixin "debian6"
239
+ # # => "http://my.occi.service/occi/infrastructure/os_tpl#debian6"
240
+ # client.find_mixin "debian6", "os_tpl"
241
+ # # => "http://my.occi.service/occi/infrastructure/os_tpl#debian6"
242
+ # client.find_mixin "large", "resource_tpl"
243
+ # # => "http://my.occi.service/occi/infrastructure/resource_tpl#large"
244
+ # client.find_mixin "debian6", "resource_tpl" # => nil
245
+ #
246
+ # @param [String] name of the mixin
247
+ # @param [String] type of the mixin
248
+ # @param [Boolean] should we describe the mixin or return its link?
249
+ # @return [String, Occi::Collection, nil] link, mixin description or nothing found
250
+ def find_mixin(name, type = nil, describe = false)
251
+
252
+ Occi::Log.debug("Looking for mixin #{name} + #{type} + #{describe}")
253
+
254
+ # is type valid?
199
255
  if type
200
- # get the first match from either os_tpls or resource_tpls
201
- case
202
- when type == "os_tpl"
203
- get_os_templates.select { |mixin| mixin.term == name }.first
204
- when type == "resource_tpl"
205
- get_resource_templates.select { |template| template.term == name }.first
206
- else
207
- nil
256
+ raise "Unknown mixin type! [#{type}]" unless @mixins.has_key? type.to_sym
257
+ end
258
+
259
+ # TODO: extend this code to support multiple matches and regex filters
260
+ # should we look for links or descriptions?
261
+ if describe
262
+ # we are looking for descriptions
263
+ if type
264
+ # get the first match from either os_tpls or resource_tpls
265
+ case
266
+ when type == "os_tpl"
267
+ get_os_templates.select { |mixin| mixin.term == name }.first
268
+ when type == "resource_tpl"
269
+ get_resource_templates.select { |template| template.term == name }.first
270
+ else
271
+ nil
272
+ end
273
+ else
274
+ # try in os_tpls first
275
+ found = get_os_templates.select { |os| os.term == name }.first
276
+
277
+ # then try in resource_tpls
278
+ found = get_resource_templates.select {
279
+ |template| template.term == name
280
+ }.first unless found
281
+
282
+ found
208
283
  end
209
284
  else
210
- # try in os_tpls first
211
- found = get_os_templates.select { |os| os.term == name }.first
212
-
213
- # then try in resource_tpls
214
- found = get_resource_templates.select {
215
- |template| template.term == name
216
- }.first unless found
217
-
218
- found
285
+ # we are looking for links
286
+ # prefix mixin name with '#' to simplify the search
287
+ name = "#" + name
288
+ if type
289
+ # return the first match with the selected type
290
+ @mixins[type.to_sym].select {
291
+ |mixin| mixin.to_s.reverse.start_with? name.reverse
292
+ }.first
293
+ else
294
+ # there is no type preference, return first global match
295
+ @mixins.flatten(2).select {
296
+ |mixin| mixin.to_s.reverse.start_with? name.reverse
297
+ }.first
298
+ end
219
299
  end
220
- else
221
- # we are looking for links
222
- # prefix mixin name with '#' to simplify the search
223
- name = "#" + name
300
+ end
301
+
302
+ # Retrieves available mixins of a specified type or all available
303
+ # mixins if the type wasn't specified. Mixins are returned in the
304
+ # form of mixin identifiers.
305
+ #
306
+ # @example
307
+ # client.get_mixins
308
+ # # => ["http://my.occi.service/occi/infrastructure/os_tpl#debian6",
309
+ # # "http://my.occi.service/occi/infrastructure/resource_tpl#small"]
310
+ # client.get_mixins "os_tpl"
311
+ # # => ["http://my.occi.service/occi/infrastructure/os_tpl#debian6"]
312
+ # client.get_mixins "resource_tpl"
313
+ # # => ["http://my.occi.service/occi/infrastructure/resource_tpl#small"]
314
+ #
315
+ # @param [String] type of mixins
316
+ # @return [Array<String>] list of available mixins
317
+ def get_mixins(type = nil)
224
318
  if type
225
- # return the first match with the selected type
226
- @mixins[type.to_sym].select {
227
- |mixin| mixin.to_s.reverse.start_with? name.reverse
228
- }.first
319
+ # is type valid?
320
+ raise "Unknown mixin type! #{type}" unless @mixins.has_key? type.to_sym
321
+
322
+ # return mixin of the selected type
323
+ @mixins[type.to_sym]
229
324
  else
230
- # there is no type preference, return first global match
231
- @mixins.flatten(2).select {
232
- |mixin| mixin.to_s.reverse.start_with? name.reverse
233
- }.first
325
+ # we did not get a type, return all mixins
326
+ mixins = []
327
+
328
+ # flatten the hash and remove its keys
329
+ get_mixin_types.each do |ltype|
330
+ mixins.concat @mixins[ltype.to_sym]
331
+ end
332
+
333
+ mixins
234
334
  end
235
335
  end
236
- end
237
336
 
238
- # Retrieves available mixins of a specified type or all available
239
- # mixins if the type wasn't specified. Mixins are returned in the
240
- # form of mixin identifiers.
241
- #
242
- # @example
243
- # client.get_mixins
244
- # # => ["http://my.occi.service/occi/infrastructure/os_tpl#debian6",
245
- # # "http://my.occi.service/occi/infrastructure/resource_tpl#small"]
246
- # client.get_mixins "os_tpl"
247
- # # => ["http://my.occi.service/occi/infrastructure/os_tpl#debian6"]
248
- # client.get_mixins "resource_tpl"
249
- # # => ["http://my.occi.service/occi/infrastructure/resource_tpl#small"]
250
- #
251
- # @param [String] type of mixins
252
- # @return [Array<String>] list of available mixins
253
- def get_mixins(type = nil)
254
- if type
255
- # is type valid?
256
- raise "Unknown mixin type! #{type}" unless @mixins.has_key? type.to_sym
337
+ # Retrieves available mixin types. Mixin types are presented
338
+ # in a shortened format (i.e. not as type identifiers).
339
+ #
340
+ # @example
341
+ # client.get_mixin_types # => [ "os_tpl", "resource_tpl" ]
342
+ #
343
+ # @return [Array<String>] list of available mixin types
344
+ def get_mixin_types
345
+ @mixins.keys.map! { |k| k.to_s }
346
+ end
257
347
 
258
- # return mixin of the selected type
259
- @mixins[type.to_sym]
260
- else
261
- # we did not get a type, return all mixins
262
- mixins = []
348
+ # Retrieves available mixin type identifiers.
349
+ #
350
+ # @example
351
+ # client.get_mixin_type_identifiers
352
+ # # => ['http://schemas.ogf.org/occi/infrastructure#os_tpl',
353
+ # # 'http://schemas.ogf.org/occi/infrastructure#resource_tpl']
354
+ #
355
+ # @return [Array<String>] list of available mixin type identifiers
356
+ def get_mixin_type_identifiers
357
+ identifiers = []
263
358
 
264
- # flatten the hash and remove its keys
265
- get_mixin_types.each do |ltype|
266
- mixins.concat @mixins[ltype.to_sym]
359
+ get_mixin_types.each do |mixin_type|
360
+ identifiers << 'http://schemas.ogf.org/occi/infrastructure#' + mixin_type
267
361
  end
268
362
 
269
- mixins
363
+ identifiers
270
364
  end
271
- end
272
365
 
273
- # Retrieves available mixin types. Mixin types are presented
274
- # in a shortened format (i.e. not as type identifiers).
275
- #
276
- # @example
277
- # client.get_mixin_types # => [ "os_tpl", "resource_tpl" ]
278
- #
279
- # @return [Array<String>] list of available mixin types
280
- def get_mixin_types
281
- @mixins.keys.map! { |k| k.to_s }
282
- end
366
+ # Retrieves available resources represented by resource locations (URIs).
367
+ # If no type identifier is specified, all available resource are listed.
368
+ # Type identifier can be specified in its shortened format (e.g. "compute",
369
+ # "storage", "network").
370
+ #
371
+ # @example
372
+ # client.list
373
+ # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j",
374
+ # # "http://localhost:3300/network/kh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j",
375
+ # # "http://localhost:3300/storage/lh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
376
+ # client.list "compute"
377
+ # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
378
+ # client.list "http://schemas.ogf.org/occi/infrastructure#compute"
379
+ # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
380
+ #
381
+ # @param [String] resource type identifier or just type name
382
+ # @return [Array<String>] list of links
383
+ def list(resource_type_identifier=nil)
384
+ if resource_type_identifier
385
+ # convert type to type identifier
386
+ resource_type_identifier = @model.kinds.select {
387
+ |kind| kind.term == resource_type_identifier
388
+ }.first.type_identifier if @model.kinds.select {
389
+ |kind| kind.term == resource_type_identifier
390
+ }.any?
391
+
392
+ # check some basic pre-conditions
393
+ raise "Endpoint is not connected!" unless @connected
394
+ raise "Unkown resource type identifier! [#{resource_type_identifier}]" unless @model.get_by_id resource_type_identifier
395
+
396
+ # split the type identifier and get the most important part
397
+ uri_part = resource_type_identifier.split('#').last
398
+
399
+ # request uri-list from the server
400
+ path = uri_part + '/'
401
+ else
402
+ path = '/'
403
+ end
283
404
 
284
- # Retrieves available mixin type identifiers.
285
- #
286
- # @example
287
- # client.get_mixin_type_identifiers
288
- # # => ['http://schemas.ogf.org/occi/infrastructure#os_tpl',
289
- # # 'http://schemas.ogf.org/occi/infrastructure#resource_tpl']
290
- #
291
- # @return [Array<String>] list of available mixin type identifiers
292
- def get_mixin_type_identifiers
293
- identifiers = []
405
+ headers = self.class.headers.clone
406
+ headers['Accept'] = 'text/uri-list'
294
407
 
295
- get_mixin_types.each do |mixin_type|
296
- identifiers << 'http://schemas.ogf.org/occi/infrastructure#' + mixin_type
408
+ self.class.get(@endpoint + path, :headers => headers).body.split("\n").compact
297
409
  end
298
410
 
299
- identifiers
300
- end
411
+ # Retrieves descriptions for available resources specified by a type
412
+ # identifier or resource location. If no type identifier or location
413
+ # is specified, all available resources in all available resource types
414
+ # will be described.
415
+ #
416
+ # @example
417
+ # client.describe
418
+ # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
419
+ # client.describe "compute"
420
+ # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
421
+ # client.describe "http://schemas.ogf.org/occi/infrastructure#compute"
422
+ # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
423
+ # client.describe "http://localhost:3300/compute/j5hk1234jk2524-2j3j2k34jjh234-adfaf1234"
424
+ # # => [#<Occi::Collection>]
425
+ #
426
+ # @param [String] resource type identifier, type name or resource location
427
+ # @return [Array<Occi::Collection>] list of resource descriptions
428
+ def describe(resource_type_identifier=nil)
301
429
 
302
- # Retrieves available resources represented by resource locations (URIs).
303
- # If no type identifier is specified, all available resource are listed.
304
- # Type identifier can be specified in its shortened format (e.g. "compute",
305
- # "storage", "network").
306
- #
307
- # @example
308
- # client.list
309
- # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j",
310
- # # "http://localhost:3300/network/kh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j",
311
- # # "http://localhost:3300/storage/lh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
312
- # client.list "compute"
313
- # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
314
- # client.list "http://schemas.ogf.org/occi/infrastructure#compute"
315
- # # => [ "http://localhost:3300/compute/jh425jhj3h413-7dj29d7djd9e3-djh2jh4j4j" ]
316
- #
317
- # @param [String] resource type identifier or just type name
318
- # @return [Array<String>] list of links
319
- def list(resource_type_identifier=nil)
320
- if resource_type_identifier
321
430
  # convert type to type identifier
322
431
  resource_type_identifier = @model.kinds.select {
323
- |kind| kind.term == resource_type_identifier
432
+ |kind| kind.term == resource_type_identifier
324
433
  }.first.type_identifier if @model.kinds.select {
325
- |kind| kind.term == resource_type_identifier
434
+ |kind| kind.term == resource_type_identifier
326
435
  }.any?
327
436
 
328
437
  # check some basic pre-conditions
329
438
  raise "Endpoint is not connected!" unless @connected
330
- raise "Unkown resource type identifier! [#{resource_type_identifier}]" unless @model.get_by_id resource_type_identifier
331
-
332
- # split the type identifier and get the most important part
333
- uri_part = resource_type_identifier.split('#').last
334
439
 
335
- # request uri-list from the server
336
- path = uri_part + '/'
337
- else
338
- path = '/'
339
- end
440
+ descriptions = []
340
441
 
341
- self.class.get(@endpoint + path,
342
- :headers => { "Accept" => 'text/uri-list' }).body.split("\n").compact
343
- end
442
+ if resource_type_identifier.nil?
443
+ descriptions << get('/')
444
+ elsif @model.get_by_id resource_type_identifier
445
+ # we got type identifier
446
+ # get all available resources of this type
447
+ locations = list resource_type_identifier
344
448
 
345
- # Retrieves descriptions for available resources specified by a type
346
- # identifier or resource location. If no type identifier or location
347
- # is specified, all available resources in all available resource types
348
- # will be described.
349
- #
350
- # @example
351
- # client.describe
352
- # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
353
- # client.describe "compute"
354
- # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
355
- # client.describe "http://schemas.ogf.org/occi/infrastructure#compute"
356
- # # => [#<Occi::Collection>, #<Occi::Collection>, #<Occi::Collection>]
357
- # client.describe "http://localhost:3300/compute/j5hk1234jk2524-2j3j2k34jjh234-adfaf1234"
358
- # # => [#<Occi::Collection>]
359
- #
360
- # @param [String] resource type identifier, type name or resource location
361
- # @return [Array<Occi::Collection>] list of resource descriptions
362
- def describe(resource_type_identifier=nil)
363
-
364
- # convert type to type identifier
365
- resource_type_identifier = @model.kinds.select {
366
- |kind| kind.term == resource_type_identifier
367
- }.first.type_identifier if @model.kinds.select {
368
- |kind| kind.term == resource_type_identifier
369
- }.any?
370
-
371
- # check some basic pre-conditions
372
- raise "Endpoint is not connected!" unless @connected
373
-
374
- descriptions = []
375
-
376
- if resource_type_identifier.nil?
377
- descriptions << get('/')
378
- elsif @model.get_by_id resource_type_identifier
379
- # we got type identifier
380
- # get all available resources of this type
381
- locations = list resource_type_identifier
382
-
383
- # make the requests
384
- locations.each do |location|
385
- descriptions << get(sanitize_resource_link(location))
449
+ # make the requests
450
+ locations.each do |location|
451
+ descriptions << get(sanitize_resource_link(location))
452
+ end
453
+ elsif resource_type_identifier.start_with? @endpoint
454
+ # we got resource link
455
+ # make the request
456
+ descriptions << get(sanitize_resource_link(resource_type_identifier))
457
+ else
458
+ raise "Unkown resource type identifier! [#{resource_type_identifier}]"
386
459
  end
387
- elsif resource_type_identifier.start_with? @endpoint
388
- # we got resource link
389
- # make the request
390
- descriptions << get(sanitize_resource_link(resource_type_identifier))
391
- else
392
- raise "Unkown resource type identifier! [#{resource_type_identifier}]"
460
+
461
+ descriptions
393
462
  end
394
463
 
395
- descriptions
396
- end
464
+ # Creates a new resource on the server. Resource must be provided
465
+ # as an instance of Occi::Core::Entity, e.g. instantiated using
466
+ # the get_resource method.
467
+ #
468
+ # @example
469
+ # res = client.get_resource "compute"
470
+ #
471
+ # res.title = "MyComputeResource1"
472
+ # res.mixins << client.find_mixin('small', "resource_tpl")
473
+ # res.mixins << client.find_mixin('debian6', "os_tpl")
474
+ #
475
+ # client.create res # => "http://localhost:3300/compute/df7698...f987fa"
476
+ #
477
+ # @param [Occi::Core::Entity] resource to be created on the server
478
+ # @return [String] URI of the new resource
479
+ def create(entity)
397
480
 
398
- # Creates a new resource on the server. Resource must be provided
399
- # as an instance of Occi::Core::Entity, e.g. instantiated using
400
- # the get_resource method.
401
- #
402
- # @example
403
- # res = client.get_resource "compute"
404
- #
405
- # res.title = "MyComputeResource1"
406
- # res.mixins << client.find_mixin('small', "resource_tpl")
407
- # res.mixins << client.find_mixin('debian6', "os_tpl")
408
- #
409
- # client.create res # => "http://localhost:3300/compute/df7698...f987fa"
410
- #
411
- # @param [Occi::Core::Entity] resource to be created on the server
412
- # @return [String] URI of the new resource
413
- def create(entity)
414
-
415
- # check some basic pre-conditions
416
- raise "Endpoint is not connected!" unless @connected
417
- raise "#{entity} not an entity" unless entity.kind_of? Occi::Core::Entity
418
-
419
- # is this entity valid?
420
- entity.model = @model
421
- entity.check
422
-
423
- Occi::Log.debug "Entity kind: #{entity.kind}"
424
- kind = entity.kind
425
- raise "No kind found for #{entity}" unless kind
426
-
427
- # get location for this kind of entity
428
- Occi::Log.debug "Kind location: #{entity.kind.location}"
429
- location = kind.location
430
- collection = Occi::Collection.new
431
-
432
- # is this entity a Resource or a Link?
433
- Occi::Log.debug "Entity class: #{entity.class.name}"
434
- collection.resources << entity if entity.kind_of? Occi::Core::Resource
435
- collection.links << entity if entity.kind_of? Occi::Core::Link
436
-
437
- # make the request
438
- post location, collection
439
- end
481
+ # check some basic pre-conditions
482
+ raise "Endpoint is not connected!" unless @connected
483
+ raise "#{entity} not an entity" unless entity.kind_of? Occi::Core::Entity
440
484
 
441
- # Deploys a compute resource based on an OVF/OVA descriptor available
442
- # on a local file system.
443
- #
444
- # @example
445
- # client.deploy "~/MyVMs/rOcciVM.ovf" # => "http://localhost:3300/compute/343423...42njhdafa"
446
- #
447
- # @param [String] location of an OVF/OVA file
448
- # @return [String] URI of the new resource
449
- def deploy(location)
450
- media_types = self.class.head(@endpoint).headers['accept'].to_s
451
- raise "File #{location} does not exist" unless File.exist? location
452
-
453
- file = File.read(location)
454
-
455
- if location.include? '.ovf'
456
- if media_types.include? 'application/ovf'
457
- headers = self.class.headers.clone
458
- headers['Content-Type'] = 'application/ovf'
459
- self.class.post(@endpoint + '/compute/',
460
- :body => file,
461
- :headers => headers)
462
- end
463
- elsif location.include? '.ova'
464
- if media_types.include? ' application/ova '
465
- headers = self.class.headers.clone
466
- headers['Content-Type'] = 'application/ova'
467
- self.class.post(@endpoint + '/compute/',
468
- :body => file,
469
- :headers => headers)
470
- end
471
- end
472
- end
485
+ # is this entity valid?
486
+ entity.model = @model
487
+ entity.check
473
488
 
474
- # Deletes a resource or all resource of a certain resource type
475
- # from the server.
476
- #
477
- # @example
478
- # client.delete "compute" # => true
479
- # client.delete "http://schemas.ogf.org/occi/infrastructure#compute" # => true
480
- # client.delete "http://localhost:3300/compute/245j42594...98s9df8s9f" # => true
481
- #
482
- # @param [String] resource type identifier, type name or location
483
- # @return [Boolean] status
484
- def delete(resource_type_identifier)
485
- # convert type to type identifier
486
- raise "Endpoint is not connected!" unless @connected
487
-
488
- path = path_for_resource_type resource_type_identifier
489
-
490
- del path
491
- end
489
+ Occi::Log.debug "Entity kind: #{entity.kind}"
490
+ kind = entity.kind
491
+ raise "No kind found for #{entity}" unless kind
492
492
 
493
- # Triggers given action on a specific resource.
494
- #
495
- # @example
496
- # TODO: add examples
497
- #
498
- # @param [String] resource location
499
- # @param [String] type of action
500
- # @return [String] resource location
501
- def trigger(resource_type_identifier, action)
502
- # TODO: not tested
503
- if @model.kinds.select { |kind| kind.term == resource_type }.any?
504
- type_identifier = @model.kinds.select {
505
- |kind| kind.term == resource_type_identifier
506
- }.first.type_identifier
507
-
508
- location = @model.get_by_id(type_identifier).location
509
- resource_type_identifier = @endpoint + location
510
- end
511
- # check some basic pre-conditions
512
- raise "Endpoint is not connected!" unless @connected
513
- raise "Unknown resource identifier! #{resource_type_identifier}" unless resource_type_identifier.start_with? @endpoint
514
-
515
- # encapsulate the acion in a collection
516
- collection = Occi::Collection.new
517
- scheme, term = action.split(' #')
518
- collection.actions << Occi::Core::Action.new(scheme + '#', term)
519
-
520
- # make the request
521
- path = sanitize_resource_link(resource_type_identifier) + '?action=' + term
522
- post path, collection
523
- end
493
+ # get location for this kind of entity
494
+ Occi::Log.debug "Kind location: #{entity.kind.location}"
495
+ location = kind.location
496
+ collection = Occi::Collection.new
524
497
 
525
- # Refreshes the Occi::Model used inside the client. Useful for
526
- # updating the model without creating a new instance or
527
- # reconnecting. Saves a lot of time in an interactive mode.
528
- #
529
- # @example
530
- # client.refresh
531
- def refresh
532
- # re-download the model from the server
533
- set_model
534
- end
498
+ # is this entity a Resource or a Link?
499
+ Occi::Log.debug "Entity class: #{entity.class.name}"
500
+ collection.resources << entity if entity.kind_of? Occi::Core::Resource
501
+ collection.links << entity if entity.kind_of? Occi::Core::Link
535
502
 
536
- private
503
+ # make the request
504
+ post location, collection
505
+ end
537
506
 
538
- # Sets the logger and log levels. This allows users to pass existing logger
539
- # instances to the rOCCI client.
540
- #
541
- # @example
542
- # set_logger { :out => STDERR, :level => Occi::Log::WARN, :logger => nil }
543
- #
544
- # @param [Hash] logger options
545
- def set_logger(log_options)
546
- if log_options[:logger].nil? or (not log_options[:logger].kind_of? Occi::Log)
547
- @logger = Occi::Log.new(log_options[:out])
548
- @logger.level = log_options[:level]
507
+ # Deploys a compute resource based on an OVF/OVA descriptor available
508
+ # on a local file system.
509
+ #
510
+ # @example
511
+ # client.deploy "~/MyVMs/rOcciVM.ovf" # => "http://localhost:3300/compute/343423...42njhdafa"
512
+ #
513
+ # @param [String] location of an OVF/OVA file
514
+ # @return [String] URI of the new resource
515
+ def deploy(location)
516
+ media_types = self.class.head(@endpoint).headers['accept'].to_s
517
+ raise "File #{location} does not exist" unless File.exist? location
518
+
519
+ file = File.read(location)
520
+
521
+ if location.include? '.ovf'
522
+ if media_types.include? 'application/ovf'
523
+ headers = self.class.headers.clone
524
+ headers['Content-Type'] = 'application/ovf'
525
+ self.class.post(@endpoint + '/compute/',
526
+ :body => file,
527
+ :headers => headers)
528
+ end
529
+ elsif location.include? '.ova'
530
+ if media_types.include? ' application/ova '
531
+ headers = self.class.headers.clone
532
+ headers['Content-Type'] = 'application/ova'
533
+ self.class.post(@endpoint + '/compute/',
534
+ :body => file,
535
+ :headers => headers)
536
+ end
537
+ end
549
538
  end
550
539
 
551
- self.class.debug_output $stderr if log_options[:level] == Occi::Log::DEBUG
552
- end
540
+ # Deletes a resource or all resource of a certain resource type
541
+ # from the server.
542
+ #
543
+ # @example
544
+ # client.delete "compute" # => true
545
+ # client.delete "http://schemas.ogf.org/occi/infrastructure#compute" # => true
546
+ # client.delete "http://localhost:3300/compute/245j42594...98s9df8s9f" # => true
547
+ #
548
+ # @param [String] resource type identifier, type name or location
549
+ # @return [Boolean] status
550
+ def delete(resource_type_identifier)
551
+ # convert type to type identifier
552
+ raise "Endpoint is not connected!" unless @connected
553
553
 
554
- # Sets auth method and appropriate httparty attributes. Supported auth methods
555
- # are: ["basic", "digest", "x509", "none"]
556
- #
557
- # @example
558
- # change_auth { :type => "none" }
559
- # change_auth { :type => "basic", :username => "123", :password => "321" }
560
- # change_auth { :type => "digest", :username => "123", :password => "321" }
561
- # change_auth { :type => "x509", :user_cert => "~/cert.pem",
562
- # :user_cert_password => "321", :ca_path => nil }
563
- # change_auth { :type => "keystone", :token => "005c8a5d7f2c437a9999302c458afbda" }
564
- #
565
- # @param [Hash] authentication options
566
- def change_auth(auth_options)
567
- @auth_options = auth_options
568
-
569
- case @auth_options[:type]
570
- when "basic"
571
- # set up basic auth
572
- raise ArgumentError, "Missing required options 'username' and 'password' for basic auth!" unless @auth_options[:username] and @auth_options[:password]
573
- self.class.basic_auth @auth_options[:username], @auth_options[:password]
574
- when "digest"
575
- # set up digest auth
576
- raise ArgumentError, "Missing required options 'username' and 'password' for digest auth!" unless @auth_options[:username] and @auth_options[:password]
577
- self.class.digest_auth @auth_options[:username], @auth_options[:password]
578
- when "x509"
579
- # set up pem and optionally pem_password and ssl_ca_path
580
- raise ArgumentError, "Missing required option 'user_cert' for x509 auth!" unless @auth_options[:user_cert]
581
- raise ArgumentError, "The file specified in 'user_cert' does not exist!" unless File.exists? @auth_options[:user_cert]
582
-
583
- self.class.pem File.read(@auth_options[:user_cert]), @auth_options[:user_cert_password]
584
- self.class.ssl_ca_path @auth_options[:ca_path] unless @auth_options[:ca_path].nil?
585
- self.class.ssl_ca_file @auth_options[:ca_file] unless @auth_options[:ca_file].nil?
586
- self.class.ssl_extra_chain_cert certs_to_file_ary(@auth_options[:proxy_ca]) unless @auth_options[:proxy_ca].nil?
587
- when "keystone"
588
- # set up OpenStack Keystone token based auth
589
- raise ArgumentError, "Missing required option 'token' for OpenStack Keystone auth!" unless @auth_options[:token]
590
- self.class.headers['X-Auth-Token'] = @auth_options[:token]
591
- when "none", nil
592
- # do nothing
593
- else
594
- raise ArgumentError, "Unknown AUTH method [#{@auth_options[:type]}]!"
595
- end
596
- end
554
+ path = path_for_resource_type resource_type_identifier
597
555
 
598
- # Reads X.509 certificates from a file to an array.
599
- #
600
- # @example
601
- # certs_to_file_ary "~/.globus/usercert.pem"
602
- # # => [#<String>, #<String>, ...]
603
- #
604
- # @param [String] Path to a PEM file containing certificates
605
- # @return [Array<String>] An array of read certificates
606
- def certs_to_file_ary(ca_file)
607
- # TODO: read and separate multiple certificates
608
- [] << File.read(ca_file)
609
- end
556
+ del path
557
+ end
610
558
 
611
- # Performs GET request and parses the responses to collections.
612
- #
613
- # @example
614
- # get "/-/" # => #<Occi::Collection>
615
- # get "/compute/" # => #<Occi::Collection>
616
- # get "/compute/fs65g4fs6g-sf54g54gsf-aa12faddf52" # => #<Occi::Collection>
617
- #
618
- # @param [String] path for the GET request
619
- # @param [Occi::Collection] collection of filters
620
- # @return [Occi::Collection] parsed result of the request
621
- def get(path='', filter=nil)
622
- # remove the leading slash
623
- path.gsub!(/\A\//, '')
559
+ # Triggers given action on a specific resource.
560
+ #
561
+ # @example
562
+ # TODO: add examples
563
+ #
564
+ # @param [String] resource location
565
+ # @param [String] type of action
566
+ # @return [String] resource location
567
+ def trigger(resource_type_identifier, action)
568
+ # TODO: not tested
569
+ if @model.kinds.select { |kind| kind.term == resource_type }.any?
570
+ type_identifier = @model.kinds.select {
571
+ |kind| kind.term == resource_type_identifier
572
+ }.first.type_identifier
573
+
574
+ location = @model.get_by_id(type_identifier).location
575
+ resource_type_identifier = @endpoint + location
576
+ end
577
+ # check some basic pre-conditions
578
+ raise "Endpoint is not connected!" unless @connected
579
+ raise "Unknown resource identifier! #{resource_type_identifier}" unless resource_type_identifier.start_with? @endpoint
624
580
 
625
- response = if filter
626
- categories = filter.categories.collect { |category| category.to_text }.join(',')
627
- attributes = filter.entities.collect { |entity| entity.attributes.combine.collect { |k, v| k + '=' + v } }.join(',')
581
+ # encapsulate the acion in a collection
582
+ collection = Occi::Collection.new
583
+ scheme, term = action.split(' #')
584
+ collection.actions << Occi::Core::Action.new(scheme + '#', term)
628
585
 
629
- headers = self.class.headers.clone
630
- headers['Content-Type'] = 'text/occi'
631
- headers['Category'] = categories unless categories.empty?
632
- headers['X-OCCI-Attributes'] = attributes unless attributes.empty?
586
+ # make the request
587
+ path = sanitize_resource_link(resource_type_identifier) + '?action=' + term
588
+ post path, collection
589
+ end
633
590
 
634
- self.class.get(@endpoint + path, :headers => headers)
635
- else
636
- self.class.get(@endpoint + path)
637
- end
591
+ # Refreshes the Occi::Model used inside the client. Useful for
592
+ # updating the model without creating a new instance or
593
+ # reconnecting. Saves a lot of time in an interactive mode.
594
+ #
595
+ # @example
596
+ # client.refresh
597
+ def refresh
598
+ # re-download the model from the server
599
+ set_model
600
+ end
638
601
 
639
- response_msg = response_message response
640
- raise "HTTP GET failed! #{response_msg}" unless response.code.between? 200, 300
602
+ private
641
603
 
642
- Occi::Log.debug "Response location: #{('/' + path).match(/\/.*\//).to_s}"
643
- kind = @model.get_by_location(('/' + path).match(/\/.*\//).to_s) if @model
604
+ # Sets the logger and log levels. This allows users to pass existing logger
605
+ # instances to the rOCCI client.
606
+ #
607
+ # @example
608
+ # set_logger { :out => STDERR, :level => Occi::Log::WARN, :logger => nil }
609
+ #
610
+ # @param [Hash] logger options
611
+ def set_logger(log_options)
612
+ if log_options[:logger].nil? or (not log_options[:logger].kind_of? Occi::Log)
613
+ @logger = Occi::Log.new(log_options[:out])
614
+ @logger.level = log_options[:level]
615
+ end
644
616
 
645
- Occi::Log.debug "Response kind: #{kind}"
617
+ self.class.debug_output $stderr if log_options[:level] == Occi::Log::DEBUG
618
+ end
646
619
 
647
- if kind
648
- kind.related_to? Occi::Core::Resource ? entity_type = Occi::Core::Resource : entity_type = nil
649
- entity_type = Occi::Core::Link if kind.related_to? Occi::Core::Link
620
+ # Sets auth method and appropriate httparty attributes. Supported auth methods
621
+ # are: ["basic", "digest", "x509", "none"]
622
+ #
623
+ # @example
624
+ # change_auth { :type => "none" }
625
+ # change_auth { :type => "basic", :username => "123", :password => "321" }
626
+ # change_auth { :type => "digest", :username => "123", :password => "321" }
627
+ # change_auth { :type => "x509", :user_cert => "~/cert.pem",
628
+ # :user_cert_password => "321", :ca_path => nil }
629
+ # change_auth { :type => "keystone", :token => "005c8a5d7f2c437a9999302c458afbda" }
630
+ #
631
+ # @param [Hash] authentication options
632
+ def change_auth(auth_options)
633
+ @auth_options = auth_options
634
+
635
+ case @auth_options[:type]
636
+ when "basic"
637
+ # set up basic auth
638
+ raise ArgumentError, "Missing required options 'username' and 'password' for basic auth!" unless @auth_options[:username] and @auth_options[:password]
639
+ self.class.basic_auth @auth_options[:username], @auth_options[:password]
640
+ when "digest"
641
+ # set up digest auth
642
+ raise ArgumentError, "Missing required options 'username' and 'password' for digest auth!" unless @auth_options[:username] and @auth_options[:password]
643
+ self.class.digest_auth @auth_options[:username], @auth_options[:password]
644
+ when "x509"
645
+ # set up pem and optionally pem_password and ssl_ca_path
646
+ raise ArgumentError, "Missing required option 'user_cert' for x509 auth!" unless @auth_options[:user_cert]
647
+ raise ArgumentError, "The file specified in 'user_cert' does not exist!" unless File.exists? @auth_options[:user_cert]
648
+
649
+ self.class.pem File.read(@auth_options[:user_cert]), @auth_options[:user_cert_password]
650
+ self.class.ssl_ca_path @auth_options[:ca_path] unless @auth_options[:ca_path].nil?
651
+ self.class.ssl_ca_file @auth_options[:ca_file] unless @auth_options[:ca_file].nil?
652
+ self.class.ssl_extra_chain_cert certs_to_file_ary(@auth_options[:proxy_ca]) unless @auth_options[:proxy_ca].nil?
653
+ when "keystone"
654
+ # set up OpenStack Keystone token based auth
655
+ raise ArgumentError, "Missing required option 'token' for OpenStack Keystone auth!" unless @auth_options[:token]
656
+ self.class.headers['X-Auth-Token'] = @auth_options[:token]
657
+ when "none", nil
658
+ # do nothing
659
+ else
660
+ raise ArgumentError, "Unknown AUTH method [#{@auth_options[:type]}]!"
661
+ end
650
662
  end
651
663
 
652
- Occi::Log.debug "Parser call: #{response.content_type} #{entity_type} #{path.include?('-/')}"
653
- collection = Occi::Parser.parse(response.content_type, response.body, path.include?('-/'), entity_type, response.headers)
664
+ # Reads X.509 certificates from a file to an array.
665
+ #
666
+ # @example
667
+ # certs_to_file_ary "~/.globus/usercert.pem"
668
+ # # => [#<String>, #<String>, ...]
669
+ #
670
+ # @param [String] Path to a PEM file containing certificates
671
+ # @return [Array<String>] An array of read certificates
672
+ def certs_to_file_ary(ca_file)
673
+ # TODO: read and separate multiple certificates
674
+ [] << File.read(ca_file)
675
+ end
654
676
 
655
- Occi::Log.debug "Parsed collection: empty? #{collection.empty?}"
656
- collection
657
- end
677
+ # Performs GET request and parses the responses to collections.
678
+ #
679
+ # @example
680
+ # get "/-/" # => #<Occi::Collection>
681
+ # get "/compute/" # => #<Occi::Collection>
682
+ # get "/compute/fs65g4fs6g-sf54g54gsf-aa12faddf52" # => #<Occi::Collection>
683
+ #
684
+ # @param [String] path for the GET request
685
+ # @param [Occi::Collection] collection of filters
686
+ # @return [Occi::Collection] parsed result of the request
687
+ def get(path='', filter=nil)
688
+ # remove the leading slash
689
+ path.gsub!(/\A\//, '')
690
+
691
+ response = if filter
692
+ categories = filter.categories.collect { |category| category.to_text }.join(',')
693
+ attributes = filter.entities.collect { |entity| entity.attributes.combine.collect { |k, v| k + '=' + v } }.join(',')
694
+
695
+ headers = self.class.headers.clone
696
+ headers['Content-Type'] = 'text/occi'
697
+ headers['Category'] = categories unless categories.empty?
698
+ headers['X-OCCI-Attributes'] = attributes unless attributes.empty?
699
+
700
+ self.class.get(@endpoint + path, :headers => headers)
701
+ else
702
+ self.class.get(@endpoint + path)
703
+ end
704
+
705
+ response_msg = response_message response
706
+ raise "HTTP GET failed! #{response_msg}" unless response.code.between? 200, 300
707
+
708
+ Occi::Log.debug "Response location: #{('/' + path).match(/\/.*\//).to_s}"
709
+ kind = @model.get_by_location(('/' + path).match(/\/.*\//).to_s) if @model
710
+
711
+ Occi::Log.debug "Response kind: #{kind}"
712
+
713
+ if kind
714
+ kind.related_to? Occi::Core::Resource ? entity_type = Occi::Core::Resource : entity_type = nil
715
+ entity_type = Occi::Core::Link if kind.related_to? Occi::Core::Link
716
+ end
658
717
 
659
- # Performs POST requests and returns URI locations. Resource data must be provided
660
- # in an Occi::Collection instance.
661
- #
662
- # @example
663
- # collection = Occi::Collection.new
664
- # collection.resources << entity if entity.kind_of? Occi::Core::Resource
665
- # collection.links << entity if entity.kind_of? Occi::Core::Link
666
- #
667
- # post "/compute/", collection # => "http://localhost:3300/compute/23sf4g65as-asdgsg2-sdfgsf2g"
668
- # post "/network/", collection # => "http://localhost:3300/network/23sf4g65as-asdgsg2-sdfgsf2g"
669
- # post "/storage/", collection # => "http://localhost:3300/storage/23sf4g65as-asdgsg2-sdfgsf2g"
670
- #
671
- # @param [String] path for the POST request
672
- # @param [Occi::Collection] resource data to be POSTed
673
- # @return [String] URI location
674
- def post(path, collection)
675
- # remove the leading slash
676
- path.gsub!(/\A\//, '')
677
-
678
- response = if @media_type == 'application/occi+json'
679
- self.class.post(@endpoint + path,
680
- :body => collection.to_json,
681
- :headers => { 'Accept' => 'text/uri-list', 'Content-Type' => 'application/occi+json' })
682
- elsif @media_type == 'text/occi'
683
- self.class.post(@endpoint + path,
684
- :headers => collection.to_header.merge({ 'Accept' => 'text/uri-list', 'Content-Type' => 'text/occi' }))
685
- else
686
- self.class.post(@endpoint + path,
687
- :body => collection.to_text,
688
- :headers => { 'Accept' => 'text/uri-list', 'Content-Type' => 'text/plain' })
689
- end
690
-
691
- response_msg = response_message response
692
- raise "HTTP POST failed! #{response_msg}" unless response.code.between? 200, 300
693
-
694
- URI.parse(response.body).to_s
695
- end
718
+ Occi::Log.debug "Parser call: #{response.content_type} #{entity_type} #{path.include?('-/')}"
719
+ collection = Occi::Parser.parse(response.content_type, response.body, path.include?('-/'), entity_type, response.headers)
696
720
 
697
- # Performs PUT requests and parses responses to collections.
698
- #
699
- # @example
700
- # TODO: add examples
701
- #
702
- # @param [String] path for the PUT request
703
- # @param [Occi::Collection] resource data to send
704
- # @return [Occi::Collection] parsed result of the request
705
- def put(path, collection)
706
- # remove the leading slash
707
- path.gsub!(/\A\//, '')
708
-
709
- response = if @media_type == 'application/occi+json'
710
- self.class.post(@endpoint + path, :body => collection.to_json, :headers => { 'Content-Type' => 'application/occi+json' })
711
- else
712
- self.class.post(@endpoint + path, { :body => collection.to_text, :headers => { 'Content-Type' => 'text/plain' } })
713
- end
714
-
715
- response_msg = response_message response
716
- raise "HTTP PUT failed! #{response_msg}" unless response.code.between? 200, 300
717
-
718
- collection = Occi::Parser.parse(response.content_type, response.body)
719
-
720
- collection
721
- end
721
+ Occi::Log.debug "Parsed collection: empty? #{collection.empty?}"
722
+ collection
723
+ end
722
724
 
723
- # Performs DELETE requests and returns True on success.
724
- #
725
- # @example
726
- # del "/compute/65sf4g65sf4g-sf6g54sf5g-sfgsf32g3" # => true
727
- #
728
- # @param [String] path for the DELETE request
729
- # @param [Occi::Collection] collection of filters (currently NOT used)
730
- # @return [Boolean] status
731
- def del(path, filter=nil)
732
- # remove the leading slash
733
- path.gsub!(/\A\//, '')
725
+ # Performs POST requests and returns URI locations. Resource data must be provided
726
+ # in an Occi::Collection instance.
727
+ #
728
+ # @example
729
+ # collection = Occi::Collection.new
730
+ # collection.resources << entity if entity.kind_of? Occi::Core::Resource
731
+ # collection.links << entity if entity.kind_of? Occi::Core::Link
732
+ #
733
+ # post "/compute/", collection # => "http://localhost:3300/compute/23sf4g65as-asdgsg2-sdfgsf2g"
734
+ # post "/network/", collection # => "http://localhost:3300/network/23sf4g65as-asdgsg2-sdfgsf2g"
735
+ # post "/storage/", collection # => "http://localhost:3300/storage/23sf4g65as-asdgsg2-sdfgsf2g"
736
+ #
737
+ # @param [String] path for the POST request
738
+ # @param [Occi::Collection] resource data to be POSTed
739
+ # @return [String] URI location
740
+ def post(path, collection)
741
+ # remove the leading slash
742
+ path.gsub!(/\A\//, '')
743
+
744
+ headers = self.class.headers.clone
745
+ headers['Content-Type'] = @media_type
746
+
747
+ response = case @media_type
748
+ when 'application/occi+json'
749
+ self.class.post(@endpoint + path,
750
+ :body => collection.to_json,
751
+ :headers => headers)
752
+ when 'text/occi'
753
+ self.class.post(@endpoint + path,
754
+ :headers => collection.to_header.merge(headers))
755
+ else
756
+ self.class.post(@endpoint + path,
757
+ :body => collection.to_text,
758
+ :headers => headers)
759
+ end
760
+
761
+ response_msg = response_message response
762
+
763
+ case response.code
764
+ when 200
765
+ collection = Occi::Parser.parse(response.header["content-type"].split(";").first, response)
766
+ if collection.empty?
767
+ Occi::Parser.locations(response.header["content-type"].split(";").first, response.body, response.header).first
768
+ else
769
+ collection.resources.first.location if collection.resources.first
770
+ end
771
+ when 201
772
+ Occi::Parser.locations(response.header["content-type"].split(";").first, response.body, response.header).first
773
+ else
774
+ raise "HTTP POST failed! #{response_msg}"
775
+ end
776
+ end
734
777
 
735
- response = self.class.delete(@endpoint + path)
778
+ # Performs PUT requests and parses responses to collections.
779
+ #
780
+ # @example
781
+ # TODO: add examples
782
+ #
783
+ # @param [String] path for the PUT request
784
+ # @param [Occi::Collection] resource data to send
785
+ # @return [Occi::Collection] parsed result of the request
786
+ def put(path, collection)
787
+ # remove the leading slash
788
+ path.gsub!(/\A\//, '')
789
+
790
+ headers = self.class.headers.clone
791
+ headers['Content-Type'] = @media_type
792
+
793
+ response = case @media_type
794
+ when 'application/occi+json'
795
+ self.class.post(@endpoint + path,
796
+ :body => collection.to_json,
797
+ :headers => headers)
798
+ when 'text/occi'
799
+ self.class.post(@endpoint + path,
800
+ :headers => collection.to_header.merge(headers))
801
+ else
802
+ self.class.post(@endpoint + path,
803
+ :body => collection.to_text,
804
+ :headers => headers)
805
+ end
806
+
807
+ response_msg = response_message response
808
+
809
+ case response.code
810
+ when 200, 201
811
+ Occi::Parser.parse(response.header["content-type"].split(";").first, response)
812
+ else
813
+ raise "HTTP POST failed! #{response_msg}"
814
+ end
815
+ end
736
816
 
737
- response_msg = response_message response
738
- raise "HTTP DELETE failed! #{response_msg}" unless response.code.between? 200, 300
817
+ # Performs DELETE requests and returns True on success.
818
+ #
819
+ # @example
820
+ # del "/compute/65sf4g65sf4g-sf6g54sf5g-sfgsf32g3" # => true
821
+ #
822
+ # @param [String] path for the DELETE request
823
+ # @param [Occi::Collection] collection of filters (currently NOT used)
824
+ # @return [Boolean] status
825
+ def del(path, filter=nil)
826
+ # remove the leading slash
827
+ path.gsub!(/\A\//, '')
739
828
 
740
- true
741
- end
829
+ response = self.class.delete(@endpoint + path)
742
830
 
743
- # Creates a link of a specified kind and binds it to the given resource.
744
- #
745
- # @example
746
- # link_kind = 'http://schemas.ogf.org/occi/infrastructure#storagelink'
747
- # compute = client.get_resource "compute"
748
- # storage_location = "http://localhost:3300/storage/321df21adfad-f3adfa5f4adf-a3d54ffadffe"
749
- # linked_resource_kind = 'http://schemas.ogf.org/occi/infrastructure#storage'
750
- #
751
- # link link_kind, compute, storage_location, linked_resource_kind
752
- #
753
- # @param [String] link type identifier (link kind)
754
- # @param [Occi::Core::Resource] resource to link to
755
- # @param [URI, String] resource to be linked
756
- # @param [String] type identifier of the linked resource
757
- # @param [Occi::Core::Attributes] link attributes
758
- # @param [Array<String>] link mixins
759
- # @return [Occi::Core::Link] link instance
760
- def link(kind, source, target_location, target_kind, attributes=Occi::Core::Attributes.new, mixins=[])
761
- link = Occi::Core::Link.new(kind)
762
- link.mixins = mixins
763
- link.attributes = attributes
764
- link.target = (target_location.kind_of? URI::Generic) ? target_location.path : target_location.to_s
765
- link.rel = target_kind
766
-
767
- jj link
768
- link.check @model
769
- source.links << link
770
-
771
- link
772
- end
831
+ response_msg = response_message response
832
+ raise "HTTP DELETE failed! #{response_msg}" unless response.code.between? 200, 300
773
833
 
774
- # Checks whether the given endpoint URI is valid and adds a trailing
775
- # slash if necessary.
776
- #
777
- # @example
778
- # prepare_endpoint "http://localhost:3300" # => "http://localhost:3300/"
779
- #
780
- # @param [String] endpoint URI in a non-canonical string
781
- # @return [String] canonical endpoint URI in a string, with a trailing slash
782
- def prepare_endpoint(endpoint)
783
- raise 'Endpoint not a valid URI' if (endpoint =~ URI::ABS_URI).nil?
784
- @endpoint = endpoint.chomp('/') + '/'
785
- end
834
+ true
835
+ end
786
836
 
787
- # Extracts the resource path from a resource link. It will remove the leading @endpoint
788
- # and replace it with a slash.
789
- #
790
- # @example
791
- # sanitize_resource_link "http://localhost:3300/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
792
- # # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
793
- #
794
- # @param [String] string containing the full resource link
795
- # @return [String] extracted path, with a leading slash
796
- def sanitize_resource_link(resource_link)
797
- raise "Resource link #{resource_link} is not valid!" unless resource_link.start_with? @endpoint
798
-
799
- resource_link.gsub @endpoint, '/'
800
- end
837
+ # Creates a link of a specified kind and binds it to the given resource.
838
+ #
839
+ # @example
840
+ # link_kind = 'http://schemas.ogf.org/occi/infrastructure#storagelink'
841
+ # compute = client.get_resource "compute"
842
+ # storage_location = "http://localhost:3300/storage/321df21adfad-f3adfa5f4adf-a3d54ffadffe"
843
+ # linked_resource_kind = 'http://schemas.ogf.org/occi/infrastructure#storage'
844
+ #
845
+ # link link_kind, compute, storage_location, linked_resource_kind
846
+ #
847
+ # @param [String] link type identifier (link kind)
848
+ # @param [Occi::Core::Resource] resource to link to
849
+ # @param [URI, String] resource to be linked
850
+ # @param [String] type identifier of the linked resource
851
+ # @param [Occi::Core::Attributes] link attributes
852
+ # @param [Array<String>] link mixins
853
+ # @return [Occi::Core::Link] link instance
854
+ def link(kind, source, target_location, target_kind, attributes=Occi::Core::Attributes.new, mixins=[])
855
+ link = Occi::Core::Link.new(kind)
856
+ link.mixins = mixins
857
+ link.attributes = attributes
858
+ link.target = (target_location.kind_of? URI::Generic) ? target_location.path : target_location.to_s
859
+ link.rel = target_kind
860
+
861
+ jj link
862
+ link.check @model
863
+ source.links << link
864
+
865
+ link
866
+ end
801
867
 
802
- # @describe find the path for the resource type identifier
803
- #
804
- # @example
805
- #
806
- #
807
- # @param [String] resource_type_identifier
808
- #
809
- # @return [String]
810
- def path_for_resource_type(resource_type_identifier)
811
- if resource_type_identifier.nil? || resource_type_identifier == "/"
812
- #we got all
813
- path = "/"
814
- else
815
- kinds = @model.kinds.select { |kind| kind.term == resource_type_identifier }
816
- if kinds.any?
817
- #we got an type identifier
818
- path = "/" + kinds.first.type_identifier.split('#').last + "/"
819
- elsif resource_type_identifier.start_with? @endpoint
820
- #we got an resource link
821
- path = sanitize_resource_link(resource_type_identifier)
822
- else
823
- raise "Unknown resource identifier! #{resource_type_identifier}"
824
- end
868
+ # Checks whether the given endpoint URI is valid and adds a trailing
869
+ # slash if necessary.
870
+ #
871
+ # @example
872
+ # prepare_endpoint "http://localhost:3300" # => "http://localhost:3300/"
873
+ #
874
+ # @param [String] endpoint URI in a non-canonical string
875
+ # @return [String] canonical endpoint URI in a string, with a trailing slash
876
+ def prepare_endpoint(endpoint)
877
+ raise 'Endpoint not a valid URI' if (endpoint =~ URI::ABS_URI).nil?
878
+ @endpoint = endpoint.chomp('/') + '/'
825
879
  end
826
880
 
827
- path
828
- end
881
+ # Extracts the resource path from a resource link. It will remove the leading @endpoint
882
+ # and replace it with a slash.
883
+ #
884
+ # @example
885
+ # sanitize_resource_link "http://localhost:3300/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
886
+ # # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
887
+ #
888
+ # @param [String] string containing the full resource link
889
+ # @return [String] extracted path, with a leading slash
890
+ def sanitize_resource_link(resource_link)
891
+ raise "Resource link #{resource_link} is not valid!" unless resource_link.start_with? @endpoint
829
892
 
830
- # Creates an Occi::Model from data retrieved from the server.
831
- #
832
- # @example
833
- # set_model
834
- def set_model
893
+ resource_link.gsub @endpoint, '/'
894
+ end
835
895
 
896
+ # @describe find the path for the resource type identifier
836
897
  #
837
- model = get('/-/')
838
- @model = Occi::Model.new(model)
898
+ # @example
899
+ #
900
+ #
901
+ # @param [String] resource_type_identifier
902
+ #
903
+ # @return [String]
904
+ def path_for_resource_type(resource_type_identifier)
905
+ if resource_type_identifier.nil? || resource_type_identifier == "/"
906
+ #we got all
907
+ path = "/"
908
+ else
909
+ kinds = @model.kinds.select { |kind| kind.term == resource_type_identifier }
910
+ if kinds.any?
911
+ #we got an type identifier
912
+ path = "/" + kinds.first.type_identifier.split('#').last + "/"
913
+ elsif resource_type_identifier.start_with? @endpoint
914
+ #we got an resource link
915
+ path = sanitize_resource_link(resource_type_identifier)
916
+ else
917
+ raise "Unknown resource identifier! #{resource_type_identifier}"
918
+ end
919
+ end
839
920
 
840
- @mixins = {
841
- :os_tpl => [],
842
- :resource_tpl => []
843
- }
921
+ path
922
+ end
844
923
 
924
+ # Creates an Occi::Model from data retrieved from the server.
845
925
  #
846
- get_os_templates.each do |os_tpl|
847
- @mixins[:os_tpl] << os_tpl.type_identifier unless os_tpl.nil? or os_tpl.type_identifier.nil?
926
+ # @example
927
+ # set_model
928
+ def set_model
929
+
930
+ #
931
+ model = get('/-/')
932
+ @model = Occi::Model.new(model)
933
+
934
+ @mixins = {
935
+ :os_tpl => [],
936
+ :resource_tpl => []
937
+ }
938
+
939
+ #
940
+ get_os_templates.each do |os_tpl|
941
+ @mixins[:os_tpl] << os_tpl.type_identifier unless os_tpl.nil? or os_tpl.type_identifier.nil?
942
+ end
943
+
944
+ #
945
+ get_resource_templates.each do |res_tpl|
946
+ @mixins[:resource_tpl] << res_tpl.type_identifier unless res_tpl.nil? or res_tpl.type_identifier.nil?
947
+ end
848
948
  end
849
949
 
950
+ # Retrieves available os_tpls from the model.
951
+ #
952
+ # @example
953
+ # get_os_templates # => #<Occi::Collection>
850
954
  #
851
- get_resource_templates.each do |res_tpl|
852
- @mixins[:resource_tpl] << res_tpl.type_identifier unless res_tpl.nil? or res_tpl.type_identifier.nil?
955
+ # @return [Occi::Collection] collection containing all registered OS templates
956
+ def get_os_templates
957
+ @model.get.mixins.select { |mixin| mixin.related.select { |rel| rel.end_with? 'os_tpl' }.any? }
853
958
  end
854
- end
855
959
 
856
- # Retrieves available os_tpls from the model.
857
- #
858
- # @example
859
- # get_os_templates # => #<Occi::Collection>
860
- #
861
- # @return [Occi::Collection] collection containing all registered OS templates
862
- def get_os_templates
863
- @model.get.mixins.select { |mixin| mixin.related.select { |rel| rel.end_with? 'os_tpl' }.any? }
864
- end
960
+ # Retrieves available resource_tpls from the model.
961
+ #
962
+ # @example
963
+ # get_resource_templates # => #<Occi::Collection>
964
+ #
965
+ # @return [Occi::Collection] collection containing all registered resource templates
966
+ def get_resource_templates
967
+ @model.get.mixins.select { |mixin| mixin.related.select { |rel| rel.end_with? 'resource_tpl' }.any? }
968
+ end
865
969
 
866
- # Retrieves available resource_tpls from the model.
867
- #
868
- # @example
869
- # get_resource_templates # => #<Occi::Collection>
870
- #
871
- # @return [Occi::Collection] collection containing all registered resource templates
872
- def get_resource_templates
873
- @model.get.mixins.select { |mixin| mixin.related.select { |rel| rel.end_with? 'resource_tpl' }.any? }
874
- end
970
+ # Sets media type. Will choose either application/occi+json or text/plain
971
+ # based on the formats supported by the server.
972
+ #
973
+ # @example
974
+ # set_media_type # => 'application/occi+json'
975
+ #
976
+ # @return [String] chosen media type
977
+ def set_media_type
978
+ media_types = self.class.head(@endpoint).headers['accept']
979
+ Occi::Log.debug("Available media types: #{media_types}")
980
+ @media_type = case media_types
981
+ when /application\/occi\+json/
982
+ 'application/occi+json'
983
+ else
984
+ 'text/plain'
985
+ end
986
+ end
875
987
 
876
- # Sets media type. Will choose either application/occi+json or text/plain
877
- # based on the formats supported by the server.
878
- #
879
- # @example
880
- # set_media_type # => 'application/occi+json'
881
- #
882
- # @return [String] chosen media type
883
- def set_media_type
884
- media_types = self.class.head(@endpoint).headers['accept']
885
- Occi::Log.debug("Available media types: #{media_types}")
886
- @media_type = case media_types
887
- when /application\/occi\+json/
888
- 'application/occi+json'
889
- else
890
- 'text/plain'
891
- end
892
- end
988
+ # Generates a human-readable response message based on the HTTP response code.
989
+ #
990
+ # @example
991
+ # response_message self.class.delete(@endpoint + path)
992
+ # # => 'HTTP Response status: [200] OK'
993
+ #
994
+ # @param [HTTParty::Response] HTTParty response object
995
+ # @return [String] message
996
+ def response_message(response)
997
+ @last_response = response
998
+ 'HTTP Response status: [' + response.code.to_s + '] ' + reason_phrase(response.code)
999
+ end
893
1000
 
894
- # Generates a human-readable response message based on the HTTP response code.
895
- #
896
- # @example
897
- # response_message self.class.delete(@endpoint + path)
898
- # # => 'HTTP Response status: [200] OK'
899
- #
900
- # @param [HTTParty::Response] HTTParty response object
901
- # @return [String] message
902
- def response_message(response)
903
- @last_response = response
904
- 'HTTP Response status: [' + response.code.to_s + '] ' + reason_phrase(response.code)
905
- end
1001
+ # Converts HTTP response codes to human-readable phrases.
1002
+ #
1003
+ # @example
1004
+ # reason_phrase(500) # => "Internal Server Error"
1005
+ #
1006
+ # @param [Integer] HTTP response code
1007
+ # @return [String] human-readable phrase
1008
+ def reason_phrase(code)
1009
+ HTTP_CODES[code.to_s]
1010
+ end
906
1011
 
907
- # Converts HTTP response codes to human-readable phrases.
908
- #
909
- # @example
910
- # reason_phrase(500) # => "Internal Server Error"
911
- #
912
- # @param [Integer] HTTP response code
913
- # @return [String] human-readable phrase
914
- def reason_phrase(code)
915
- HTTP_CODES[code.to_s]
916
1012
  end
917
1013
 
918
1014
  end
919
-
920
- end
921
1015
  end
922
1016
  end