Class: DeltaCloud::API
- Inherits:
-
Object
- Object
- DeltaCloud::API
- Defined in:
- lib/deltacloud.rb
Defined Under Namespace
Classes: BackendError
Instance Attribute Summary collapse
-
#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.
-
#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.
-
#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.
67 68 69 70 71 72 73 74 75 |
# File 'lib/deltacloud.rb', line 67 def initialize(user_name, password, api_url, opts={}, &block) opts[:version] = true @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 |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
Generate create_* methods dynamically
211 212 213 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 |
# File 'lib/deltacloud.rb', line 211 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_uri ⇒ Object (readonly)
Returns the value of attribute api_uri.
65 66 67 |
# File 'lib/deltacloud.rb', line 65 def api_uri @api_uri end |
#api_version ⇒ Object (readonly)
Returns the value of attribute api_version.
65 66 67 |
# File 'lib/deltacloud.rb', line 65 def api_version @api_version end |
#driver_name ⇒ Object (readonly)
Returns the value of attribute driver_name.
65 66 67 |
# File 'lib/deltacloud.rb', line 65 def driver_name @driver_name end |
#entry_points ⇒ Object (readonly)
Returns the value of attribute entry_points.
65 66 67 |
# File 'lib/deltacloud.rb', line 65 def entry_points @entry_points end |
#features ⇒ Object (readonly)
Returns the value of attribute features.
65 66 67 |
# File 'lib/deltacloud.rb', line 65 def features @features end |
Instance Method Details
#api_host ⇒ Object
Return API hostname
82 |
# File 'lib/deltacloud.rb', line 82 def api_host; @api_uri.host ; end |
#api_path ⇒ Object
Return API path
88 |
# File 'lib/deltacloud.rb', line 88 def api_path; @api_uri.path ; end |
#api_port ⇒ Object
Return API port
85 |
# File 'lib/deltacloud.rb', line 85 def api_port; @api_uri.port ; end |
#base_object(model, response) ⇒ Object
Add default attributes [id and href] to class
125 126 127 128 |
# File 'lib/deltacloud.rb', line 125 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
118 119 120 121 122 |
# File 'lib/deltacloud.rb', line 118 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
77 78 79 |
# File 'lib/deltacloud.rb', line 77 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’
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 92 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
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/deltacloud.rb', line 188 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
332 333 334 |
# File 'lib/deltacloud.rb', line 332 def discovered? true if @entry_points!={} end |
#documentation(collection, operation = nil) ⇒ Object
This method will retrieve API documentation for given collection
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/deltacloud.rb', line 337 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 |
#feature?(collection, name) ⇒ Boolean
Check if specified collection have wanted feature
304 305 306 |
# File 'lib/deltacloud.rb', line 304 def feature?(collection, name) @features.has_key?(collection) && @features[collection].include?(name) end |
#handle_backend_error(response) ⇒ Object
299 300 301 |
# File 'lib/deltacloud.rb', line 299 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
327 328 329 |
# File 'lib/deltacloud.rb', line 327 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
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/deltacloud.rb', line 309 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
246 247 248 249 250 251 252 253 254 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 284 285 286 |
# File 'lib/deltacloud.rb', line 246 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) 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) 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 |
#xml_to_class(base_object, item) ⇒ Object
Convert XML response to defined Ruby Class
131 132 133 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 |
# File 'lib/deltacloud.rb', line 131 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 |