occi-cli 4.2.0.beta.2 → 4.2.0.beta.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -110,18 +110,12 @@ ruby -v
110
110
  Usage
111
111
  -----
112
112
  ### Client
113
- The OCCI gem includes a client you can use directly from shell with the following auth methods: x509 (with --password, --user-cred and --ca-path), basic (with --username and --password), digest (with --username and --password), none. If you won't set a password using --password, the client will ask for it later on. There is also an interactive mode, which will allow you to interact with the client through menus and answers to simple questions (this feature is still experimental).
113
+ The OCCI gem includes a client you can use directly from shell with the following auth methods: x509 (with --password, --user-cred and --ca-path), basic (with --username and --password), digest (with --username and --password), none. If you won't set a password using --password, the client will ask for it later on.
114
114
 
115
115
  To find out more about available options and defaults use
116
116
 
117
117
  occi --help
118
118
 
119
- To run the client in an interactive mode use
120
-
121
- occi --interactive
122
- occi --interactive --endpoint https://<ENDPOINT>:<PORT>/
123
- occi --interactive --endpoint https://<ENDPOINT>:<PORT>/ --auth x509
124
-
125
119
  To list available resources use
126
120
 
127
121
  occi --endpoint https://<ENDPOINT>:<PORT>/ --action list --resource compute --auth x509
@@ -161,6 +155,12 @@ To delete a compute resource use
161
155
  Changelog
162
156
  ---------
163
157
 
158
+ ### Version 4.2
159
+ * Droppped the interactive mode (it might return in the future)
160
+ * Updated internals
161
+ * Updated user interface and human-readable rendering
162
+ * __Includes interface changes incompatible with v4.1.x__
163
+
164
164
  ### Version 4.1
165
165
  * Dropped Ruby 1.8.x support
166
166
  * Dropped jRuby 1.6.x support
data/bin/occi CHANGED
@@ -16,7 +16,6 @@
16
16
 
17
17
  require 'rubygems'
18
18
  require 'pp'
19
- require 'highline/import'
20
19
  require 'openssl'
21
20
 
22
21
  require 'occi-cli'
@@ -47,9 +46,7 @@ if options.auth[:password].nil? || options.auth[:user_cert_password].nil?
47
46
  options.auth[:password] = options.auth[:user_cert_password]
48
47
  end
49
48
 
50
- # establish a connection before entering the loop
51
- # this will considerably speed-up the interactive mode and has
52
- # no effect on the non-interactive one
49
+ # establish a connection
53
50
  begin
54
51
  Occi::Log.info "Establishing a connection to #{options.endpoint} ..."
55
52
 
@@ -58,7 +55,7 @@ begin
58
55
  rescue OpenSSL::SSL::SSLError => ssl_ex
59
56
  # generic SSL error raised whilst establishing a connection
60
57
  # possibly an untrusted server cert or invalid user credentials
61
- Occi::Log.error "An SSL error occurred! Please, make sure your credentials " \
58
+ Occi::Log.fatal "An SSL error occurred! Please, make sure your credentials " \
62
59
  "are valid and recognized by the endpoint! Message: #{ssl_ex.message}"
63
60
 
64
61
  raise ssl_ex if options.debug
@@ -66,7 +63,7 @@ rescue OpenSSL::SSL::SSLError => ssl_ex
66
63
  rescue OpenSSL::PKey::RSAError => key_ex
67
64
  # generic X509 error raised whilst reading user's credentials from a file
68
65
  # possibly a wrong password or mangled/unsupported credential format
69
- Occi::Log.error "An X509 error occurred! Please, make sure you are using the " \
66
+ Occi::Log.fatal "An X509 error occurred! Please, make sure you are using the " \
70
67
  "right password and the file contains both your certificate " \
71
68
  "and your private key! Message: #{key_ex.message}"
72
69
 
@@ -75,12 +72,16 @@ rescue OpenSSL::PKey::RSAError => key_ex
75
72
  rescue Errno::ECONNREFUSED
76
73
  # the remote server has refused our connection attempt(s)
77
74
  # there is nothing we can do ...
78
- Occi::Log.error "Connection refused by #{options.endpoint}!"
75
+ Occi::Log.fatal "Connection refused by #{options.endpoint}!"
76
+ exit!
77
+ rescue Errno::ETIMEDOUT
78
+ # connection attempt timed out
79
+ Occi::Log.fatal "Connection to #{options.endpoint} timed out!"
79
80
  exit!
80
81
  rescue Exception => ex
81
82
  # something went wrong during the execution
82
83
  # hide the stack trace in non-debug modes
83
- Occi::Log.error "An error occurred! Message: #{ex.message}"
84
+ Occi::Log.fatal "An error occurred! Message: #{ex.message}"
84
85
 
85
86
  raise ex if options.debug
86
87
  exit!
@@ -90,7 +91,7 @@ end
90
91
  if options.dump_model
91
92
 
92
93
  if !model.respond_to? :instance_variables
93
- Occi::Log.error "Your Ruby doesn't support 'instance_variables' calls!"
94
+ Occi::Log.fatal "Your Ruby doesn't support 'instance_variables' calls!"
94
95
  exit!
95
96
  end
96
97
 
@@ -125,193 +126,9 @@ if options.dump_model
125
126
  exit! true
126
127
  end
127
128
 
128
- # start of the main loop, this part of the code is responsible for
129
- # interactive menus and actions execution
130
- # this block will run while options.interactive is True, i.e.
131
- # only once in the non-interactive mode
129
+ # start executing actions
132
130
  begin
133
131
 
