steamcannon-deltacloud-client 0.0.9.7.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/COPYING +176 -0
  2. data/Rakefile +61 -0
  3. data/bin/deltacloudc +158 -0
  4. data/init.rb +20 -0
  5. data/lib/deltacloud.rb +586 -0
  6. data/lib/documentation.rb +98 -0
  7. data/lib/plain_formatter.rb +86 -0
  8. data/specs/data/images/img1.yml +4 -0
  9. data/specs/data/images/img2.yml +4 -0
  10. data/specs/data/images/img3.yml +4 -0
  11. data/specs/data/instances/inst0.yml +16 -0
  12. data/specs/data/instances/inst1.yml +9 -0
  13. data/specs/data/instances/inst2.yml +9 -0
  14. data/specs/data/storage_snapshots/snap1.yml +4 -0
  15. data/specs/data/storage_snapshots/snap2.yml +4 -0
  16. data/specs/data/storage_snapshots/snap3.yml +4 -0
  17. data/specs/data/storage_volumes/vol1.yml +6 -0
  18. data/specs/data/storage_volumes/vol2.yml +6 -0
  19. data/specs/data/storage_volumes/vol3.yml +6 -0
  20. data/specs/fixtures/images/img1.yml +4 -0
  21. data/specs/fixtures/images/img2.yml +4 -0
  22. data/specs/fixtures/images/img3.yml +4 -0
  23. data/specs/fixtures/instances/inst0.yml +16 -0
  24. data/specs/fixtures/instances/inst1.yml +9 -0
  25. data/specs/fixtures/instances/inst2.yml +9 -0
  26. data/specs/fixtures/storage_snapshots/snap1.yml +4 -0
  27. data/specs/fixtures/storage_snapshots/snap2.yml +4 -0
  28. data/specs/fixtures/storage_snapshots/snap3.yml +4 -0
  29. data/specs/fixtures/storage_volumes/vol1.yml +6 -0
  30. data/specs/fixtures/storage_volumes/vol2.yml +6 -0
  31. data/specs/fixtures/storage_volumes/vol3.yml +6 -0
  32. data/specs/hardware_profiles_spec.rb +78 -0
  33. data/specs/images_spec.rb +105 -0
  34. data/specs/initialization_spec.rb +60 -0
  35. data/specs/instance_states_spec.rb +78 -0
  36. data/specs/instances_spec.rb +191 -0
  37. data/specs/realms_spec.rb +64 -0
  38. data/specs/shared/resources.rb +30 -0
  39. data/specs/spec_helper.rb +52 -0
  40. data/specs/storage_snapshot_spec.rb +77 -0
  41. data/specs/storage_volume_spec.rb +89 -0
  42. metadata +191 -0
