class Ravello::Client

A client for the Ravello API. The client is a thin layer on top of the RESTful API. The client manages a single HTTPS connection, and implements login and retry functionality.

Some general comments on how the RESTful API is mapped:

Attributes

retries[RW]

The number of times to retry an API call before giving up. Only idempotent API calls are retried.

timeout[RW]

The default network timeout.

url[R]

The parsed URL used in the current connection.

user_info[R]

A hash containing user information. Available when the client is logged in.

Public Class Methods

new(options={}) click to toggle source

Create a new API client. The following options are supported: @param :username [String] The API user name. @param :password [String] The API password. @param :timeout [Integer] The network timeout. @param :retries [Integer] Times to retry a failed operation.

# File lib/ravello-sdk.rb, line 156
def initialize(options={})
  @username = options[:username]
  @password = options[:password]
  @timeout = options.fetch(:timeout, 60)
  @retries = options.fetch(:retries, 3)
  @logger = Logger.new(STDERR)
  @logger.level = if $DEBUG then Logger::DEBUG \
                    elsif $VERBOSE then Logger::INFO else Logger::WARN end
  @redirects = 3
  @autologin = true
  @cookies = nil
  @user_info = nil
  @connection = nil
  set_url(options.fetch(:url, DEFAULT_URL))
end

Public Instance Methods

close() click to toggle source

Close the connection to the API.

# File lib/ravello-sdk.rb, line 209
def close
  @connection.finish if !@connection.nil?
  @connection = nil
  @cookies = nil
end
connect(url=nil) click to toggle source

Connect to the API. @param url [String] The URL to connect to. If not provided, use the

default service end point.
# File lib/ravello-sdk.rb, line 185
def connect(url=nil)
  url = url unless url.nil?
  do_connect
end
connected?() click to toggle source

@return [Boolean] Whether the client is connected.

# File lib/ravello-sdk.rb, line 173
def connected?
  !@connection.nil?
end
create_application(app) click to toggle source

Create a new application. @param app [Hash] The application. @return [Hash] The application that was created.

# File lib/ravello-sdk.rb, line 268
def create_application(app)
  request(:POST, '/applications', app)
end
create_blueprint(req) click to toggle source

Create a new blueprint. @param req [Hash] The blueprint creation request. @return [Hash] The blueprint that was created.

# File lib/ravello-sdk.rb, line 404
def create_blueprint(req)
  request(:POST, '/blueprints', req)
end
create_keypair(keypair) click to toggle source

Create a new keypair. @param keypair [Hash] The keypair to created. @return [Hash] The keypair that was created.

# File lib/ravello-sdk.rb, line 476
def create_keypair(keypair)
  request(:POST, '/keypairs', keypair)
end
delete_application(id) click to toggle source

Delete an application @param id [Numeric,Hash] The ID of the application. This parameter may

also be a Hash with a numeric "id" key.

@return nil

# File lib/ravello-sdk.rb, line 283
def delete_application(id)
  if id.is_a? Hash then id = id['id'] end
  request(:DELETE, "/applications/#{id}")
end
delete_blueprint(id) click to toggle source

Delete a blueprint. @param id [Integer, Hash] The ID of the blueprint to delete. This

parameter may also be a Hash, in which case it must have an "id" key.

@return nil

# File lib/ravello-sdk.rb, line 412
def delete_blueprint(id)
  if id.is_a? Hash then id = id['id'] end
  request(:DELETE, "/blueprints/#{id}")
end
delete_image(id) click to toggle source

Delete an image. @param id [Numeric, Hash] The Id of the image to delete. This may also be

a Hash, in which case it must have an "id" key.

@return nil

# File lib/ravello-sdk.rb, line 448
def delete_image(id)
  if id.is_a? Hash then id = id['id'] end
  request(:DELETE, "/images/#{id}")
end
delete_keypair(id) click to toggle source

Delete a keypair. @param id The ID of the keypair to delete. This parameter may also be a

Hash, in which case it must have an "id" key.

@return nil

# File lib/ravello-sdk.rb, line 491
def delete_keypair(id)
  if id.is_a? Hash then id = id['id'] end
  request(:DELETE, "/keypairs/#{id}")