134
- # display menus in the interactive mode, there are two main variables
135
- # that need to be set here: options.action and options.resource
136
- if options.interactive
137
-
138
- Occi::Log.debug "Running in an interactive mode ..."
139
-
140
- # reset action and resource, just to be sure
141
- options.action = nil
142
- options.resource = nil
143
-
144
- # offer just the resource types we will be able to process
145
- menu_resources = []
146
- menu_resources << resource_type_identifiers.select { |i| i.include?("infrastructure#") }
147
- menu_resources << ["http://schemas.ogf.org/occi/infrastructure#os_tpl", "http://schemas.ogf.org/occi/infrastructure#resource_tpl"]
148
- menu_resources.flatten!
149
- menu_resources.uniq!
150
-
151
- # separate menus from each other
152
- say("\n")
153
-
154
- # first we need an action
155
- choose do |menu|
156
- menu.prompt = "Please, choose an action: "
157
-
158
- # list action requires a resource type
159
- menu.choice(:list) {
160
- options.action = :list
161
-
162
- # separate menus from each other
163
- say("\n")
164
-
165
- choose do |list_menu|
166
- list_menu.prompt = "Which one should I list? "
167
-
168
- menu_resources.each do |menu_resource|
169
- list_menu.choice(menu_resource) { options.resource = menu_resource.to_s }
170
- end
171
-
172
- list_menu.choice(:back) { options.action = :skip }
173
- end
174
- }
175
-
176
- # describe action requires a resource type or a resource location
177
- menu.choice(:describe) {
178
- options.action = :describe
179
-
180
- # separate menus from each other
181
- say("\n")
182
-
183
- # display the resource types first
184
- choose do |describe_menu|
185
- describe_menu.prompt = "Which one should I describe? "
186
-
187
- menu_resources.each do |menu_resource|
188
- describe_menu.choice(menu_resource) {
189
- options.resource = menu_resource.to_s
190
-
191
- # separate menus from each other
192
- say("\n")
193
-
194
- # display available resources for this resource type
195
- choose do |describe_menu_spec|
196
- describe_menu_spec.prompt = "Should I describe a specific resource? "
197
-
198
- describe_menu_spec.choice(:all) {
199
- # leave options.resource set to compute/network/storage
200
- }
201
-
202
- found = helper_list options
203
- found.each do |found_resource|
204
- describe_menu_spec.choice(found_resource.to_sym) { options.resource = found_resource }
205
- end
206
-
207
- describe_menu_spec.choice(:back) { options.action = :skip }
208
- end unless menu_resource.to_s.reverse.start_with? "lpt_"
209
- }
210
- end
211
-
212
- describe_menu.choice(:back) { options.action = :skip }
213
- end
214
- }
215
-
216
- # create action requires resource type, resource title
217
- # and optionally mixins (usually two, os_tpl and resource_tpl)
218
- menu.choice(:create) {
219
- options.action = :create
220
-
221
- # separate menus from each other
222
- say("\n")
223
-
224
- # display the resource types
225
- choose do |create_menu|
226
- create_menu.prompt = "Which one should I create? "
227
-
228
- menu_resources.each do |menu_resource|
229
- create_menu.choice(menu_resource) {
230
- options.resource = menu_resource.to_s
231
- } unless menu_resource.to_s.reverse.start_with? "lpt_"
232
- end
233
-
234
- create_menu.choice(:back) { options.action = :skip }
235
- end
236
-
237
- # if the user didn't choose "Back", ask for details
238
- # TODO: currently only COMPUTE is supported
239
- if options.action == :create
240
- options.attributes = {} if options.attributes.nil?
241
-
242
- options.attributes[:title] = ask("What name should I give to the new resource? ")
243
- number_of_mixins = ask("How many mixins do you wish me to mix into this resource? ",
244
- Integer) { |q| q.in = 0..2 }
245
-
246
- options.mixins = Occi::Core::Mixins.new
247
- (1..number_of_mixins).each do |mixin_number|
248
- mixin = ask("What mixin should I mix in? ") { |q| q.validate = Occi::Cli::OcciOpts::MIXIN_REGEXP }
249
- parts = mixin.split("#")
250
-
251
- options.mixins << Occi::Core::Mixin.new("#{parts[0]}#", parts[1])
252
- end
253
- end
254
- }
255
-
256
- # delete action requires a resource location
257
- menu.choice(:delete) {
258
- options.action = :delete
259
-
260
- # separate menus from each other
261
- say("\n")
262
-
263
- # display the resource types first
264
- choose do |delete_menu|
265
- delete_menu.prompt = "Please, choose a resource type: "
266
-
267
- menu_resources.each do |menu_resource|
268
- delete_menu.choice(menu_resource) {
269
-
270
- # separate menus from each other
271
- say("\n")
272
-
273
- # display available resources for this type
274
- choose do |delete_menu_spec|
275
- delete_menu_spec.prompt = "Which resource should I delete? "
276
-
277
- opts = OpenStruct.new
278
- opts.resource = menu_resource.to_s
279
-
280
- found = helper_list opts
281
- found.each do |found_resource|
282
- delete_menu_spec.choice(found_resource.to_sym) { options.resource = found_resource }
283
- end
284
-
285
- delete_menu_spec.choice(:back) { options.action = :skip }
286
- end unless menu_resource.to_s.reverse.start_with? "lpt_"
287
- } unless menu_resource.to_s.reverse.start_with? "lpt_"
288
- end
289
-
290
- delete_menu.choice(:back) { options.action = :skip }
291
- end
292
- }
293
-
294
- # TODO: trigger is not yet implemented
295
- menu.choice(:trigger) {
296
- options.action = :skip
297
- say("Not implemented yet!")
298
- }
299
-
300
- # refresh the OCCI model structures without exiting/re-launching
301
- # the client, useful when adding new os_tpls/resource_tpls on
302
- # the server
303
- menu.choice(:refresh) {
304
- options.action = :refresh
305
- }
306
-
307
- # enough is enough, bye!
308
- menu.choice(:quit) {
309
- say("Good bye!")
310
- exit!(true)
311
- }
312
- end
313
- end
314
-
315
132
  Occi::Log.info "Executing action #{options.action.to_s} on #{options.resource} ..."
316
133
 
317
134
  # call the appropriate helper and then format its output
@@ -337,15 +154,15 @@ begin
337
154
  rescue Errno::ECONNREFUSED
338
155
  # remote server refused our connection attempt(s)
339
156
  # even though initial connect was successful
340
- Occi::Log.error "Connection refused by #{options.endpoint}!"
157
+ Occi::Log.fatal "Connection refused by #{options.endpoint}!"
341
158
  exit!
342
159
  rescue Exception => ex
343
160
  # something went wrong during the execution
344
161
  # hide the stack trace in non-debug modes
345
- Occi::Log.error "An error occurred! Message: #{ex.message}"
162
+ Occi::Log.fatal "An error occurred! Message: #{ex.message}"
346
163
 
