occi 3.0.0 → 3.1.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|