end
generate_keypair() click to toggle source

Generate a new keyapair. @return [Hash] The newly generated keypair.

# File lib/ravello-sdk.rb, line 498
def generate_keypair
  request(:POST, '/keypairs/generate')
end
get_application(id) click to toggle source

Get an application by its ID. @param id [Integer, Hash] The numeric ID of the application. This may

also be a hash, in which case it must have a numeric "id" key.

@return [Hash, nil] The application, or nil if the application does not

exist.
# File lib/ravello-sdk.rb, line 250
def get_application(id)
  if id.is_a? Hash then id = id['id'] end
  request(:GET, "/applications/#{id}")
end
get_applications(filter={}) click to toggle source

Get a list of all applications. @param filter [Hash] A hash containing key/value pairs the application

must have.

@return [Array<Hash>] A list of applications.

# File lib/ravello-sdk.rb, line 259
def get_applications(filter={})
  result = request(:GET, '/applications')
  result.select! do |app| match_filter(app, filter) end if !filter.empty?
  result
end
get_blueprint(id) click to toggle source

Get a blueprint. @param id [Integer, Hash] The ID of the blueprint. This may also be a

Hash, in which case it must have an "id" key.

@return [Hash, nil] The blueprint as a Hash, or nil in case the blueprint

does not exist.
# File lib/ravello-sdk.rb, line 386
def get_blueprint(id)
  if id.is_a? Hash then id = id['id'] end
  request(:GET, "/blueprints/#{id}")
end
get_blueprints(filter={}) click to toggle source

Get a list of all blueprints. @param filter [Hash] An optional filter. Only blueprints that have

key/value pairs as specified in the filter will be returned.

@return [Array<Hash>] A list of blueprints.

# File lib/ravello-sdk.rb, line 395
def get_blueprints(filter={})
  result = request(:GET, '/blueprints')
  result.select! do |bp| match_filter(bp, filter) end if !filter.empty?
  result
end
get_image(id) click to toggle source

Get an image. @param id [Integer, Hash] The ID of the image. This may also be a

Hash, in which case it must have an "id" key.

@return [Hash, nil] The image as a Hash, or nil in case the image

does not exist.
# File lib/ravello-sdk.rb, line 422
def get_image(id)
  if id.is_a? Hash then id = id['id'] end
  request(:GET, "/images/#{id}")
end
get_images(filter={}) click to toggle source

Get a list of all images. @param filter [Hash] An optional filter. Only images that have

key/value pairs as specified in the filter will be returned.

@return [Array<Hash>] A list of images.

# File lib/ravello-sdk.rb, line 431
def get_images(filter={})
  result = request(:GET, '/images')
  result.select! do |img| match_filter(img, filter) end if !filter.empty?
  result
end
get_keypair(id) click to toggle source

Get a keypair. @param id [Integer, Hash] The ID of the keypair. This parameter may also

be a Hash, in which case it must have an "id" key.

@return [Hash, nil] The keypair as a Hash, or nil in case the keypair

does not exist.
# File lib/ravello-sdk.rb, line 458
def get_keypair(id)
  if id.is_a? Hash then id = id['id'] end
  request(:GET, "/keypairs/#{id}")
end
get_keypairs(filter={}) click to toggle source

Get a list of all keypairs. @param filter [Hash] An optional filter. Only keypairs that have

key/value pairs as specified in the filter will be returned.

@return [Array<Hash>] A list of keypairs.

# File lib/ravello-sdk.rb, line 467
def get_keypairs(filter={})
  result = request(:GET, '/keypairs')
  result.select! do |kp| match_filter(kp, filter) end if !filter.empty?
  result
end
inspect() click to toggle source
# File lib/ravello-sdk.rb, line 502
def inspect
  "#<RavelloClient:#{object_id}>"
end
logged_in?() click to toggle source

@return [Boolean] Whether the client is logged in.

# File lib/ravello-sdk.rb, line 178
def logged_in?
  !@cookies.nil?
end
login(username=nil, password=nil) click to toggle source