347
164
  raise ex if options.debug
348
165
  exit!
349
- end while options.interactive
166
+ end
350
167
 
351
168
  Occi::Log.info "OCCI client is shutting down ..."
@@ -0,0 +1,5 @@
1
+ module Occi::Cli::Errors
2
+
3
+ class MixinLookupError < ArgumentError; end
4
+
5
+ end
@@ -4,33 +4,50 @@ module Occi::Cli::Helpers::CreateHelper
4
4
  location = nil
5
5
 
6
6
  if resource_types.include?(options.resource) || resource_type_identifiers.include?(options.resource)
7
- Occi::Log.debug "#{options.resource.inspect} is a resource type."
8
- raise "Not yet implemented!" unless options.resource.include? "compute"
7
+ location = helper_create_resource(options)
8
+ else
9
+ Occi::Log.warn "I have no idea what #{options.resource.inspect} is ..."
10
+ raise "Unknown resource #{options.resource.inspect}, there is nothing to create here!"
11
+ end
12
+
13
+ return location if output.nil?
14
+
15
+ puts location
16
+ end
17
+
18
+ def helper_create_resource(options)
19
+ Occi::Log.debug "#{options.resource.inspect} is a resource type."
20
+
21
+ # TODO: implement the rest
22
+ raise "Not yet implemented!" unless options.resource.include? "compute"
23
+
24
+ res = resource(options.resource)
9
25
 
10
- res = resource options.resource
26
+ Occi::Log.debug "Creating #{options.resource.inspect}: #{res.inspect}"
11
27
 
12
- Occi::Log.debug "Creating #{options.resource.inspect}:\n#{res.inspect}"
28
+ helper_attach_mixins(options, res)
13
29
 
30
+ if res.kind_of? Occi::Infrastructure::Compute
14
31
  helper_attach_links(options, res)
15
- helper_attach_mixins(options, res)
32
+ # TODO: context vars are only attributes!
16
33
  helper_attach_context_vars(options, res)
34
+ end
17
35
 
18
- # TODO: set other attributes
19
- # TODO: OCCI-OS uses occi.compute.hostname instead of title
20
- res.title = options.attributes[:title]
21
- res.hostname = options.attributes[:title]
22
-
23
- Occi::Log.debug "Creating #{options.resource.inspect}:\n#{res.inspect}"
36
+ options.attributes.names.each_pair do |attribute, value|
37
+ res.attributes[attribute.to_s] = value
38
+ end
24
39
 
25
- location = create res
26
- else
27
- Occi::Log.warn "I have no idea what #{options.resource.inspect} is ..."
28
- raise "Unknown resource #{options.resource.inspect}, there is nothing to create here!"
40
+ # TODO: OCCI-OS uses occi.compute.hostname instead of title
41
+ if res.kind_of? Occi::Infrastructure::Compute
42
+ res.hostname = options.attributes["occi.core.title"] if res.hostname.blank?
29
43
  end
30
44
 
31
- return location if output.nil?
45
+ # TODO: enable check
46
+ #res.check
32
47
 
33
- puts location
48
+ Occi::Log.debug "Creating #{options.resource.inspect}: #{res.inspect}"
49
+
50
+ create res
34
51
  end
35
52
 
36
53
  def helper_attach_links(options, res)
@@ -56,10 +73,15 @@ module Occi::Cli::Helpers::CreateHelper
56
73
 
57
74
  def helper_attach_mixins(options, res)
58
75
  return unless options.mixins
59
- Occi::Log.debug "with mixins: #{options.mixins}"
76
+ Occi::Log.debug "with mixins: #{options.mixins.inspect}"
60
77
 
61
78
  options.mixins.to_a.each do |mxn|
62
79
  Occi::Log.debug "Adding mixin #{mxn.inspect} to #{options.resource.inspect}"
80
+
81
+ mxn = model.get_by_id(mxn.type_identifier)
82
+ raise Occi::Cli::Errors::MixinLookupError,
83
+ "The specified mixin is not declared in the model! #{mxn.type_identifier.inspect}" if mxn.blank?
84
+
63
85
  res.mixins << mxn
64
86
  end
65
87
  end
@@ -67,7 +89,7 @@ module Occi::Cli::Helpers::CreateHelper
67
89
  def helper_attach_context_vars(options, res)
68
90
  # TODO: find a better/universal way to do contextualization
69
91
  return unless options.context_vars
70
- Occi::Log.debug "with context variables: #{options.context_vars}"
92
+ Occi::Log.debug "with context variables: #{options.context_vars.inspect}"
71
93
 
72
94
  options.context_vars.each_pair do |var, val|
73
95
  schema = nil
@@ -82,6 +104,7 @@ module Occi::Cli::Helpers::CreateHelper
82
104
  schema = "http://schemas.openstack.org/compute/instance#"
83
105
  mxn_attrs['org.openstack.compute.user_data'] = {}
84
106
  else
107
+ Occi::Log.warn "Unknown context variable! #{var.to_s.inspect}"
85
108
  schema = "http://schemas.ogf.org/occi/core#"
86
109
  end
87
110
 
@@ -95,7 +118,7 @@ module Occi::Cli::Helpers::CreateHelper
95
118
  when :user_data
96
119
  res.attributes['org.openstack.compute.user_data'] = val
97
120
  else
98
- # do nothing
121
+ Occi::Log.warn "Not setting attributes for an unknown context variable! #{var.to_s.inspect}"
99
122
  end
100
123
  end
101
124
  end
@@ -3,8 +3,6 @@ require 'optparse'
3
3
  require 'uri'
4
4
  require 'base64'
5
5
 
6
- require 'occi/cli/resource_output_factory'
7
-
8
6
  module Occi::Cli
9
7
 
10
8
  class OcciOpts
@@ -14,6 +12,7 @@ module Occi::Cli
14
12
  ACTIONS = [:list, :describe, :create, :delete, :trigger].freeze
15
13
  LOG_OUTPUTS = [:stdout, :stderr].freeze
16
14
  ALLOWED_CONTEXT_VARS = [:public_key, :user_data].freeze
15
+ LOG_LEVELS = [:debug, :error, :fatal, :info, :unknown, :warn].freeze
17
16
 
18
17
  MIXIN_REGEXP = /^(https?:\/\/\S+?)#(\S+)$/
19
18
  CONTEXT_REGEXP = ATTR_REGEXP = /^(.+?)=(.+)$/
@@ -25,17 +24,14 @@ module Occi::Cli
25
24
  options = OpenStruct.new
26
25
 
27
26
  options.debug = false
28
- options.verbose = false
29
27
 
30
28
  options.log = {}
31
29
  options.log[:out] = STDERR
32
- options.log[:level] = Occi::Log::WARN
30
+ options.log[:level] = Occi::Log::ERROR
33
31
 
34
32
  options.filter = nil
35
33
  options.dump_model = false
36
34
 
37
- options.interactive = false
38
-
39
35
  options.endpoint = "https://localhost:3300/"
40
36
 
41
37
  options.auth = {}
@@ -50,7 +46,7 @@ module Occi::Cli
50
46
 
51
47
  options.mixins = Occi::Core::Mixins.new
52
48
  options.links = nil
53
- options.attributes = nil
49
+ options.attributes = Occi::Core::Attributes.new
54
50
  options.context_vars = nil
55
51
 
56
52
  # TODO: change media type back to occi+json after the rOCCI-server update
