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
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
if defined? JRUBY_VERSION
|
4
|
+
require 'java'
|
5
|
+
end
|
6
|
+
|
7
|
+
module Occi
|
8
|
+
module Api
|
9
|
+
module Client
|
10
|
+
|
11
|
+
class AuthnUtils
|
12
|
+
# Reads credentials from a PKCS#12 compliant file. Returns
|
13
|
+
# X.509 certificate and decrypted private key in PEM
|
14
|
+
# formatted string.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# extract_pem_from_pkcs12 "~/.globus/usercert.p12", "123456"
|
18
|
+
# # => #<String>
|
19
|
+
#
|
20
|
+
# @param [String] Path to a PKCS#12 file with credentials
|
21
|
+
# @param [String] Password needed to unlock the PKCS#12 file
|
22
|
+
# @return [String] Decrypted credentials in a PEM formatted string
|
23
|
+
def self.extract_pem_from_pkcs12(path_to_p12_file, p12_password)
|
24
|
+
# decode certificate and its private key
|
25
|
+
pem_from_pkcs12 = ""
|
26
|
+
if defined? JRUBY_VERSION
|
27
|
+
# Java-based Ruby, read PKCS12 manually
|
28
|
+
# using KeyStore
|
29
|
+
keystore = Java::JavaSecurity::KeyStore.getInstance("PKCS12")
|
30
|
+
p12_input_stream = Java::JavaIo::FileInputStream.new(path_to_p12_file)
|
31
|
+
pass_char_array = Java::JavaLang::String.new(p12_password).to_char_array
|
32
|
+
|
33
|
+
# load and unlock PKCS#12 store
|
34
|
+
keystore.load p12_input_stream, pass_char_array
|
35
|
+
|
36
|
+
# read the first certificate and PK
|
37
|
+
cert = keystore.getCertificate("1")
|
38
|
+
pk = keystore.getKey("1", pass_char_array)
|
39
|
+
|
40
|
+
pem_from_pkcs12 << "-----BEGIN CERTIFICATE-----\n"
|
41
|
+
pem_from_pkcs12 << Java::JavaxXmlBind::DatatypeConverter.printBase64Binary(cert.getEncoded())
|
42
|
+
pem_from_pkcs12 << "\n-----END CERTIFICATE-----"
|
43
|
+
|
44
|
+
pem_from_pkcs12 << "\n"
|
45
|
+
|
46
|
+
pem_from_pkcs12 << "-----BEGIN PRIVATE KEY-----\n"
|
47
|
+
pem_from_pkcs12 << Java::JavaxXmlBind::DatatypeConverter.printBase64Binary(pk.getEncoded())
|
48
|
+
pem_from_pkcs12 << "\n-----END PRIVATE KEY-----"
|
49
|
+
else
|
50
|
+
# C-based Ruby, use OpenSSL::PKCS12
|
51
|
+
pkcs12 = OpenSSL::PKCS12.new(
|
52
|
+
File.open(
|
53
|
+
path_to_p12_file,
|
54
|
+
'rb'
|
55
|
+
),
|
56
|
+
p12_password
|
57
|
+
)
|
58
|
+
|
59
|
+
# store cert and private key in a single PEM formatted string
|
60
|
+
pem_from_pkcs12 << pkcs12.certificate.to_pem << pkcs12.key.to_pem
|
61
|
+
end
|
62
|
+
|
63
|
+
pem_from_pkcs12
|
64
|
+
end
|
65
|
+
|
66
|
+
# Reads X.509 certificates from a file to an array.
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# certs_to_file_ary "~/.globus/usercert.pem"
|
70
|
+
# # => [#<String>, #<String>, ...]
|
71
|
+
#
|
72
|
+
# @param [String] Path to a PEM file containing certificates
|
73
|
+
# @return [Array<String>] An array of read certificates
|
74
|
+
def self.certs_to_file_ary(ca_file)
|
75
|
+
# TODO: read and separate multiple certificates
|
76
|
+
[] << File.open(ca_file).read
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/occi/bin/helpers.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# a bunch of OCCI client helpers for bin/occi
|
2
2
|
|
3
|
-
def helper_list(options)
|
3
|
+
def helper_list(options, output = nil)
|
4
4
|
found = []
|
5
5
|
|
6
6
|
if resource_types.include? options.resource
|
@@ -10,17 +10,23 @@ def helper_list(options)
|
|
10
10
|
Occi::Log.debug "#{options.resource} is a mixin type."
|
11
11
|
found = mixins options.resource
|
12
12
|
else
|
13
|
-
Occi::Log.
|
14
|
-
|
13
|
+
Occi::Log.warn "I have no idea what #{options.resource} is ..."
|
14
|
+
raise "Unknown resource #{options.resource}, there is nothing to list here!"
|
15
15
|
end
|
16
16
|
|
17
|
-
found
|
17
|
+
return found if output.nil?
|
18
|
+
|
19
|
+
if Occi::Bin::ResourceOutputFactory.allowed_resource_types.include? options.resource.to_sym
|
20
|
+
puts output.format(found, :locations, options.resource.to_sym)
|
21
|
+
else
|
22
|
+
Occi::Log.warn "Not printing, the resource type is not supported!"
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
|
-
def helper_describe(options)
|
26
|
+
def helper_describe(options, output = nil)
|
21
27
|
found = []
|
22
28
|
|
23
|
-
if resource_types.include?
|
29
|
+
if resource_types.include?(options.resource) || options.resource.start_with?(options.endpoint) || options.resource.start_with?('/')
|
24
30
|
Occi::Log.debug "#{options.resource} is a resource type or an actual resource."
|
25
31
|
|
26
32
|
found = describe(options.resource)
|
@@ -37,15 +43,37 @@ def helper_describe(options)
|
|
37
43
|
mxn_type,mxn = options.resource.split('#')
|
38
44
|
found << mixin(mxn, mxn_type, true)
|
39
45
|
else
|
40
|
-
Occi::Log.
|
46
|
+
Occi::Log.warn "I have no idea what #{options.resource} is ..."
|
47
|
+
raise "Unknown resource #{options.resource}, there is nothing to describe here!"
|
48
|
+
end
|
49
|
+
|
50
|
+
return found if output.nil?
|
41
51
|
|
42
|
-
|
52
|
+
if options.resource.start_with? options.endpoint
|
53
|
+
# resource contains full endpoint URI
|
54
|
+
# e.g., http://localhost:3300/network/adfgadf-daf5a6df4afadf-adfad65f4ad
|
55
|
+
resource_type = options.resource.split('/')[3].to_sym
|
56
|
+
elsif options.resource.start_with? '/'
|
57
|
+
# resource contains a path relative to endpoint URI
|
58
|
+
# e.g., /network/adfgadf-daf5a6df4afadf-adfad65f4ad
|
59
|
+
resource_type = options.resource.split('/')[1].to_sym
|
60
|
+
elsif mixin_types.include? options.resource.split('#').first
|
61
|
+
# resource contains a mixin with a type
|
62
|
+
# e.g., os_tpl#debian6
|
63
|
+
resource_type = options.resource.split('#').first.to_sym
|
64
|
+
else
|
65
|
+
# resource probably contains RAW resource_type
|
66
|
+
resource_type = options.resource.to_sym
|
43
67
|
end
|
44
68
|
|
45
|
-
|
69
|
+
if Occi::Bin::ResourceOutputFactory.allowed_resource_types.include? resource_type
|
70
|
+
puts output.format(found, :resources, resource_type)
|
71
|
+
else
|
72
|
+
Occi::Log.warn "Not printing, the resource type [#{resource_type.to_s}] is not supported!"
|
73
|
+
end
|
46
74
|
end
|
47
75
|
|
48
|
-
def helper_create(options)
|
76
|
+
def helper_create(options, output = nil)
|
49
77
|
location = nil
|
50
78
|
|
51
79
|
if resource_types.include? options.resource
|
@@ -55,37 +83,67 @@ def helper_create(options)
|
|
55
83
|
res = resource options.resource
|
56
84
|
|
57
85
|
Occi::Log.debug "Creating #{options.resource}:\n#{res.inspect}"
|
58
|
-
Occi::Log.debug "with mixins:#{options.mixin}"
|
59
86
|
|
60
|
-
options.
|
61
|
-
Occi::Log.debug "
|
62
|
-
|
63
|
-
|
87
|
+
if options.links
|
88
|
+
Occi::Log.debug "with links: #{options.links}"
|
89
|
+
|
90
|
+
options.links.each do |link|
|
91
|
+
link = options.endpoint.chomp('/') + link unless link.start_with? options.endpoint
|
92
|
+
|
93
|
+
if link.include? "/storage/"
|
94
|
+
Occi::Log.debug "Adding storagelink to #{options.resource}"
|
95
|
+
res.storagelink link
|
96
|
+
elsif link.include? "/network/"
|
97
|
+
Occi::Log.debug "Adding networkinterface to #{options.resource}"
|
98
|
+
res.networkinterface link
|
99
|
+
else
|
100
|
+
raise "Unknown link type #{link}, stopping here!"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if options.mixins
|
106
|
+
Occi::Log.debug "with mixins: #{options.mixins}"
|
107
|
+
|
108
|
+
options.mixins.keys.each do |type|
|
109
|
+
Occi::Log.debug "Adding mixins of type #{type} to #{options.resource}"
|
64
110
|
|
65
|
-
|
66
|
-
|
67
|
-
|
111
|
+
options.mixins[type].each do |name|
|
112
|
+
mxn = mixin name, type
|
113
|
+
|
114
|
+
raise "Unknown mixin #{type}##{name}, stopping here!" if mxn.nil?
|
115
|
+
Occi::Log.debug "Adding mixin #{mxn} to #{options.resource}"
|
116
|
+
res.mixins << mxn
|
117
|
+
end
|
68
118
|
end
|
69
119
|
end
|
70
120
|
|
71
121
|
#TODO: set other attributes
|
72
|
-
res.title = options.
|
122
|
+
res.title = options.attributes[:title]
|
73
123
|
|
74
124
|
Occi::Log.debug "Creating #{options.resource}:\n#{res.inspect}"
|
75
125
|
|
76
126
|
location = create res
|
77
127
|
else
|
78
|
-
Occi::Log.
|
79
|
-
|
128
|
+
Occi::Log.warn "I have no idea what #{options.resource} is ..."
|
129
|
+
raise "Unknown resource #{options.resource}, there is nothing to create here!"
|
80
130
|
end
|
81
131
|
|
82
|
-
location
|
132
|
+
return location if output.nil?
|
133
|
+
|
134
|
+
puts location
|
83
135
|
end
|
84
136
|
|
85
|
-
def helper_delete(options)
|
86
|
-
delete
|
137
|
+
def helper_delete(options, output = nil)
|
138
|
+
if delete(options.resource)
|
139
|
+
Occi::Log.info "Resource #{options.resource} successfully removed!"
|
140
|
+
else
|
141
|
+
raise "Failed to remove resource #{options.resource}!"
|
142
|
+
end
|
143
|
+
|
144
|
+
true
|
87
145
|
end
|
88
146
|
|
89
|
-
def helper_trigger(options)
|
147
|
+
def helper_trigger(options, output = nil)
|
90
148
|
raise "Not yet implemented!"
|
91
|
-
end
|
149
|
+
end
|
data/lib/occi/bin/occi_opts.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
require 'optparse'
|
3
|
+
require 'uri'
|
4
|
+
|
3
5
|
require 'occi/bin/resource_output_factory'
|
4
6
|
|
5
7
|
module Occi
|
@@ -12,7 +14,9 @@ module Occi
|
|
12
14
|
ACTIONS = [:list, :describe, :create, :delete, :trigger].freeze
|
13
15
|
LOG_OUTPUTS = [:stdout, :stderr].freeze
|
14
16
|
|
15
|
-
def self.parse(args)
|
17
|
+
def self.parse(args, test_env = false)
|
18
|
+
|
19
|
+
@@quiet = test_env
|
16
20
|
|
17
21
|
options = OpenStruct.new
|
18
22
|
|
@@ -39,13 +43,31 @@ module Occi
|
|
39
43
|
options.auth[:proxy_ca] = nil
|
40
44
|
|
41
45
|
options.output_format = :plain
|
46
|
+
|
47
|
+
options.mixins = nil
|
48
|
+
options.links = nil
|
49
|
+
options.attributes = nil
|
50
|
+
options.context_vars = nil
|
42
51
|
|
43
52
|
# TODO: change media type back to occi+json after the rOCCI-server update
|
44
53
|
#options.media_type = "application/occi+json"
|
45
54
|
options.media_type = "text/plain,text/occi"
|
46
55
|
|
47
56
|
opts = OptionParser.new do |opts|
|
48
|
-
opts.banner =
|
57
|
+
opts.banner = %{Usage: occi [OPTIONS]
|
58
|
+
|
59
|
+
Examples:
|
60
|
+
occi --interactive --endpoint https://localhost:3300/ --auth x509
|
61
|
+
|
62
|
+
occi --endpoint https://localhost:3300/ --action list --resource os_tpl --auth x509
|
63
|
+
|
64
|
+
occi --endpoint https://localhost:3300/ --action list --resource resource_tpl --auth x509
|
65
|
+
|
66
|
+
occi --endpoint https://localhost:3300/ --action describe --resource os_tpl#debian6 --auth x509
|
67
|
+
|
68
|
+
occi --endpoint https://localhost:3300/ --action create --resource compute --mixin os_tpl#debian6 --mixin resource_tpl#small --attributes title="My rOCCI VM" --auth x509
|
69
|
+
|
70
|
+
occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd4f654sf65g4-s5fg65sfg465sfg-sf65g46sf5g4sdfg --auth x509}
|
49
71
|
|
50
72
|
opts.separator ""
|
51
73
|
opts.separator "Options:"
|
@@ -60,7 +82,7 @@ module Occi
|
|
60
82
|
"--endpoint URI",
|
61
83
|
String,
|
62
84
|
"OCCI server URI, defaults to '#{options.endpoint}'") do |endpoint|
|
63
|
-
options.endpoint = endpoint
|
85
|
+
options.endpoint = URI(endpoint).to_s
|
64
86
|
end
|
65
87
|
|
66
88
|
opts.on("-n",
|
@@ -80,36 +102,56 @@ module Occi
|
|
80
102
|
opts.on("-p",
|
81
103
|
"--password PASSWORD",
|
82
104
|
String,
|
83
|
-
"Password for basic, digest and x509 authentication or an auth. token
|
105
|
+
"Password for basic, digest and x509 authentication or an auth. token from OS Keystone") do |password|
|
84
106
|
options.auth[:password] = password
|
85
107
|
options.auth[:user_cert_password] = password
|
86
108
|
options.auth[:token] = password
|
87
109
|
end
|
88
110
|
|
89
111
|
opts.on("-c",
|
90
|
-
"--ca-path PATH",
|
112
|
+
"--ca-path PATH",
|
113
|
+
String,
|
114
|
+
"Path to CA certificates directory, defaults to '#{options.auth[:ca_path]}'") do |ca_path|
|
115
|
+
raise ArgumentError, "Path specified in --ca-path is not a directory!" unless File.directory? ca_path
|
116
|
+
raise ArgumentError, "Path specified in --ca-path is not readable!" unless File.readable? ca_path
|
117
|
+
|
91
118
|
options.auth[:ca_path] = ca_path
|
92
119
|
end
|
93
120
|
|
94
121
|
opts.on("-f",
|
95
|
-
"--ca-file PATH",
|
122
|
+
"--ca-file PATH",
|
123
|
+
String,
|
124
|
+
"Path to CA certificates in a file") do |ca_file|
|
125
|
+
raise ArgumentError, "File specified in --ca-file is not a file!" unless File.file? ca_file
|
126
|
+
raise ArgumentError, "File specified in --ca-file is not readable!" unless File.readable? ca_file
|
127
|
+
|
96
128
|
options.auth[:ca_file] = ca_file
|
97
129
|
end
|
98
130
|
|
99
131
|
opts.on("-F",
|
100
|
-
"--filter CATEGORY",
|
132
|
+
"--filter CATEGORY",
|
133
|
+
String,
|
134
|
+
"Category type identifier to filter categories from model, must be used together with the -m option") do |filter|
|
101
135
|
options.filter = filter
|
102
136
|
end
|
103
137
|
|
104
138
|
opts.on("-x",
|
105
|
-
"--user-cred
|
139
|
+
"--user-cred FILE",
|
106
140
|
String,
|
107
141
|
"Path to user's x509 credentials, defaults to '#{options.auth[:user_cert]}'") do |user_cred|
|
142
|
+
raise ArgumentError, "File specified in --user-cred is not a file!" unless File.file? user_cred
|
143
|
+
raise ArgumentError, "File specified in --user-cred is not readable!" unless File.readable? user_cred
|
144
|
+
|
108
145
|
options.auth[:user_cert] = user_cred
|
109
146
|
end
|
110
147
|
|
111
148
|
opts.on("-X",
|
112
|
-
"--proxy-ca
|
149
|
+
"--proxy-ca FILE",
|
150
|
+
String,
|
151
|
+
"Path to a file with GSI proxy's CA certificate(s)") do |proxy_ca|
|
152
|
+
raise ArgumentError, "File specified in --proxy-ca is not a file!" unless File.file? proxy_ca
|
153
|
+
raise ArgumentError, "File specified in --proxy-ca is not readable!" unless File.readable? proxy_ca
|
154
|
+
|
113
155
|
options.auth[:proxy_ca] = proxy_ca
|
114
156
|
end
|
115
157
|
|
@@ -128,10 +170,31 @@ module Occi
|
|
128
170
|
end
|
129
171
|
|
130
172
|
opts.on("-t",
|
131
|
-
"--
|
132
|
-
|
133
|
-
"
|
134
|
-
options.
|
173
|
+
"--attributes ATTRS",
|
174
|
+
Array,
|
175
|
+
"Comma separated attributes for new resources such as title=\"Name\", required") do |attributes|
|
176
|
+
options.attributes = {}
|
177
|
+
|
178
|
+
attributes.each do |attribute|
|
179
|
+
ary = /^(.+?)=(.+)$/.match(attribute).to_a.drop 1
|
180
|
+
raise ArgumentError, "Attributes must always contain ATTR=VALUE pairs!" if ary.length != 2
|
181
|
+
|
182
|
+
options.attributes[ary[0].to_sym] = ary[1]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
opts.on("-T",
|
187
|
+
"--context CTX_VARS",
|
188
|
+
Array,
|
189
|
+
"Comma separated context variables for new compute resources such as SSH_KEY=\"ssh-rsa dfsdf...adfdf== user@localhost\"") do |context|
|
190
|
+
options.context_vars = {}
|
191
|
+
|
192
|
+
context.each do |ctx|
|
193
|
+
ary = /^(.+?)=(.+)$/.match(ctx).to_a.drop 1
|
194
|
+
raise ArgumentError, "Context variables must always contain ATTR=VALUE pairs!" if ary.length != 2
|
195
|
+
|
196
|
+
options.context_vars[ary[0].to_sym] = ary[1]
|
197
|
+
end
|
135
198
|
end
|
136
199
|
|
137
200
|
opts.on("-a",
|
@@ -149,9 +212,21 @@ module Occi
|
|
149
212
|
|
150
213
|
raise "Unknown mixin format! Use TYPE#NAME!" unless parts.length == 2
|
151
214
|
|
152
|
-
options.
|
153
|
-
options.
|
154
|
-
options.
|
215
|
+
options.mixins = {} if options.mixins.nil?
|
216
|
+
options.mixins[parts[0]] = [] if options.mixins[parts[0]].nil?
|
217
|
+
options.mixins[parts[0]] << parts[1]
|
218
|
+
end
|
219
|
+
|
220
|
+
opts.on("-j",
|
221
|
+
"--link URI",
|
222
|
+
String,
|
223
|
+
"Link specified resource to the resource being created, only for action CREATE and resource COMPUTE") do |link|
|
224
|
+
link_relative_path = URI(link).path
|
225
|
+
|
226
|
+
raise ArgumentError, "Specified link URI is not valid!" unless link_relative_path.start_with? '/'
|
227
|
+
|
228
|
+
options.links = [] if options.links.nil?
|
229
|
+
options.links << link_relative_path
|
155
230
|
end
|
156
231
|
|
157
232
|
opts.on("-g",
|
@@ -198,68 +273,111 @@ module Occi
|
|
198
273
|
opts.on_tail("-h",
|
199
274
|
"--help",
|
200
275
|
"Show this message") do
|
201
|
-
|
202
|
-
|
276
|
+
if @@quiet
|
277
|
+
exit true
|
278
|
+
else
|
279
|
+
puts opts
|
280
|
+
exit! true
|
281
|
+
end
|
203
282
|
end
|
204
283
|
|
205
284
|
opts.on_tail("-v",
|
206
285
|
"--version",
|
207
286
|
"Show version") do
|
208
|
-
|
209
|
-
|
287
|
+
if @@quiet
|
288
|
+
exit true
|
289
|
+
else
|
290
|
+
puts Occi::VERSION
|
291
|
+
exit! true
|
292
|
+
end
|
210
293
|
end
|
211
|
-
|
212
294
|
end
|
213
295
|
|
214
296
|
begin
|
215
297
|
opts.parse!(args)
|
216
298
|
rescue Exception => ex
|
217
|
-
|
218
|
-
|
219
|
-
|
299
|
+
if @@quiet
|
300
|
+
exit false
|
301
|
+
else
|
302
|
+
puts ex.message.capitalize
|
303
|
+
puts opts
|
304
|
+
exit!
|
305
|
+
end
|
220
306
|
end
|
221
307
|
|
222
|
-
|
223
|
-
|
224
|
-
|
308
|
+
check_restrictions options, opts
|
309
|
+
|
310
|
+
options
|
311
|
+
end
|
312
|
+
|
313
|
+
private
|
225
314
|
|
226
|
-
|
315
|
+
def self.check_restrictions(options, opts)
|
316
|
+
if options.interactive && options.dump_model
|
317
|
+
if @@quiet
|
318
|
+
exit false
|
319
|
+
else
|
320
|
+
puts "You cannot use '--dump-model' and '--interactive' at the same time!"
|
321
|
+
puts opts
|
322
|
+
exit!
|
323
|
+
end
|
227
324
|
end
|
228
325
|
|
229
326
|
if !options.dump_model && options.filter
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
327
|
+
if @@quiet
|
328
|
+
exit false
|
329
|
+
else
|
330
|
+
puts "You cannot use '--filter' without '--dump-model'!"
|
331
|
+
puts opts
|
332
|
+
exit!
|
333
|
+
end
|
234
334
|
end
|
235
335
|
|
236
|
-
if
|
237
|
-
mandatory = []
|
336
|
+
return if options.interactive || options.dump_model
|
238
337
|
|
239
|
-
|
240
|
-
|
241
|
-
|
338
|
+
mandatory = []
|
339
|
+
|
340
|
+
if options.action == :trigger
|
341
|
+
mandatory << :trigger_action
|
342
|
+
end
|
242
343
|
|
243
|
-
|
244
|
-
|
344
|
+
if options.action == :create
|
345
|
+
if !options.links.nil?
|
346
|
+
mandatory << :links
|
347
|
+
else
|
348
|
+
mandatory << :mixins
|
245
349
|
end
|
246
350
|
|
247
|
-
mandatory
|
248
|
-
|
249
|
-
|
351
|
+
mandatory << :attributes
|
352
|
+
check_attrs = true
|
353
|
+
end
|
354
|
+
|
355
|
+
mandatory.concat [:resource, :action]
|
356
|
+
|
357
|
+
check_hash options, mandatory, opts
|
250
358
|
|
251
|
-
|
252
|
-
|
359
|
+
if check_attrs
|
360
|
+
mandatory = [:title]
|
361
|
+
check_hash options.attributes, mandatory, opts
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def self.check_hash(hash, mandatory, opts)
|
366
|
+
if !hash.is_a? Hash
|
367
|
+
hash = hash.marshal_dump
|
368
|
+
end
|
369
|
+
|
370
|
+
missing = mandatory.select{ |param| hash[param].nil? }
|
371
|
+
if !missing.empty?
|
372
|
+
if @@quiet
|
373
|
+
exit false
|
374
|
+
else
|
253
375
|
puts "Missing required arguments: #{missing.join(', ')}"
|
254
376
|
puts opts
|
255
|
-
|
256
377
|
exit!
|
257
378
|
end
|
258
379
|
end
|
259
|
-
|
260
|
-
options
|
261
380
|
end
|
262
|
-
|
263
381
|
end
|
264
382
|
|
265
383
|
end
|
data/lib/occi/version.rb
CHANGED
data/occi.gemspec
CHANGED
@@ -39,7 +39,7 @@ Gem::Specification.new do |gem|
|
|
39
39
|
gem.add_development_dependency "yard-rspec"
|
40
40
|
gem.add_development_dependency "yard-cucumber"
|
41
41
|
gem.add_development_dependency "rspec-http"
|
42
|
-
|
42
|
+
gem.add_development_dependency "rubygems-tasks"
|
43
43
|
gem.add_development_dependency "webmock"
|
44
44
|
|
45
45
|
gem.required_ruby_version = ">= 1.8.7"
|
@@ -23,9 +23,12 @@ module Occi
|
|
23
23
|
|
24
24
|
=begin
|
25
25
|
before(:all) do
|
26
|
-
@client = Occi::Api::Client::ClientAmqp.new(
|
27
|
-
|
28
|
-
|
26
|
+
@client = Occi::Api::Client::ClientAmqp.new({
|
27
|
+
:endpoint => "http://localhost:9292/",
|
28
|
+
:auth => { :type => "none" },
|
29
|
+
:log => { :out => STDERR, :level => Occi::Log::WARN, :logger => nil },
|
30
|
+
:media_type => "application/occi+json"
|
31
|
+
})
|
29
32
|
end
|
30
33
|
|
31
34
|
it "initialize and connect client" do
|
@@ -11,14 +11,14 @@ module Occi
|
|
11
11
|
context "using media type text/plain" do
|
12
12
|
|
13
13
|
before(:each) do
|
14
|
-
@client = Occi::Api::Client::ClientHttp.new(
|
15
|
-
'https://localhost:3300',
|
16
|
-
{ :type => "none" },
|
17
|
-
{ :out => "/dev/null",
|
18
|
-
|
19
|
-
true,
|
20
|
-
"text/plain,text/occi"
|
21
|
-
)
|
14
|
+
@client = Occi::Api::Client::ClientHttp.new({
|
15
|
+
:endpoint => 'https://localhost:3300',
|
16
|
+
:auth => { :type => "none" },
|
17
|
+
:log => { :out => "/dev/null",
|
18
|
+
:level => Occi::Log::DEBUG },
|
19
|
+
:auto_connect => true,
|
20
|
+
:media_type => "text/plain,text/occi"
|
21
|
+
})
|
22
22
|
end
|
23
23
|
|
24
24
|
after(:each) do
|
@@ -189,14 +189,14 @@ module Occi
|
|
189
189
|
context "using media type application/occi+json" do
|
190
190
|
|
191
191
|
before(:each) do
|
192
|
-
#@client = Occi::Api::ClientHttp.new(
|
193
|
-
# 'https://localhost:3300',
|
194
|
-
# { :type => "none" },
|
195
|
-
# { :out => "/dev/null",
|
196
|
-
#
|
197
|
-
# true,
|
198
|
-
# "application/occi+json"
|
199
|
-
#)
|
192
|
+
#@client = Occi::Api::ClientHttp.new({
|
193
|
+
# :endpoint => 'https://localhost:3300',
|
194
|
+
# :auth => { :type => "none" },
|
195
|
+
# :log => { :out => "/dev/null",
|
196
|
+
# :level => Occi::Log::DEBUG },
|
197
|
+
# :auto_connect => true,
|
198
|
+
# :media_type => "application/occi+json"
|
199
|
+
#})
|
200
200
|
end
|
201
201
|
|
202
202
|
it "establishes connection"
|