Authenticate to the API. Authentication is required for most operations. @param username The API username. If not provided, use the username

specified in the constructor.

@param password The API password If not provided, use the password

specified in the constructor.
# File lib/ravello-sdk.rb, line 195
def login(username=nil, password=nil)
  raise "already logged in" if logged_in?
  @username = username unless username.nil?
  @password = password unless password.nil?
  raise "username and password must be set" unless have_credentials?
  do_login
end
logout() click to toggle source

Logout. The connection is maintained.

# File lib/ravello-sdk.rb, line 204
def logout
  do_logout if logged_in?
end
publish_application(id, req={}) click to toggle source

Publish an application @param id [Numeric, Hash] The ID of the application to publish. This

parameter may also be a Hash with a numeric "id" key.

@param req [Hash] The publish request. @return [Hash] The publish response.

# File lib/ravello-sdk.rb, line 293
def publish_application(id, req={})
  if id.is_a? Hash then id = id['id'] end
  request(:POST, "/applications/#{id}/publish", req)
end
publish_application_updates(id) click to toggle source

Publish application updates. @param id [Numeric, Hash] The ID of the application to publish updates

for. This  parameter may also be a Hash with a numeric "id" key.

@return [Hash] The publish updates response.

# File lib/ravello-sdk.rb, line 329
def publish_application_updates(id)
  if id.is_a? Hash then id = id['id'] end
  request(:POST, "/applications/#{id}/publishUpdates")
end
request(method, path, entity=nil) click to toggle source

Issue a call to the API. This is a low-level method that you should only use in case the call you want is not mapped as a method. @param method [Symbol] The HTTP method, e.g. :GET or :POST. @param path [String] The path relative to the API root. @param entity [Hash] A JSON serializable hash that is specific to

the method and path.

@return [Hash,Array<Hash>] The parsed JSON response.

# File lib/ravello-sdk.rb, line 222
def request(method, path, entity=nil)
  body = JSON.generate(entity) unless entity.nil?
  response = make_request(method, path, body)
  response.entity
end
restart_application(id) click to toggle source

Restart an application. @param id [Numeric, Hash] The ID of the application to restart. This

parameter may also be a Hash with a numeric "id" key.

@return [Hash] The restart response.

# File lib/ravello-sdk.rb, line 320
def restart_application(id)
  if id.is_a? Hash then id = id['id'] end
  request(:POST, "/applications/#{id}/restart")
end
restart_vm(appid, vmid) click to toggle source

Restart a virtual machine @param appid [Numeric, Hash] The ID of the application that contains the

VM. This parameter may also be a Hash with an "id" key.

@param vmid [Numeric, Hash] The ID of the VM to restart. This parameter

may also be a Hash with an "id" key.

@return [Hash] The restart VM response.

# File lib/ravello-sdk.rb, line 375
def restart_vm(appid, vmid)
  if appid.is_a? Hash then appid = appid['id'] end
  if vmid.is_a? Hash then vmid = vmid['id'] end
  request(:POST, "/applications/#{appid}/vms/#{vmid}/restart")
end
set_application_expiration(id, req) click to toggle source

Set the application expiration time. @param id [Numeric, Hash] The ID of the application to set the

expiration time of. This parameter may also be a Hash with a numeric
"id" key.

@param req [Hash] The set expiration time request. @return [Hash] The set expiration time response.

# File lib/ravello-sdk.rb, line 340
def set_application_expiration(id, req)
  if id.is_a? Hash then id = id['id'] end
  request(:POST, "/applications/#{id}/setExpiration", req)
end
start_application(id) click to toggle source

Start an application. @param id [Numeric, Hash] The ID of the application to start. This

parameter may also be a Hash with a numeric "id" key.

@return [Hash] The start response.

# File lib/ravello-sdk.rb, line 302
def start_application(id)
  if id.is_a? Hash then id = id['id'] end
  request(:POST, "/applications/#{id}/start")
end
start_vm(appid, vmid) click to toggle source

Start a virtual machine @param appid [Numeric, Hash] The ID of the application that contains the

VM. This parameter may also be a Hash with an "id" key.

