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 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 = false
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 :delete
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 "Skipping this action, probably not implemented yet!"
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
@@ -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
- helper_attach_mixins(options, res)
25
+ helper_create_attach_mixins(options, res)
29
26
 
30
27
  if res.kind_of? Occi::Infrastructure::Compute
31
- helper_attach_links(options, res)
28
+ helper_create_attach_links(options, res)
32
29
  # TODO: context vars are only attributes!
33
- helper_attach_context_vars(options, res)
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 helper_attach_links(options, res)
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 helper_attach_mixins(options, res)
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 helper_attach_context_vars(options, res)
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.resourcre.inspect} is a mixin type or type identifier."
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
@@ -1,7 +1,9 @@
1
- require 'ostruct'
2
1
  require 'optparse'
3
2
  require 'uri'
4
- require 'base64'
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
- MIXIN_REGEXP = /^(https?:\/\/\S+?)#(\S+)$/
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 = OpenStruct.new
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, defaults to '#{options.auth[:type]}'") do |auth|
85
- options.auth[:type] = auth.to_s
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 '#{options.auth[:username]}'") do |username|
92
- options.auth[:username] = username
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[:password] = password
100
- options.auth[:user_cert_password] = password
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[:ca_path]}'") do |ca_path|
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[:ca_path] = ca_path
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[:ca_file] = ca_file
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 be used together with the -m option") do |filter|
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[:user_cert]}'") do |user_cred|
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[:user_cert] = user_cred
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[:voms] = true
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, defaults to '#{options.media_type}'") do |media_type|
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
- "Resource to be queried (e.g. network, compute, storage etc.), required") do |resource|
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 resources such as occi.core.title=\"Name\", required") do |attributes|
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
- ary = ATTR_REGEXP.match(attribute).to_a.drop 1
169
- raise ArgumentError, "Attribute must always contain ATTR=VALUE pairs!" unless ary.length == 2
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 resources such as public_key=\"ssh-rsa dfsdf...adfdf== user@localhost\"") do |context|
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
- ary = CONTEXT_REGEXP.match(ctx).to_a.drop 1
184
- raise ArgumentError, "Context variables must always contain ATTR=VALUE pairs!" unless ary.length == 2
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 the resource, required") do |action|
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 NAME",
158
+ "--mixin IDENTIFIER",
214
159
  Array,
215
- "Type and name of the mixin as SCHEME#NAME (e.g. http://localhost/os_tpl#monitoring, http://localhost/resource_tpl#medium)") do |mixins|
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
- parts = MIXIN_REGEXP.match(mixin).to_a.drop(1)
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 specified resource to the resource being created, only for action CREATE and resource COMPUTE") do |links|
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 TRIGGER",
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 'STDERR'") do |log_to|
250
- options.log[:out] = STDOUT if log_to == :stdout or log_to == :STDOUT
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, defaults to human-readable 'plain'") do |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, less intrusive than debug mode") do |log_level|
264
- unless options.log[:level] == Occi::Log::DEBUG
265
- options.log[:level] = Occi::Log.const_get(log_level.to_s.upcase)
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[:level] = Occi::Log::DEBUG
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[:type] != "x509"
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
- return if options.dump_model
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
- mandatory.concat [:resource, :action]
374
+ if options.action == :link
375
+ mandatory << :links
376
+ end
371
377
 
372
- check_hash options, mandatory, opts
378
+ mandatory.concat [:resource, :action]
373
379
 
374
- if check_attrs
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
@@ -1,5 +1,5 @@
1
1
  module Occi
2
2
  module Cli
3
- VERSION = "4.2.0.beta.3" unless defined?(::Occi::Cli::VERSION)
3
+ VERSION = "4.2.0.beta.6" unless defined?(::Occi::Cli::VERSION)
4
4
  end
5
5
  end
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.2'
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.3
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: 2013-12-06 00:00:00.000000000 Z
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.2
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.2
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