occi 3.0.0 → 3.1.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +0 -1
- data/.travis.yml +26 -2
- data/Gemfile +5 -2
- data/Gemfile.lock +42 -26
- data/README.md +64 -4
- data/Rakefile +7 -3
- data/bin/occi +15 -58
- data/config/warble.rb +151 -0
- data/doc/macosx.md +27 -0
- data/examples/dsl_example.rb +16 -7
- data/examples/x509auth_example.rb +13 -7
- data/ext/mkrf_conf.rb +4 -3
- data/features/common/step_definitions/common_steps.rb +9 -9
- data/lib/occi/api/client/client_amqp.rb +25 -14
- data/lib/occi/api/client/client_http.rb +173 -156
- data/lib/occi/api/client/http/authn_utils.rb +82 -0
- data/lib/occi/bin/helpers.rb +84 -26
- data/lib/occi/bin/occi_opts.rb +166 -48
- data/lib/occi/version.rb +1 -1
- data/occi.gemspec +1 -1
- data/spec/occi/api/client/client_amqp_spec.rb +6 -3
- data/spec/occi/api/client/client_http_spec.rb +16 -16
- data/spec/occi/api/client/http/authn_utils_spec.rb +55 -0
- data/spec/occi/api/client/http/httparty_fix_spec.rb +0 -0
- data/spec/occi/api/client/http/net_http_fix_spec.rb +0 -0
- data/spec/occi/api/client/http/rocci-cred-cert.pem +3 -0
- data/spec/occi/api/client/http/rocci-cred-key-jruby.pem +3 -0
- data/spec/occi/api/client/http/rocci-cred-key.pem +3 -0
- data/spec/occi/api/client/http/rocci-cred.p12 +0 -0
- data/spec/occi/bin/helpers_spec.rb +12 -0
- data/spec/occi/bin/occi_opts_spec.rb +60 -0
- data/spec/occi/bin/resource_output_factory_spec.rb +12 -0
- data/spec/spec_helper.rb +26 -0
- metadata +35 -86
data/ext/mkrf_conf.rb
CHANGED
@@ -5,7 +5,8 @@ require 'rubygems/dependency_installer.rb'
|
|
5
5
|
begin
|
6
6
|
Gem::Command.build_args = ARGV
|
7
7
|
rescue NoMethodError
|
8
|
-
# do nothing
|
8
|
+
# do nothing but warn the user
|
9
|
+
warn "Gem::Command doesn't have a method named 'build_args'!"
|
9
10
|
end
|
10
11
|
|
11
12
|
if defined? RUBY_PLATFORM && RUBY_PLATFORM == "java"
|
@@ -14,8 +15,8 @@ if defined? RUBY_PLATFORM && RUBY_PLATFORM == "java"
|
|
14
15
|
begin
|
15
16
|
inst.install "jruby-openssl" if ((defined? JRUBY_VERSION) && (JRUBY_VERSION.split('.')[1].to_i < 7))
|
16
17
|
rescue
|
17
|
-
|
18
|
-
exit
|
18
|
+
warn "Gem::DependencyInstaller failed to install 'jruby-openssl'!"
|
19
|
+
exit
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
@@ -17,16 +17,16 @@ Given /^category filter : (.*)$/ do |category_filter|
|
|
17
17
|
end
|
18
18
|
|
19
19
|
Given /^have an initialize Client$/ do
|
20
|
-
@client = Occi::Api::Client::ClientHttp.new(
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
)
|
20
|
+
@client = Occi::Api::Client::ClientHttp.new({
|
21
|
+
:endpoint => @endpoint, #141.5.99.69 #11.5.99.82
|
22
|
+
:auth => { :type => "none" },
|
23
|
+
:log => { :out => "/dev/null",
|
24
|
+
:level => Occi::Log::DEBUG },
|
25
|
+
:auto_connect => true,
|
26
|
+
:media_type => @accept_type#"text/plain,text/occi"
|
27
|
+
})
|
28
28
|
end
|
29
29
|
|
30
30
|
Then /^the Client should have the response code (.*)$/ do |response_code|
|
31
31
|
@client.last_response.code.should == response_code.to_i
|
32
|
-
end
|
32
|
+
end
|
@@ -67,28 +67,39 @@ module Occi
|
|
67
67
|
# from the server.
|
68
68
|
#
|
69
69
|
# @example
|
70
|
-
#
|
70
|
+
# options = {
|
71
|
+
# :endpoint => "http://localhost:3300/",
|
72
|
+
# :auth => {:type => "none"},
|
73
|
+
# :log => {:out => STDERR, :level => Occi::Log::WARN, :logger => nil},
|
74
|
+
# :media_type => "text/plain"
|
75
|
+
# }
|
71
76
|
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
# @param [Hash]
|
75
|
-
# @param [Boolean] enable autoconnect
|
76
|
-
# @param [String] media type identifier
|
77
|
+
# Occi::Api::Client::ClientAmqp.new options # => #<Occi::Api::Client::ClientAmqp>
|
78
|
+
#
|
79
|
+
# @param [Hash] options, for available options and defaults see examples
|
77
80
|
# @return [Occi::Api::Client::ClientAmqp] client instance
|
78
|
-
def initialize(
|
79
|
-
|
80
|
-
|
81
|
+
def initialize(options = {})
|
82
|
+
|
83
|
+
defaults = {
|
84
|
+
:endpoint => "http://localhost:3300/",
|
85
|
+
:auth => {:type => "none"},
|
86
|
+
:log => {:out => STDERR, :level => Occi::Log::WARN, :logger => nil},
|
87
|
+
:media_type => "text/plain"
|
88
|
+
}
|
89
|
+
|
90
|
+
options = options.marshal_dump if options.is_a? OpenStruct
|
91
|
+
options = defaults.merge options
|
81
92
|
|
82
93
|
# check the validity and canonize the endpoint URI
|
83
|
-
prepare_endpoint endpoint
|
94
|
+
prepare_endpoint options[:endpoint]
|
84
95
|
|
85
96
|
# set Occi::Log
|
86
|
-
set_logger
|
97
|
+
set_logger options[:log]
|
87
98
|
|
88
99
|
# pass auth options to HTTParty
|
89
|
-
change_auth
|
100
|
+
change_auth options[:auth]
|
90
101
|
|
91
|
-
@media_type = media_type
|
102
|
+
@media_type = options[:media_type]
|
92
103
|
|
93
104
|
Occi::Log.debug("Media Type: #{@media_type}")
|
94
105
|
|
@@ -96,7 +107,7 @@ module Occi
|
|
96
107
|
|
97
108
|
Thread.new { run }
|
98
109
|
|
99
|
-
|
110
|
+
Occi::Log.debug("Waiting for connection amqp ...")
|
100
111
|
|
101
112
|
#TODO find a better solution for the thread issue
|
102
113
|
while(!@thread_error && !@connected)
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'httparty'
|
3
|
+
|
3
4
|
require 'occi/api/client/http/net_http_fix'
|
4
5
|
require 'occi/api/client/http/httparty_fix'
|
6
|
+
require 'occi/api/client/http/authn_utils'
|
5
7
|
|
6
8
|
module Occi
|
7
9
|
module Api
|
@@ -27,79 +29,93 @@ module Occi
|
|
27
29
|
|
28
30
|
# hash mapping HTTP response codes to human-readable messages
|
29
31
|
HTTP_CODES = {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
32
|
+
"100" => "Continue",
|
33
|
+
"101" => "Switching Protocols",
|
34
|
+
"200" => "OK",
|
35
|
+
"201" => "Created",
|
36
|
+
"202" => "Accepted",
|
37
|
+
"203" => "Non-Authoritative Information",
|
38
|
+
"204" => "No Content",
|
39
|
+
"205" => "Reset Content",
|
40
|
+
"206" => "Partial Content",
|
41
|
+
"300" => "Multiple Choices",
|
42
|
+
"301" => "Moved Permanently",
|
43
|
+
"302" => "Found",
|
44
|
+
"303" => "See Other",
|
45
|
+
"304" => "Not Modified",
|
46
|
+
"305" => "Use Proxy",
|
47
|
+
"307" => "Temporary Redirect",
|
48
|
+
"400" => "Bad Request",
|
49
|
+
"401" => "Unauthorized",
|
50
|
+
"402" => "Payment Required",
|
51
|
+
"403" => "Forbidden",
|
52
|
+
"404" => "Not Found",
|
53
|
+
"405" => "Method Not Allowed",
|
54
|
+
"406" => "Not Acceptable",
|
55
|
+
"407" => "Proxy Authentication Required",
|
56
|
+
"408" => "Request Time-out",
|
57
|
+
"409" => "Conflict",
|
58
|
+
"410" => "Gone",
|
59
|
+
"411" => "Length Required",
|
60
|
+
"412" => "Precondition Failed",
|
61
|
+
"413" => "Request Entity Too Large",
|
62
|
+
"414" => "Request-URI Too Large",
|
63
|
+
"415" => "Unsupported Media Type",
|
64
|
+
"416" => "Requested range not satisfiable",
|
65
|
+
"417" => "Expectation Failed",
|
66
|
+
"500" => "Internal Server Error",
|
67
|
+
"501" => "Not Implemented",
|
68
|
+
"502" => "Bad Gateway",
|
69
|
+
"503" => "Service Unavailable",
|
70
|
+
"504" => "Gateway Time-out",
|
71
|
+
"505" => "HTTP Version not supported"
|
70
72
|
}
|
71
73
|
|
72
74
|
# Initializes client data structures and retrieves OCCI model
|
73
75
|
# from the server.
|
74
76
|
#
|
75
77
|
# @example
|
76
|
-
#
|
78
|
+
# options = {
|
79
|
+
# :endpoint => "http://localhost:3300/",
|
80
|
+
# :auth => {:type => "none"},
|
81
|
+
# :log => {:out => STDERR, :level => Occi::Log::WARN, :logger => nil},
|
82
|
+
# :auto_connect => "value", auto_connect => true,
|
83
|
+
# :media_type => nil
|
84
|
+
# }
|
85
|
+
#
|
86
|
+
# Occi::Api::Client::ClientHttp.new options # => #<Occi::Api::Client::ClientHttp>
|
77
87
|
#
|
78
|
-
# @param [
|
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
|
88
|
+
# @param [Hash] options, for available options and defaults see examples
|
83
89
|
# @return [Occi::Api::Client::ClientHttp] client instance
|
84
|
-
def initialize(
|
85
|
-
|
86
|
-
|
90
|
+
def initialize(options = {})
|
91
|
+
|
92
|
+
defaults = {
|
93
|
+
:endpoint => "http://localhost:3300/",
|
94
|
+
:auth => {:type => "none"},
|
95
|
+
:log => {:out => STDERR, :level => Occi::Log::WARN, :logger => nil},
|
96
|
+
:auto_connect => true,
|
97
|
+
:media_type => nil
|
98
|
+
}
|
99
|
+
|
100
|
+
options = options.marshal_dump if options.is_a? OpenStruct
|
101
|
+
options = defaults.merge options
|
102
|
+
|
87
103
|
# set Occi::Log
|
88
|
-
set_logger
|
104
|
+
set_logger options[:log]
|
89
105
|
|
90
106
|
# pass auth options to HTTParty
|
91
|
-
change_auth
|
107
|
+
change_auth options[:auth]
|
92
108
|
|
93
109
|
# check the validity and canonize the endpoint URI
|
94
|
-
prepare_endpoint endpoint
|
110
|
+
prepare_endpoint options[:endpoint]
|
95
111
|
|
96
112
|
# get accepted media types from HTTParty
|
97
113
|
set_media_type
|
98
114
|
|
99
115
|
# force media_type if provided
|
100
|
-
if media_type
|
101
|
-
self.class.headers 'Accept' => media_type
|
102
|
-
@media_type = media_type
|
116
|
+
if options[:media_type]
|
117
|
+
self.class.headers 'Accept' => options[:media_type]
|
118
|
+
@media_type = options[:media_type]
|
103
119
|
end
|
104
120
|
|
105
121
|
Occi::Log.debug("Media Type: #{@media_type}")
|
@@ -110,7 +126,7 @@ module Occi
|
|
110
126
|
set_model
|
111
127
|
|
112
128
|
# auto-connect?
|
113
|
-
@connected = auto_connect
|
129
|
+
@connected = options[:auto_connect]
|
114
130
|
end
|
115
131
|
|
116
132
|
# Creates a new resource instance, resource should be specified
|
@@ -134,7 +150,7 @@ module Occi
|
|
134
150
|
elsif @model.kinds.select { |kind| kind.term == resource_type }.any?
|
135
151
|
# we got a resource type name
|
136
152
|
Occi::Core::Resource.new @model.kinds.select {
|
137
|
-
|
153
|
+
|kind| kind.term == resource_type
|
138
154
|
}.first.type_identifier
|
139
155
|
else
|
140
156
|
raise "Unknown resource type! [#{resource_type}]"
|
@@ -263,12 +279,12 @@ module Occi
|
|
263
279
|
if type
|
264
280
|
# get the first match from either os_tpls or resource_tpls
|
265
281
|
case
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
282
|
+
when type == "os_tpl"
|
283
|
+
get_os_templates.select { |mixin| mixin.term == name }.first
|
284
|
+
when type == "resource_tpl"
|
285
|
+
get_resource_templates.select { |template| template.term == name }.first
|
286
|
+
else
|
287
|
+
nil
|
272
288
|
end
|
273
289
|
else
|
274
290
|
# try in os_tpls first
|
@@ -276,7 +292,7 @@ module Occi
|
|
276
292
|
|
277
293
|
# then try in resource_tpls
|
278
294
|
found = get_resource_templates.select {
|
279
|
-
|
295
|
+
|template| template.term == name
|
280
296
|
}.first unless found
|
281
297
|
|
282
298
|
found
|
@@ -288,12 +304,12 @@ module Occi
|
|
288
304
|
if type
|
289
305
|
# return the first match with the selected type
|
290
306
|
@mixins[type.to_sym].select {
|
291
|
-
|
307
|
+
|mixin| mixin.to_s.reverse.start_with? name.reverse
|
292
308
|
}.first
|
293
309
|
else
|
294
310
|
# there is no type preference, return first global match
|
295
311
|
@mixins.flatten(2).select {
|
296
|
-
|
312
|
+
|mixin| mixin.to_s.reverse.start_with? name.reverse
|
297
313
|
}.first
|
298
314
|
end
|
299
315
|
end
|
@@ -342,7 +358,7 @@ module Occi
|
|
342
358
|
#
|
343
359
|
# @return [Array<String>] list of available mixin types
|
344
360
|
def get_mixin_types
|
345
|
-
@mixins.keys.map
|
361
|
+
@mixins.keys.map { |k| k.to_s }
|
346
362
|
end
|
347
363
|
|
348
364
|
# Retrieves available mixin type identifiers.
|
@@ -384,9 +400,9 @@ module Occi
|
|
384
400
|
if resource_type_identifier
|
385
401
|
# convert type to type identifier
|
386
402
|
resource_type_identifier = @model.kinds.select {
|
387
|
-
|
403
|
+
|kind| kind.term == resource_type_identifier
|
388
404
|
}.first.type_identifier if @model.kinds.select {
|
389
|
-
|
405
|
+
|kind| kind.term == resource_type_identifier
|
390
406
|
}.any?
|
391
407
|
|
392
408
|
# check some basic pre-conditions
|
@@ -429,9 +445,9 @@ module Occi
|
|
429
445
|
|
430
446
|
# convert type to type identifier
|
431
447
|
resource_type_identifier = @model.kinds.select {
|
432
|
-
|
448
|
+
|kind| kind.term == resource_type_identifier
|
433
449
|
}.first.type_identifier if @model.kinds.select {
|
434
|
-
|
450
|
+
|kind| kind.term == resource_type_identifier
|
435
451
|
}.any?
|
436
452
|
|
437
453
|
# check some basic pre-conditions
|
@@ -450,7 +466,7 @@ module Occi
|
|
450
466
|
locations.each do |location|
|
451
467
|
descriptions << get(sanitize_resource_link(location))
|
452
468
|
end
|
453
|
-
elsif resource_type_identifier.start_with?
|
469
|
+
elsif resource_type_identifier.start_with?(@endpoint) || resource_type_identifier.start_with?('/')
|
454
470
|
# we got resource link
|
455
471
|
# make the request
|
456
472
|
descriptions << get(sanitize_resource_link(resource_type_identifier))
|
@@ -568,7 +584,7 @@ module Occi
|
|
568
584
|
# TODO: not tested
|
569
585
|
if @model.kinds.select { |kind| kind.term == resource_type }.any?
|
570
586
|
type_identifier = @model.kinds.select {
|
571
|
-
|
587
|
+
|kind| kind.term == resource_type_identifier
|
572
588
|
}.first.type_identifier
|
573
589
|
|
574
590
|
location = @model.get_by_id(type_identifier).location
|
@@ -633,45 +649,41 @@ module Occi
|
|
633
649
|
@auth_options = auth_options
|
634
650
|
|
635
651
|
case @auth_options[:type]
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
self.class.
|
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
|
652
|
+
when "basic"
|
653
|
+
# set up basic auth
|
654
|
+
raise ArgumentError, "Missing required options 'username' and 'password' for basic auth!" unless @auth_options[:username] and @auth_options[:password]
|
655
|
+
self.class.basic_auth @auth_options[:username], @auth_options[:password]
|
656
|
+
when "digest"
|
657
|
+
# set up digest auth
|
658
|
+
raise ArgumentError, "Missing required options 'username' and 'password' for digest auth!" unless @auth_options[:username] and @auth_options[:password]
|
659
|
+
self.class.digest_auth @auth_options[:username], @auth_options[:password]
|
660
|
+
when "x509"
|
661
|
+
# set up pem and optionally pem_password and ssl_ca_path
|
662
|
+
raise ArgumentError, "Missing required option 'user_cert' for x509 auth!" unless @auth_options[:user_cert]
|
663
|
+
raise ArgumentError, "The file specified in 'user_cert' does not exist!" unless File.exists? @auth_options[:user_cert]
|
664
|
+
|
665
|
+
# handle PKCS#12 credentials before passing them
|
666
|
+
# to httparty
|
667
|
+
if /\A(.)+\.p12\z/ =~ @auth_options[:user_cert]
|
668
|
+
self.class.pem AuthnUtils.extract_pem_from_pkcs12(@auth_options[:user_cert], @auth_options[:user_cert_password]), ''
|
659
669
|
else
|
660
|
-
|
661
|
-
|
662
|
-
|
670
|
+
# httparty will handle ordinary PEM formatted credentials
|
671
|
+
# TODO: Issue #49, check PEM credentials in jRuby
|
672
|
+
self.class.pem File.open(@auth_options[:user_cert], 'rb').read, @auth_options[:user_cert_password]
|
673
|
+
end
|
663
674
|
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
+
self.class.ssl_ca_path @auth_options[:ca_path] unless @auth_options[:ca_path].nil?
|
676
|
+
self.class.ssl_ca_file @auth_options[:ca_file] unless @auth_options[:ca_file].nil?
|
677
|
+
self.class.ssl_extra_chain_cert AuthnUtils.certs_to_file_ary(@auth_options[:proxy_ca]) unless @auth_options[:proxy_ca].nil?
|
678
|
+
when "keystone"
|
679
|
+
# set up OpenStack Keystone token based auth
|
680
|
+
raise ArgumentError, "Missing required option 'token' for OpenStack Keystone auth!" unless @auth_options[:token]
|
681
|
+
self.class.headers['X-Auth-Token'] = @auth_options[:token]
|
682
|
+
when "none", nil
|
683
|
+
# do nothing
|
684
|
+
else
|
685
|
+
raise ArgumentError, "Unknown AUTH method [#{@auth_options[:type]}]!"
|
686
|
+
end
|
675
687
|
end
|
676
688
|
|
677
689
|
# Performs GET request and parses the responses to collections.
|
@@ -686,7 +698,7 @@ module Occi
|
|
686
698
|
# @return [Occi::Collection] parsed result of the request
|
687
699
|
def get(path='', filter=nil)
|
688
700
|
# remove the leading slash
|
689
|
-
path.gsub
|
701
|
+
path = path.gsub(/\A\//, '')
|
690
702
|
|
691
703
|
response = if filter
|
692
704
|
categories = filter.categories.collect { |category| category.to_text }.join(',')
|
@@ -739,39 +751,39 @@ module Occi
|
|
739
751
|
# @return [String] URI location
|
740
752
|
def post(path, collection)
|
741
753
|
# remove the leading slash
|
742
|
-
path.gsub
|
754
|
+
path = path.gsub(/\A\//, '')
|
743
755
|
|
744
756
|
headers = self.class.headers.clone
|
745
757
|
headers['Content-Type'] = @media_type
|
746
758
|
|
747
759
|
response = case @media_type
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
760
|
+
when 'application/occi+json'
|
761
|
+
self.class.post(@endpoint + path,
|
762
|
+
:body => collection.to_json,
|
763
|
+
:headers => headers)
|
764
|
+
when 'text/occi'
|
765
|
+
self.class.post(@endpoint + path,
|
766
|
+
:headers => collection.to_header.merge(headers))
|
767
|
+
else
|
768
|
+
self.class.post(@endpoint + path,
|
769
|
+
:body => collection.to_text,
|
770
|
+
:headers => headers)
|
759
771
|
end
|
760
772
|
|
761
773
|
response_msg = response_message response
|
762
774
|
|
763
775
|
case response.code
|
764
|
-
|
765
|
-
|
766
|
-
|
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
|
776
|
+
when 200
|
777
|
+
collection = Occi::Parser.parse(response.header["content-type"].split(";").first, response)
|
778
|
+
if collection.empty?
|
772
779
|
Occi::Parser.locations(response.header["content-type"].split(";").first, response.body, response.header).first
|
773
780
|
else
|
774
|
-
|
781
|
+
collection.resources.first.location if collection.resources.first
|
782
|
+
end
|
783
|
+
when 201
|
784
|
+
Occi::Parser.locations(response.header["content-type"].split(";").first, response.body, response.header).first
|
785
|
+
else
|
786
|
+
raise "HTTP POST failed! #{response_msg}"
|
775
787
|
end
|
776
788
|
end
|
777
789
|
|
@@ -785,32 +797,32 @@ module Occi
|
|
785
797
|
# @return [Occi::Collection] parsed result of the request
|
786
798
|
def put(path, collection)
|
787
799
|
# remove the leading slash
|
788
|
-
path.gsub
|
800
|
+
path = path.gsub(/\A\//, '')
|
789
801
|
|
790
802
|
headers = self.class.headers.clone
|
791
803
|
headers['Content-Type'] = @media_type
|
792
804
|
|
793
805
|
response = case @media_type
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
806
|
+
when 'application/occi+json'
|
807
|
+
self.class.post(@endpoint + path,
|
808
|
+
:body => collection.to_json,
|
809
|
+
:headers => headers)
|
810
|
+
when 'text/occi'
|
811
|
+
self.class.post(@endpoint + path,
|
812
|
+
:headers => collection.to_header.merge(headers))
|
813
|
+
else
|
814
|
+
self.class.post(@endpoint + path,
|
815
|
+
:body => collection.to_text,
|
816
|
+
:headers => headers)
|
805
817
|
end
|
806
818
|
|
807
819
|
response_msg = response_message response
|
808
820
|
|
809
821
|
case response.code
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
822
|
+
when 200, 201
|
823
|
+
Occi::Parser.parse(response.header["content-type"].split(";").first, response)
|
824
|
+
else
|
825
|
+
raise "HTTP POST failed! #{response_msg}"
|
814
826
|
end
|
815
827
|
end
|
816
828
|
|
@@ -824,7 +836,7 @@ module Occi
|
|
824
836
|
# @return [Boolean] status
|
825
837
|
def del(path, filter=nil)
|
826
838
|
# remove the leading slash
|
827
|
-
path.gsub
|
839
|
+
path = path.gsub(/\A\//, '')
|
828
840
|
|
829
841
|
response = self.class.delete(@endpoint + path)
|
830
842
|
|
@@ -884,10 +896,15 @@ module Occi
|
|
884
896
|
# @example
|
885
897
|
# sanitize_resource_link "http://localhost:3300/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
|
886
898
|
# # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
|
899
|
+
# sanitize_resource_link "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
|
900
|
+
# # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
|
887
901
|
#
|
888
902
|
# @param [String] string containing the full resource link
|
889
903
|
# @return [String] extracted path, with a leading slash
|
890
904
|
def sanitize_resource_link(resource_link)
|
905
|
+
# everything starting with '/' is considered to be a resource path
|
906
|
+
return resource_link if resource_link.start_with? '/'
|
907
|
+
|
891
908
|
raise "Resource link #{resource_link} is not valid!" unless resource_link.start_with? @endpoint
|
892
909
|
|
893
910
|
resource_link.gsub @endpoint, '/'
|
@@ -910,7 +927,7 @@ module Occi
|
|
910
927
|
if kinds.any?
|
911
928
|
#we got an type identifier
|
912
929
|
path = "/" + kinds.first.type_identifier.split('#').last + "/"
|
913
|
-
elsif resource_type_identifier.start_with?
|
930
|
+
elsif resource_type_identifier.start_with?(@endpoint) || resource_type_identifier.start_with?('/')
|
914
931
|
#we got an resource link
|
915
932
|
path = sanitize_resource_link(resource_type_identifier)
|
916
933
|
else
|
@@ -932,8 +949,8 @@ module Occi
|
|
932
949
|
@model = Occi::Model.new(model)
|
933
950
|
|
934
951
|
@mixins = {
|
935
|
-
|
936
|
-
|
952
|
+
:os_tpl => [],
|
953
|
+
:resource_tpl => []
|
937
954
|
}
|
938
955
|
|
939
956
|
#
|
@@ -978,10 +995,10 @@ module Occi
|
|
978
995
|
media_types = self.class.head(@endpoint).headers['accept']
|
979
996
|
Occi::Log.debug("Available media types: #{media_types}")
|
980
997
|
@media_type = case media_types
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
998
|
+
when /application\/occi\+json/
|
999
|
+
'application/occi+json'
|
1000
|
+
else
|
1001
|
+
'text/plain'
|
985
1002
|
end
|
986
1003
|
end
|
987
1004
|
|