@param vmid [Numeric, Hash] The ID of the VM to start. This parameter

may also be a Hash with an "id" key.

@return [Hash] The start VM response.

# File lib/ravello-sdk.rb, line 351
def start_vm(appid, vmid)
  if appid.is_a? Hash then appid = appid['id'] end
  if vmid.is_a? Hash then vmid = vmid['id'] end
  request(:POST, "/applications/#{appid}/vms/#{vmid}/start")
end
stop_application(id) click to toggle source

Stop an application. @param id [Numeric, Hash] The ID of the application to stop. This

parameter may also be a Hash with a numeric "id" key.

@return [Hash] The stop response.

# File lib/ravello-sdk.rb, line 311
def stop_application(id)
  if id.is_a? Hash then id = id['id'] end
  request(:POST, "/applications/#{id}/stop")
end
stop_vm(appid, vmid) click to toggle source

Stop a virtual machine @param appid [Numeric, Hash] The ID of the application that contains the

VM. This parameter may also be a Hash with an "id" key.

@param vmid [Numeric, Hash] The ID of the VM to stop. This parameter

may also be a Hash with an "id" key.

@return [Hash] The stop VM response.

# File lib/ravello-sdk.rb, line 363
def stop_vm(appid, vmid)
  if appid.is_a? Hash then appid = appid['id'] end
  if vmid.is_a? Hash then vmid = vmid['id'] end
  request(:POST, "/applications/#{appid}/vms/#{vmid}/stop")
end
update_application(app) click to toggle source

Update an existing application @param app [Hash] The application to update. @return [Hash] The updated application.

# File lib/ravello-sdk.rb, line 275
def update_application(app)
  request(:PUT, "/applications/#{app['id']}", app)
end
update_image(image) click to toggle source

Update an image. @param image [Hash] The image to update. @return [Hash] The updated image.

# File lib/ravello-sdk.rb, line 440
def update_image(image)
  request(:PUT, "/images/#{image['id']}", image)
end
update_keypair(keypair) click to toggle source

Update a keypair. @param keypair [Hash] The keypair to update. @return [Hash] The updated keypair.

# File lib/ravello-sdk.rb, line 483
def update_keypair(keypair)
  request(:PUT, "/keypairs/#{keypair['id']}", keypair)
end
wait_for(obj, timeout) { |request(:GET, href)| ... } click to toggle source

Wait until a condition on the object evaluates to true. @param obj [Hash] The object to wait for. It must be a hash returned by

this client that has a "href" attribute.

@param timeout [Numeric] The number of seconds to wait. @param block [Block] A block that evaluates the condition. The block must

return true if the condition holds, false otherwise.
# File lib/ravello-sdk.rb, line 234
def wait_for(obj, timeout, &block)
  end_time = Time.now + timeout
  raise 'object requires a "href" key' if !obj.key? 'href'
  href = obj['href']
  while end_time >= Time.now do
    break if yield request(:GET, href)
    sleep 5
  end
  raise 'timeout' if end_time < Time.now
end

Private Instance Methods

do_connect() click to toggle source
# File lib/ravello-sdk.rb, line 519
def do_connect()
  @connection = Net::HTTP.new(url.host, url.port)
  @connection.use_ssl = true
  @connection.set_debug_output $stderr if $DEBUG
  @connection.start
  @logger.debug("connected to #{url.host}:#{url.port}")
end
do_login() click to toggle source
# File lib/ravello-sdk.rb, line 527
def do_login()
  raise "should have credentials" if not have_credentials?
  @logger.debug('performing a username/password login')
  @autologin = false
  auth = Base64.encode64("#{@username}:#{@password}").gsub(/\s/, '')
  headers = [['Authorization', "Basic #{auth}"]]
  response = make_request(:POST, '/login', nil, headers)
  cookies = response.get_fields('Set-Cookie')
  @cookies = cookies.map{ |v| v.split(';')[0]}.join(', ')
  @autologin = true
  @user_info = response.entity
end
do_logout() click to toggle source
# File lib/ravello-sdk.rb, line 540
def do_logout
  make_request(:POST, '/logout')
  @cookies = nil
