Class: DeltaCloud::API

Inherits:
Object
  • Object
show all
Defined in:
lib/deltacloud.rb,
doc/deltacloud.rb,
doc/deltacloud.rb,
doc/deltacloud.rb,
doc/deltacloud.rb,
doc/deltacloud.rb,
doc/deltacloud.rb

Defined Under Namespace

Classes: HardwareProfile, Image, Instance, Realm, StorageSnapshot, StorageVolume

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (API) initialize(user_name, password, api_url, opts = {}) {|_self| ... }

A new instance of API

Yields:

  • (_self)

Yield Parameters:



62
63
64
65
66
67
68
69
70
71
# File 'lib/deltacloud.rb', line 62

def initialize(user_name, password, api_url, opts={}, &block)
  opts[:version] = true
  @logger = opts[:verbose] ? Logger.new(STDERR) : []
  @username, @password = user_name, password
  @api_uri = URI.parse(api_url)
  @features, @entry_points = {}, {}
  @verbose = opts[:verbose] || false
  discover_entry_points
  yield self if block_given?
end

Instance Attribute Details

- (Object) api_uri (readonly)

Returns the value of attribute api_uri



60
61
62
# File 'lib/deltacloud.rb', line 60

def api_uri
  @api_uri
end

- (Object) api_version (readonly)

Returns the value of attribute api_version



60
61
62
# File 'lib/deltacloud.rb', line 60

def api_version
  @api_version
end

- (Object) driver_name (readonly)

Returns the value of attribute driver_name



60
61
62
# File 'lib/deltacloud.rb', line 60

def driver_name
  @driver_name
end

- (Object) entry_points (readonly)

Returns the value of attribute entry_points



60
61
62
# File 'lib/deltacloud.rb', line 60

def entry_points
  @entry_points
end

- (Object) features (readonly)

Returns the value of attribute features



60
61
62
# File 'lib/deltacloud.rb', line 60

def features
  @features
end

- (Object) logger

Returns the value of attribute logger



59
60
61
# File 'lib/deltacloud.rb', line 59

def logger
  @logger
end

Instance Method Details

- (Object) api_host

Return API hostname



78
# File 'lib/deltacloud.rb', line 78

def api_host; @api_uri.host  end

- (Object) api_path

Return API path



84
# File 'lib/deltacloud.rb', line 84

def api_path; @api_uri.path  end

- (Object) api_port

Return API port



81
# File 'lib/deltacloud.rb', line 81

def api_port; @api_uri.port  end

- (Object) base_object(c, model, response)

Add default attributes id and href to class



131
132
133
134
135
136
137
138
139
140
141
# File 'lib/deltacloud.rb', line 131

def base_object(c, model, response)
  obj = nil
  Nokogiri::XML(response).xpath("#{model.to_s.singularize}").each do |item|
    c.instance_eval do
      attr_accessor :id
      attr_accessor :uri
    end
    obj = xml_to_class(c, item)
  end
  return obj
end

- (Object) base_object_collection(c, model, response)



118
119
120
121
122
123
124
125
126
127
128
# File 'lib/deltacloud.rb', line 118

def base_object_collection(c, model, response)
  collection = []
  Nokogiri::XML(response).xpath("#{model}/#{model.to_s.singularize}").each do |item|
    c.instance_eval do
      attr_accessor :id
      attr_accessor :uri
    end
    collection << xml_to_class(c, item)
  end
  return collection
end

- (Object) connect {|_self| ... }

Yields:

  • (_self)

Yield Parameters:



73
74
75
# File 'lib/deltacloud.rb', line 73

def connect(&block)
  yield self
end

- (Object) create_instance(image_id, opts = {}, &block)

Create a new instance, using image +image_id+. Possible optiosn are

name - a user-defined name for the instance realm - a specific realm for placement of the instance hardware_profile - either a string giving the name of the hardware profile or a hash. The hash must have an entry +id+, giving the id of the hardware profile, and may contain additional names of properties, e.g. ‘storage’, to override entries in the hardware profile



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/deltacloud.rb', line 255

