mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
CRUD for OpenStack heat's Stack model
This commit is contained in:
parent
a2e2f1cc61
commit
ecef54c8bc
10 changed files with 445 additions and 0 deletions
|
@ -47,3 +47,4 @@ require 'fog/cdn'
|
||||||
require 'fog/dns'
|
require 'fog/dns'
|
||||||
require 'fog/network'
|
require 'fog/network'
|
||||||
require 'fog/storage'
|
require 'fog/storage'
|
||||||
|
require 'fog/orchestration'
|
||||||
|
|
|
@ -48,6 +48,7 @@ module Fog
|
||||||
service(:storage, 'openstack/storage', 'Storage')
|
service(:storage, 'openstack/storage', 'Storage')
|
||||||
service(:volume, 'openstack/volume', 'Volume')
|
service(:volume, 'openstack/volume', 'Volume')
|
||||||
service(:metering, 'openstack/metering', 'Metering')
|
service(:metering, 'openstack/metering', 'Metering')
|
||||||
|
service(:orchestration, 'openstack/orchestration', 'Orchestration')
|
||||||
|
|
||||||
def self.authenticate(options, connection_options = {})
|
def self.authenticate(options, connection_options = {})
|
||||||
case options[:openstack_auth_uri].path
|
case options[:openstack_auth_uri].path
|
||||||
|
|
52
lib/fog/openstack/models/orchestration/stack.rb
Normal file
52
lib/fog/openstack/models/orchestration/stack.rb
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
require 'fog/core/model'
|
||||||
|
|
||||||
|
module Fog
|
||||||
|
module Orchestration
|
||||||
|
class OpenStack
|
||||||
|
class Stack < Fog::Model
|
||||||
|
identity :id
|
||||||
|
|
||||||
|
attribute :stack_name
|
||||||
|
attribute :stack_status
|
||||||
|
attribute :stack_status_reason
|
||||||
|
attribute :creation_time
|
||||||
|
attribute :updated_time
|
||||||
|
attribute :id
|
||||||
|
|
||||||
|
attribute :template_url
|
||||||
|
attribute :template
|
||||||
|
attribute :parameters
|
||||||
|
attribute :timeout_in_minutes
|
||||||
|
|
||||||
|
def initialize(attributes)
|
||||||
|
# Old 'connection' is renamed as service and should be used instead
|
||||||
|
prepare_service_value(attributes)
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
requires :stack_name
|
||||||
|
identity ? update : create
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
requires :stack_name
|
||||||
|
service.create_stack(stack_name, self.attributes)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
requires :stack_name
|
||||||
|
service.update_stack(stack_name, self.attributes)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
requires :id
|
||||||
|
service.delete_stack(self.stack_name, self.id)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
21
lib/fog/openstack/models/orchestration/stacks.rb
Normal file
21
lib/fog/openstack/models/orchestration/stacks.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
require 'fog/core/collection'
|
||||||
|
require 'fog/openstack/models/orchestration/stack'
|
||||||
|
|
||||||
|
module Fog
|
||||||
|
module Orchestration
|
||||||
|
class OpenStack
|
||||||
|
class Stacks < Fog::Collection
|
||||||
|
model Fog::Orchestration::OpenStack::Stack
|
||||||
|
|
||||||
|
def all
|
||||||
|
load(service.list_stacks.body['stacks'])
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_by_id(id)
|
||||||
|
self.find {|stack| stack.id == id}
|
||||||
|
end
|
||||||
|
alias_method :get, :find_by_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
181
lib/fog/openstack/orchestration.rb
Normal file
181
lib/fog/openstack/orchestration.rb
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
require 'fog/aws/cloud_formation'
|
||||||
|
|
||||||
|
module Fog
|
||||||
|
module Orchestration
|
||||||
|
class OpenStack < Fog::Service
|
||||||
|
requires :openstack_auth_url
|
||||||
|
recognizes :openstack_auth_token, :openstack_management_url,
|
||||||
|
:persistent, :openstack_service_type, :openstack_service_name,
|
||||||
|
:openstack_tenant,
|
||||||
|
:openstack_api_key, :openstack_username, :openstack_identity_endpoint,
|
||||||
|
:current_user, :current_tenant, :openstack_region,
|
||||||
|
:openstack_endpoint_type
|
||||||
|
|
||||||
|
model_path 'fog/openstack/models/orchestration'
|
||||||
|
model :stack
|
||||||
|
collection :stacks
|
||||||
|
|
||||||
|
request_path 'fog/openstack/requests/orchestration'
|
||||||
|
request :create_stack
|
||||||
|
request :update_stack
|
||||||
|
request :delete_stack
|
||||||
|
request :list_stacks
|
||||||
|
|
||||||
|
class Mock
|
||||||
|
|
||||||
|
def initialize(options={})
|
||||||
|
Fog::Mock.not_implemented
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Real
|
||||||
|
attr_reader :auth_token
|
||||||
|
attr_reader :auth_token_expiration
|
||||||
|
attr_reader :current_user
|
||||||
|
attr_reader :current_tenant
|
||||||
|
|
||||||
|
def initialize(options={})
|
||||||
|
@openstack_auth_token = options[:openstack_auth_token]
|
||||||
|
@auth_token = options[:openstack_auth_token]
|
||||||
|
@openstack_identity_public_endpoint = options[:openstack_identity_endpoint]
|
||||||
|
|
||||||
|
unless @auth_token
|
||||||
|
missing_credentials = Array.new
|
||||||
|
@openstack_api_key = options[:openstack_api_key]
|
||||||
|
@openstack_username = options[:openstack_username]
|
||||||
|
|
||||||
|
missing_credentials << :openstack_api_key unless @openstack_api_key
|
||||||
|
missing_credentials << :openstack_username unless @openstack_username
|
||||||
|
raise ArgumentError, "Missing required arguments: #{missing_credentials.join(', ')}" unless missing_credentials.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
@openstack_tenant = options[:openstack_tenant]
|
||||||
|
@openstack_auth_uri = URI.parse(options[:openstack_auth_url])
|
||||||
|
@openstack_management_url = options[:openstack_management_url]
|
||||||
|
@openstack_must_reauthenticate = false
|
||||||
|
@openstack_service_type = options[:openstack_service_type] || ['orchestration']
|
||||||
|
@openstack_service_name = options[:openstack_service_name]
|
||||||
|
@openstack_identity_service_type = options[:openstack_identity_service_type] || 'identity'
|
||||||
|
@openstack_endpoint_type = options[:openstack_endpoint_type] || 'publicURL'
|
||||||
|
@openstack_region = options[:openstack_region]
|
||||||
|
|
||||||
|
@connection_options = options[:connection_options] || {}
|
||||||
|
|
||||||
|
@current_user = options[:current_user]
|
||||||
|
@current_tenant = options[:current_tenant]
|
||||||
|
|
||||||
|
authenticate
|
||||||
|
|
||||||
|
@persistent = options[:persistent] || false
|
||||||
|
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def credentials
|
||||||
|
{ :provider => 'openstack',
|
||||||
|
:openstack_auth_url => @openstack_auth_uri.to_s,
|
||||||
|
:openstack_auth_token => @auth_token,
|
||||||
|
:openstack_management_url => @openstack_management_url,
|
||||||
|
:openstack_identity_endpoint => @openstack_identity_public_endpoint,
|
||||||
|
:openstack_region => @openstack_region,
|
||||||
|
:current_user => @current_user,
|
||||||
|
:current_tenant => @current_tenant }
|
||||||
|
end
|
||||||
|
|
||||||
|
def reload
|
||||||
|
@connection.reset
|
||||||
|
end
|
||||||
|
|
||||||
|
def request(params)
|
||||||
|
begin
|
||||||
|
response = @connection.request(params.merge({
|
||||||
|
:headers => {
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'X-Auth-Token' => @auth_token
|
||||||
|
}.merge!(params[:headers] || {}),
|
||||||
|
:host => @host,
|
||||||
|
:path => "#{@path}/#{@tenant_id}/#{params[:path]}",
|
||||||
|
:query => params[:query]
|
||||||
|
}))
|
||||||
|
rescue Excon::Errors::Unauthorized => error
|
||||||
|
if error.response.body != 'Bad username or password' # token expiration
|
||||||
|
@openstack_must_reauthenticate = true
|
||||||
|
authenticate
|
||||||
|
retry
|
||||||
|
else # Bad Credentials
|
||||||
|
raise error
|
||||||
|
end
|
||||||
|
rescue Excon::Errors::HTTPStatusError => error
|
||||||
|
raise case error
|
||||||
|
when Excon::Errors::NotFound
|
||||||
|
Fog::Compute::OpenStack::NotFound.slurp(error)
|
||||||
|
else
|
||||||
|
error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if response.status == 200 && !response.body.empty?
|
||||||
|
response.body = Fog::JSON.decode(response.body)
|
||||||
|
end
|
||||||
|
|
||||||
|
response
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def authenticate
|
||||||
|
if !@openstack_management_url || @openstack_must_reauthenticate
|
||||||
|
options = {
|
||||||
|
:openstack_api_key => @openstack_api_key,
|
||||||
|
:openstack_username => @openstack_username,
|
||||||
|
:openstack_auth_token => @auth_token,
|
||||||
|
:openstack_auth_uri => @openstack_auth_uri,
|
||||||
|
:openstack_region => @openstack_region,
|
||||||
|
:openstack_tenant => @openstack_tenant,
|
||||||
|
:openstack_service_type => @openstack_service_type,
|
||||||
|
:openstack_service_name => @openstack_service_name,
|
||||||
|
:openstack_identity_service_type => @openstack_identity_service_type,
|
||||||
|
:openstack_endpoint_type => @openstack_endpoint_type
|
||||||
|
}
|
||||||
|
|
||||||
|
if @openstack_auth_uri.path =~ /\/v2.0\//
|
||||||
|
|
||||||
|
credentials = Fog::OpenStack.authenticate_v2(options, @connection_options)
|
||||||
|
else
|
||||||
|
credentials = Fog::OpenStack.authenticate_v1(options, @connection_options)
|
||||||
|
end
|
||||||
|
|
||||||
|
@current_user = credentials[:user]
|
||||||
|
@current_tenant = credentials[:tenant]
|
||||||
|
|
||||||
|
@openstack_must_reauthenticate = false
|
||||||
|
@auth_token = credentials[:token]
|
||||||
|
@auth_token_expiration = credentials[:expires]
|
||||||
|
@openstack_management_url = credentials[:server_management_url]
|
||||||
|
@openstack_identity_public_endpoint = credentials[:identity_public_endpoint]
|
||||||
|
end
|
||||||
|
|
||||||
|
uri = URI.parse(@openstack_management_url)
|
||||||
|
@host = uri.host
|
||||||
|
@path, @tenant_id = uri.path.scan(/(\/.*)\/(.*)/).flatten
|
||||||
|
|
||||||
|
@path.sub!(/\/$/, '')
|
||||||
|
|
||||||
|
@port = uri.port
|
||||||
|
@scheme = uri.scheme
|
||||||
|
|
||||||
|
# Not all implementations have identity service in the catalog
|
||||||
|
if @openstack_identity_public_endpoint || @openstack_management_url
|
||||||
|
@identity_connection = Fog::Connection.new(
|
||||||
|
@openstack_identity_public_endpoint || @openstack_management_url,
|
||||||
|
false, @connection_options)
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
43
lib/fog/openstack/requests/orchestration/create_stack.rb
Normal file
43
lib/fog/openstack/requests/orchestration/create_stack.rb
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
module Fog
|
||||||
|
module Orchestration
|
||||||
|
class OpenStack
|
||||||
|
class Real
|
||||||
|
|
||||||
|
# Create a stack.
|
||||||
|
#
|
||||||
|
# * stack_name [String] Name of the stack to create.
|
||||||
|
# * options [Hash]:
|
||||||
|
# * :template_body [String] Structure containing the template body.
|
||||||
|
# or (one of the two Template parameters is required)
|
||||||
|
# * :template_url [String] URL of file containing the template body.
|
||||||
|
# * :disable_rollback [Boolean] Controls rollback on stack creation failure, defaults to false.
|
||||||
|
# * :parameters [Hash] Hash of providers to supply to template
|
||||||
|
# * :timeout_in_minutes [Integer] Minutes to wait before status is set to CREATE_FAILED
|
||||||
|
#
|
||||||
|
# @see http://docs.amazonwebservices.com/AWSCloudFormation/latest/APIReference/API_CreateStack.html
|
||||||
|
|
||||||
|
def create_stack(stack_name, options = {})
|
||||||
|
params = {
|
||||||
|
:stack_name => stack_name
|
||||||
|
}.merge(options)
|
||||||
|
|
||||||
|
request(
|
||||||
|
:path => 'stacks',
|
||||||
|
:method => 'POST',
|
||||||
|
:body => MultiJson.encode(params)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Mock
|
||||||
|
def create_stack(stack_name, options = {})
|
||||||
|
response = Excon::Response.new
|
||||||
|
response.status = 202
|
||||||
|
response.body = {}
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
34
lib/fog/openstack/requests/orchestration/delete_stack.rb
Normal file
34
lib/fog/openstack/requests/orchestration/delete_stack.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
module Fog
|
||||||
|
module Orchestration
|
||||||
|
class OpenStack
|
||||||
|
class Real
|
||||||
|
|
||||||
|
# Delete a stack.
|
||||||
|
#
|
||||||
|
# @param stack_name [String] Name of the stack to delete.
|
||||||
|
# @param stack_id [String] ID of the stack to delete.
|
||||||
|
#
|
||||||
|
# @return [Excon::Response]
|
||||||
|
#
|
||||||
|
# @see http://docs.amazonwebservices.com/AWSCloudFormation/latest/APIReference/API_DeleteStack.html
|
||||||
|
|
||||||
|
def delete_stack(stack_name, stack_id)
|
||||||
|
request(
|
||||||
|
:path => "stacks/#{stack_name}/#{stack_id}",
|
||||||
|
:method => 'DELETE'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Mock
|
||||||
|
def delete_stack(stack_name, stack_id)
|
||||||
|
response = Excon::Response.new
|
||||||
|
response.status = 202
|
||||||
|
response.body = {}
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
46
lib/fog/openstack/requests/orchestration/list_stacks.rb
Normal file
46
lib/fog/openstack/requests/orchestration/list_stacks.rb
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
module Fog
|
||||||
|
module Orchestration
|
||||||
|
class OpenStack
|
||||||
|
class Real
|
||||||
|
|
||||||
|
# List stacks.
|
||||||
|
#
|
||||||
|
# @param options [Hash]
|
||||||
|
#
|
||||||
|
# @return [Excon::Response]
|
||||||
|
# * body [Hash]:
|
||||||
|
# * stacks [Array] - Matching stacks
|
||||||
|
# * stack [Hash]:
|
||||||
|
# * id [String] -
|
||||||
|
# * stack_name [String] -
|
||||||
|
# * description [String]
|
||||||
|
# * links [Array]
|
||||||
|
# * stack_status [String] -
|
||||||
|
# * stack_status_reason [String]
|
||||||
|
# * creation_time [Time] -
|
||||||
|
# * updated_time [Time] -
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# @see http://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_ListStacks.html
|
||||||
|
|
||||||
|
def list_stacks(options = {})
|
||||||
|
request(
|
||||||
|
:path => 'stacks',
|
||||||
|
:method => 'GET',
|
||||||
|
:query => options
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Mock
|
||||||
|
def list_stacks(options = {})
|
||||||
|
Excon::Response.new(
|
||||||
|
:body => { 'stacks' => [] },
|
||||||
|
:status => 200
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
41
lib/fog/openstack/requests/orchestration/update_stack.rb
Normal file
41
lib/fog/openstack/requests/orchestration/update_stack.rb
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
module Fog
|
||||||
|
module Orchestration
|
||||||
|
class OpenStack
|
||||||
|
class Real
|
||||||
|
|
||||||
|
# Update a stack.
|
||||||
|
#
|
||||||
|
# @param [String] stack_name Name of the stack to update.
|
||||||
|
# @param [Hash] options
|
||||||
|
# * :template_body [String] Structure containing the template body.
|
||||||
|
# or (one of the two Template parameters is required)
|
||||||
|
# * :template_url [String] URL of file containing the template body.
|
||||||
|
# * :parameters [Hash] Hash of providers to supply to template.
|
||||||
|
#
|
||||||
|
# @see http://docs.amazonwebservices.com/AWSCloudFormation/latest/APIReference/API_UpdateStack.html
|
||||||
|
#
|
||||||
|
def update_stack(stack_name, options = {})
|
||||||
|
params = {
|
||||||
|
:stack_name => stack_name
|
||||||
|
}.merge(options)
|
||||||
|
|
||||||
|
request(
|
||||||
|
:path => 'stacks',
|
||||||
|
:method => 'PUT',
|
||||||
|
:body => MultiJson.encode(params)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Mock
|
||||||
|
def update_stack(stack_name, options = {})
|
||||||
|
response = Excon::Response.new
|
||||||
|
response.status = 202
|
||||||
|
response.body = {}
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
25
lib/fog/orchestration.rb
Normal file
25
lib/fog/orchestration.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
module Fog
|
||||||
|
module Orchestration
|
||||||
|
|
||||||
|
def self.[](provider)
|
||||||
|
self.new(:provider => provider)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.new(attributes)
|
||||||
|
attributes = attributes.dup # Prevent delete from having side effects
|
||||||
|
provider = attributes.delete(:provider).to_s.downcase.to_sym
|
||||||
|
|
||||||
|
if self.providers.include?(provider)
|
||||||
|
require "fog/#{provider}/network"
|
||||||
|
return Fog::Orchestration.const_get(Fog.providers[provider]).new(attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
raise ArgumentError.new("#{provider} has no orchestration service")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.providers
|
||||||
|
Fog.services[:orchestration]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue