occi-cli 4.2.0.beta.3 → 4.2.0.beta.6
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/bin/occi +7 -4
- data/lib/occi/cli/helpers.rb +2 -1
- data/lib/occi/cli/helpers/create_helper.rb +6 -9
- data/lib/occi/cli/helpers/describe_helper.rb +1 -1
- data/lib/occi/cli/helpers/link_helper.rb +76 -0
- data/lib/occi/cli/occi_opts.rb +122 -119
- data/lib/occi/cli/occi_opts/cli_examples.erb +11 -0
- data/lib/occi/cli/occi_opts/occi_opts_helper.rb +61 -0
- data/lib/occi/cli/version.rb +1 -1
- data/occi-cli.gemspec +2 -1
- metadata +23 -4
data/bin/occi
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
require 'rubygems'
|
18
18
|
require 'pp'
|
19
19
|
require 'openssl'
|
20
|
+
require 'highline/import'
|
20
21
|
|
21
22
|
require 'occi-cli'
|
22
23
|
|
@@ -40,7 +41,7 @@ if options.auth[:password].nil? || options.auth[:user_cert_password].nil?
|
|
40
41
|
Occi::Log.debug "Password is not set, asking for it now ..."
|
41
42
|
|
42
43
|
options.auth[:user_cert_password] = ask("Enter a password: ") {
|
43
|
-
|q| q.echo =
|
44
|
+
|q| q.echo = '*'
|
44
45
|
} unless options.auth[:type] == "none" || (options.auth[:voms] && options.auth[:type] == "x509")
|
45
46
|
|
46
47
|
options.auth[:password] = options.auth[:user_cert_password]
|
@@ -139,14 +140,16 @@ begin
|
|
139
140
|
helper_describe options, output
|
140
141
|
when :create
|
141
142
|
helper_create options, output
|
142
|
-
when :
|
143
|
+
when :link
|
144
|
+
helper_link options, output
|
145
|
+
when :delete, :unlink
|
143
146
|
helper_delete options, output
|
144
147
|
when :trigger
|
145
148
|
helper_trigger options, output
|
146
149
|
when :refresh
|
147
150
|
refresh
|
148
|
-
when :skip
|
149
|
-
Occi::Log.info "
|
151
|
+
when :skip, :test, :dry_run
|
152
|
+
Occi::Log.info "Just a connection test ..."
|
150
153
|
else
|
151
154
|
raise "Unknown action [#{options.action}]!"
|
152
155
|
end
|
data/lib/occi/cli/helpers.rb
CHANGED
@@ -9,4 +9,5 @@ extend Occi::Cli::Helpers::ListHelper
|
|
9
9
|
extend Occi::Cli::Helpers::DescribeHelper
|
10
10
|
extend Occi::Cli::Helpers::CreateHelper
|
11
11
|
extend Occi::Cli::Helpers::DeleteHelper
|
12
|
-
extend Occi::Cli::Helpers::TriggerHelper
|
12
|
+
extend Occi::Cli::Helpers::TriggerHelper
|
13
|
+
extend Occi::Cli::Helpers::LinkHelper
|
@@ -18,19 +18,16 @@ module Occi::Cli::Helpers::CreateHelper
|
|
18
18
|
def helper_create_resource(options)
|
19
19
|
Occi::Log.debug "#{options.resource.inspect} is a resource type."
|
20
20
|
|
21
|
-
# TODO: implement the rest
|
22
|
-
raise "Not yet implemented!" unless options.resource.include? "compute"
|
23
|
-
|
24
21
|
res = resource(options.resource)
|
25
22
|
|
26
23
|
Occi::Log.debug "Creating #{options.resource.inspect}: #{res.inspect}"
|
27
24
|
|
28
|
-
|
25
|
+
helper_create_attach_mixins(options, res)
|
29
26
|
|
30
27
|
if res.kind_of? Occi::Infrastructure::Compute
|
31
|
-
|
28
|
+
helper_create_attach_links(options, res)
|
32
29
|
# TODO: context vars are only attributes!
|
33
|
-
|
30
|
+
helper_create_attach_context_vars(options, res)
|
34
31
|
end
|
35
32
|
|
36
33
|
options.attributes.names.each_pair do |attribute, value|
|
@@ -50,7 +47,7 @@ module Occi::Cli::Helpers::CreateHelper
|
|
50
47
|
create res
|
51
48
|
end
|
52
49
|
|
53
|
-
def
|
50
|
+
def helper_create_attach_links(options, res)
|
54
51
|
return unless options.links
|
55
52
|
Occi::Log.debug "with links: #{options.links.inspect}"
|
56
53
|
|
@@ -71,7 +68,7 @@ module Occi::Cli::Helpers::CreateHelper
|
|
71
68
|
end
|
72
69
|
end
|
73
70
|
|
74
|
-
def
|
71
|
+
def helper_create_attach_mixins(options, res)
|
75
72
|
return unless options.mixins
|
76
73
|
Occi::Log.debug "with mixins: #{options.mixins.inspect}"
|
77
74
|
|
@@ -86,7 +83,7 @@ module Occi::Cli::Helpers::CreateHelper
|
|
86
83
|
end
|
87
84
|
end
|
88
85
|
|
89
|
-
def
|
86
|
+
def helper_create_attach_context_vars(options, res)
|
90
87
|
# TODO: find a better/universal way to do contextualization
|
91
88
|
return unless options.context_vars
|
92
89
|
Occi::Log.debug "with context variables: #{options.context_vars.inspect}"
|
@@ -7,7 +7,7 @@ module Occi::Cli::Helpers::DescribeHelper
|
|
7
7
|
found = Occi::Core::Resources.new
|
8
8
|
found.merge describe(options.resource)
|
9
9
|
elsif mixin_types.include?(options.resource) || mixin_type_identifiers.include?(options.resource)
|
10
|
-
Occi::Log.debug "#{options.
|
10
|
+
Occi::Log.debug "#{options.resource.inspect} is a mixin type or type identifier."
|
11
11
|
|
12
12
|
found = Occi::Core::Mixins.new
|
13
13
|
found.merge mixins(options.resource)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Occi::Cli::Helpers::LinkHelper
|
2
|
+
|
3
|
+
def helper_link(options, output = nil)
|
4
|
+
location = nil
|
5
|
+
|
6
|
+
unless options.resource.start_with?(options.endpoint) || options.resource.start_with?('/')
|
7
|
+
raise "Given resource is not a valid instance URL! #{options.resource.inspect}"
|
8
|
+
end
|
9
|
+
|
10
|
+
unless options.links.length == 1
|
11
|
+
raise "You can assign only one link at a time!"
|
12
|
+
end
|
13
|
+
|
14
|
+
link = sanitize_instance_link(options.links.first)
|
15
|
+
unless link.start_with?('/')
|
16
|
+
raise "Given link is not a valid instance URL! #{link.inspect}"
|
17
|
+
end
|
18
|
+
|
19
|
+
link_kind = helper_link_kind(options, link)
|
20
|
+
location = helper_link_create_link(options, link_kind, link)
|
21
|
+
|
22
|
+
return location if output.nil?
|
23
|
+
|
24
|
+
puts location
|
25
|
+
end
|
26
|
+
|
27
|
+
def helper_link_kind(options, link)
|
28
|
+
raise "No valid links given!" if link.blank?
|
29
|
+
|
30
|
+
case link
|
31
|
+
when /\/network\//
|
32
|
+
link_kind = model.get_by_id("http://schemas.ogf.org/occi/infrastructure#networkinterface")
|
33
|
+
raise "#{options.endpoint.inspect} does not support networkinterface links!" unless link_kind
|
34
|
+
when /\/storage\//
|
35
|
+
link_kind = model.get_by_id("http://schemas.ogf.org/occi/infrastructure#storagelink")
|
36
|
+
raise "#{options.endpoint.inspect} does not support storagelink links!" unless link_kind
|
37
|
+
else
|
38
|
+
raise "Unknown link target #{link.inspect}! Only network and storage targets are supported!"
|
39
|
+
end
|
40
|
+
|
41
|
+
link_kind
|
42
|
+
end
|
43
|
+
|
44
|
+
def helper_link_create_link(options, link_kind, link)
|
45
|
+
Occi::Log.debug "Linking #{link.inspect} to #{options.resource.inspect}"
|
46
|
+
|
47
|
+
link_instance = Occi::Core::Link.new(link_kind)
|
48
|
+
link_instance.source = sanitize_instance_link(options.resource)
|
49
|
+
link_instance.target = link
|
50
|
+
|
51
|
+
helper_link_attach_mixins(options.mixins, link_instance)
|
52
|
+
|
53
|
+
options.attributes.names.each_pair do |attribute, value|
|
54
|
+
link_instance.attributes[attribute.to_s] = value
|
55
|
+
end
|
56
|
+
|
57
|
+
create link_instance
|
58
|
+
end
|
59
|
+
|
60
|
+
def helper_link_attach_mixins(mixins, link)
|
61
|
+
return if mixins.blank?
|
62
|
+
|
63
|
+
Occi::Log.debug "with mixins: #{mixins.inspect}"
|
64
|
+
|
65
|
+
mixins.to_a.each do |mxn|
|
66
|
+
Occi::Log.debug "Adding mixin #{mxn.inspect} to #{link.inspect}"
|
67
|
+
|
68
|
+
mxn = model.get_by_id(mxn.type_identifier)
|
69
|
+
raise Occi::Cli::Errors::MixinLookupError,
|
70
|
+
"The specified mixin is not declared in the model! #{mxn.type_identifier.inspect}" if mxn.blank?
|
71
|
+
|
72
|
+
link.mixins << mxn
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
data/lib/occi/cli/occi_opts.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
require 'ostruct'
|
2
1
|
require 'optparse'
|
3
2
|
require 'uri'
|
4
|
-
require '
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
# load all parts of OcciOpts
|
6
|
+
Dir[File.join(File.dirname(__FILE__), 'occi_opts', '*.rb')].each { |file| require file.gsub('.rb', '') }
|
5
7
|
|
6
8
|
module Occi::Cli
|
7
9
|
|
@@ -9,64 +11,21 @@ module Occi::Cli
|
|
9
11
|
|
10
12
|
AUTH_METHODS = [:x509, :basic, :digest, :none].freeze
|
11
13
|
MEDIA_TYPES = ["application/occi+json", "application/occi+xml", "text/plain,text/occi", "text/plain"].freeze
|
12
|
-
ACTIONS = [:list, :describe, :create, :delete, :trigger].freeze
|
14
|
+
ACTIONS = [:list, :describe, :create, :delete, :trigger, :link, :unlink].freeze
|
13
15
|
LOG_OUTPUTS = [:stdout, :stderr].freeze
|
14
|
-
ALLOWED_CONTEXT_VARS = [:public_key, :user_data].freeze
|
15
16
|
LOG_LEVELS = [:debug, :error, :fatal, :info, :unknown, :warn].freeze
|
16
17
|
|
17
|
-
|
18
|
-
CONTEXT_REGEXP = ATTR_REGEXP = /^(.+?)=(.+)$/
|
18
|
+
REQ_CREATE_ATTRS = ["occi.core.title"].freeze
|
19
19
|
|
20
20
|
def self.parse(args, test_env = false)
|
21
21
|
|
22
22
|
@@quiet = test_env
|
23
23
|
|
24
|
-
options =
|
25
|
-
|
26
|
-
options.debug = false
|
27
|
-
|
28
|
-
options.log = {}
|
29
|
-
options.log[:out] = STDERR
|
30
|
-
options.log[:level] = Occi::Log::ERROR
|
31
|
-
|
32
|
-
options.filter = nil
|
33
|
-
options.dump_model = false
|
34
|
-
|
35
|
-
options.endpoint = "https://localhost:3300/"
|
36
|
-
|
37
|
-
options.auth = {}
|
38
|
-
options.auth[:type] = "none"
|
39
|
-
options.auth[:user_cert] = ENV['HOME'] + "/.globus/usercred.pem"
|
40
|
-
options.auth[:ca_path] = "/etc/grid-security/certificates"
|
41
|
-
options.auth[:username] = "anonymous"
|
42
|
-
options.auth[:ca_file] = nil
|
43
|
-
options.auth[:voms] = nil
|
44
|
-
|
45
|
-
options.output_format = :plain
|
46
|
-
|
47
|
-
options.mixins = Occi::Core::Mixins.new
|
48
|
-
options.links = nil
|
49
|
-
options.attributes = Occi::Core::Attributes.new
|
50
|
-
options.context_vars = nil
|
51
|
-
|
52
|
-
# TODO: change media type back to occi+json after the rOCCI-server update
|
53
|
-
#options.media_type = "application/occi+json"
|
54
|
-
options.media_type = "text/plain,text/occi"
|
24
|
+
options = Hashie::Mash.new
|
25
|
+
set_defaults(options)
|
55
26
|
|
56
27
|
opts = OptionParser.new do |opts|
|
57
|
-
opts.banner = %{Usage: occi [OPTIONS]
|
58
|
-
|
59
|
-
Examples:
|
60
|
-
|
61
|
-
occi --endpoint https://localhost:3300/ --action list --resource os_tpl --auth x509
|
62
|
-
|
63
|
-
occi --endpoint https://localhost:3300/ --action list --resource resource_tpl --auth x509
|
64
|
-
|
65
|
-
occi --endpoint https://localhost:3300/ --action describe --resource os_tpl#debian6 --auth x509
|
66
|
-
|
67
|
-
occi --endpoint https://localhost:3300/ --action create --resource compute --mixin os_tpl#debian6 --mixin resource_tpl#small --attribute title="My rOCCI VM" --auth x509
|
68
|
-
|
69
|
-
occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd4f654sf65g4-s5fg65sfg465sfg-sf65g46sf5g4sdfg --auth x509}
|
28
|
+
opts.banner = %{Usage: occi [OPTIONS]}
|
70
29
|
|
71
30
|
opts.separator ""
|
72
31
|
opts.separator "Options:"
|
@@ -81,33 +40,35 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
|
|
81
40
|
opts.on("-n",
|
82
41
|
"--auth METHOD",
|
83
42
|
AUTH_METHODS,
|
84
|
-
"Authentication method,
|
85
|
-
|
43
|
+
"Authentication method, only: [#{AUTH_METHODS.join('|')}], defaults " \
|
44
|
+
"to '#{options.auth.type}'") do |auth|
|
45
|
+
options.auth.type = auth.to_s
|
86
46
|
end
|
87
47
|
|
88
48
|
opts.on("-u",
|
89
49
|
"--username USER",
|
90
50
|
String,
|
91
|
-
"Username for basic or digest authentication, defaults to
|
92
|
-
|
51
|
+
"Username for basic or digest authentication, defaults to " \
|
52
|
+
"'#{options.auth.username}'") do |username|
|
53
|
+
options.auth.username = username
|
93
54
|
end
|
94
55
|
|
95
56
|
opts.on("-p",
|
96
57
|
"--password PASSWORD",
|
97
58
|
String,
|
98
59
|
"Password for basic, digest and x509 authentication") do |password|
|
99
|
-
options.auth
|
100
|
-
options.auth
|
60
|
+
options.auth.password = password
|
61
|
+
options.auth.user_cert_password = password
|
101
62
|
end
|
102
63
|
|
103
64
|
opts.on("-c",
|
104
65
|
"--ca-path PATH",
|
105
66
|
String,
|
106
|
-
"Path to CA certificates directory, defaults to '#{options.auth
|
67
|
+
"Path to CA certificates directory, defaults to '#{options.auth.ca_path}'") do |ca_path|
|
107
68
|
raise ArgumentError, "Path specified in --ca-path is not a directory!" unless File.directory? ca_path
|
108
69
|
raise ArgumentError, "Path specified in --ca-path is not readable!" unless File.readable? ca_path
|
109
70
|
|
110
|
-
options.auth
|
71
|
+
options.auth.ca_path = ca_path
|
111
72
|
end
|
112
73
|
|
113
74
|
opts.on("-f",
|
@@ -117,116 +78,98 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
|
|
117
78
|
raise ArgumentError, "File specified in --ca-file is not a file!" unless File.file? ca_file
|
118
79
|
raise ArgumentError, "File specified in --ca-file is not readable!" unless File.readable? ca_file
|
119
80
|
|
120
|
-
options.auth
|
81
|
+
options.auth.ca_file = ca_file
|
121
82
|
end
|
122
83
|
|
123
84
|
opts.on("-F",
|
124
85
|
"--filter CATEGORY",
|
125
86
|
String,
|
126
|
-
"Category type identifier to filter categories from model, must
|
87
|
+
"Category type identifier to filter categories from model, must " \
|
88
|
+
"be used together with the -m option") do |filter|
|
127
89
|
options.filter = filter
|
128
90
|
end
|
129
91
|
|
130
92
|
opts.on("-x",
|
131
93
|
"--user-cred FILE",
|
132
94
|
String,
|
133
|
-
"Path to user's x509 credentials, defaults to '#{options.auth
|
95
|
+
"Path to user's x509 credentials, defaults to '#{options.auth.user_cert}'") do |user_cred|
|
134
96
|
raise ArgumentError, "File specified in --user-cred is not a file!" unless File.file? user_cred
|
135
97
|
raise ArgumentError, "File specified in --user-cred is not readable!" unless File.readable? user_cred
|
136
98
|
|
137
|
-
options.auth
|
99
|
+
options.auth.user_cert = user_cred
|
138
100
|
end
|
139
101
|
|
140
102
|
opts.on("-X",
|
141
103
|
"--voms",
|
142
104
|
"Using VOMS credentials; modifies behavior of the X509 authN module") do |voms|
|
143
105
|
|
144
|
-
options.auth
|
106
|
+
options.auth.voms = true
|
145
107
|
end
|
146
108
|
|
147
109
|
opts.on("-y",
|
148
110
|
"--media-type MEDIA_TYPE",
|
149
111
|
MEDIA_TYPES,
|
150
|
-
"Media type for client <-> server communication,
|
112
|
+
"Media type for client <-> server communication, only: [#{MEDIA_TYPES.join('|')}], " \
|
113
|
+
"defaults to '#{options.media_type}'") do |media_type|
|
151
114
|
options.media_type = media_type
|
152
115
|
end
|
153
116
|
|
154
117
|
opts.on("-r",
|
155
118
|
"--resource RESOURCE",
|
156
119
|
String,
|
157
|
-
"
|
120
|
+
"Term, identifier or URI of a resource to be queried, required") do |resource|
|
158
121
|
options.resource = resource
|
159
122
|
end
|
160
123
|
|
161
124
|
opts.on("-t",
|
162
125
|
"--attribute ATTRS",
|
163
126
|
Array,
|
164
|
-
"Comma separated attributes for new
|
127
|
+
"Comma separated attributes for new resource instances, mandatory: " \
|
128
|
+
"[#{REQ_CREATE_ATTRS.join(', ')}]") do |attributes|
|
165
129
|
options.attributes ||= Occi::Core::Attributes.new
|
166
130
|
|
167
131
|
attributes.each do |attribute|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
ary[0] = "occi.core.#{ary[0]}" unless ary[0].include?('.')
|
172
|
-
options.attributes[ary[0]] = ary[1]
|
132
|
+
key, value = Occi::Cli::OcciOpts::Helper.parse_attribute(attribute)
|
133
|
+
options.attributes[key] = value
|
173
134
|
end
|
174
135
|
end
|
175
136
|
|
176
137
|
opts.on("-T",
|
177
138
|
"--context CTX_VARS",
|
178
139
|
Array,
|
179
|
-
"Comma separated context variables for new compute
|
140
|
+
"Comma separated context variables for new 'compute' resource instances, " \
|
141
|
+
"only: [#{Occi::Cli::OcciOpts::Helper::ALLOWED_CONTEXT_VARS.join(', ')}]") do |context|
|
180
142
|
options.context_vars ||= {}
|
181
143
|
|
182
144
|
context.each do |ctx|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
symbol = ary[0].to_sym
|
187
|
-
if ALLOWED_CONTEXT_VARS.include?(symbol)
|
188
|
-
context_data = ary[1]
|
189
|
-
if context_data.gsub!(/^file:\/\//,'')
|
190
|
-
raise 'File does not exist! #{context_data}' unless File.exist? context_data
|
191
|
-
context_data = File.read(context_data)
|
192
|
-
end
|
193
|
-
|
194
|
-
if symbol == :user_data
|
195
|
-
context_data = Base64.encode64(context_data).gsub("\n", '')
|
196
|
-
end
|
197
|
-
|
198
|
-
options.context_vars[symbol] = context_data.strip
|
199
|
-
else
|
200
|
-
Occi::Log.warn "Only #{ALLOWED_CONTEXT_VARS.join(', ')} context variables are supported! Skipping #{ary[0].to_s} ..."
|
201
|
-
end
|
145
|
+
key, value = Occi::Cli::OcciOpts::Helper.parse_context_variable(ctx)
|
146
|
+
options.context_vars[key] = value
|
202
147
|
end
|
203
148
|
end
|
204
149
|
|
205
150
|
opts.on("-a",
|
206
151
|
"--action ACTION",
|
207
152
|
ACTIONS,
|
208
|
-
"Action to be performed on
|
153
|
+
"Action to be performed on a resource instance, required") do |action|
|
209
154
|
options.action = action
|
210
155
|
end
|
211
156
|
|
212
157
|
opts.on("-M",
|
213
|
-
"--mixin
|
158
|
+
"--mixin IDENTIFIER",
|
214
159
|
Array,
|
215
|
-
"
|
160
|
+
"Identifier of a mixin, formatted as SCHEME#TERM or SHORT_SCHEME#TERM") do |mixins|
|
216
161
|
options.mixins ||= Occi::Core::Mixins.new
|
217
162
|
|
218
163
|
mixins.each do |mixin|
|
219
|
-
|
220
|
-
raise "Unknown mixin format #{mixin.inspect}! Use SCHEME#NAME!" unless parts.length == 2
|
221
|
-
|
222
|
-
options.mixins << Occi::Core::Mixin.new("#{parts[0]}#", parts[1])
|
164
|
+
options.mixins << Occi::Cli::OcciOpts::Helper.parse_mixin(mixin)
|
223
165
|
end
|
224
166
|
end
|
225
167
|
|
226
168
|
opts.on("-j",
|
227
169
|
"--link URI",
|
228
170
|
Array,
|
229
|
-
"Link
|
171
|
+
"Link this resource to the resource being created, only for action " \
|
172
|
+
"'create' and resource 'compute'") do |links|
|
230
173
|
options.links ||= []
|
231
174
|
|
232
175
|
links.each do |link|
|
@@ -237,32 +180,49 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
|
|
237
180
|
end
|
238
181
|
|
239
182
|
opts.on("-g",
|
240
|
-
"--trigger-action
|
183
|
+
"--trigger-action TRIGGER_ACTION",
|
241
184
|
String,
|
242
|
-
"Action to be triggered on the resource") do |trigger_action|
|
243
|
-
options.trigger_action = trigger_action
|
185
|
+
"Action to be triggered on the resource, formatted as SCHEME#TERM or SHORT_SCHEME#TERM") do |trigger_action|
|
186
|
+
options.trigger_action = Occi::Cli::OcciOpts::Helper.parse_action(trigger_action)
|
244
187
|
end
|
245
188
|
|
246
189
|
opts.on("-l",
|
247
190
|
"--log-to OUTPUT",
|
248
191
|
LOG_OUTPUTS,
|
249
|
-
"Log to the specified device, defaults to '
|
250
|
-
options.log
|
192
|
+
"Log to the specified device, only: [#{LOG_OUTPUTS.join('|')}], defaults to 'stderr'") do |log_to|
|
193
|
+
options.log.out = STDOUT if log_to.to_s == "stdout"
|
251
194
|
end
|
252
195
|
|
253
196
|
opts.on("-o",
|
254
197
|
"--output-format FORMAT",
|
255
198
|
Occi::Cli::ResourceOutputFactory.allowed_formats,
|
256
|
-
"Output format,
|
199
|
+
"Output format, only: [#{Occi::Cli::ResourceOutputFactory.allowed_formats.join('|')}], " \
|
200
|
+
"defaults to '#{options.output_format}'") do |output_format|
|
257
201
|
options.output_format = output_format
|
258
202
|
end
|
259
203
|
|
260
204
|
opts.on("-b",
|
261
205
|
"--log-level LEVEL",
|
262
206
|
LOG_LEVELS,
|
263
|
-
"Set the specified logging level,
|
264
|
-
unless options.log
|
265
|
-
options.log
|
207
|
+
"Set the specified logging level, only: [#{LOG_LEVELS.join('|')}]") do |log_level|
|
208
|
+
unless options.log.level == Occi::Log::DEBUG
|
209
|
+
options.log.level = Occi::Log.const_get(log_level.to_s.upcase)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
opts.on_tail("-z",
|
214
|
+
"--examples",
|
215
|
+
"Show usage examples") do |examples|
|
216
|
+
if examples
|
217
|
+
if @@quiet
|
218
|
+
exit true
|
219
|
+
else
|
220
|
+
file = "#{File.expand_path('..', __FILE__)}/occi_opts/cli_examples.erb"
|
221
|
+
template = ERB.new(File.new(file).read, nil, '-')
|
222
|
+
|
223
|
+
puts template.result(binding)
|
224
|
+
exit! true
|
225
|
+
end
|
266
226
|
end
|
267
227
|
end
|
268
228
|
|
@@ -276,7 +236,7 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
|
|
276
236
|
"--debug",
|
277
237
|
"Enable debugging messages") do |debug|
|
278
238
|
options.debug = debug
|
279
|
-
options.log
|
239
|
+
options.log.level = Occi::Log::DEBUG
|
280
240
|
end
|
281
241
|
|
282
242
|
opts.on_tail("-h",
|
@@ -327,7 +287,52 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
|
|
327
287
|
|
328
288
|
private
|
329
289
|
|
290
|
+
def self.set_defaults(options)
|
291
|
+
options.debug = false
|
292
|
+
|
293
|
+
options.log = {}
|
294
|
+
options.log.out = STDERR
|
295
|
+
options.log.level = Occi::Log::ERROR
|
296
|
+
|
297
|
+
options.filter = nil
|
298
|
+
options.dump_model = false
|
299
|
+
|
300
|
+
options.endpoint = "http://localhost:3000"
|
301
|
+
|
302
|
+
options.auth = {}
|
303
|
+
options.auth.type = "none"
|
304
|
+
options.auth.user_cert = "#{ENV['HOME']}/.globus/usercred.pem"
|
305
|
+
options.auth.ca_path = "/etc/grid-security/certificates"
|
306
|
+
options.auth.username = "anonymous"
|
307
|
+
options.auth.ca_file = nil
|
308
|
+
options.auth.voms = nil
|
309
|
+
|
310
|
+
options.output_format = :plain
|
311
|
+
|
312
|
+
options.mixins = Occi::Core::Mixins.new
|
313
|
+
options.links = nil
|
314
|
+
options.attributes = Occi::Core::Attributes.new
|
315
|
+
options.context_vars = nil
|
316
|
+
|
317
|
+
# TODO: change media type back to occi+json after the rOCCI-server update
|
318
|
+
#options.media_type = "application/occi+json"
|
319
|
+
options.media_type = "text/plain,text/occi"
|
320
|
+
|
321
|
+
options
|
322
|
+
end
|
323
|
+
|
330
324
|
def self.check_restrictions(options, opts)
|
325
|
+
check_incompatible_args(options, opts)
|
326
|
+
|
327
|
+
return if options.dump_model
|
328
|
+
|
329
|
+
mandatory = get_mandatory_args(options)
|
330
|
+
check_hash(options, mandatory, opts)
|
331
|
+
|
332
|
+
check_attributes(options.attributes, REQ_CREATE_ATTRS, opts) if options.action == :create
|
333
|
+
end
|
334
|
+
|
335
|
+
def self.check_incompatible_args(options, opts)
|
331
336
|
if !options.dump_model && options.filter
|
332
337
|
if @@quiet
|
333
338
|
exit false
|
@@ -338,7 +343,7 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
|
|
338
343
|
end
|
339
344
|
end
|
340
345
|
|
341
|
-
if options.voms && options.auth
|
346
|
+
if options.voms && options.auth.type != "x509"
|
342
347
|
if @@quiet
|
343
348
|
exit false
|
344
349
|
else
|
@@ -347,9 +352,9 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
|
|
347
352
|
exit!
|
348
353
|
end
|
349
354
|
end
|
355
|
+
end
|
350
356
|
|
351
|
-
|
352
|
-
|
357
|
+
def self.get_mandatory_args(options)
|
353
358
|
mandatory = []
|
354
359
|
|
355
360
|
if options.action == :trigger
|
@@ -364,17 +369,15 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
|
|
364
369
|
end
|
365
370
|
|
366
371
|
mandatory << :attributes
|
367
|
-
check_attrs = true
|
368
372
|
end
|
369
373
|
|
370
|
-
|
374
|
+
if options.action == :link
|
375
|
+
mandatory << :links
|
376
|
+
end
|
371
377
|
|
372
|
-
|
378
|
+
mandatory.concat [:resource, :action]
|
373
379
|
|
374
|
-
|
375
|
-
mandatory = ["occi.core.title"]
|
376
|
-
check_attributes options.attributes, mandatory, opts
|
377
|
-
end
|
380
|
+
mandatory
|
378
381
|
end
|
379
382
|
|
380
383
|
def self.check_hash(hash, mandatory, opts)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Examples:
|
2
|
+
|
3
|
+
occi --endpoint https://localhost:3300/ --action list --resource os_tpl --auth x509
|
4
|
+
|
5
|
+
occi --endpoint https://localhost:3300/ --action list --resource resource_tpl --auth x509
|
6
|
+
|
7
|
+
occi --endpoint https://localhost:3300/ --action describe --resource os_tpl#debian6 --auth x509
|
8
|
+
|
9
|
+
occi --endpoint https://localhost:3300/ --action create --resource compute --mixin os_tpl#debian6 --mixin resource_tpl#small --attribute title="My rOCCI VM" --auth x509
|
10
|
+
|
11
|
+
occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd4f654sf65g4-s5fg65sfg465sfg-sf65g46sf5g4sdfg --auth x509
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Occi::Cli
|
4
|
+
class OcciOpts
|
5
|
+
module Helper
|
6
|
+
|
7
|
+
ALLOWED_CONTEXT_VARS = [:public_key, :user_data].freeze
|
8
|
+
|
9
|
+
MIXIN_REGEXP = ACTION_REGEXP = /^(\S+?)#(\S+)$/
|
10
|
+
CONTEXT_REGEXP = ATTR_REGEXP = /^(\S+?)=(.+)$/
|
11
|
+
|
12
|
+
def self.parse_context_variable(cvar)
|
13
|
+
ary = CONTEXT_REGEXP.match(cvar).to_a.drop 1
|
14
|
+
raise ArgumentError, "Context variables must always contain ATTR=VALUE pairs!" unless ary.length == 2
|
15
|
+
|
16
|
+
symbol = ary[0].to_sym
|
17
|
+
unless ALLOWED_CONTEXT_VARS.include?(symbol)
|
18
|
+
raise ArgumentError,
|
19
|
+
"Only #{ALLOWED_CONTEXT_VARS.join(', ')} context " \
|
20
|
+
"variables are supported! #{symbol.to_s.inspect}"
|
21
|
+
end
|
22
|
+
|
23
|
+
context_data = ary[1]
|
24
|
+
if context_data.gsub!(/^file:\/\//,'')
|
25
|
+
raise 'File does not exist! #{context_data}' unless File.exist? context_data
|
26
|
+
context_data = File.read(context_data)
|
27
|
+
end
|
28
|
+
|
29
|
+
if symbol == :user_data
|
30
|
+
context_data = Base64.encode64(context_data).gsub("\n", '')
|
31
|
+
end
|
32
|
+
|
33
|
+
[symbol, context_data.strip]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.parse_attribute(attribute)
|
37
|
+
ary = ATTR_REGEXP.match(attribute).to_a.drop 1
|
38
|
+
raise ArgumentError, "Attribute must always contain ATTR=VALUE pairs!" unless ary.length == 2
|
39
|
+
|
40
|
+
ary[0] = "occi.core.#{ary[0]}" unless ary[0].include?('.')
|
41
|
+
|
42
|
+
ary
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.parse_mixin(mixin)
|
46
|
+
parts = MIXIN_REGEXP.match(mixin).to_a.drop(1)
|
47
|
+
raise "Unknown mixin format '#{mixin.inspect}'! Use SCHEME#TERM or SHORT_SCHEME#TERM!" unless parts.length == 2
|
48
|
+
|
49
|
+
Occi::Core::Mixin.new("#{parts[0]}#", parts[1])
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.parse_action(action)
|
53
|
+
parts = ACTION_REGEXP.match(action).to_a.drop(1)
|
54
|
+
raise "Unknown action format '#{action.inspect}'! Use SCHEME#TERM or SHORT_SCHEME#TERM!" unless parts.length == 2
|
55
|
+
|
56
|
+
Occi::Core::Action.new("#{parts[0]}#", parts[1])
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/occi/cli/version.rb
CHANGED
data/occi-cli.gemspec
CHANGED
@@ -19,8 +19,9 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.test_files = `git ls-files -- {test,spec}/*`.split("\n")
|
20
20
|
gem.require_paths = ["lib"]
|
21
21
|
|
22
|
-
gem.add_dependency 'occi-api', '= 4.2.0.beta.
|
22
|
+
gem.add_dependency 'occi-api', '= 4.2.0.beta.6'
|
23
23
|
gem.add_dependency 'json'
|
24
|
+
gem.add_dependency 'highline'
|
24
25
|
|
25
26
|
gem.required_ruby_version = ">= 1.9.3"
|
26
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: occi-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.2.0.beta.
|
4
|
+
version: 4.2.0.beta.6
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2014-01-06 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: occi-api
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - '='
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 4.2.0.beta.
|
23
|
+
version: 4.2.0.beta.6
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
requirements:
|
29
29
|
- - '='
|
30
30
|
- !ruby/object:Gem::Version
|
31
|
-
version: 4.2.0.beta.
|
31
|
+
version: 4.2.0.beta.6
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
33
|
name: json
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,6 +45,22 @@ dependencies:
|
|
45
45
|
- - ! '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: highline
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
48
64
|
description: This gem is a client implementation of the Open Cloud Computing Interface
|
49
65
|
in Ruby
|
50
66
|
email:
|
@@ -78,9 +94,12 @@ files:
|
|
78
94
|
- lib/occi/cli/helpers/create_helper.rb
|
79
95
|
- lib/occi/cli/helpers/delete_helper.rb
|
80
96
|
- lib/occi/cli/helpers/describe_helper.rb
|
97
|
+
- lib/occi/cli/helpers/link_helper.rb
|
81
98
|
- lib/occi/cli/helpers/list_helper.rb
|
82
99
|
- lib/occi/cli/helpers/trigger_helper.rb
|
83
100
|
- lib/occi/cli/occi_opts.rb
|
101
|
+
- lib/occi/cli/occi_opts/cli_examples.erb
|
102
|
+
- lib/occi/cli/occi_opts/occi_opts_helper.rb
|
84
103
|
- lib/occi/cli/resource_output_factory.rb
|
85
104
|
- lib/occi/cli/templates/mixins.erb
|
86
105
|
- lib/occi/cli/templates/resources.erb
|