Introduction to Fog
  and Openstack
    Hunter Nield - 1/3/2013
     Twitter: @hunternield
Fogとは
• 複数のクラウド・サービスを接続する共通インター
  フェイス

• オープンソース Ruby ライブラリ (MIT License)

• OpenStack への接続が容易

• http://fog.io

• https://github.com/fog/fog
Fogの歴史

• 2010年 Wesley Beary (geemus on Github) に
 より開始

• 初期バージョンは Amazon、Rackspace、
 Slicehostのみ
Fog と OpenStack の歴史

• Diablo バージョンにて開発開始

• Morphlabs が Essex からサポートを始め、
 Folsom、その後のバージョンと継続する予
 定。
Basics
Fog provides high level interfaces to cloud services
Services
Fog Services map closely to the Openstack Services
Compute
    Connects to the Openstack Nova API for managing
  Instances (Servers), Security Groups, Floating IPs, etc

http://rubydoc.info/gems/fog/1.9.0/Fog/Compute/OpenStack
Identity
Connects to the Openstack Keystone API for managing Users, Tenants and Authentication

               http://rubydoc.info/gems/fog/1.9.0/Fog/Identity/OpenStack
Volumes
Connects to the Openstack Nova/Cinder API for managing Block Storage

      http://rubydoc.info/gems/fog/1.9.0/Fog/Volume/OpenStack
Images
Connects to the Openstack Glance API for managing VM Images and Snapshots

          http://rubydoc.info/gems/fog/1.9.0/Fog/Images/OpenStack
Storage
Connects to the Openstack Swift API for managing Object Storage

   http://rubydoc.info/gems/fog/1.9.0/Fog/Storage/OpenStack
Network
Connects to the Openstack Quantum API for managing Networks

  http://rubydoc.info/gems/fog/1.9.0/Fog/Network/OpenStack
Internals
Fog follows a simple structure to handle the
      management of cloud services
Requests
Query the cloud service APIs
Mock


• Test data to return example API responses