data/lib/deltacloud.rb ADDED
@@ -0,0 +1,586 @@
1
+ #
2
+ # Copyright (C) 2009 Red Hat, Inc.
3
+ #
4
+ # Licensed to the Apache Software Foundation (ASF) under one or more
5
+ # contributor license agreements. See the NOTICE file distributed with
6
+ # this work for additional information regarding copyright ownership. The
7
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance with the
9
+ # License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
+ # License for the specific language governing permissions and limitations
17
+ # under the License.
18
+
19
+ require 'nokogiri'
20
+ require 'rest_client'
21
+ require 'base64'
22
+ require 'logger'
23
+
24
+ module DeltaCloud
25
+
26
+ # Get a new API client instance
27
+ #
28
+ # @param [String, user_name] API user name
29
+ # @param [String, password] API password
30
+ # @param [String, user_name] API URL (eg. http://localhost:3001/api)
31
+ # @return [DeltaCloud::API]
32
+ def self.new(user_name, password, api_url, &block)
33
+ API.new(user_name, password, api_url, &block)
34
+ end
35
+
36
+ # Check given credentials if their are valid against
37
+ # backend cloud provider
38
+ #
39
+ # @param [String, user_name] API user name
40
+ # @param [String, password] API password
41
+ # @param [String, user_name] API URL (eg. http://localhost:3001/api)
42
+ # @return [true|false]
43
+ def self.valid_credentials?(user_name, password, api_url)
44
+ api=API.new(user_name, password, api_url)
45
+ result = false
46
+ api.request(:get, '', :force_auth => '1') do |response|
47
+ result = true if response.code.eql?(200)
48
+ end
49
+ return result
50
+ end
51
+
52
+ # Return a API driver for specified URL
53
+ #
54
+ # @param [String, url] API URL (eg. http://localhost:3001/api)
55
+ def self.driver_name(url)
56
+ API.new(nil, nil, url).driver_name
57
+ end
58
+
59
+ def self.define_class(name)
60
+ @defined_classes ||= []
61
+ if @defined_classes.include?(name)
62
+ self.module_eval("API::#{name}")
63
+ else
64
+ @defined_classes << name unless @defined_classes.include?(name)
65
+ API.const_set(name, Class.new)
66
+ end
67
+ end
68
+
69
+ def self.classes
70
+ @defined_classes || []
71
+ end
72
+
73
+ class API
74
+ attr_accessor :logger
75
+ attr_reader :api_uri, :driver_name, :api_version, :features, :entry_points
76
+
77
+ def initialize(user_name, password, api_url, opts={}, &block)
78
+ opts[:version] = true
79
+ @logger = opts[:verbose] ? Logger.new(STDERR) : []
80
+ @username, @password = user_name, password
81
+ @api_uri = URI.parse(api_url)
82
+ @features, @entry_points = {}, {}
83
+ @verbose = opts[:verbose] || false
84
+ discover_entry_points
85
+ yield self if block_given?
86
+ end
87
+
88
+ def connect(&block)
89
+ yield self
90
+ end
91
+
92
+ # Return API hostname
93
+ def api_host; @api_uri.host ; end
94
+
95
+ # Return API port
96
+ def api_port; @api_uri.port ; end
97
+
98
+ # Return API path
99
+ def api_path; @api_uri.path ; end
100
+
101
+ # Define methods based on 'rel' attribute in entry point
102
+ # Two methods are declared: 'images' and 'image'
103
+ def declare_entry_points_methods(entry_points)
104
+ logger = @logger
105
+ API.instance_eval do
106
+ entry_points.keys.select {|k| [:instance_states].include?(k)==false }.each do |model|
107
+ define_method model do |*args|
108
+ request(:get, "/#{model}", args.first) do |response|
109
+ # Define a new class based on model name
110
+ c = DeltaCloud.define_class("#{model.to_s.classify}")
111
+ # Create collection from index operation
112
+ base_object_collection(c, model, response)
113
+ end
114
+ end
115
+ logger << "[API] Added method #{model}\n"
116
+ define_method :"#{model.to_s.singularize}" do |*args|
117
+ request(:get, "/#{model}/#{args[0]}") do |response|
118
+ # Define a new class based on model name
119
+ c = DeltaCloud.define_class("#{model.to_s.classify}")
120
+ # Build class for returned object
121
+ base_object(c, model, response)
122
+ end
123
+ end
124
+ logger << "[API] Added method #{model.to_s.singularize}\n"
125
+ define_method :"fetch_#{model.to_s.singularize}" do |url|
126
+ id = url.grep(/\/#{model}\/(.*)$/)
127
+ self.send(model.to_s.singularize.to_sym, $1)
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ def base_object_collection(c, model, response)
134
+ collection = []
135
+ Nokogiri::XML(response).xpath("#{model}/#{model.to_s.singularize}").each do |item|
136
+ c.instance_eval do
137
+ attr_accessor :id
138
+ attr_accessor :uri
139
+ end
140
+ collection << xml_to_class(c, item)
141
+ end
142
+ return collection
143
+ end
144
+
145
+ # Add default attributes [id and href] to class
146
+ def base_object(c, model, response)
147
+ obj = nil
148
+ Nokogiri::XML(response).xpath("#{model.to_s.singularize}").each do |item|
149
+ c.instance_eval do
150
+ attr_accessor :id
151
+ attr_accessor :uri
152
+ end
153
+ obj = xml_to_class(c, item)
154
+ end
155
+ return obj
156
+ end
157
+
158
+ # Convert XML response to defined Ruby Class
159
+ def xml_to_class(c, item)
160
+ obj = c.new
161
+ # Set default attributes
162
+ obj.id = item['id']
163
+ api = self
164
+ c.instance_eval do
165
+ define_method :client do
166
+ api
167
+ end
168
+ end
169
+ obj.uri = item['href']
170
+ logger = @logger
171
+ logger << "[DC] Creating class #{obj.class.name}\n"
172
+ obj.instance_eval do
173
+ # Declare methods for all attributes in object
174
+ item.xpath('./*').each do |attribute|
175
+ # If attribute is a link to another object then
176
+ # create a method which request this object from API
177
+ if api.entry_points.keys.include?(:"#{attribute.name}s")
178
+ c.instance_eval do
179
+ define_method :"#{attribute.name.sanitize}" do
180
+ client.send(:"#{attribute.name}", attribute['id'] )
181
+ end
182
+ logger << "[DC] Added #{attribute.name} to class #{obj.class.name}\n"
183
+ end
184
+ else
185
+ # Define methods for other attributes
186
+ c.instance_eval do
187
+ case attribute.name
188
+ # When response cointains 'link' block, declare
189
+ # methods to call links inside. This is used for instance
190
+ # to dynamicaly create .stop!, .start! methods
191
+ when "actions":
192
+ actions = []
193
+ attribute.xpath('link').each do |link|
194
+ actions << [link['rel'], link[:href]]
195
+ define_method :"#{link['rel'].sanitize}!" do |*params|
196
+ client.request(:"#{link['method']}", link['href'], {}, params.first || {})
197
+ @current_state = client.send(:"#{item.name}", item['id']).state
198
+ obj.instance_eval do |o|
199
+ def state
200
+ @current_state
201
+ end
202
+ end
203
+ end
204
+ end
205
+ define_method :actions do
206
+ actions.collect { |a| a.first }
207
+ end
208
+ define_method :actions_urls do
209
+ urls = {}
210
+ actions.each { |a| urls[a.first] = a.last }
211
+ urls
212
+ end
213
+ # Property attribute is handled differently
214
+ when "property":
215
+ attr_accessor :"#{attribute['name'].sanitize}"
216
+ if attribute['value'] =~ /^(\d+)$/
217
+ obj.send(:"#{attribute['name'].sanitize}=",
218
+ DeltaCloud::HWP::FloatProperty.new(attribute, attribute['name']))
219
+ else
220
+ obj.send(:"#{attribute['name'].sanitize}=",
221
+ DeltaCloud::HWP::Property.new(attribute, attribute['name']))
222
+ end
223
+ # Public and private addresses are returned as Array
224
+ when "public_addresses", "private_addresses":
225
+ attr_accessor :"#{attribute.name.sanitize}"
226
+ obj.send(:"#{attribute.name.sanitize}=",
227
+ attribute.xpath('address').collect { |address| address.text })
228
+ # Value for other attributes are just returned using
229
+ # method with same name as attribute (eg. .owner_id, .state)
230
+ else
231
+ attr_accessor :"#{attribute.name.sanitize}"
232
+ obj.send(:"#{attribute.name.sanitize}=", attribute.text.convert)
233
+ logger << "[DC] Added method #{attribute.name}[#{attribute.text}] to #{obj.class.name}\n"
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
239
+ return obj
240
+ end
241
+
242
+ # Get /api and parse entry points
243
+ def discover_entry_points
244
+ return if discovered?
245
+ request(:get, @api_uri.to_s) do |response|
246
+ api_xml = Nokogiri::XML(response)
247
+ @driver_name = api_xml.xpath('/api').first['driver']
248
+ @api_version = api_xml.xpath('/api').first['version']
249
+ logger << "[API] Version #{@api_version}\n"
250
+ logger << "[API] Driver #{@driver_name}\n"
251
+ api_xml.css("api > link").each do |entry_point|
252
+ rel, href = entry_point['rel'].to_sym, entry_point['href']
253
+ @entry_points.store(rel, href)
254
+ logger << "[API] Entry point '#{rel}' added\n"
255
+ entry_point.css("feature").each do |feature|
256
+ @features[rel] ||= []
257
+ @features[rel] << feature['name'].to_sym
258
+ logger << "[API] Feature #{feature['name']} added to #{rel}\n"
259
+ end
260
+ end
261
+ end
262
+ declare_entry_points_methods(@entry_points)
263
+ end
264
+
265
+ def create_key(opts={}, &block)
266
+ params = { :name => opts[:name] }
267
+ key = nil
268
+ request(:post, entry_points[:keys], {}, params) do |response|
269
+ c = DeltaCloud.define_class("Key")
270
+ key = base_object(c, :key, response)
271
+ yield key if block_given?
272
+ end
273
+ return key
274
+ end
275
+
276
+ # Create a new instance, using image +image_id+. Possible optiosn are
277
+ #
278
+ # name - a user-defined name for the instance
279
+ # realm - a specific realm for placement of the instance
280
+ # hardware_profile - either a string giving the name of the
281
+ # hardware profile or a hash. The hash must have an
282
+ # entry +id+, giving the id of the hardware profile,
283
+ # and may contain additional names of properties,
284
+ # e.g. 'storage', to override entries in the
285
+ # hardware profile
286
+ def create_instance(image_id, opts={}, &block)
287
+ name = opts[:name]
288
+ realm_id = opts[:realm]
289
+ user_data = opts[:user_data]
290
+ key_name = opts[:key_name]
291
+
292
+ params = opts.dup
293
+ ( params[:realm_id] = realm_id ) if realm_id
294
+ ( params[:name] = name ) if name
295
+ ( params[:user_data] = user_data ) if user_data
296
+ ( params[:keyname] = user_data ) if key_name
297
+
298
+ if opts[:hardware_profile].is_a?(String)
299
+ params[:hwp_id] = opts[:hardware_profile]
300
+ elsif opts[:hardware_profile].is_a?(Hash)
301
+ params.delete(:hardware_profile)
302
+ opts[:hardware_profile].each do |k,v|
303
+ params[:"hwp_#{k}"] = v
304
+ end
305
+ end
306
+
307
+ params[:image_id] = image_id
308
+ instance = nil
309
+
310
+ request(:post, entry_points[:instances], {}, params) do |response|
311
+ c = DeltaCloud.define_class("Instance")
312
+ instance = base_object(c, :instance, response)
313
+ yield instance if block_given?
314
+ end
315
+
316
+ return instance
317
+ end
318
+
319
+
320
+ def create_storage_volume(opts={}, &block)
321
+ params = opts.dup
322
+ params[:realm_id] ||= params.delete(:realm)
323
+ storage_volume = nil
324
+
325
+ request(:post, entry_points[:storage_volumes], {}, params) do |response|
326
+ c = DeltaCloud.define_class("StorageVolume")
327
+ storage_volume = base_object(c, :storage_volume, response)
328
+ yield storage_volume if block_given?
329
+ end
330
+
331
+ storage_volume
332
+ end
333
+
334
+ # Basic request method
335
+ #
336
+ def request(*args, &block)
337
+ conf = {
338
+ :method => (args[0] || 'get').to_sym,
339
+ :path => (args[1]=~/^http/) ? args[1] : "#{api_uri.to_s}#{args[1]}",
340
+ :query_args => args[2] || {},
341
+ :form_data => args[3] || {}
342
+ }
343
+ if conf[:query_args] != {}
344
+ conf[:path] += '?' + URI.escape(conf[:query_args].collect{ |key, value| "#{key}=#{value}" }.join('&')).to_s
345
+ end
346
+ logger << "[#{conf[:method].to_s.upcase}] #{conf[:path]}\n"
347
+ if conf[:method].eql?(:post)
348
+ RestClient.send(:post, conf[:path], conf[:form_data], default_headers) do |response, request, block|
349
+ if response.respond_to?('body')
350
+ yield response.body if block_given?
351
+ else
352
+ yield response.to_s if block_given?
353
+ end
354
+ end
355
+ else
356
+ RestClient.send(conf[:method], conf[:path], default_headers) do |response, request, block|
357
+ if response.respond_to?('body')
358
+ yield response.body if block_given?
359
+ else
360
+ yield response.to_s if block_given?
361
+ end
362
+ end
363
+ end
364
+ end
365
+
366
+ # Check if specified collection have wanted feature
367
+ def feature?(collection, name)
368
+ @features.has_key?(collection) && @features[collection].include?(name)
369
+ end
370
+
371
+ # List available instance states and transitions between them
372
+ def instance_states
373
+ states = []
374
+ request(:get, entry_points[:instance_states]) do |response|
375
+ Nokogiri::XML(response).xpath('states/state').each do |state_el|
376
+ state = DeltaCloud::InstanceState::State.new(state_el['name'])
377
+ state_el.xpath('transition').each do |transition_el|
378
+ state.transitions << DeltaCloud::InstanceState::Transition.new(
379
+ transition_el['to'],
380
+ transition_el['action']
381
+ )
382
+ end
383
+ states << state
384
+ end
385
+ end
386
+ states
387
+ end
388
+
389
+ # Select instance state specified by name
390
+ def instance_state(name)
391
+ instance_states.select { |s| s.name.to_s.eql?(name.to_s) }.first
392
+ end
393
+
394
+ # Skip parsing /api when we already got entry points
395
+ def discovered?
396
+ true if @entry_points!={}
397
+ end
398
+
399
+ def documentation(collection, operation=nil)
400
+ data = {}
401
+ request(:get, "/docs/#{collection}") do |body|
402
+ document = Nokogiri::XML(body)
403
+ if operation
404
+ data[:operation] = operation
405
+ data[:description] = document.xpath('/docs/collection/operations/operation[@name = "'+operation+'"]/description').first.text.strip
406
+ return false unless data[:description]
407
+ data[:params] = []
408
+ (document/"/docs/collection/operations/operation[@name='#{operation}']/parameter").each do |param|
409
+ data[:params] << {
410
+ :name => param['name'],
411
+ :required => param['type'] == 'optional',
412
+ :type => (param/'class').text
413
+ }
414
+ end
415
+ else
416
+ data[:description] = (document/'/docs/collection/description').text
417
+ data[:collection] = collection
418
+ data[:operations] = (document/"/docs/collection/operations/operation").collect{ |o| o['name'] }
419
+ end
420
+ end
421
+ return Documentation.new(self, data)
422
+ end
423
+
424
+ private
425
+
426
+ def default_headers
427
+ # The linebreaks inserted every 60 characters in the Base64
428
+ # encoded header cause problems under JRuby
429
+ auth_header = "Basic "+Base64.encode64("#{@username}:#{@password}")
430
+ auth_header.gsub!("\n", "")
431
+ {
432
+ :authorization => auth_header,
433
+ :accept => "application/xml"
434
+ }
435
+ end
436
+
437
+ end
438
+
439
+ class Documentation
440
+
441
+ attr_reader :api, :description, :params, :collection_operations
442
+ attr_reader :collection, :operation
443
+
444
+ def initialize(api, opts={})
445
+ @description, @api = opts[:description], api
446
+ @params = parse_parameters(opts[:params]) if opts[:params]
447
+ @collection_operations = opts[:operations] if opts[:operations]
448
+ @collection = opts[:collection]
449
+ @operation = opts[:operation]
450
+ self
451
+ end
452
+
453
+ def operations
454
+ @collection_operations.collect { |o| api.documentation(@collection, o) }
455
+ end
456
+
457
+ class OperationParameter
458
+ attr_reader :name
459
+ attr_reader :type
460
+ attr_reader :required
461
+ attr_reader :description
462
+
463
+ def initialize(data)
464
+ @name, @type, @required, @description = data[:name], data[:type], data[:required], data[:description]
465
+ end
466
+
467
+ def to_comment
468
+ " # @param [#{@type}, #{@name}] #{@description}"
469
+ end
470
+
471
+ end
472
+
473
+ private
474
+
475
+ def parse_parameters(params)
476
+ params.collect { |p| OperationParameter.new(p) }
477
+ end
478
+
479
+ end
480
+
481
+ module InstanceState
482
+
483
+ class State
484
+ attr_reader :name
485
+ attr_reader :transitions
486
+
487
+ def initialize(name)
488
+ @name, @transitions = name, []
489
+ end
490
+ end
491
+
492
+ class Transition
493
+ attr_reader :to
494
+ attr_reader :action
495
+
496
+ def initialize(to, action)
497
+ @to = to
498
+ @action = action
499
+ end
500
+
501
+ def auto?
502
+ @action.nil?
503
+ end
504
+ end
505
+ end
506
+
507
+ module HWP
508
+
509
+ class Property
510
+ attr_reader :name, :unit, :value, :kind
511
+
512
+ def initialize(xml, name)
513
+ @name, @kind, @value, @unit = xml['name'], xml['kind'].to_sym, xml['value'], xml['unit']
514
+ declare_ranges(xml)
515
+ self
516
+ end
517
+
518
+ def present?
519
+ ! @value.nil?
520
+ end
521
+
522
+ private
523
+
524
+ def declare_ranges(xml)
525
+ case xml['kind']
526
+ when 'range':
527
+ self.class.instance_eval do
528
+ attr_reader :range
529
+ end
530
+ @range = { :from => xml.xpath('range').first['first'], :to => xml.xpath('range').first['last'] }
531
+ when 'enum':
532
+ self.class.instance_eval do
533
+ attr_reader :options
534
+ end
535
+ @options = xml.xpath('enum/entry').collect { |e| e['value'] }
536
+ end
537
+ end
538
+
539
+ end
540
+
541
+ # FloatProperty is like Property but return value is Float instead of String.
542
+ class FloatProperty < Property
543
+ def initialize(xml, name)
544
+ super(xml, name)
545
+ @value = @value.to_f if @value
546
+ end
547
+ end
548
+ end
549
+
550
+ end
551
+
552
+ class String
553
+
554
+ unless method_defined?(:classify)
555
+ # Create a class name from string
556
+ def classify
557
+ self.singularize.camelize
558
+ end
559
+ end
560
+
561
+ unless method_defined?(:camelize)
562
+ # Camelize converts strings to UpperCamelCase
563
+ def camelize
564
+ self.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
565
+ end
566
+ end
567
+
568
+ unless method_defined?(:singularize)
569
+ # Strip 's' character from end of string
570
+ def singularize
571
+ self.gsub(/s$/, '')
572
+ end
573
+ end
574
+
575
+ # Convert string to float if string value seems like Float
576
+ def convert
577
+ return self.to_f if self.strip =~ /^([\d\.]+$)/
578
+ self
579
+ end
580
+
581
+ # Simply converts whitespaces and - symbols to '_' which is safe for Ruby
582
+ def sanitize
583
+ self.gsub(/(\W+)/, '_')
584
+ end
585
+
586
+ end
@@ -0,0 +1,98 @@
1
+ require 'lib/deltacloud'
2
+
3
+ skip_methods = [ "id=", "uri=" ]
4
+
5
+ begin
6
+ @dc=DeltaCloud.new('mockuser', 'mockpassword', 'http://localhost:3001/api')
7
+ rescue
8
+ puts "Please make sure that Deltacloud API is running with Mock driver"
9
+ exit(1)
10
+ end
11
+
12
+ @dc.entry_points.keys.each do |ep|
13
+ @dc.send(ep)
14
+ end
15
+
16
+ class_list = DeltaCloud::classes.collect { |c| DeltaCloud::module_eval("::DeltaCloud::API::#{c}")}
17
+
18
+ def read_method_description(c, method)
19
+ if method =~ /es$/
20
+ " # Read #{c.downcase} collection from Deltacloud API"
21
+ else
22
+ case method
23
+ when "uri"
24
+ " # Return URI to API for this object"
25
+ when "action_urls"
26
+ " # Return available actions API URL"
27
+ when "client"
28
+ " # Return instance of API client"
29
+ else
30
+ " # Get #{method} attribute value from #{c.downcase}"
31
+ end
32
+ end
33
+ end
34
+
35
+ def read_parameters(c, method)
36
+ out = []
37
+ if method =~ /es$/
38
+ out << " # @param [String, #id] Filter by ID"
39
+ end
40
+ out.join("\n")
41
+ end
42
+
43
+ def read_return_value(c, method)
44
+ if method =~ /es$/
45
+ rt = "Array"
46
+ else
47
+ rt = "String"
48
+ end
49
+ " # @return [String] Value of #{method}"
50
+ end
51
+
52
+ out = []
53
+
54
+ class_list.each do |c|
55
+ class_name = "#{c}".gsub(/^DeltaCloud::/, '')
56
+ out << "module DeltaCloud"
57
+ out << " class API"
58
+ @dc.entry_points.keys.each do |ep|
59
+ out << "# Return #{ep.to_s.classify} object with given id\n"
60
+ out << "# "
61
+ out << "# #{@dc.documentation(ep.to_s).description.split("\n").join("\n# ")}"
62
+ out << "# @return [#{ep.to_s.classify}]"
63
+ out << "def #{ep.to_s.gsub(/s$/, '')}"
64
+ out << "end"
65
+ out << "# Return collection of #{ep.to_s.classify} objects"
66
+ out << "# "
67
+ out << "# #{@dc.documentation(ep.to_s).description.split("\n").join("\n# ")}"
68
+ @dc.documentation(ep.to_s, 'index').params.each do |p|
69
+ out << p.to_comment
70
+ end
71
+ out << "# @return [Array] [#{ep.to_s.classify}]"
72
+ out << "def #{ep}(opts={})"
73
+ out << "end"
74
+ end
75
+ out << " end"
76
+ out << " class #{class_name}"
77
+ c.instance_methods(false).each do |method|
78
+ next if skip_methods.include?(method)
79
+ params = read_parameters(class_name, method)
80
+ retval = read_return_value(class_name, method)
81
+ out << read_method_description(class_name, method)
82
+ out << params if params
83
+ out << retval if retval
84
+ out << " def #{method}"
85
+ out << " # This method was generated dynamically from API"
86
+ out << " end\n"
87
+ end
88
+ out << " end"
89
+ out << "end"
90
+ end
91
+
92
+ FileUtils.rm_r('doc') rescue nil
93
+ FileUtils.mkdir_p('doc')
94
+ File.open('doc/deltacloud.rb', 'w') do |f|
95
+ f.puts(out.join("\n"))
96
+ end
97
+ system("yardoc -m markdown --readme README --title 'Deltacloud Client Library' 'lib/*.rb' 'doc/deltacloud.rb' --verbose")
98
+ FileUtils.rm('doc/deltacloud.rb')