1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Rackspace Orchestration Support

This commit is contained in:
Matt Darby 2014-12-11 11:27:19 -05:00
parent fedb21dfd8
commit 2e24b6eee5
32 changed files with 1197 additions and 0 deletions

View file

@ -11,3 +11,4 @@ require 'fog/rackspace/monitoring'
require 'fog/rackspace/queues'
require 'fog/rackspace/storage'
require 'fog/rackspace/networking'
require 'fog/rackspace/orchestration'

View file

@ -98,6 +98,7 @@ module Fog
service(:monitoring, 'Monitoring')
service(:queues, 'Queues')
service(:networking, 'Networking')
service(:orchestration, 'Orchestration')
def self.authenticate(options, connection_options = {})
rackspace_auth_url = options[:rackspace_auth_url]

View file

@ -0,0 +1,356 @@
# OpenStack Orchestration
The mission of the OpenStack Orchestration program is to create a human- and machine-accessible service for managing the entire lifecycle of infrastructure and applications within OpenStack clouds.
## Heat
Heat is the main project in the OpenStack Orchestration program. It implements an orchestration engine to launch multiple composite cloud applications based on templates in the form of text files that can be treated like code. A native Heat template format is evolving, but Heat also endeavours to provide compatibility with the AWS CloudFormation template format, so that many existing CloudFormation templates can be launched on OpenStack. Heat provides both an OpenStack-native ReST API and a CloudFormation-compatible Query API.
*Why Heat? It makes the clouds rise!*
**How it works**
* A Heat template describes the infrastructure for a cloud application in a text file that is readable and writable by humans, and can be checked into version control, diffed, &c.
* Infrastructure resources that can be described include: servers, floating ips, volumes, security groups, users, etc.
* Heat also provides an autoscaling service that integrates with Ceilometer, so you can include a scaling group as a resource in a template.
* Templates can also specify the relationships between resources (e.g. this volume is connected to this server). This enables Heat to call out to the OpenStack APIs to create all of your infrastructure in the correct order to completely launch your application.
* Heat manages the whole lifecycle of the application - when you need to change your infrastructure, simply modify the template and use it to update your existing stack. Heat knows how to make the necessary changes. It will delete all of the resources when you are finished with the application, too.
* Heat primarily manages infrastructure, but the templates integrate well with software configuration management tools such as Puppet and Chef. The Heat team is working on providing even better integration between infrastructure and software.
_Source: [OpenStack Wiki](https://wiki.openstack.org/wiki/Heat)_
# Rackspace Orchestration (Heat) Client
[Full Rackspace Orchestration/Heat API Docs](http://docs.rackspace.com/orchestration/api/v1/orchestration-devguide/content/API_Operations_dle7023.html)
## Orchestration Service
Get a handle on the Orchestration service:
```ruby
irb: service = Fog::Rackspace::Orchestration.new({
:rackspace_username => username,
:rackspace_api_key => api_key,
:rackspace_region => :iad #:ord, :dfw, :syd
})
===> #<Fog::Rackspace::Orchestration::Real:2168274880 ...
```
We will use this `service` to interact with the Orchestration resources, `stack`, `event`, `resource`, and `template`
## Stacks
Get a list of stacks you own:
```ruby
irb: service.stacks
===> <Fog::Rackspace::Orchestration::Stacks
[]
>
```
Create a new `stack` with a [Heat Template (HOT)](http://docs.openstack.org/developer/heat/template_guide/hot_guide.html). Here we are using Rackspace's HOT for [a single redis server]("https://github.com/rackspace-orchestration-templates/redis-single/blob/master/redis-single.yaml"):
```ruby
redis_template = File.read("spec/support/redis_template.yml")
===> "heat_template_version: 2013-05-23\n\ndescription: ....
irb: service.stacks.new.save({
:stack_name => "a_redis_stack",
:template => redis_template
})
```
We get back a JSON blob filled with info about our new stack:
```ruby
===> {"id"=>"73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "links"=>[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"self"}]}
```
Now that we have the `id` of our new stack, we can get a reference to it using the stack's `name` and `id`:
```ruby
irb: stack = service.stacks.get("a_redis_stack", "73e0f38a-a9fb-4a4e-8196-2b63039ef31f")
===> <Fog::Rackspace::Orchestration::Stack
id="73e0f38a-a9fb-4a4e-8196-2b63039ef31f",
description="This is a Heat template to deploy a standalone redis server on\nRackspace Cloud Servers\n",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"self"}],
stack_status_reason="Stack CREATE started",
stack_name="a_redis_stack",
creation_time="2014-11-13T16:21:02Z",
updated_time=nil
>
```
A stack knows about related `events`:
```ruby
irb: stack.events
===> <Fog::Rackspace::Orchestration::Events
[
<Fog::Rackspace::Orchestration::Event
id="7b1830a3-5d7b-43b2-bc1b-cffbb25c8b3e",
resource_name="redis_server_config",
event_time="2014-11-13T16:21:45Z",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f/resources/redis_server_config/events/7b1830a3-5d7b-43b2-bc1b-cffbb25c8b3e", "rel"=>"self"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f/resources/redis_server_config", "rel"=>"resource"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"stack"}],
logical_resource_id="redis_server_config",
resource_status="CREATE_IN_PROGRESS",
resource_status_reason="state changed",
physical_resource_id=nil
>,
```
A stack knows about related `resources`:
```ruby
irb: stack.resources
===> <Fog::Rackspace::Orchestration::Resources
[
<Fog::Rackspace::Orchestration::Resource
id=nil,
resource_name="redis_server",
description=nil,
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f/resources/redis_server", "rel"=>"self"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"stack"}],
logical_resource_id="redis_server",
resource_status="CREATE_COMPLETE",
updated_time="2014-11-13T16:21:04Z",
required_by=["redis_server_config"],
resource_status_reason="state changed",
resource_type="Rackspace::Cloud::Server"
>,
```
You can list, limit, sort stacks based on certain keywords:
** Available keywords:**
* status
* name
* limit
* marker
* sort_keys
* sort_dir
```ruby
irb: stacks = service.stacks.all(sort_key: "stack_name", sort_dir: "asc")
===> <Fog::Rackspace::Orchestration::Stacks
[
<Fog::Rackspace::Orchestration::Stack
id="73e0f38a-a9fb-4a4e-8196-2b63039ef31f",
description="This is a Heat template to deploy a standalone redis server on\nRackspace Cloud Servers\n",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"self"}],
stack_status_reason="Stack CREATE started",
stack_name="a_redis_stack",
creation_time="2014-11-13T16:21:02Z",
updated_time=nil
>
]
>
```
You can get a stack's `template`
```ruby
irb: stack.template
===> <Fog::Rackspace::Orchestration::Template
description="This is a Heat template to deploy a standalone redis server on\nRackspace Cloud Servers\n",
heat_template_version="2013-05-23",
....
```
You can abandon a stack -- essentially, it will delete the stack, but keep the resources around for potential further use:
```ruby
irb: stack.abandon
===> #<Excon::Response:0x00000104d6b870 @data={:body=>{"status"=>"IN_PROGRESS", "name"=>"a_redis_stack", "stack_user_project_id"=>"930035", "environment"=>{"parameters"=>{}, "resource_registry"=>{"resources"=>{}}}, "template"=>{"parameter_groups"=>[{"parameters"=>["flavor", "image"], "label"=>"Server Settings"}, {"parameters"=>["redis_port"], "label"=>"Redis Settings"}, {"parameters"=>["redis_version", "redis_hostname", "kitchen", "chef_version"], "label"=>"rax-dev-params"}], "heat_template_version"=>"2013-05-23", "description"=>"This is a Heat te
```
You can preview a stack:
```ruby
irb: service.stacks.preview({
:stack_name => "a_redis_template",
:template => redis_template
})
===> <Fog::Rackspace::Orchestration::Stack
id="None",
description="This is a Heat template to deploy a standalone redis server on\nRackspace Cloud Servers\n",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_template/None", "rel"=>"self"}],
stack_status_reason=nil,
stack_name="a_redis_template",
creation_time="2014-11-13T16:33:50Z",
updated_time=nil
>
```
Of course, you can just delete a stack. This deletes associated `resources` (as opposed to `abandon`):
```ruby
irb: stack.delete
===> #<Excon::Response:0x0000010198b000 @data={:body=>"", :headers=>{"Server"=>"nginx/1.2.1", "Date"=>"Thu, 13 Nov 2014 16:28:38 GMT", "Content-Type"=>"text/html; charset=UTF-8", "Connection"=>"keep-alive", "Via"=>"1.0 Repose (Repose/6.0.2)"}, :status=>204, :reason_phrase=>"No Content", :remote_ip=>"23.253.147.138", :local_port=>54721, :local_address=>"192.168.1.65"}, @body="", @headers={"Server"=>"nginx/1.2.1", "Date"=>"Thu, 13 Nov 2014 16:28:38 GMT", "Content-Type"=>"text/html; charset=UTF-8", "Connection"=>"keep-alive", "Via"=>"1.0 Repose (Repose/6.0.2)"}, @status=204, @remote_ip="23.253.147.138", @local_port=54721, @local_address="192.168.1.65">
```
Reload any object by calling `reload` on it:
```ruby
irb: stacks.reload
===> <Fog::Rackspace::Orchestration::Stacks
[]
>
```
You can get build information:
```ruby
irb: service.stacks.build_info
===> {"engine"=>{"revision"=>"2014.k1-20141027-1178"}, "fusion-api"=>{"revision"=>"j1-20140915-10d9ee4-98"}, "api"=>{"revision"=>"2014.k1-20141027-1178"}}
```
## Events
`Events` are indexable and can be scoped by `stack`:
```ruby
irb: event = stack.events.first
===> <Fog::Rackspace::Orchestration::Event
id="7b1830a3-5d7b-43b2-bc1b-cffbb25c8b3e",
resource_name="redis_server_config",
event_time="2014-11-13T16:21:45Z",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f/resources/redis_server_config/events/7b1830a3-5d7b-43b2-bc1b-cffbb25c8b3e", "rel"=>"self"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f/resources/redis_server_config", "rel"=>"resource"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"stack"}],
logical_resource_id="redis_server_config",
resource_status="CREATE_IN_PROGRESS",
resource_status_reason="state changed",
physical_resource_id=nil
>
```
`Events` can be sorted, limited, etc by passing an hash like so:
`service.events.all(stack, limit: 1)`
** Available keys: **
* resource_action
* resource_status
* resource_name
* resource_type
* limit
* marker
* sort_keys
* sort_dir
They are getable:
```ruby
irb: event = service.events.get(stack, resource, event_id)
===> <Fog::Rackspace::Orchestration::Event
id="7b1830a3-5d7b-43b2-bc1b-cffbb25c8b3e",
resource_name="redis_server_config",
event_time="2014-11-13T16:21:45Z",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f/resources/redis_server_config/events/7b1830a3-5d7b-43b2-bc1b-cffbb25c8b3e", "rel"=>"self"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f/resources/redis_server_config", "rel"=>"resource"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"stack"}],
logical_resource_id="redis_server_config",
resource_status="CREATE_IN_PROGRESS",
resource_status_reason="state changed",
physical_resource_id=nil
>
```
An `event` knows about its associated `stack`:
```ruby
irb: event.stack
===> <Fog::Rackspace::Orchestration::Stack
id="73e0f38a-a9fb-4a4e-8196-2b63039ef31f",
description="This is a Heat template to deploy a standalone redis server on\nRackspace Cloud Servers\n",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"self"}],
stack_status_reason="Stack CREATE completed successfully",
stack_name="a_redis_stack",
creation_time="2014-11-13T16:21:02Z",
updated_time=nil
>
```
You can list, limit, sort events based on certain keywords:
```ruby
irb: events = stack.events.all(stack, sort_key: "resource_name", sort_dir: "desc", limit: 3)
===> <Fog::Rackspace::Orchestration::Events
[
<Fog::Rackspace::Orchestration::Event
id="9cdae7d7-f44e-4dbb-bc0b-61ea6da9cf81",
resource_name="redis_server_config",
event_time="2014-11-13T16:24:07Z",
....
```
An `event` has an associated `resource`:
```ruby
irb: resource = event.resource
===> <Fog::Rackspace::Orchestration::Resource
id=nil,
resource_name="redis_server_config",
description="",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f/resources/redis_server_config", "rel"=>"self"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"stack"}],
logical_resource_id="redis_server_config",
resource_status="CREATE_COMPLETE",
updated_time="2014-11-13T16:21:45Z",
required_by=[],
resource_status_reason="state changed",
resource_type="OS::Heat::ChefSolo"
>
```
## Resource
`resources` are indexable:
```ruby
irb: service.resources.all(stack, {nested_depth: 1})
===> <Fog::Rackspace::Orchestration::Resources
[
<Fog::Rackspace::Orchestration::Resource
id=nil,
resource_name="redis_server",
description=nil,
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/ee648a3b-14a3-4df8-aa58-620a9d67e3e5/resources/redis_server", "rel"=>"self"}, {"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/ee648a3b-14a3-4df8-aa58-620a9d67e3e5", "rel"=>"stack"}],
logical_resource_id="redis_server",
resource_status="CREATE_COMPLETE",
updated_time="2014-11-13T16:32:30Z",
required_by=["redis_server_config"],
resource_status_reason="state changed",
resource_type="Rackspace::Cloud::Server"
>,
...
```
A `resource` knows about its associated `stack`:
```ruby
irb: resource.stack
===> <Fog::Rackspace::Orchestration::Stack
id="73e0f38a-a9fb-4a4e-8196-2b63039ef31f",
description="This is a Heat template to deploy a standalone redis server on\nRackspace Cloud Servers\n",
links=[{"href"=>"https://iad.orchestration.api.rackspacecloud.com/v1/930035/stacks/a_redis_stack/73e0f38a-a9fb-4a4e-8196-2b63039ef31f", "rel"=>"self"}],
stack_status_reason="Stack CREATE completed successfully",
stack_name="a_redis_stack",
creation_time="2014-11-13T16:21:02Z",
updated_time=nil
>
```
Resource metadata is visible:
```ruby
irb: resource.metadata
===> {}
```
A `resource's` template is visible (if one exists)
```ruby
irb: resource.template
===> nil
```
## Validation
You can validate a Heat template (HOT) before using it:
```ruby
irb: service.templates.validate({:template => redis_template})
===> <Fog::Rackspace::Orchestration::Template
description="This is a Heat template to deploy a standalone redis server on\nRackspace Cloud Servers\n",
heat_template_version=nil,
...
```

View file

@ -0,0 +1,18 @@
module Fog
module Rackspace
class Orchestration
class Event < Fog::Model
include Reflectable
identity :id
%w{resource_name event_time links logical_resource_id resource_status
resource_status_reason physical_resource_id}.each do |a|
attribute a.to_sym
end
end
end
end
end

View file

@ -0,0 +1,28 @@
require 'fog/rackspace/models/orchestration/event'
module Fog
module Rackspace
class Orchestration
class Events < Fog::Collection
model Fog::Rackspace::Orchestration::Event
def all(obj, options={})
data = if obj.is_a?(Stack)
service.list_stack_events(obj, options).body['events']
else
service.list_resource_events(obj.stack, obj, options).body['events']
end
load data
end
def get(stack, resource, event_id)
data = service.show_event_details(stack, resource, event_id).body['event']
new(data)
rescue Fog::Rackspace::Orchestration::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,30 @@
module Fog
module Rackspace
class Orchestration
class Resource < Fog::Model
include Reflectable
identity :id
%w{resource_name description links logical_resource_id resource_status
updated_time required_by resource_status_reason resource_type}.each do |a|
attribute a.to_sym
end
def events(options={})
@events ||= service.events.all(self, options)
end
def metadata
@metadata ||= service.show_resource_metadata(stack, self.resource_name).body['metadata']
end
def template
@template ||= service.templates.get(self)
end
end
end
end
end

View file

@ -0,0 +1,16 @@
module Fog
module Rackspace
class Orchestration
class ResourceSchemas < Fog::Collection
def get(resource_type)
service.show_resource_schema(resource_type).body
rescue Fog::Rackspace::Orchestration::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,35 @@
require 'fog/rackspace/models/orchestration/resource'
module Fog
module Rackspace
class Orchestration
class Resources < Fog::Collection
model Fog::Rackspace::Orchestration::Resource
def types
service.list_resource_types.body['resource_types'].sort
end
def all(stack, options={})
data = service.list_resources(stack, options).body['resources']
load(data)
end
def get(resource_name, stack=nil)
stack = self.first.stack if stack.nil?
data = service.show_resource_data(stack.stack_name, stack.id, resource_name).body['resource']
new(data)
rescue Fog::Rackspace::Orchestration::NotFound
nil
end
def metadata(stack_name, stack_id, resource_name)
service.show_resource_metadata(stack_name, stack_id, resource_name).body['resource']
rescue Fog::Rackspace::Orchestration::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,48 @@
module Fog
module Rackspace
class Orchestration
class Stack < Fog::Model
identity :id
%w{description links stack_status_reason stack_name creation_time updated_time}.each do |a|
attribute a.to_sym
end
def details
service.show_stack_details(self.stack_name, self.id).body['stack']
rescue Fog::Rackspace::Orchestration::NotFound
nil
end
def resources
@resources ||= service.resources.all(self)
end
def events(options={})
@events ||= service.events.all(self, options)
end
def template
@template ||= service.templates.get(self)
end
def save(options={})
if persisted?
service.update_stack(self, options).body['stack']
else
service.stacks.create(options)
end
end
def abandon
service.abandon_stack(self)
end
def delete
service.delete_stack(self)
end
end
end
end
end

View file

@ -0,0 +1,40 @@
require 'fog/rackspace/models/orchestration/stack'
module Fog
module Rackspace
class Orchestration
class Stacks < Fog::Collection
model Fog::Rackspace::Orchestration::Stack
def all(options={})
data = service.list_stack_data(options).body['stacks']
load(data)
end
def get(name, id)
data = service.show_stack_details(name, id).body['stack']
new(data)
rescue Fog::Rackspace::Orchestration::NotFound
nil
end
def adopt(options={})
service.create_stack(options)
end
def create(options={})
service.create_stack(options).body['stack']
end
def preview(options={})
data = service.preview_stack(options).body['stack']
new(data)
end
def build_info
service.build_info.body
end
end
end
end
end

View file

@ -0,0 +1,13 @@
module Fog
module Rackspace
class Orchestration
class Template < Fog::Model
%w{description heat_template_version parameters resources}.each do |a|
attribute a.to_sym
end
end
end
end
end

View file

@ -0,0 +1,31 @@
require 'fog/rackspace/models/orchestration/template'
module Fog
module Rackspace
class Orchestration
class Templates < Fog::Collection
model Fog::Rackspace::Orchestration::Template
def get(obj)
data = if obj.is_a?(Stack)
service.get_stack_template(obj).body
else
service.show_resource_template(obj.resource_name).body
end
new(data)
rescue Fog::Rackspace::Orchestration::NotFound
nil
end
def validate(options={})
data = service.validate_template(options).body
temp = new
temp.parameters = data['Parameters']
temp.description = data['Description']
temp
end
end
end
end
end

View file

@ -0,0 +1,227 @@
require 'fog/rackspace/core'
module Fog
module Rackspace
class Orchestration < Fog::Service
include Fog::Rackspace::Errors
class ServiceError < Fog::Rackspace::Errors::ServiceError; end
class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end
class BadRequest < Fog::Rackspace::Errors::BadRequest; end
ORCHESTRATION_DFW_URL = "https://dfw.orchestration.api.rackspacecloud.com/v1"
ORCHESTRATION_LON_URL = "https://lon.orchestration.api.rackspacecloud.com/v1"
ORCHESTRATION_IAD_URL = "https://iad.orchestration.api.rackspacecloud.com/v1"
ORCHESTRATION_ORD_URL = "https://ord.orchestration.api.rackspacecloud.com/v1"
requires :rackspace_username, :rackspace_api_key
recognizes :rackspace_endpoint
recognizes :rackspace_auth_url
recognizes :rackspace_auth_token
recognizes :rackspace_region
recognizes :rackspace_orchestration_url
model_path 'fog/rackspace/models/orchestration'
model :stack
collection :stacks
model :resource
collection :resources
collection :resource_schemas
model :event
collection :events
model :template
collection :templates
request_path 'fog/rackspace/requests/orchestration'
request :abandon_stack
request :build_info
request :create_stack
request :delete_stack
request :get_stack_template
request :list_resource_events
request :list_resource_types
request :list_resources
request :list_stack_data
request :list_stack_events
request :preview_stack
request :show_event_details
request :show_resource_data
request :show_resource_metadata
request :show_resource_schema
request :show_resource_template
request :show_stack_details
request :update_stack
request :validate_template
## Redundant / Redirect requests:
# request :adopt_stack => :create_stack
# request :find_stack => :show_stack_details
# request :find_stack_events => :list_stack_events
# request :find_stack_resources => :list_resources
module Reflectable
REFLECTION_REGEX = /\/stacks\/(\w+)\/([\w|-]+)\/resources\/(\w+)/
def resource
@resource ||= service.resources.get(r[3], stack)
end
def stack
@stack ||= service.stacks.get(r[1], r[2])
end
private
def reflection
@reflection ||= REFLECTION_REGEX.match(self.links[0]['href'])
end
alias :r :reflection
end
class Mock < Fog::Rackspace::Service
include Fog::Rackspace::MockData
def initialize(options)
@rackspace_api_key = options[:rackspace_api_key]
end
def request(params)
Fog::Mock.not_implemented
end
def response(params={})
body = params[:body] || {}
status = params[:status] || 200
headers = params[:headers] || {}
response = Excon::Response.new(:body => body, :headers => headers, :status => status)
if params.key?(:expects) && ![*params[:expects]].include?(response.status)
raise(Excon::Errors.status_error(params, response))
else response
end
end
end
class Real < Fog::Rackspace::Service
def initialize(options = {})
@rackspace_api_key = options[:rackspace_api_key]
@rackspace_username = options[:rackspace_username]
@rackspace_auth_url = options[:rackspace_auth_url]
setup_custom_endpoint(options)
@rackspace_must_reauthenticate = false
@connection_options = options[:connection_options] || {}
authenticate
deprecation_warnings(options)
@persistent = options[:persistent] || false
@connection = Fog::Core::Connection.new(endpoint_uri.to_s, @persistent, @connection_options)
end
def request(params, parse_json = true)
super
rescue Excon::Errors::NotFound => error
raise NotFound.slurp(error, self)
rescue Excon::Errors::BadRequest => error
raise BadRequest.slurp(error, self)
rescue Excon::Errors::InternalServerError => error
raise InternalServerError.slurp(error, self)
rescue Excon::Errors::HTTPStatusError => error
raise ServiceError.slurp(error, self)
end
def authenticate(options={})
super({
:rackspace_api_key => @rackspace_api_key,
:rackspace_username => @rackspace_username,
:rackspace_auth_url => @rackspace_auth_url,
:connection_options => @connection_options
})
end
def service_name
:cloudOrchestration
end
def request_id_header
"x-orchestration-request-id"
end
def region
@rackspace_region
end
def endpoint_uri(service_endpoint_url=nil)
@uri = super(@rackspace_endpoint || service_endpoint_url, :rackspace_orchestration_url)
end
def request_uri(path, options={})
return path if options == {}
require "addressable/uri"
Addressable::URI.new({:path=>path, :query_values=>options}).request_uri
end
private
def setup_custom_endpoint(options)
@rackspace_endpoint = Fog::Rackspace.normalize_url(options[:rackspace_orchestration_url] || options[:rackspace_endpoint])
if v2_authentication?
case @rackspace_endpoint
when ORCHESTRATION_DFW_URL
@rackspace_endpoint = nil
@rackspace_region = :dfw
when ORCHESTRATION_ORD_URL
@rackspace_endpoint = nil
@rackspace_region = :ord
when ORCHESTRATION_IAD_URL
@rackspace_endpoint = nil
@rackspace_region = :iad
when ORCHESTRATION_LON_URL
@rackspace_endpoint = nil
@rackspace_region = :lon
else
# we are actually using a custom endpoint
@rackspace_region = options[:rackspace_region]
end
else
#if we are using auth1 and the endpoint is not set, default to DFW_URL for historical reasons
@rackspace_endpoint ||= ORCHESTRATION_DFW_URL
end
end
def deprecation_warnings(options)
Fog::Logger.deprecation("The :rackspace_endpoint option is deprecated. Please use :rackspace_orchestration_url for custom endpoints") if options[:rackspace_endpoint]
if [ORCHESTRATION_DFW_URL, ORCHESTRATION_ORD_URL, ORCHESTRATION_IAD_URL, ORCHESTRATION_LON_URL].include?(@rackspace_endpoint) && v2_authentication?
regions = @identity_service.service_catalog.display_service_regions(service_name)
Fog::Logger.deprecation("Please specify region using :rackspace_region rather than :rackspace_endpoint. Valid regions for :rackspace_region are #{regions}.")
end
end
def append_tenant_v1(credentials)
account_id = credentials['X-Server-Management-Url'].match(/.*\/([\d]+)$/)[1]
endpoint = @rackspace_endpoint || credentials['X-Server-Management-Url'] || ORCHESTRATION_DFW_URL
@uri = URI.parse(endpoint)
@uri.path = "#{@uri.path}/#{account_id}"
end
def authenticate_v1(options)
credentials = Fog::Rackspace.authenticate(options, @connection_options)
append_tenant_v1 credentials
@auth_token = credentials['X-Auth-Token']
end
end
end
end
end

View file

@ -0,0 +1,15 @@
module Fog
module Rackspace
class Orchestration
class Real
def abandon_stack(stack)
request(
:expects => [200],
:method => 'DELETE',
:path => "stacks/#{stack.stack_name}/#{stack.id}/abandon"
)
end
end
end
end
end

View file

@ -0,0 +1,15 @@
module Fog
module Rackspace
class Orchestration
class Real
def build_info
request(
:expects => [200],
:method => 'GET',
:path => 'build_info'
)
end
end
end
end
end

View file

@ -0,0 +1,16 @@
module Fog
module Rackspace
class Orchestration
class Real
def create_stack(options={})
request(
:body => Fog::JSON.encode(options),
:expects => [201],
:method => 'POST',
:path => "stacks"
)
end
end
end
end
end

View file

@ -0,0 +1,15 @@
module Fog
module Rackspace
class Orchestration
class Real
def delete_stack(stack)
request(
:expects => [204],
:method => 'DELETE',
:path => "stacks/#{stack.stack_name}/#{stack.id}"
)
end
end
end
end
end

View file

@ -0,0 +1,20 @@
module Fog
module Rackspace
class Orchestration
class Real
def get_stack_template(stack)
request(
:method => 'GET',
:path => "stacks/#{stack.stack_name}/#{stack.id}/template",
:expects => 200
)
end
end
class Mock
def get_stack_template(stack)
end
end
end
end
end

View file

@ -0,0 +1,19 @@
module Fog
module Rackspace
class Orchestration
class Real
def list_resource_events(stack, resource, options={})
uri = request_uri("stacks/#{stack.stack_name}/#{stack.id}/resources/#{resource.resource_name}/events", options)
request(:method => 'GET', :path => uri, :expects => 200)
end
end
class Mock
def list_stack_events
events = self.data[:events].values
response(:body => { 'events' => events })
end
end
end
end
end

View file

@ -0,0 +1,22 @@
module Fog
module Rackspace
class Orchestration
class Real
def list_resource_types
request(
:method => 'GET',
:path => "resource_types",
:expects => 200
)
end
end
class Mock
def list_resource_types
resources = self.data[:resource_types].values
response(:body => { 'resource_types' => resources })
end
end
end
end
end

View file

@ -0,0 +1,19 @@
module Fog
module Rackspace
class Orchestration
class Real
def list_resources(stack, options={})
uri = request_uri("stacks/#{stack.stack_name}/#{stack.id}/resources", options)
request(:method => 'GET', :path => uri, :expects => 200)
end
end
class Mock
def list_resources(stack)
resources = self.data[:resources].values
response(:body => { 'resources' => resources })
end
end
end
end
end

View file

@ -0,0 +1,22 @@
module Fog
module Rackspace
class Orchestration
class Real
def list_stack_data(options={})
request(
:method => 'GET',
:path => request_uri("stacks", options),
:expects => 200
)
end
end
class Mock
def list_stack_data
stacks = self.data[:stacks].values
response(:body => { 'stacks' => stacks })
end
end
end
end
end

View file

@ -0,0 +1,19 @@
module Fog
module Rackspace
class Orchestration
class Real
def list_stack_events(stack, options={})
uri = request_uri("stacks/#{stack.stack_name}/#{stack.id}/events", options)
request(:method => 'GET', :path => uri, :expects => 200)
end
end
class Mock
def list_stack_events
events = self.data[:events].values
response(:body => { 'events' => events })
end
end
end
end
end

View file

@ -0,0 +1,16 @@
module Fog
module Rackspace
class Orchestration
class Real
def preview_stack(options = {})
request(
:body => Fog::JSON.encode(options),
:expects => [200],
:method => 'POST',
:path => 'stacks/preview'
)
end
end
end
end
end

View file

@ -0,0 +1,22 @@
module Fog
module Rackspace
class Orchestration
class Real
def show_event_details(stack, resource, event_id)
request(
:method => 'GET',
:path => "stacks/#{stack.stack_name}/#{stack.id}/resources/#{resource.resource_name}/events/#{event_id}",
:expects => 200
)
end
end
class Mock
def show_event_details(stack, event)
events = self.data[:events].values
response(:body => { 'events' => events })
end
end
end
end
end

View file

@ -0,0 +1,22 @@
module Fog
module Rackspace
class Orchestration
class Real
def show_resource_data(stack_name, stack_id, resource_name)
request(
:method => 'GET',
:path => "stacks/#{stack_name}/#{stack_id}/resources/#{resource_name}",
:expects => 200
)
end
end
class Mock
def show_resource_data(stack_name, stack_id, resource_name)
resources = self.data[:resources].values
response(:body => { 'resources' => resources })
end
end
end
end
end

View file

@ -0,0 +1,22 @@
module Fog
module Rackspace
class Orchestration
class Real
def show_resource_metadata(stack, resource_name)
request(
:method => 'GET',
:path => "stacks/#{stack.stack_name}/#{stack.id}/resources/#{resource_name}/metadata",
:expects => 200
)
end
end
class Mock
def show_resource_metadata(stack, resource_name)
resources = self.data[:resources].values
response(:body => { 'resources' => resources })
end
end
end
end
end

View file

@ -0,0 +1,15 @@
module Fog
module Rackspace
class Orchestration
class Real
def show_resource_schema(name)
request(
:method => 'GET',
:path => "resource_types/#{name}",
:expects => 200
)
end
end
end
end
end

View file

@ -0,0 +1,20 @@
module Fog
module Rackspace
class Orchestration
class Real
def show_resource_template(name)
request(
:method => 'GET',
:path => "resource_types/#{name}/template",
:expects => 200
)
end
end
class Mock
def show_resource_template(name)
end
end
end
end
end

View file

@ -0,0 +1,22 @@
module Fog
module Rackspace
class Orchestration
class Real
def show_stack_details(name, id)
request(
:method => 'GET',
:path => "stacks/#{name}/#{id}",
:expects => 200
)
end
end
class Mock
def show_stack_details(name, id)
stack = self.data[:stack].values
response(:body => { 'stack' => stack })
end
end
end
end
end

View file

@ -0,0 +1,16 @@
module Fog
module Rackspace
class Orchestration
class Real
def update_stack(stack, options = {})
request(
:body => Fog::JSON.encode(options),
:expects => [202],
:method => 'PUT',
:path => "stacks/#{stack.stack_name}/#{stack.id}"
)
end
end
end
end
end

View file

@ -0,0 +1,16 @@
module Fog
module Rackspace
class Orchestration
class Real
def validate_template(options = {})
request(
:body => Fog::JSON.encode(options),
:expects => [200],
:method => 'POST',
:path => 'validate'
)
end
end
end
end
end