• Requires no network connection
Mock (Example)
     class Mock

        def list_flavors
          response = Excon::Response.new
          response.status = 200
          response.body = {
            'flavors' => [
              { 'name' => '256 server', 'id' =>   '1', 'links' =>   ['https://itdoesntmatterwhatshere.heh']   },
              { 'name' => '512 server', 'id' =>   '2', 'links' =>   ['https://itdoesntmatterwhatshere.heh']   },
              { 'name' => '1GB server', 'id' =>   '3', 'links' =>   ['https://itdoesntmatterwhatshere.heh']   },
              { 'name' => '2GB server', 'id' =>   '4', 'links' =>   ['https://itdoesntmatterwhatshere.heh']   },
              { 'name' => '4GB server', 'id' =>   '5', 'links' =>   ['https://itdoesntmatterwhatshere.heh']   },
              { 'name' => '8GB server', 'id' =>   '6', 'links' =>   ['https://itdoesntmatterwhatshere.heh']   },
              { 'name' => '15.5GB server', 'id'   => '7', 'links'   => ['https://
itdoesntmatterwhatshere.heh'] }
            ]
          }
          response
        end

      end
Real


• Returns actual data from the API
Real (Example)
   class Real

      def list_flavors
        request(
          :expects => [200, 203],
          :method   => 'GET',
          :path     => 'flavors.json'
        )
      end

    end
Models
• Ruby Object representation of a Cloud
  Service Entity (Instance, Image, etc)

• Uses one or many ‘Request’ methods to
  retrieve data about an Entity

• Includes convenience methods for easy
  access
Models (Example)
 class Server < Fog::Compute::Server

    identity :id
    attribute :instance_name, :aliases => 'OS-EXT-SRV-ATTR:instance_name'

    attribute   :addresses
    attribute   :flavor
    attribute   :host_id,      :aliases => 'hostId'
    attribute   :image
    attribute   :metadata
    attribute   :links
    attribute   :name
    attribute   :progress
    attribute   :accessIPv4
    attribute   :accessIPv6
    attribute   :state,        :aliases => 'status'
    attribute   :created,      :type => :time
    attribute   :updated,      :type => :time

    def ready?
      self.state == 'ACTIVE'
    end

    def reboot(type = 'SOFT')
      requires :id
      service.reboot_server(id, type)
      true
    end
  end
Collections

• Ruby Object representation of many groups of
  Cloud Service Entities (Instances, Images,
  etc)

• Handles querying and iteration of multiple
  models of a single type
Collections (Example)
   class Servers < Fog::Collection

      model Fog::Compute::OpenStack::Server


      def all(filters = filters)
        self.filters = filters
        data = service.list_servers_detail(filters).body['servers']
        load(data)
      end

      def get(server_id)
        if server = service.get_server_details(server_id).body['server']
          new(server)
        end
      rescue Fog::Compute::OpenStack::NotFound
        nil
      end

    end
Collection                Servers




 Models      Server   Server   Server   Server
Other methods
 Specifically for Openstack
• service.unscoped_token

  •   The reusable token which can be used to retrieve scoped tokens “auth_token” on each
      tenant.

• service.auth_token

  •   The current authentication token sent to OpenStack on each request as a header (“X-
      Auth-Token”).

• service.current_user

  •   The Hash representation of the JSON returned information about the current user
      returned by OpenStack upon authentication.

• service.current_tenant

  •   The Hash representation of the JSON returned information about the current tenant
      returned by OpenStack upon authentication.

• service.credentials

  •   A convenience method to extract needed credentials to easily instantiate a new usable
      service object. The new service object uses the “auth_token” returned by the
      OpenStack API and not the provided username and password originally used for
      authentication.
Example
Requirements


• Ruby (1.8.7, 1.9.2 or 1.9.3)

• Fog (Installed via: gem install fog)
Connection
     # Connect to Openstack Nova
>> compute = Fog::Compute.new({:provider => 'openstack', :openstack_tenant => 'demo', :openstack_api_key =>
'yourpassword', :openstack_username => 'admin', :openstack_auth_url => 'http://localhost:35357/v2.0/tokens'})

#<Fog::Compute::OpenStack::Real:25457260 @openstack_region=nil @openstack_auth_token=nil
@openstack_username="admin" @openstack_service_type=["nova", "compute"]
@auth_token_expiration="2013-02-21T10:30:10Z" ... snip ... @tenant_id="ee1b6e1715644f2ca020c4190769d496"
@openstack_identity_public_endpoint="http://localhost:5000/v2.0" @openstack_management_url="http://localhost:
8774/v2/ee1b6e1715644f2ca020c4190769d496" @port=8774 @scheme="http" @openstack_service_name=nil>

# Query the user
>> compute.current_user
{"username"=>"admin", "roles_links"=>[], "id"=>"5b772e8e179249aeb7152742a4b4f6e9", "roles"=>[{"name"=>"admin"},
{"name"=>"project_manager"}, {"name"=>"Member"}], "name"=>"admin"}

# Get information about the tenant
>> compute.current_tenant
{"enabled"=>true, "description"=>"Demo Account", "name"=>"demo", "id"=>"ee1b6e1715644f2ca020c4190769d496"}

# Check the current state of the running instances
>> compute.list_servers
#<Excon::Response:0x000000030b1a28 @headers={"X-Compute-Request-Id"=>"req-eb228f6f-bec7-4fe3-8d41-69ad69dbee43",
"Content-Type"=>"application/json", "Content-Length"=>"15", "Date"=>"Wed, 20 Feb 2013 10:30:13 GMT"},
@status=200, @remote_ip="127.0.0.1", @body={"servers"=>[]}>
Servers
     # Get a flavor (VM Size) to use for starting a instance
>> flavor = compute.list_flavors.body['flavors'].first
{"id"=>"2", "links"=>[{"href"=>"http://localhost:8774/v2/ee1b6e1715644f2ca020c4190769d496/flavors/2", "rel"=>"self"},
{"href"=>"http://localhost:8774/ee1b6e1715644f2ca020c4190769d496/flavors/2", "rel"=>"bookmark"}], "name"=>"m1.small"}

# Get an image to use for starting a instance
>> image = compute.list_images.body['images'].first
{"id"=>"10a11aa4-3d9c-49e5-988c-3fde3cf37842", "links"=>[{"href"=>"http://localhost:8774/v2/
ee1b6e1715644f2ca020c4190769d496/images/10a11aa4-3d9c-49e5-988c-3fde3cf37842", "rel"=>"self"}, {"href"=>"http://
localhost:8774/ee1b6e1715644f2ca020c4190769d496/images/10a11aa4-3d9c-49e5-988c-3fde3cf37842", "rel"=>"bookmark"},
{"href"=>"http://10.50.2.1:9292/ee1b6e1715644f2ca020c4190769d496/images/10a11aa4-3d9c-49e5-988c-3fde3cf37842",
"type"=>"application/vnd.openstack.image", "rel"=>"alternate"}], "name"=>"'64Bit_Ubuntu_12.04'"}

# Boot a new server
>> compute.create_server('MyFirstServer', image['id'], flavor['id'])
#<Excon::Response:0x000000031d3af0 @headers={"X-Compute-Request-Id"=>"req-a0379de9-a129-496b-b627-11853e0eefca",
"Location"=>"http://localhost:8774/v2/ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10",
"Content-Type"=>"application/json", "Content-Length"=>"462", "Date"=>"Wed, 20 Feb 2013 10:36:37 GMT"}, @status=202,
@remote_ip="127.0.0.1", @body={"server"=>{"security_groups"=>[{"name"=>"default"}], "OS-DCF:diskConfig"=>"MANUAL",
"id"=>"1334c522-ab51-403f-b694-0efd92ef0b10", "links"=>[{"href"=>"http://localhost:8774/v2/
ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10", "rel"=>"self"}, {"href"=>"http://
localhost:8774/ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10", "rel"=>"bookmark"}],
"adminPass"=>"maUXeZE76o64"}}>

# Check the current state of running instances
>> servers = compute.list_servers.body['servers']
#<Excon::Response:0x000000031e16c8 @headers={"X-Compute-Request-Id"=>"req-cae13781-1377-4fc5-a8d2-77394468344d",
"Content-Type"=>"application/json", "Content-Length"=>"388", "Date"=>"Wed, 20 Feb 2013 10:37:01 GMT"}, @status=200,
@remote_ip="127.0.0.1", @body={"servers"=>[{"id"=>"1334c522-ab51-403f-b694-0efd92ef0b10", "links"=>[{"href"=>"http://
localhost:8774/v2/ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10", "rel"=>"self"},
{"href"=>"http://localhost:8774/ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10",
"rel"=>"bookmark"}], "name"=>"MyFirstServer"}]}>
Model Queries
      # Example of a Collection query for the same data
>> compute.servers
<Fog::Compute::OpenStack::Servers
    filters={}
    [
      <Fog::Compute::OpenStack::Server
        id="1334c522-ab51-403f-b694-0efd92ef0b10",
        instance_name=nil,
        addresses={"novanetwork"=>[{"version"=>4, "addr"=>"10.2.0.6"}]},
        flavor={"id"=>"2", "links"=>[{"href"=>"http://localhost:8774/ee1b6e1715644f2ca020c4190769d496/flavors/2", "rel"=>"bookmark"}]},
        host_id="c1e95b9f69157e41baebad3092bd069baaf840215ecbee7edddd9bb2",
        image={"id"=>"10a11aa4-3d9c-49e5-988c-3fde3cf37842", "links"=>[{"href"=>"http://localhost:8774/../images/...",
"rel"=>"bookmark"}]},
        metadata=        <Fog::Compute::OpenStack::Metadata
           []
        >,
        links=[{"href"=>"http://localhost:8774/v2/.../servers/...", "rel"=>"self"}, {"href"=>"http://localhost:8774/.../servers/...",
"rel"=>"bookmark"}],
        name="MyFirstServer",
        personality=nil,
        progress=0,
        accessIPv4="",
        accessIPv6="",
        availability_zone=nil,
        user_data_encoded=nil,
        state="ACTIVE",
        created=2013-02-20 10:36:37 UTC,
        updated=2013-02-20 10:37:24 UTC,
        tenant_id="ee1b6e1715644f2ca020c4190769d496",
        user_id="5b772e8e179249aeb7152742a4b4f6e9",
        key_name=nil,
        fault=nil,
        os_dcf_disk_config="MANUAL",
        os_ext_srv_attr_host="cn26.la-1-2.morphlabs.net",
        os_ext_srv_attr_hypervisor_hostname="cn26.la-1-2.morphlabs.net",
        os_ext_srv_attr_instance_name="instance-00000038",
        os_ext_sts_power_state=1,
        os_ext_sts_task_state=nil,
        os_ext_sts_vm_state="active"
      >
    ]
  >
Volumes
     # Create a 1GB persistent volume
>> compute.create_volume("MyFirstVolume", "Test Volume", 1000)
# <Excon::Response:0x00000003257940 @headers={"X-Compute-Request-Id"=>"req-e98c1f91-d2b9-49cc-bf14-353fd8fa46be",
"Location"=>"http://localhost:8774/v2/ee1b6e1715644f2ca020c4190769d496/os-volumes?
ignore_awful_caching1361357305/664000aa-e275-4e86-a477-7be86927979b", "Content-Type"=>"application/json", "Content-
Length"=>"311", "Date"=>"Wed, 20 Feb 2013 10:48:27 GMT"}, @status=200, @remote_ip="127.0.0.1",
@body={"volume"=>{"status"=>"creating", "displayDescription"=>"Test Volume", "availabilityZone"=>"nova",
"displayName"=>"MyFirstVolume", "attachments"=>[{}], "volumeType"=>nil, "snapshotId"=>nil, "metadata"=>{},
"id"=>"664000aa-e275-4e86-a477-7be86927979b", "createdAt"=>"2013-02-20T10:48:26.709904", "size"=>1000}}>

# Query information about the current volumes for this tenant
>> compute.list_volumes.body['volumes'].first
{"status"=>"available", "displayDescription"=>"Test Volume", "availabilityZone"=>"nova",
"displayName"=>"MyFirstVolume", "attachments"=>[{}], "volumeType"=>nil, "snapshotId"=>nil, "metadata"=>{},
"id"=>"664000aa-e275-4e86-a477-7be86927979b", "createdAt"=>"2013-02-20T10:48:26.000000", "size"=>1000}

# Attach the Volume to the running server
>> compute.attach_volume(compute.list_volumes.body['volumes'].first['id'], compute.servers.first.id, "vdc")
#<Excon::Response:0x000000032b0680 @headers={"X-Compute-Request-Id"=>"req-b6a2bad1-b69d-4abc-a3e6-88d1fc044827",
"Content-Type"=>"application/json", "Content-Length"=>"194", "Date"=>"Wed, 20 Feb 2013 10:54:12 GMT"}, @status=200,
@remote_ip="127.0.0.1", @body={"volumeAttachment"=>{"device"=>"/dev/vdc", "serverId"=>"1334c522-ab51-403f-
b694-0efd92ef0b10", "id"=>"664000aa-e275-4e86-a477-7be86927979b", "volumeId"=>"664000aa-e275-4e86-a477-7be86927979b"}}>

# Check volumes by querying the Volumes collection
>> compute.volumes.first
  <Fog::Compute::OpenStack::Volume
    id="664000aa-e275-4e86-a477-7be86927979b",
    name="MyFirstVolume",
    description="Test Volume",
    status="in-use",
    size=1000,
    type=nil,
    snapshot_id=nil,
    availability_zone="nova",
    created_at="2013-02-20T10:48:26.000000",
    attachments=[{"device"=>"/dev/vdc", "serverId"=>"1334c522-ab51-403f-b694-0efd92ef0b10", "id"=>"664000aa-e275-4e86-
a477-7be86927979b", "volumeId"=>"664000aa-e275-4e86-a477-7be86927979b"}]
  >
Cleanup

     # Remove the Volume from the instance
>> compute.detach_volume(compute.servers.first.id, compute.list_volumes.body['volumes'].first['id'])
#<Excon::Response:0x0000000338e278 @headers={"Content-Type"=>"text/html; charset=UTF-8", "Content-Length"=>"0",
"Date"=>"Wed, 20 Feb 2013 10:58:10 GMT"}, @status=202, @remote_ip="127.0.0.1", @body="">

# Delete the Volume from the system
>> compute.delete_volume(compute.list_volumes.body['volumes'].first['id'])
#<Excon::Response:0x0000000339f6b8 @headers={"Content-Type"=>"text/html; charset=UTF-8", "Content-Length"=>"0",
"Date"=>"Wed, 20 Feb 2013 10:59:22 GMT"}, @status=202, @remote_ip="127.0.0.1", @body="">

# Check volumes again
>> compute.list_volumes.body['volumes']
# []

# Cleanup the system by deleting the instance
compute.delete_server(servers.first['id'])
#<Excon::Response:0x000000033b9dd8 @headers={"Content-Length"=>"0", "X-Compute-Request-Id"=>"req-
ef6c799f-7832-4edf-9929-387d5957320a", "Content-Type"=>"application/json", "Date"=>"Wed, 20 Feb 2013 11:00:17
GMT"}, @status=204, @remote_ip="127.0.0.1", @body="">
Thank you!

Intro to fog and openstack jp

  • 1.
    Introduction to Fog and Openstack Hunter Nield - 1/3/2013 Twitter: @hunternield
  • 2.
    Fogとは • 複数のクラウド・サービスを接続する共通インター フェイス • オープンソース Ruby ライブラリ (MIT License) • OpenStack への接続が容易 • http://fog.io • https://github.com/fog/fog
  • 3.
    Fogの歴史 • 2010年 WesleyBeary (geemus on Github) に より開始 • 初期バージョンは Amazon、Rackspace、 Slicehostのみ
  • 4.
    Fog と OpenStackの歴史 • Diablo バージョンにて開発開始 • Morphlabs が Essex からサポートを始め、 Folsom、その後のバージョンと継続する予 定。
  • 5.
    Basics Fog provides highlevel interfaces to cloud services
  • 6.
    Services Fog Services mapclosely to the Openstack Services
  • 7.
    Compute Connects to the Openstack Nova API for managing Instances (Servers), Security Groups, Floating IPs, etc http://rubydoc.info/gems/fog/1.9.0/Fog/Compute/OpenStack
  • 8.
    Identity Connects to theOpenstack Keystone API for managing Users, Tenants and Authentication http://rubydoc.info/gems/fog/1.9.0/Fog/Identity/OpenStack
  • 9.
    Volumes Connects to theOpenstack Nova/Cinder API for managing Block Storage http://rubydoc.info/gems/fog/1.9.0/Fog/Volume/OpenStack
  • 10.
    Images Connects to theOpenstack Glance API for managing VM Images and Snapshots http://rubydoc.info/gems/fog/1.9.0/Fog/Images/OpenStack
  • 11.
    Storage Connects to theOpenstack Swift API for managing Object Storage http://rubydoc.info/gems/fog/1.9.0/Fog/Storage/OpenStack
  • 12.
    Network Connects to theOpenstack Quantum API for managing Networks http://rubydoc.info/gems/fog/1.9.0/Fog/Network/OpenStack
  • 13.
    Internals Fog follows asimple structure to handle the management of cloud services
  • 14.
  • 15.
    Mock • Test datato return example API responses • Requires no network connection
  • 16.
    Mock (Example) class Mock def list_flavors response = Excon::Response.new response.status = 200 response.body = { 'flavors' => [ { 'name' => '256 server', 'id' => '1', 'links' => ['https://itdoesntmatterwhatshere.heh'] }, { 'name' => '512 server', 'id' => '2', 'links' => ['https://itdoesntmatterwhatshere.heh'] }, { 'name' => '1GB server', 'id' => '3', 'links' => ['https://itdoesntmatterwhatshere.heh'] }, { 'name' => '2GB server', 'id' => '4', 'links' => ['https://itdoesntmatterwhatshere.heh'] }, { 'name' => '4GB server', 'id' => '5', 'links' => ['https://itdoesntmatterwhatshere.heh'] }, { 'name' => '8GB server', 'id' => '6', 'links' => ['https://itdoesntmatterwhatshere.heh'] }, { 'name' => '15.5GB server', 'id' => '7', 'links' => ['https:// itdoesntmatterwhatshere.heh'] } ] } response end end
  • 17.
    Real • Returns actualdata from the API
  • 18.
    Real (Example) class Real def list_flavors request( :expects => [200, 203], :method => 'GET', :path => 'flavors.json' ) end end
  • 19.
    Models • Ruby Objectrepresentation of a Cloud Service Entity (Instance, Image, etc) • Uses one or many ‘Request’ methods to retrieve data about an Entity • Includes convenience methods for easy access
  • 20.
    Models (Example) classServer < Fog::Compute::Server identity :id attribute :instance_name, :aliases => 'OS-EXT-SRV-ATTR:instance_name' attribute :addresses attribute :flavor attribute :host_id, :aliases => 'hostId' attribute :image attribute :metadata attribute :links attribute :name attribute :progress attribute :accessIPv4 attribute :accessIPv6 attribute :state, :aliases => 'status' attribute :created, :type => :time attribute :updated, :type => :time def ready? self.state == 'ACTIVE' end def reboot(type = 'SOFT') requires :id service.reboot_server(id, type) true end end
  • 21.
    Collections • Ruby Objectrepresentation of many groups of Cloud Service Entities (Instances, Images, etc) • Handles querying and iteration of multiple models of a single type
  • 22.
    Collections (Example) class Servers < Fog::Collection model Fog::Compute::OpenStack::Server def all(filters = filters) self.filters = filters data = service.list_servers_detail(filters).body['servers'] load(data) end def get(server_id) if server = service.get_server_details(server_id).body['server'] new(server) end rescue Fog::Compute::OpenStack::NotFound nil end end
  • 23.
    Collection Servers Models Server Server Server Server
  • 24.
  • 25.
    • service.unscoped_token • The reusable token which can be used to retrieve scoped tokens “auth_token” on each tenant. • service.auth_token • The current authentication token sent to OpenStack on each request as a header (“X- Auth-Token”). • service.current_user • The Hash representation of the JSON returned information about the current user returned by OpenStack upon authentication. • service.current_tenant • The Hash representation of the JSON returned information about the current tenant returned by OpenStack upon authentication. • service.credentials • A convenience method to extract needed credentials to easily instantiate a new usable service object. The new service object uses the “auth_token” returned by the OpenStack API and not the provided username and password originally used for authentication.
  • 26.
  • 27.
    Requirements • Ruby (1.8.7,1.9.2 or 1.9.3) • Fog (Installed via: gem install fog)
  • 28.
    Connection # Connect to Openstack Nova >> compute = Fog::Compute.new({:provider => 'openstack', :openstack_tenant => 'demo', :openstack_api_key => 'yourpassword', :openstack_username => 'admin', :openstack_auth_url => 'http://localhost:35357/v2.0/tokens'}) #<Fog::Compute::OpenStack::Real:25457260 @openstack_region=nil @openstack_auth_token=nil @openstack_username="admin" @openstack_service_type=["nova", "compute"] @auth_token_expiration="2013-02-21T10:30:10Z" ... snip ... @tenant_id="ee1b6e1715644f2ca020c4190769d496" @openstack_identity_public_endpoint="http://localhost:5000/v2.0" @openstack_management_url="http://localhost: 8774/v2/ee1b6e1715644f2ca020c4190769d496" @port=8774 @scheme="http" @openstack_service_name=nil> # Query the user >> compute.current_user {"username"=>"admin", "roles_links"=>[], "id"=>"5b772e8e179249aeb7152742a4b4f6e9", "roles"=>[{"name"=>"admin"}, {"name"=>"project_manager"}, {"name"=>"Member"}], "name"=>"admin"} # Get information about the tenant >> compute.current_tenant {"enabled"=>true, "description"=>"Demo Account", "name"=>"demo", "id"=>"ee1b6e1715644f2ca020c4190769d496"} # Check the current state of the running instances >> compute.list_servers #<Excon::Response:0x000000030b1a28 @headers={"X-Compute-Request-Id"=>"req-eb228f6f-bec7-4fe3-8d41-69ad69dbee43", "Content-Type"=>"application/json", "Content-Length"=>"15", "Date"=>"Wed, 20 Feb 2013 10:30:13 GMT"}, @status=200, @remote_ip="127.0.0.1", @body={"servers"=>[]}>
  • 29.
    Servers # Get a flavor (VM Size) to use for starting a instance >> flavor = compute.list_flavors.body['flavors'].first {"id"=>"2", "links"=>[{"href"=>"http://localhost:8774/v2/ee1b6e1715644f2ca020c4190769d496/flavors/2", "rel"=>"self"}, {"href"=>"http://localhost:8774/ee1b6e1715644f2ca020c4190769d496/flavors/2", "rel"=>"bookmark"}], "name"=>"m1.small"} # Get an image to use for starting a instance >> image = compute.list_images.body['images'].first {"id"=>"10a11aa4-3d9c-49e5-988c-3fde3cf37842", "links"=>[{"href"=>"http://localhost:8774/v2/ ee1b6e1715644f2ca020c4190769d496/images/10a11aa4-3d9c-49e5-988c-3fde3cf37842", "rel"=>"self"}, {"href"=>"http:// localhost:8774/ee1b6e1715644f2ca020c4190769d496/images/10a11aa4-3d9c-49e5-988c-3fde3cf37842", "rel"=>"bookmark"}, {"href"=>"http://10.50.2.1:9292/ee1b6e1715644f2ca020c4190769d496/images/10a11aa4-3d9c-49e5-988c-3fde3cf37842", "type"=>"application/vnd.openstack.image", "rel"=>"alternate"}], "name"=>"'64Bit_Ubuntu_12.04'"} # Boot a new server >> compute.create_server('MyFirstServer', image['id'], flavor['id']) #<Excon::Response:0x000000031d3af0 @headers={"X-Compute-Request-Id"=>"req-a0379de9-a129-496b-b627-11853e0eefca", "Location"=>"http://localhost:8774/v2/ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10", "Content-Type"=>"application/json", "Content-Length"=>"462", "Date"=>"Wed, 20 Feb 2013 10:36:37 GMT"}, @status=202, @remote_ip="127.0.0.1", @body={"server"=>{"security_groups"=>[{"name"=>"default"}], "OS-DCF:diskConfig"=>"MANUAL", "id"=>"1334c522-ab51-403f-b694-0efd92ef0b10", "links"=>[{"href"=>"http://localhost:8774/v2/ ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10", "rel"=>"self"}, {"href"=>"http:// localhost:8774/ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10", "rel"=>"bookmark"}], "adminPass"=>"maUXeZE76o64"}}> # Check the current state of running instances >> servers = compute.list_servers.body['servers'] #<Excon::Response:0x000000031e16c8 @headers={"X-Compute-Request-Id"=>"req-cae13781-1377-4fc5-a8d2-77394468344d", "Content-Type"=>"application/json", "Content-Length"=>"388", "Date"=>"Wed, 20 Feb 2013 10:37:01 GMT"}, @status=200, @remote_ip="127.0.0.1", @body={"servers"=>[{"id"=>"1334c522-ab51-403f-b694-0efd92ef0b10", "links"=>[{"href"=>"http:// localhost:8774/v2/ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10", "rel"=>"self"}, {"href"=>"http://localhost:8774/ee1b6e1715644f2ca020c4190769d496/servers/1334c522-ab51-403f-b694-0efd92ef0b10", "rel"=>"bookmark"}], "name"=>"MyFirstServer"}]}>
  • 30.
    Model Queries # Example of a Collection query for the same data >> compute.servers <Fog::Compute::OpenStack::Servers filters={} [ <Fog::Compute::OpenStack::Server id="1334c522-ab51-403f-b694-0efd92ef0b10", instance_name=nil, addresses={"novanetwork"=>[{"version"=>4, "addr"=>"10.2.0.6"}]}, flavor={"id"=>"2", "links"=>[{"href"=>"http://localhost:8774/ee1b6e1715644f2ca020c4190769d496/flavors/2", "rel"=>"bookmark"}]}, host_id="c1e95b9f69157e41baebad3092bd069baaf840215ecbee7edddd9bb2", image={"id"=>"10a11aa4-3d9c-49e5-988c-3fde3cf37842", "links"=>[{"href"=>"http://localhost:8774/../images/...", "rel"=>"bookmark"}]}, metadata= <Fog::Compute::OpenStack::Metadata [] >, links=[{"href"=>"http://localhost:8774/v2/.../servers/...", "rel"=>"self"}, {"href"=>"http://localhost:8774/.../servers/...", "rel"=>"bookmark"}], name="MyFirstServer", personality=nil, progress=0, accessIPv4="", accessIPv6="", availability_zone=nil, user_data_encoded=nil, state="ACTIVE", created=2013-02-20 10:36:37 UTC, updated=2013-02-20 10:37:24 UTC, tenant_id="ee1b6e1715644f2ca020c4190769d496", user_id="5b772e8e179249aeb7152742a4b4f6e9", key_name=nil, fault=nil, os_dcf_disk_config="MANUAL", os_ext_srv_attr_host="cn26.la-1-2.morphlabs.net", os_ext_srv_attr_hypervisor_hostname="cn26.la-1-2.morphlabs.net", os_ext_srv_attr_instance_name="instance-00000038", os_ext_sts_power_state=1, os_ext_sts_task_state=nil, os_ext_sts_vm_state="active" > ] >
  • 31.
    Volumes # Create a 1GB persistent volume >> compute.create_volume("MyFirstVolume", "Test Volume", 1000) # <Excon::Response:0x00000003257940 @headers={"X-Compute-Request-Id"=>"req-e98c1f91-d2b9-49cc-bf14-353fd8fa46be", "Location"=>"http://localhost:8774/v2/ee1b6e1715644f2ca020c4190769d496/os-volumes? ignore_awful_caching1361357305/664000aa-e275-4e86-a477-7be86927979b", "Content-Type"=>"application/json", "Content- Length"=>"311", "Date"=>"Wed, 20 Feb 2013 10:48:27 GMT"}, @status=200, @remote_ip="127.0.0.1", @body={"volume"=>{"status"=>"creating", "displayDescription"=>"Test Volume", "availabilityZone"=>"nova", "displayName"=>"MyFirstVolume", "attachments"=>[{}], "volumeType"=>nil, "snapshotId"=>nil, "metadata"=>{}, "id"=>"664000aa-e275-4e86-a477-7be86927979b", "createdAt"=>"2013-02-20T10:48:26.709904", "size"=>1000}}> # Query information about the current volumes for this tenant >> compute.list_volumes.body['volumes'].first {"status"=>"available", "displayDescription"=>"Test Volume", "availabilityZone"=>"nova", "displayName"=>"MyFirstVolume", "attachments"=>[{}], "volumeType"=>nil, "snapshotId"=>nil, "metadata"=>{}, "id"=>"664000aa-e275-4e86-a477-7be86927979b", "createdAt"=>"2013-02-20T10:48:26.000000", "size"=>1000} # Attach the Volume to the running server >> compute.attach_volume(compute.list_volumes.body['volumes'].first['id'], compute.servers.first.id, "vdc") #<Excon::Response:0x000000032b0680 @headers={"X-Compute-Request-Id"=>"req-b6a2bad1-b69d-4abc-a3e6-88d1fc044827", "Content-Type"=>"application/json", "Content-Length"=>"194", "Date"=>"Wed, 20 Feb 2013 10:54:12 GMT"}, @status=200, @remote_ip="127.0.0.1", @body={"volumeAttachment"=>{"device"=>"/dev/vdc", "serverId"=>"1334c522-ab51-403f- b694-0efd92ef0b10", "id"=>"664000aa-e275-4e86-a477-7be86927979b", "volumeId"=>"664000aa-e275-4e86-a477-7be86927979b"}}> # Check volumes by querying the Volumes collection >> compute.volumes.first <Fog::Compute::OpenStack::Volume id="664000aa-e275-4e86-a477-7be86927979b", name="MyFirstVolume", description="Test Volume", status="in-use", size=1000, type=nil, snapshot_id=nil, availability_zone="nova", created_at="2013-02-20T10:48:26.000000", attachments=[{"device"=>"/dev/vdc", "serverId"=>"1334c522-ab51-403f-b694-0efd92ef0b10", "id"=>"664000aa-e275-4e86- a477-7be86927979b", "volumeId"=>"664000aa-e275-4e86-a477-7be86927979b"}] >
  • 32.
    Cleanup # Remove the Volume from the instance >> compute.detach_volume(compute.servers.first.id, compute.list_volumes.body['volumes'].first['id']) #<Excon::Response:0x0000000338e278 @headers={"Content-Type"=>"text/html; charset=UTF-8", "Content-Length"=>"0", "Date"=>"Wed, 20 Feb 2013 10:58:10 GMT"}, @status=202, @remote_ip="127.0.0.1", @body=""> # Delete the Volume from the system >> compute.delete_volume(compute.list_volumes.body['volumes'].first['id']) #<Excon::Response:0x0000000339f6b8 @headers={"Content-Type"=>"text/html; charset=UTF-8", "Content-Length"=>"0", "Date"=>"Wed, 20 Feb 2013 10:59:22 GMT"}, @status=202, @remote_ip="127.0.0.1", @body=""> # Check volumes again >> compute.list_volumes.body['volumes'] # [] # Cleanup the system by deleting the instance compute.delete_server(servers.first['id']) #<Excon::Response:0x000000033b9dd8 @headers={"Content-Length"=>"0", "X-Compute-Request-Id"=>"req- ef6c799f-7832-4edf-9929-387d5957320a", "Content-Type"=>"application/json", "Date"=>"Wed, 20 Feb 2013 11:00:17 GMT"}, @status=204, @remote_ip="127.0.0.1", @body="">
  • 33.