def create_instance(image_id, opts={}, &block)
  name = opts[:name]
  realm_id = opts[:realm]
  user_data = opts[:user_data]

  params = {}
  ( params[:realm_id] = realm_id ) if realm_id
  ( params[:name] = name ) if name
  ( params[:user_data] = user_data ) if user_data

  if opts[:hardware_profile].is_a?(String)
    params[:hwp_id] = opts[:hardware_profile]
  elsif opts[:hardware_profile].is_a?(Hash)
    opts[:hardware_profile].each do |k,v|
      params[:"hwp_#{k}"] = v
    end
  end

  params[:image_id] = image_id
  instance = nil

  request(:post, entry_points[:instances], {}, params) do |response|
    c = DeltaCloud.define_class("Instance")
    instance = base_object(c, :instance, response)
    yield instance if block_given?
  end

  return instance
end

- (Object) declare_entry_points_methods(entry_points)

Define methods based on ‘rel’ attribute in entry point Two methods are declared: ‘images’ and ‘image’



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/deltacloud.rb', line 88

def declare_entry_points_methods(entry_points)
  logger = @logger
  API.instance_eval do
    entry_points.keys.select {|k| [:instance_states].include?(k)==false }.each do |model|
      define_method model do |*args|
        request(:get, "/#{model}", args.first) do |response|
          # Define a new class based on model name
          c = DeltaCloud.define_class("#{model.to_s.classify}")
          # Create collection from index operation
          base_object_collection(c, model, response)
        end
      end
      logger << "[API] Added method #{model}\n"
      define_method :"#{model.to_s.singularize}" do |*args|
        request(:get, "/#{model}/#{args[0]}") do |response|
          # Define a new class based on model name
          c = DeltaCloud.define_class("#{model.to_s.classify}")
          # Build class for returned object
          base_object(c, model, response)
        end
      end
      logger << "[API] Added method #{model.to_s.singularize}\n"
      define_method :"fetch_#{model.to_s.singularize}" do |url|
        id = url.grep(/\/#{model}\/(.*)$/)
        self.send(model.to_s.singularize.to_sym, $1)
      end
    end
  end
end

- (Object) discover_entry_points

Get /api and parse entry points



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/deltacloud.rb', line 223

def discover_entry_points
  return if discovered?
  request(:get, @api_uri.to_s) do |response|
    api_xml = Nokogiri::XML(response)
    @driver_name = api_xml.xpath('/api').first['driver']
    @api_version = api_xml.xpath('/api').first['version']
    logger << "[API] Version #{@api_version}\n"
    logger << "[API] Driver #{@driver_name}\n"
    api_xml.css("api > link").each do |entry_point|
      rel, href = entry_point['rel'].to_sym, entry_point['href']
      @entry_points.store(rel, href)
      logger << "[API] Entry point '#{rel}' added\n"
      entry_point.css("feature").each do |feature|
        @features[rel] ||= []
        @features[rel] << feature['name'].to_sym
        logger << "[API] Feature #{feature['name']} added to #{rel}\n"
      end
    end
  end
  declare_entry_points_methods(@entry_points)
end

- (Boolean) discovered?

Skip parsing /api when we already got entry points

Returns:

  • (Boolean)


346
347
348
# File 'lib/deltacloud.rb', line 346

def discovered?
  true if @entry_points!={}
end

- (Object) documentation(collection, operation = nil)



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/deltacloud.rb', line 350

def documentation(collection, operation=nil)
  data = {}
  request(:get, "/docs/#{collection}") do |body|
    document = Nokogiri::XML(body)
    if operation
      data[:description] = document.xpath('/docs/collection/operations/operation[@name = "'+operation+'"]/description').first
      return false unless data[:description]
      data[:params] = []
      (document/"/docs/collection/operations/operation[@name='#{operation}']/parameter").each do |param|
        data[:params] << {
          :name => param['name'],
          :required => param['type'] == 'optional',
          :type => (param/'class').text
        }
      end
    else
      data[:description] = (document/'/docs/collection/description').text
    end
  end
  return Documentation.new(data)
end

- (Boolean) feature?(collection, name)

Check if specified collection have wanted feature

Returns:

  • (Boolean)


318
319
320
# File 'lib/deltacloud.rb', line 318

def feature?(collection, name)
  @feature.has_key?(collection) && @feature[collection].include?(name)
end

- (HardwareProfile) hardware_profile

A hardware profile represents a configuration of resources upon which a machine may be deployed. It defines aspects such as local disk storage, available RAM, and architecture. Each provider is free to define as many (or as few) hardware profiles as desired.

Returns:



61
62
# File 'doc/deltacloud.rb', line 61

def hardware_profile
end

- (Array) hardware_profiles(opts = {})

Return collection of HardwareProfile objects

   A hardware profile represents a configuration of resources upon which a
   machine may be deployed. It defines aspects such as local disk storage,
   available RAM, and architecture. Each provider is free to define as many
   (or as few) hardware profiles as desired.

Parameters:

  • (string, architecture)
  • (string, id)

Returns:

  • (Array)

    HardwareProfile



74
75
# File 'doc/deltacloud.rb', line 74

def hardware_profiles(opts={})
end

- (Image) image

An image is a platonic form of a machine. Images are not directly executable, but are a template for creating actual instances of machines.”

Returns:



98
99
# File 'doc/deltacloud.rb', line 98

def image
end

- (Array) images(opts = {})

Return collection of Image objects

    An image is a platonic form of a machine. Images are not directly executable,
    but are a template for creating actual instances of machines."

Parameters:

  • (string, architecture)
  • (string, owner_id)
  • (string, id)

Returns:

  • (Array)

    Image



110
111
# File 'doc/deltacloud.rb', line 110

def images(opts={})
end

- (Instance) instance

An instance is a concrete machine realized from an image. The images collection may be obtained by following the link from the primary entry-point.”

Returns:



38
39
# File 'doc/deltacloud.rb', line 38

def instance
end

- (InstanceState) instance_state

The possible states of an instance, and how to traverse between them

Returns:



341
342
# File 'lib/deltacloud.rb', line 341

def instance_state
end

- (Array) instance_states(opts = {})

Return collection of InstanceState objects

The possible states of an instance, and how to traverse between them

Returns:

  • (Array)

    InstanceState



323
324
# File 'lib/deltacloud.rb', line 323

def instance_states(opts={})
end

- (Array) instances(opts = {})

Return collection of Instance objects

    An instance is a concrete machine realized from an image.
    The images collection may be obtained by following the link from the primary entry-point."

Parameters:

  • (string, state)
  • (string, id)

Returns:

  • (Array)

    Instance



49
50
# File 'doc/deltacloud.rb', line 49

def instances(opts={})
end

- (Realm) realm

Within a cloud provider a realm represents a boundary containing resources. The exact definition of a realm is left to the cloud provider. In some cases, a realm may represent different datacenters, different continents, or different pools of resources within a single datacenter. A cloud provider may insist that resources must all exist within a single realm in order to cooperate. For instance, storage volumes may only be allowed to be mounted to instances within the same realm.

Returns:



125
126
# File 'doc/deltacloud.rb', line 125

def realm
end

- (Array) realms(opts = {})

Return collection of Realm objects

    Within a cloud provider a realm represents a boundary containing resources.
    The exact definition of a realm is left to the cloud provider.
    In some cases, a realm may represent different datacenters, different continents,
    or different pools of resources within a single datacenter.
    A cloud provider may insist that resources must all exist within a single realm in
    order to cooperate. For instance, storage volumes may only be allowed to be mounted to
    instances within the same realm.

Parameters:

  • (string, architecture)
  • (string, id)

Returns:

  • (Array)

    Realm



141
142
# File 'doc/deltacloud.rb', line 141

def realms(opts={})
end

- (Object) request(*args, &block)

Basic request method



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/deltacloud.rb', line 287

def request(*args, &block)
  conf = {
    :method => (args[0] || 'get').to_sym,
    :path => (args[1]=~/^http/) ? args[1] : "#{api_uri.to_s}#{args[1]}",
    :query_args => args[2] || {},
    :form_data => args[3] || {}
  }
  if conf[:query_args] != {}
    conf[:path] += '?' + URI.escape(conf[:query_args].collect{ |key, value| "#{key}=#{value}" }.join('&')).to_s
  end
  logger << "[#{conf[:method].to_s.upcase}] #{conf[:path]}\n"
  if conf[:method].eql?(:post)
    RestClient.send(:post, conf[:path], conf[:form_data], default_headers) do |response, request, block|
      if response.respond_to?('body')
        yield response.body if block_given?
      else
        yield response.to_s if block_given?
      end
    end
  else
    RestClient.send(conf[:method], conf[:path], default_headers) do |response, request, block|
      if response.respond_to?('body')
        yield response.body if block_given?
      else
        yield response.to_s if block_given?
      end
    end
  end
end

- (StorageSnapshot) storage_snapshot

Storage snapshots description here

Returns:



81
82
# File 'doc/deltacloud.rb', line 81

def storage_snapshot
end

- (Array) storage_snapshots(opts = {})

Return collection of StorageSnapshot objects

Storage snapshots description here

Parameters:

  • (string, id)

Returns:

  • (Array)

    StorageSnapshot



88
89
# File 'doc/deltacloud.rb', line 88

def storage_snapshots(opts={})
end

- (StorageVolume) storage_volume

Storage volumes description here

Returns:



21
22
# File 'doc/deltacloud.rb', line 21

def storage_volume
end

- (Array) storage_volumes(opts = {})

Return collection of StorageVolume objects

Storage volumes description here

Parameters:

  • (string, id)

Returns:

  • (Array)

    StorageVolume



28
29
# File 'doc/deltacloud.rb', line 28

def storage_volumes(opts={})
end

- (Object) xml_to_class(c, item)

Convert XML response to defined Ruby Class



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/deltacloud.rb', line 144

def xml_to_class(c, item)
  obj = c.new
  # Set default attributes
  obj.id = item['id']
  api = self
  c.instance_eval do
    define_method :client do
      api
    end
  end
  obj.uri = item['href']
  logger = @logger
  logger << "[DC] Creating class #{obj.class.name}\n"
  obj.instance_eval do
    # Declare methods for all attributes in object
    item.xpath('./*').each do |attribute|
      # If attribute is a link to another object then
      # create a method which request this object from API
      if api.entry_points.keys.include?(:"#{attribute.name}s")
        c.instance_eval do
          define_method :"#{attribute.name.sanitize}" do
            client.send(:"#{attribute.name}", attribute['id'] )
          end
          logger << "[DC] Added #{attribute.name} to class #{obj.class.name}\n"
        end
      else
        # Define methods for other attributes
        c.instance_eval do
          case attribute.name
            # When response cointains 'link' block, declare
            # methods to call links inside. This is used for instance
            # to dynamicaly create .stop!, .start! methods
            when "actions":
              actions = []
              attribute.xpath('link').each do |link|
                actions << [link['rel'], link[:href]]
                define_method :"#{link['rel'].sanitize}!" do
                  client.request(:"#{link['method']}", link['href'], {}, {})
                  client.send(:"#{item.name}", item['id'])
                end
              end
              define_method :actions do
                actions.collect { |a| a.first }
              end
              define_method :actions_urls do
                urls = {}
                actions.each { |a| urls[a.first] = a.last }
                urls
              end
            # Property attribute is handled differently
            when "property":
              attr_accessor :"#{attribute['name'].sanitize}"
              if attribute['value'] =~ /^(\d+)$/
                obj.send(:"#{attribute['name'].sanitize}=",
                  DeltaCloud::HWP::FloatProperty.new(attribute, attribute['name']))
              else
                obj.send(:"#{attribute['name'].sanitize}=",
                  DeltaCloud::HWP::Property.new(attribute, attribute['name']))
              end
            # Public and private addresses are returned as Array
            when "public_addresses", "private_addresses":
              attr_accessor :"#{attribute.name.sanitize}"
              obj.send(:"#{attribute.name.sanitize}=",
                attribute.xpath('address').collect { |address| address.text })
            # Value for other attributes are just returned using
            # method with same name as attribute (eg. .owner_id, .state)
            else
              attr_accessor :"#{attribute.name.sanitize}"
              obj.send(:"#{attribute.name.sanitize}=", attribute.text.convert)
              logger << "[DC] Added method #{attribute.name}[#{attribute.text}] to #{obj.class.name}\n"
          end
        end
      end
    end
  end
  return obj
end