end
do_request(request) click to toggle source
# File lib/ravello-sdk.rb, line 574
def do_request(request)
  retries = redirects = 0
  while retries < @retries and redirects < @redirects do
    do_connect if !connected?
    do_login if @autologin && have_credentials? && !logged_in?
    begin
      @logger.info("request: #{request.method} #{request.path}")
      response = @connection.request(request)
      @logger.info("response: #{response.code} #{response.message}")
      case response.code.to_i
      when 200..299
        body = response.read_body
        ctype = response.content_type
        entity = JSON.parse(body) if ctype == 'application/json'
        if entity.is_a?(Hash) && !entity['id'].nil? then
          if response.key? 'Content-Location'
            href = URI.parse(response['Content-Location']).path
          elsif response.key? 'Location'
            href = URI.parse(response['Location']).path
          elsif request.method == 'POST'
            # missing location header with e.g. /pubkeys
            href = "#{request.uri.path}/#{entity['id']}"
          else
            href = request.uri.path
          end
          entity['href'] = href.sub(/^#{@url.path}/, '')
        end
        response.entity = entity
      when 300..399
        location = response['Location']
        raise "no location for #{response.code} response" if location.nil?
        url = URI.parse(location)
        raise "will not redirect to #{url.to_s}" if url.route_from(@url).host
        request.url = url
        response.entity = nil
        redirects += 1
        next
      when 404
        response.entity = nil
        break
      else
        message = "#{response.code} #{response.message.dump} " \
                  "[#{response.fetch('ERROR-CODE', 'unknown')}: " \
                  "#{response.fetch('ERROR-MESSAGE', 'unknown')}]"
        raise response.error_type.new(message, response)
      end
    rescue Timeout::Error => e
      @logger.debug("timeout: #{e.message}")
      close
      retries += 1
      next if idempotent request
      raise "not retrying #{request.method.to_s} request"
    end
    break
  end
  raise "maximum number of retries reached" if retries == @retries
  raise "maximum number of redirects reached" if redirects == @redirects
  response
end
have_credentials?() click to toggle source
# File lib/ravello-sdk.rb, line 515
def have_credentials?
  !@username.nil? && !@password.nil?
end
idempotent(request) click to toggle source
# File lib/ravello-sdk.rb, line 570
def idempotent(request)
  [:GET, :HEAD, :PUT].include? request.method
end
make_request(method, path, body=nil, headers=nil) click to toggle source
# File lib/ravello-sdk.rb, line 545
def make_request(method, path, body=nil, headers=nil)
  uri = @url.merge(@url.path + path)
  case method
  when :GET
    request = Net::HTTP::Get.new uri
  when :POST
    request = Net::HTTP::Post.new uri
  when :DELETE
    request = Net::HTTP::Delete.new uri
  when :PUT
    request = Net::HTTP::Put.new uri
  when :PATCH
    request = New::HTTP::Patch.new uri
  else
    raise ArgumentError, "unknown method: #{method.to_s}"
  end
  request['Accept'] = 'application/json'
  request['Cookie'] = @cookies unless @cookies.nil?
  request['Accept-Encoding'] = 'identity' if $DEBUG
  headers.each { |kv| request.add_field(kv[0], kv[1]) } unless headers.nil?
  request.body = body
  request.content_type = 'application/json'
  do_request(request)
end
match_filter(obj, filter) click to toggle source
# File lib/ravello-sdk.rb, line 634
def match_filter(obj, filter)
  filter.each_pair do |fkey,fvalue|
    obval = obj[fkey.to_s]
    if obval.nil?
      return false
    elsif fvalue.is_a? Hash
      return false if !obval.is_a? Hash || !match_filter(obval, fvalue)
    elsif fvalue != obval
      return false
    end
  end
  true
end
set_url(url) click to toggle source
# File lib/ravello-sdk.rb, line 508
def set_url(url)
  raise 'cannot change URL when connected' if connected?
  parsed = URI.parse(url.chomp '/')
  raise ArgumentError, 'https is required' if parsed.scheme != "https"
  @url = parsed
end