Skip to content

Instantly share code, notes, and snippets.

@krames
Last active December 21, 2015 23:09
Show Gist options
  • Select an option

  • Save krames/6379967 to your computer and use it in GitHub Desktop.

Select an option

Save krames/6379967 to your computer and use it in GitHub Desktop.
This is a quick crash course on fog development.

#Cloud Monitoring Pairing

Using curl with Rackspace Cloud

Authenticate

To authenticate with the Rackspace Cloud, execute the following curl command substituting USERNAME and API_KEY with the appropriate values:

curl -s https://identity.api.rackspacecloud.com/v2.0/tokens -X 'POST' \
 -d '{"auth":{"RAX-KSKEY:apiKeyCredentials":{"username":"USERNAME", "apiKey":"API_KEY"}}}' \
 -H "Content-Type: application/json"  | python -m json.tool

This will provide you with your access token and a list of end points for all of our avaliable services.

List entities

From the list entities documentation you can see we want to hit the /entities URI using the GET method. Combining this with our service endpoint and access token we get the following curl command:

 curl -s https://monitoring.api.rackspacecloud.com/v1.0/TENANT_ID/entities  -H "X-Auth-Token:ACCESS_TOKEN" | python -m json.tool

This returns the following:

{
    "metadata": {
        "count": 75, 
        "limit": 100, 
        "marker": null, 
        "next_href": null, 
        "next_marker": null
    }, 
    "values": [
        {
            "agent_id": null, 
            "created_at": 1377640854996, 
            "id": "en01YHC2X5", 
            "ip_addresses": {
                "private0_v4": "10.208.152.138"
            }, 
            "label": "aseb74d9ed-webhead", 
            "managed": false, 
            "metadata": null, 
            "updated_at": 1377640854996, 
            "uri": "https://ord.servers.api.rackspacecloud.com/TENANT_ID/servers/87ca85b1-e192-4744-9713-ef7922850ccc"
        }, ...

Using Monitoring in Fog

Now that we understand the underlying concept, lets see how this is implemented in fog.

Start by firing up irb or pry and create a Rackspace monitoring service as follows:

require 'fog'

service = Fog::Rackspace::Monitoring.new :rackspace_username => RACKSPACE_USER_NAME,
    :rackspace_api_key   => RACKSPACE_API

Request Layer

We will start off by looking at the low level request layer. To see the avaliable methods for you can execute service.requests.

This returns the following:

:list_agent_tokens, :list_alarms, :list_alarm_examples, :list_checks, :list_entities, :list_metrics, :list_data_points, :list_check_types, :list_overview, :list_notification_plans, :get_agent_token, :get_alarm, :get_alarm_example, :get_check, :get_entity, :create_agent_token, :create_alarm, :create_check, :create_entity, :update_check, :update_entity, :update_alarm, :delete_agent_token, :delete_alarm, :delete_check, :delete_entity, :evaluate_alarm_example] 

We are interested in the list_entities method. Executing service.list_entities returns the following:

 <Excon::Response:0x007f8fc7461ff0 @data={:body=>{"values"=>[{"id"=>"en01YHC2X5", "label"=>"aseb74d9ed-webhead", "ip_addresses"=>{"private0_v4"=>"10.208.152.138"}, "metadata"=>nil, "managed"=>false, "uri"=>"https://ord.servers.api.rackspacecloud.com/772045/servers/87ca85b1-e192-4744-9713-ef7922850ccc", "agent_id"=>nil, "created_at"=>1377640854996, "updated_at"=>1377640854996}, ..}]}}, :headers=>{"Date"=>"Thu, 29 Aug 2013 15:12:18 GMT", "Content-Type"=>"application/json; charset=UTF-8", "X-RateLimit-Limit"=>"50000", "X-RateLimit-Remaining"=>"49694", "X-RateLimit-Window"=>"24 hours", "X-RateLimit-Type"=>"global", "X-Response-Id"=>".rh-3puT.h-dfw1-maas-prod-api1.r-qQA9Cj1w.c-5580568.ts-1377789138662.v-0b83008", "X-LB"=>"dfw1-maas-prod-api0", "Vary"=>"Accept-Encoding", "Transfer-Encoding"=>"chunked"}, :status=>200, :remote_ip=>"74.205.66.16"}> 

This is the implementation of the list_entities method:

module Fog
  module Rackspace
    class Monitoring
      class Real

        def list_entities(options={})
          request(
            :expects  => [200, 203],
            :method   => 'GET',
            :path     => 'entities',
            :query    => options
          )
        end

      end
    end
  end
end

Notice how we are passing our uri and http method to the request method. We also put an expectation that we are expecting to get back an http 200 or http 203 back. Anything other than this will result in an Excon exception being thrown.

The request method is defined on the `Fog::Rackspace::Monitoring' class. This method is show here:

        def request(params, parse_json = true, &block)
          super(params, parse_json, &block)
          rescue Excon::Errors::BadRequest => error
            raise BadRequest.slurp(error, self)
          rescue Excon::Errors::Conflict => error
            raise Conflict.slurp(error, self)
          rescue Excon::Errors::NotFound => error
            raise NotFound.slurp(error, self)
          rescue Excon::Errors::ServiceUnavailable => error
            raise ServiceUnavailable.slurp(error, self)
          rescue Excon::Errors::InternalServerError => error
            raise InternalServerError.slurp(error, self)
          rescue Excon::Errors::HTTPStatusError => error
            raise ServiceError.slurp(error, self)
        end

The request method in the super class more or less handles all the heavy lifting and can be found here. It takes care of setting the X-Auth-Token header, picking the service end point, as well as renewing expired tokens.

Model Layer

The request layer provides a one to one mapping between requests and the remote cloud. The model layer provides a more generalized object based abstraction.

At the center of this abstraction are collections. You can see a list of collections by executing service.collections. The collections for the monitoring servers are show below:

[:entities, :checks, :alarms, :alarm_examples, :agent_tokens, :metrics, :data_points, :check_types] 

To access the list of entities from the collection layer we would call service.entities.all or we can lazly retrieve this by executing service.entities.

The model layer will typically have an implementation for both the collection and the associated model.

Shown below is the code for the all method on the Entities collection:

def all(options={})
    data = service.list_entities(options).body
    marker = data['metadata']['next_marker']
    
    load(data['values'])
end

You can see that under the covers the model layer uses the request layer. In fact, the model layer should never make a direct http call to the underlying cloud. One the request has been made it is pass along to the load method. This will instantiate the underlying model and populate all of the associated model attributes.

Below you can see the attribute declaration of the Entity model:

    identity :id

    attribute :label
    attribute :metadata
    attribute :ip_addresses
    attribute :agent_id
    attribute :managed, :default => false
    attribute :uri

Fog automatically assumes that the attribute name maps to the object json. The attributes mechanism can be found here

Testing

Fog uses shindo for testing. You can find more information about shindo testing here.

Shindo tests are executed as follows:

bundle exec shindo <testname>

To skip prompts you can optionally use the shindont binary. To execute it with mocks you can preface your command with FOG_MOCK=true.

Debugging

To see all of fog's HTTP traffic you can set the EXCON_DEBUG variable to true as follows:

EXCON_DEBUG=true <command>

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment