Class: DeltaCloud::API
- Inherits:
-
Object
- Object
- DeltaCloud::API
- Defined in:
- lib/deltacloud.rb,
lib/base_object.rb
Defined Under Namespace
Classes: Action, BackendError, Base, Stateful
Instance Attribute Summary collapse
-
#api_driver ⇒ Object
readonly
Returns the value of attribute api_driver.
-
#api_provider ⇒ Object
readonly
Returns the value of attribute api_provider.
-
#api_uri ⇒ Object
readonly
Returns the value of attribute api_uri.
-
#api_version ⇒ Object
readonly
Returns the value of attribute api_version.
-
#driver_name ⇒ Object
readonly
Returns the value of attribute driver_name.
-
#entry_points ⇒ Object
readonly
Returns the value of attribute entry_points.
-
#features ⇒ Object
readonly
Returns the value of attribute features.
Instance Method Summary collapse
-
#api_host ⇒ Object
Return API hostname.
-
#api_path ⇒ Object
Return API path.
-
#api_port ⇒ Object
Return API port.
-
#base_object(model, response) ⇒ Object
Add default attributes [id and href] to class.
- #base_object_collection(model, response) ⇒ Object
- #connect {|_self| ... } ⇒ Object
-
#declare_entry_points_methods(entry_points) ⇒ Object
Define methods based on ‘rel’ attribute in entry point Two methods are declared: ‘images’ and ‘image’.
-
#discover_entry_points ⇒ Object
Get /api and parse entry points.
-
#discovered? ⇒ Boolean
Skip parsing /api when we already got entry points.
-
#documentation(collection, operation = nil) ⇒ Object
This method will retrieve API documentation for given collection.
- #extended_headers ⇒ Object
-
#feature?(collection, name) ⇒ Boolean
Check if specified collection have wanted feature.
- #handle_backend_error(response) ⇒ Object
-
#initialize(user_name, password, api_url, opts = {}) {|_self| ... } ⇒ API
constructor
A new instance of API.
-
#instance_state(name) ⇒ Object
Select instance state specified by name.
-
#instance_states ⇒ Object
List available instance states and transitions between them.
-
#method_missing(name, *args) ⇒ Object
Generate create_* methods dynamically.
-
#request(*args, &block) ⇒ Object
Basic request method.
- #use_driver(driver, opts = {}) ⇒ Object
-
#xml_to_class(base_object, item) ⇒ Object
Convert XML response to defined Ruby Class.
Constructor Details
#initialize(user_name, password, api_url, opts = {}) {|_self| ... } ⇒ API
Returns a new instance of API.
69 70 71 72 73 74 75 76 77 78 |
# File 'lib/deltacloud.rb', line 69 def initialize(user_name, password, api_url, opts={}, &block) opts[:version] = true @api_driver, @api_provider = opts[:driver], opts[:provider] @username, @password = opts[:username] || user_name, opts[:password] || password @api_uri = URI.parse(api_url) @features, @entry_points = {}, {} @verbose = opts[:verbose] || false discover_entry_points yield self if block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
Generate create_* methods dynamically
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/deltacloud.rb', line 214 def method_missing(name, *args) if name.to_s =~ /create_(\w+)/ params = args[0] if args[0] and args[0].class.eql?(Hash) params ||= args[1] if args[1] and args[1].class.eql?(Hash) params ||= {} # FIXME: This fixes are related to Instance model and should be # replaced by 'native' parameter names params[:realm_id] ||= params[:realm] if params[:realm] params[:keyname] ||= params[:key_name] if params[:key_name] if params[:hardware_profile] and params[:hardware_profile].class.eql?(Hash) params[:hardware_profile].each do |k,v| params[:"hwp_#{k}"] ||= v end else params[:hwp_id] ||= params[:hardware_profile] end params[:image_id] ||= params[:image_id] || args[0] if args[0].class!=Hash obj = nil request(:post, entry_points[:"#{$1}s"], {}, params) do |response| obj = base_object(:"#{$1}", response) yield obj if block_given? end return obj end raise NoMethodError end |
Instance Attribute Details
#api_driver ⇒ Object (readonly)
Returns the value of attribute api_driver.
67 68 69 |
# File 'lib/deltacloud.rb', line 67 def api_driver @api_driver end |
#api_provider ⇒ Object (readonly)
Returns the value of attribute api_provider.
67 68 69 |
# File 'lib/deltacloud.rb', line 67 def api_provider @api_provider end |
#api_uri ⇒ Object (readonly)
Returns the value of attribute api_uri.
66 67 68 |
# File 'lib/deltacloud.rb', line 66 def api_uri @api_uri end |
#api_version ⇒ Object (readonly)
Returns the value of attribute api_version.
66 67 68 |
# File 'lib/deltacloud.rb', line 66 def api_version @api_version end |
#driver_name ⇒ Object (readonly)
Returns the value of attribute driver_name.
66 67 68 |
# File 'lib/deltacloud.rb', line 66 def driver_name @driver_name end |
#entry_points ⇒ Object (readonly)
Returns the value of attribute entry_points.
66 67 68 |
# File 'lib/deltacloud.rb', line 66 def entry_points @entry_points end |
#features ⇒ Object (readonly)
Returns the value of attribute features.
66 67 68 |
# File 'lib/deltacloud.rb', line 66 def features @features end |
Instance Method Details
#api_host ⇒ Object
Return API hostname
85 |
# File 'lib/deltacloud.rb', line 85 def api_host; @api_uri.host ; end |
#api_path ⇒ Object
Return API path
91 |
# File 'lib/deltacloud.rb', line 91 def api_path; @api_uri.path ; end |
#api_port ⇒ Object
Return API port
88 |
# File 'lib/deltacloud.rb', line 88 def api_port; @api_uri.port ; end |
#base_object(model, response) ⇒ Object
Add default attributes [id and href] to class
128 129 130 131 |
# File 'lib/deltacloud.rb', line 128 def base_object(model, response) c = DeltaCloud.add_class("#{model}", DeltaCloud::guess_model_type(response)) xml_to_class(c, Nokogiri::XML(response).xpath("#{model.to_s.singularize}").first) end |
#base_object_collection(model, response) ⇒ Object
121 122 123 124 125 |
# File 'lib/deltacloud.rb', line 121 def base_object_collection(model, response) Nokogiri::XML(response).xpath("#{model}/#{model.to_s.singularize}").collect do |item| base_object(model, item.to_s) end end |
#connect {|_self| ... } ⇒ Object
80 81 82 |
# File 'lib/deltacloud.rb', line 80 def connect(&block) yield self end |
#declare_entry_points_methods(entry_points) ⇒ Object
Define methods based on ‘rel’ attribute in entry point Two methods are declared: ‘images’ and ‘image’
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/deltacloud.rb', line 95 def declare_entry_points_methods(entry_points) API.instance_eval do entry_points.keys.select {|k| [:instance_states].include?(k)==false }.each do |model| define_method model do |*args| request(:get, entry_points[model], args.first) do |response| base_object_collection(model, response) end end define_method :"#{model.to_s.singularize}" do |*args| request(:get, "#{entry_points[model]}/#{args[0]}") do |response| base_object(model, response) end end 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 |
#discover_entry_points ⇒ Object
Get /api and parse entry points
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/deltacloud.rb', line 191 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'] api_xml.css("api > link").each do |entry_point| rel, href = entry_point['rel'].to_sym, entry_point['href'] @entry_points.store(rel, href) entry_point.css("feature").each do |feature| @features[rel] ||= [] @features[rel] << feature['name'].to_sym end end end declare_entry_points_methods(@entry_points) end |
#discovered? ⇒ Boolean
Skip parsing /api when we already got entry points
354 355 356 |
# File 'lib/deltacloud.rb', line 354 def discovered? true if @entry_points!={} end |
#documentation(collection, operation = nil) ⇒ Object
This method will retrieve API documentation for given collection
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/deltacloud.rb', line 359 def documentation(collection, operation=nil) data = {} request(:get, "/docs/#{collection}") do |body| document = Nokogiri::XML(body) if operation data[:operation] = operation data[:description] = document.xpath('/docs/collection/operations/operation[@name = "'+operation+'"]/description').first.text.strip 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 data[:collection] = collection data[:operations] = (document/"/docs/collection/operations/operation").collect{ |o| o['name'] } end end return Documentation.new(self, data) end |
#extended_headers ⇒ Object
259 260 261 262 263 264 |
# File 'lib/deltacloud.rb', line 259 def extended_headers headers = {} headers["X-Deltacloud-Driver"] = @api_driver.to_s if @api_driver headers["X-Deltacloud-Provider"] = @api_provider.to_s if @api_provider headers end |
#feature?(collection, name) ⇒ Boolean
Check if specified collection have wanted feature
326 327 328 |
# File 'lib/deltacloud.rb', line 326 def feature?(collection, name) @features.has_key?(collection) && @features[collection].include?(name) end |
#handle_backend_error(response) ⇒ Object
321 322 323 |
# File 'lib/deltacloud.rb', line 321 def handle_backend_error(response) raise BackendError.new(:message => (Nokogiri::XML(response)/'error/message').text) end |
#instance_state(name) ⇒ Object
Select instance state specified by name
349 350 351 |
# File 'lib/deltacloud.rb', line 349 def instance_state(name) instance_states.select { |s| s.name.to_s.eql?(name.to_s) }.first end |
#instance_states ⇒ Object
List available instance states and transitions between them
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/deltacloud.rb', line 331 def instance_states states = [] request(:get, entry_points[:instance_states]) do |response| Nokogiri::XML(response).xpath('states/state').each do |state_el| state = DeltaCloud::InstanceState::State.new(state_el['name']) state_el.xpath('transition').each do |transition_el| state.transitions << DeltaCloud::InstanceState::Transition.new( transition_el['to'], transition_el['action'] ) end states << state end end states end |
#request(*args, &block) ⇒ Object
Basic request method
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/deltacloud.rb', line 268 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 if conf[:method].eql?(:post) RestClient.send(:post, conf[:path], conf[:form_data], default_headers.merge(extended_headers)) do |response, request, block| handle_backend_error(response) if response.code.eql?(500) 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.merge(extended_headers)) do |response, request, block| handle_backend_error(response) if response.code.eql?(500) if conf[:method].eql?(:get) and [301, 302, 307].include? response.code response.follow_redirection(request) 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 if response.respond_to?('body') yield response.body if block_given? else yield response.to_s if block_given? end end end end end |
#use_driver(driver, opts = {}) ⇒ Object
247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/deltacloud.rb', line 247 def use_driver(driver, opts={}) if driver @api_driver = driver @driver_name = driver discover_entry_points end @username = opts[:username] if opts[:username] @password = opts[:password] if opts[:password] @api_provider = opts[:provider] if opts[:provider] return self end |
#xml_to_class(base_object, item) ⇒ Object
Convert XML response to defined Ruby Class
134 135 136 137 138 139 140 141 142 143 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 |
# File 'lib/deltacloud.rb', line 134 def xml_to_class(base_object, item) return nil unless item params = { :id => item['id'], :url => item['href'], :name => item.name, :client => self } params.merge!({ :initial_state => (item/'state').text.sanitize }) if (item/'state').length > 0 obj = base_object.new(params) # Traverse across XML document and deal with elements item.xpath('./*').each do |attribute| # Do a link for elements which are links to other REST models if self.entry_points.keys.include?(:"#{attribute.name}s") obj.add_link!(attribute.name, attribute['id']) && next end # Do a HWP property for hardware profile properties if attribute.name == 'property' if attribute['value'] =~ /^(\d+)$/ obj.add_hwp_property!(attribute['name'], attribute, :float) && next else obj.add_hwp_property!(attribute['name'], attribute, :integer) && next end end # If there are actions, add they to ActionObject/StateFullObject if attribute.name == 'actions' (attribute/'link').each do |link| obj.add_action_link!(item['id'], link) end && next end if attribute.name == 'mount' obj.add_link!("instance", (attribute/"./instance/@id").first.value) obj.add_text!("device", (attribute/"./device/@name").first.value) next end # Deal with collections like public-addresses, private-addresses if (attribute/'./*').length > 0 obj.add_collection!(attribute.name, (attribute/'*').collect { |value| value.text }) && next end # Anything else is treaten as text object obj.add_text!(attribute.name, attribute.text.convert) end return obj end |