@@ -61,7 +57,6 @@ module Occi::Cli
61
57
  opts.banner = %{Usage: occi [OPTIONS]
62
58
 
63
59
  Examples:
64
- occi --interactive --endpoint https://localhost:3300/ --auth x509
65
60
 
66
61
  occi --endpoint https://localhost:3300/ --action list --resource os_tpl --auth x509
67
62
 
@@ -76,12 +71,6 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
76
71
  opts.separator ""
77
72
  opts.separator "Options:"
78
73
 
79
- opts.on("-i",
80
- "--interactive",
81
- "Run as an interactive client without additional arguments") do |interactive|
82
- options.interactive = interactive
83
- end
84
-
85
74
  opts.on("-e",
86
75
  "--endpoint URI",
87
76
  String,
@@ -172,14 +161,15 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
172
161
  opts.on("-t",
173
162
  "--attribute ATTRS",
174
163
  Array,
175
- "Comma separated attributes for new resources such as title=\"Name\", required") do |attributes|
176
- options.attributes ||= {}
164
+ "Comma separated attributes for new resources such as occi.core.title=\"Name\", required") do |attributes|
165
+ options.attributes ||= Occi::Core::Attributes.new
177
166
 
178
167
  attributes.each do |attribute|
179
168
  ary = ATTR_REGEXP.match(attribute).to_a.drop 1
180
169
  raise ArgumentError, "Attribute must always contain ATTR=VALUE pairs!" unless ary.length == 2
181
170
 
182
- options.attributes[ary[0].to_sym] = ary[1]
171
+ ary[0] = "occi.core.#{ary[0]}" unless ary[0].include?('.')
172
+ options.attributes[ary[0]] = ary[1]
183
173
  end
184
174
  end
185
175
 
@@ -267,9 +257,18 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
267
257
  options.output_format = output_format
268
258
  end
269
259
 
260
+ opts.on("-b",
261
+ "--log-level LEVEL",
262
+ 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)
266
+ end
267
+ end
268
+
270
269
  opts.on_tail("-m",
271
270
  "--dump-model",
272
- "Contact the endpoint and dump its model, cannot be used with the interactive mode") do |dump_model|
271
+ "Contact the endpoint and dump its model") do |dump_model|
273
272
  options.dump_model = dump_model
274
273
  end
275
274
 
@@ -280,13 +279,6 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
280
279
  options.log[:level] = Occi::Log::DEBUG
281
280
  end
282
281
 
283
- opts.on_tail("-b",
284
- "--verbose",
285
- "Be more verbose, less intrusive than debug mode") do |verbose|
286
- options.verbose = verbose
287
- options.log[:level] = Occi::Log::INFO unless options.log[:level] == Occi::Log::DEBUG
288
- end
289
-
290
282
  opts.on_tail("-h",
291
283
  "--help",
292
284
  "Show this message") do
@@ -336,16 +328,6 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
336
328
  private
337
329
 
338
330
  def self.check_restrictions(options, opts)
339
- if options.interactive && options.dump_model
340
- if @@quiet
341
- exit false
342
- else
343
- puts "You cannot use '--dump-model' and '--interactive' at the same time!"
344
- puts opts
345
- exit!
346
- end
347
- end
348
-
349
331
  if !options.dump_model && options.filter
350
332
  if @@quiet
351
333
  exit false
@@ -366,7 +348,7 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
366
348
  end
367
349
  end
368
350
 
369
- return if options.interactive || options.dump_model
351
+ return if options.dump_model
370
352
 
371
353
  mandatory = []
372
354
 
@@ -390,8 +372,8 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
390
372
  check_hash options, mandatory, opts
391
373
 
392
374
  if check_attrs
393
- mandatory = [:title]
394
- check_hash options.attributes, mandatory, opts
375
+ mandatory = ["occi.core.title"]
376
+ check_attributes options.attributes, mandatory, opts
395
377
  end
396
378
  end
397
379
 
@@ -400,7 +382,28 @@ occi --endpoint https://localhost:3300/ --action delete --resource /compute/65sd
400
382
  hash = hash.marshal_dump
401
383
  end
402
384
 
403
- missing = mandatory.select{ |param| hash[param].nil? }
385
+ missing = mandatory.select { |param| hash[param].blank? }
386
+ report_missing missing, opts
387
+ end
388
+
389
+ def self.check_attributes(attributes, mandatory, opts)
390
+ missing = []
391
+ attributes = Occi::Core::Attributes.new(attributes)
392
+
393
+ mandatory.each do |attribute|
394
+ begin
395
+ attributes[attribute]
396
+ raise Occi::Errors::AttributeMissingError,
397
+ "Attribute #{attribute.inspect} is empty!" unless attributes[attribute]
398
+ rescue Occi::Errors::AttributeMissingError
399
+ missing << attribute
400
+ end
401
+ end
402
+
403
+ report_missing missing, opts
404
+ end
405
+
406
+ def self.report_missing(missing, opts)
404
407
  unless missing.empty?
405
408
  if @@quiet
406
409
  exit false
@@ -39,11 +39,21 @@ module Occi::Cli
39
39
 
40
40
  def resources_to_json(occi_resources)
41
41
  # generate JSON document from Occi::Core::Resources
42
+ occi_resources = occi_resources.to_a
43
+
42
44
  if @output_format == :json_pretty
43
- JSON.pretty_generate occi_resources.as_json
45
+ output_first = "[\n"
46
+ output_ary = occi_resources.collect { |r| JSON.pretty_generate(r.as_json.to_hash) }
47
+ separator = ",\n"
48
+ output_last = "\n]"
44
49
  else
45
- JSON.generate occi_resources.as_json
50
+ output_first = "["
51
+ output_ary = occi_resources.collect { |r| JSON.generate(r.as_json.to_hash) }
52
+ separator = ","
53
+ output_last = "]"
46
54
  end
55
+
56
+ "#{output_first}#{output_ary.join(separator)}#{output_last}"
47
57
  end
48
58
  alias_method :resources_to_json_pretty, :resources_to_json
49
59
  alias_method :mixins_to_json, :resources_to_json
@@ -52,9 +62,9 @@ module Occi::Cli
52
62
  def locations_to_json(url_locations)
53
63
  # generate JSON document from an array of strings
54
64
  if @output_format == :json_pretty
55
- JSON.pretty_generate locations
65
+ JSON.pretty_generate url_locations
56
66
  else
57
- JSON.generate locations
67
+ JSON.generate url_locations
58
68
  end
59
69
  end
60
70
  alias_method :locations_to_json_pretty, :locations_to_json
@@ -1,5 +1,5 @@
1
1
  module Occi
2
2
  module Cli
3
- VERSION = "4.2.0.beta.2" unless defined?(::Occi::Cli::VERSION)
3
+ VERSION = "4.2.0.beta.3" unless defined?(::Occi::Cli::VERSION)
4
4
  end
5
5
  end
data/lib/occi-cli.rb CHANGED
@@ -5,8 +5,8 @@ module Occi::Cli; end
5
5
 
6
6
  require 'occi/cli/version'
7
7
  require 'occi/cli/errors'
8
- require 'occi/cli/occi_opts'
9
8
  require 'occi/cli/resource_output_factory'
9
+ require 'occi/cli/occi_opts'
10
10
 
11
11
  # get DSL definitions
12
12
  extend Occi::Api::Dsl
data/occi-cli.gemspec CHANGED
@@ -20,7 +20,6 @@ Gem::Specification.new do |gem|
20
20
  gem.require_paths = ["lib"]
21
21
 
22
22
  gem.add_dependency 'occi-api', '= 4.2.0.beta.2'
23
- gem.add_dependency 'highline'
24
23
  gem.add_dependency 'json'
25
24
 
26
25
  gem.required_ruby_version = ">= 1.9.3"
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.2
4
+ version: 4.2.0.beta.3
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-04 00:00:00.000000000 Z
14
+ date: 2013-12-06 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: occi-api
@@ -29,22 +29,6 @@ dependencies:
29
29
  - - '='
30
30
  - !ruby/object:Gem::Version
31
31
  version: 4.2.0.beta.2
32
- - !ruby/object:Gem::Dependency
33
- name: highline
34
- requirement: !ruby/object:Gem::Requirement
35
- none: false
36
- requirements:
37
- - - ! '>='
38
- - !ruby/object:Gem::Version
39
- version: '0'
40
- type: :runtime
41
- prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- none: false
44
- requirements:
45
- - - ! '>='
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
32
  - !ruby/object:Gem::Dependency
49
33
  name: json
50
34
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +72,7 @@ files:
88
72
  - lib/occi/cli/errors.rb
89
73
  - lib/occi/cli/errors/formatter_input_type_error.rb
90
74
  - lib/occi/cli/errors/formatter_output_type_error.rb
75
+ - lib/occi/cli/errors/mixin_lookup_error.rb
91
76
  - lib/occi/cli/helpers.rb
92
77
  - lib/occi/cli/helpers/common_helper.rb
93
78
  - lib/occi/cli/helpers/create_helper.rb