deltadsl 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +92 -0
- data/lib/client.rb +17 -0
- data/lib/dsl.rb +21 -0
- data/lib/instance.rb +194 -0
- data/lib/instance_configuration.rb +13 -0
- data/lib/instance_definition.rb +45 -0
- data/lib/instance_profile.rb +37 -0
- data/lib/models.rb +20 -0
- data/lib/task.rb +142 -0
- data/tests/deltacloud_perf_test.rb +52 -0
- data/tests/dsl_test.rb +203 -0
- data/tests/test_test.rb +28 -0
- metadata +93 -0
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
Deltacloud API client DSL
|
2
|
+
-------------------------
|
3
|
+
|
4
|
+
Documentation
|
5
|
+
|
6
|
+
<a href="http://rdoc.info/github/mifo/deltadsl/master/frames">rdoc.info/github/mifo/deltadsl/master/frames</a>
|
7
|
+
|
8
|
+
Installation:
|
9
|
+
|
10
|
+
* No installation available yet ;-)
|
11
|
+
|
12
|
+
Prerequires:
|
13
|
+
|
14
|
+
* Deltacloud API server and client gems installed:
|
15
|
+
|
16
|
+
$ gem install deltacloud-core deltacloud-client
|
17
|
+
|
18
|
+
* Eventmachine (gem install eventmachine)
|
19
|
+
* Thin (gem install thin)
|
20
|
+
|
21
|
+
Examples
|
22
|
+
-------------------------
|
23
|
+
|
24
|
+
Simple scenario:
|
25
|
+
|
26
|
+
<script src="https://gist.github.com/1933563.js?file=dsl_sample.rb"></script>
|
27
|
+
|
28
|
+
@sample = Deltacloud::DSL::Task('launch some EC2 and RHEV-M instances') do
|
29
|
+
|
30
|
+
instances(:driver => :ec2, :username => '', :password => '') do
|
31
|
+
instance 'test-ec2-1' do
|
32
|
+
realm 'us-west-1'
|
33
|
+
image 'ami-12345'
|
34
|
+
profile 't1.micro'
|
35
|
+
end
|
36
|
+
|
37
|
+
instance 'test-ec2-2' do
|
38
|
+
realm 'us-west-1'
|
39
|
+
image 'ami-54321'
|
40
|
+
profile 't1.micro'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
instances(:driver => :rhevm, :username => '', :password => '', :provider => '') do
|
45
|
+
instance 'test-rhev-1' do
|
46
|
+
image '12345-12345-12345-12345'
|
47
|
+
profile 'SERVER' do |p|
|
48
|
+
p.memory = 512
|
49
|
+
p.cpu = 4
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
on(:instance_started) do |i|
|
55
|
+
# i.pool_for_ssh ??
|
56
|
+
end
|
57
|
+
|
58
|
+
on(:running) do
|
59
|
+
ec2_instance('test-ec2-1') do |i|
|
60
|
+
# do something with this instance
|
61
|
+
end
|
62
|
+
|
63
|
+
rhevm_instance('test-rhev-1') do |i|
|
64
|
+
# Do someting ;-)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Thing above is just an definition, so now let start it:
|
70
|
+
|
71
|
+
@sample.start!
|
72
|
+
|
73
|
+
# All instances will be started in parallel (using threads)
|
74
|
+
|
75
|
+
|
76
|
+
License
|
77
|
+
-----------------
|
78
|
+
|
79
|
+
Licensed to the Apache Software Foundation (ASF) under one or more
|
80
|
+
contributor license agreements. See the NOTICE file distributed with
|
81
|
+
this work for additional information regarding copyright ownership. The
|
82
|
+
ASF licenses this file to you under the Apache License, Version 2.0 (the
|
83
|
+
"License"); you may not use this file except in compliance with the
|
84
|
+
License. You may obtain a copy of the License at
|
85
|
+
|
86
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
87
|
+
|
88
|
+
Unless required by applicable law or agreed to in writing, software
|
89
|
+
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
90
|
+
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
91
|
+
License for the specific language governing permissions and limitations
|
92
|
+
under the License.
|
data/lib/client.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'deltacloud'
|
2
|
+
|
3
|
+
module Deltacloud
|
4
|
+
|
5
|
+
def self.Client(d)
|
6
|
+
config = {
|
7
|
+
:driver => d.configuration.driver || :mock,
|
8
|
+
:username => d.configuration.user || 'mockuser',
|
9
|
+
:password => d.configuration.password || 'mockpassword',
|
10
|
+
}
|
11
|
+
config.merge!({
|
12
|
+
:provider => d.configuration.provider
|
13
|
+
}) unless d.configuration.provider.nil?
|
14
|
+
DeltaCloud::API.new(nil, nil, d.configuration.url || 'http://localhost:3001/api').with_config(config)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/lib/dsl.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Deltacloud
|
2
|
+
module DSL
|
3
|
+
|
4
|
+
def self.Task(name, &block)
|
5
|
+
Task.new(name, &block)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.Instance(name, &block)
|
9
|
+
Instance.new(name, &block) if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.Configuration(params={})
|
13
|
+
InstanceConfiguration.new(params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.Instances(configuration={}, &block)
|
17
|
+
InstanceDefinition.new(configuration, &block) if block_given?
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/instance.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
module Deltacloud
|
2
|
+
module DSL
|
3
|
+
|
4
|
+
class Instance
|
5
|
+
|
6
|
+
include EM::Deferrable
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
attr_reader :parameters
|
10
|
+
|
11
|
+
def initialize(name, &block)
|
12
|
+
@name = name
|
13
|
+
@parameters = {
|
14
|
+
:state => :new
|
15
|
+
}
|
16
|
+
instance_eval(&block) if block_given?
|
17
|
+
warn "WARNING: Realm is not defined for instance '#{name}'. (Default driver realm will be used)." if params.realm_id.nil?
|
18
|
+
raise "Image is not defined for instance '#{@name}'" if params.image_id.nil?
|
19
|
+
raise "Profile is not defined for instance '#{@name}'" if params.profile.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Make call to Deltacloud to create this instance object
|
23
|
+
# Please note that this call will put the instance into
|
24
|
+
# PENDING state in most cases (except Mock).
|
25
|
+
#
|
26
|
+
# Use .wait_for_running! to pool Deltacloud until instance
|
27
|
+
# is not RUNNING
|
28
|
+
#
|
29
|
+
def create(definition)
|
30
|
+
@client = Deltacloud::Client(@definition = definition)
|
31
|
+
instance_opts = {
|
32
|
+
:name => self.name
|
33
|
+
}
|
34
|
+
instance_opts.merge!(profile.to_instance_params)
|
35
|
+
instance_opts.merge!({
|
36
|
+
:realm_id => instance_realm_id,
|
37
|
+
})
|
38
|
+
from_instance!(@client.create_instance(instance_image_id, instance_opts))
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
# Pool Deltacloud API for the state change of instance every 5 seconds.
|
43
|
+
# This will block program execution for time needed to transient from
|
44
|
+
#
|
45
|
+
|
46
|
+
%w(running stopped pending).each do |state|
|
47
|
+
define_method :"wait_for_#{state}!" do |*max_retries|
|
48
|
+
retries = 0
|
49
|
+
return if state_is?(state)
|
50
|
+
begin
|
51
|
+
update!
|
52
|
+
# Some Deltacloud drivers (like RHEV-M) put instance to STOPPED state
|
53
|
+
# instead of RUNNING. Is not an error, but backend cloud behavior.
|
54
|
+
# If instance transient to STOPPED, then we try to START it without
|
55
|
+
# incrementing retry counter.
|
56
|
+
if state == 'running' and is_stopped?
|
57
|
+
start!
|
58
|
+
raise 'NotRunning'
|
59
|
+
else
|
60
|
+
retries += 1
|
61
|
+
raise 'NotInState' if (!state_is?(state)) && sleep(5)
|
62
|
+
end
|
63
|
+
rescue => e
|
64
|
+
retry if (e.message == 'NotInState') && (retries <= max_retries.first)
|
65
|
+
raise "Failed to put instance '#{self.name}' in #{state} state."
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# This method will try to connect to Deltacloud API and refresh all attributes
|
71
|
+
#
|
72
|
+
def update!
|
73
|
+
raise 'Instance must be created first in order to call update' if @definition.nil?
|
74
|
+
from_instance!(@client.instance(params.instance_id))
|
75
|
+
end
|
76
|
+
|
77
|
+
# Instance actions:
|
78
|
+
#
|
79
|
+
# instance.start! will start stopped instance (if supported)
|
80
|
+
# instance.stop! will stop running instance (if supported)
|
81
|
+
# instance.destroy! will destroy instance and set state to ':destroyed'
|
82
|
+
#
|
83
|
+
%w(start stop destroy).each do |action|
|
84
|
+
define_method :"#{action}!" do
|
85
|
+
instance_action(action.intern)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Helper for instance actions
|
90
|
+
#
|
91
|
+
def instance_action(action)
|
92
|
+
must_have_definition!
|
93
|
+
@client.instance(params.instance_id).send(:"#{action}!")
|
94
|
+
instance = @client.instance(params.instance_id)
|
95
|
+
if instance.nil?
|
96
|
+
@parameters[:state] = :destroyed
|
97
|
+
@parameters.delete(:instance_id)
|
98
|
+
self
|
99
|
+
else
|
100
|
+
from_instance!(instance)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Convert attributes from DeltaCloud::Instance object to Instance
|
105
|
+
#
|
106
|
+
def from_instance!(instance)
|
107
|
+
attrs = {
|
108
|
+
:instance_id => instance.id,
|
109
|
+
:state => instance.state.downcase.intern,
|
110
|
+
:public_addresses => instance.public_addresses,
|
111
|
+
:private_addresses => instance.private_addresses
|
112
|
+
}
|
113
|
+
attrs.merge!(:owner_id => instance.owner_id)
|
114
|
+
@parameters.merge!(attrs)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
# Assing InstanceProfile to the instance.
|
119
|
+
# If no profile name is provided, will return the active profile
|
120
|
+
#
|
121
|
+
# InstanceProfile DSL example:
|
122
|
+
#
|
123
|
+
# instance 'test-instance' do
|
124
|
+
# profile 'm1-small' do |p|
|
125
|
+
# p.memory = 500
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
def profile(name=nil, &block)
|
130
|
+
if name
|
131
|
+
@parameters[:profile] = Deltacloud::DSL::InstanceProfile(name, &block)
|
132
|
+
else
|
133
|
+
instance_profile
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Convert instance param hash to OpenStruct object for easy retrieval
|
138
|
+
#
|
139
|
+
def params
|
140
|
+
Deltacloud::DSL::Configuration(@parameters)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Define various helper methods:
|
144
|
+
#
|
145
|
+
# instance_[attribute] -> retrieve instance attribute (instance_state,
|
146
|
+
# instance_public_addresses, etc...)
|
147
|
+
# is_[state]? -> true if instance is in given state
|
148
|
+
# is_not_[state]? -> same as above just negated
|
149
|
+
#
|
150
|
+
# Whatever else method is called on this object with some parameters,
|
151
|
+
# this method will automatically be transformed to instance variable.
|
152
|
+
#
|
153
|
+
def method_missing(name, *args)
|
154
|
+
if name.to_s =~ /^instance_([\w_]+)$/
|
155
|
+
@parameters[$1.intern]
|
156
|
+
elsif name.to_s =~ /^is_(\w+)\?$/
|
157
|
+
state_is?($1.intern)
|
158
|
+
elsif name.to_s =~ /^is_not_(\w+)\?$/
|
159
|
+
!state_is?($1.intern)
|
160
|
+
elsif !args.empty?
|
161
|
+
set_param(name.to_sym, args)
|
162
|
+
else
|
163
|
+
super
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def state_is?(state)
|
170
|
+
instance_state == state.to_sym
|
171
|
+
end
|
172
|
+
|
173
|
+
def must_have_definition!
|
174
|
+
raise 'Instance must be created first in order to start it' if @definition.nil?
|
175
|
+
end
|
176
|
+
|
177
|
+
def convert_id_param(name)
|
178
|
+
case name
|
179
|
+
when :realm then :realm_id
|
180
|
+
when :image then :image_id
|
181
|
+
else name
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def set_param(key, val)
|
186
|
+
@parameters ||= {}
|
187
|
+
k = convert_id_param(key)
|
188
|
+
@parameters[k] = (val.size == 1) ? val[0] : val
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Deltacloud
|
2
|
+
module DSL
|
3
|
+
|
4
|
+
class InstanceDefinition
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :instances, :configuration
|
8
|
+
|
9
|
+
def initialize(configuration, &block)
|
10
|
+
@instances = []
|
11
|
+
@configuration = Deltacloud::DSL::Configuration(configuration)
|
12
|
+
define &block
|
13
|
+
end
|
14
|
+
|
15
|
+
def define(&block)
|
16
|
+
instance_eval(&block) if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add more instances to this instance definition
|
20
|
+
#
|
21
|
+
# @task.mock_instances.first << Deltacloud::DSL::Instance('instance-2') do
|
22
|
+
# realm 'us'
|
23
|
+
# image 'img1'
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
def <<(instance)
|
27
|
+
@instances << instance
|
28
|
+
end
|
29
|
+
|
30
|
+
# Syntax suggar for adding new instances to instance definition
|
31
|
+
#
|
32
|
+
def instance(name, &block)
|
33
|
+
self << Deltacloud::DSL::Instance(name, &block) if block_given?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Make instance definition enumerative for instances
|
37
|
+
#
|
38
|
+
def each(&block)
|
39
|
+
@instances.each { |instance| block.call(instance) }
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Deltacloud
|
4
|
+
module DSL
|
5
|
+
|
6
|
+
def self.InstanceProfile(name, &block)
|
7
|
+
InstanceProfile.new(name, &block) if block_given?
|
8
|
+
end
|
9
|
+
|
10
|
+
class InstanceProfile < OpenStruct
|
11
|
+
|
12
|
+
def initialize(name, &block)
|
13
|
+
super(:name => name)
|
14
|
+
define &block
|
15
|
+
end
|
16
|
+
|
17
|
+
def define(&block)
|
18
|
+
yield self if block_given?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Convert InstanceProfile to DeltaCloud create_instance method parameters.
|
22
|
+
# Some property names varies from the names used in DeltaCloud. This
|
23
|
+
# method will deal with them.
|
24
|
+
#
|
25
|
+
def to_instance_params
|
26
|
+
params = self.marshal_dump
|
27
|
+
params[:hardware_profile] = params.delete(:name)
|
28
|
+
params[:hwp_memory] = params.delete(:memory) unless params[:memory].nil?
|
29
|
+
params[:hwp_cpu] = params.delete(:cpu) unless params[:cpu].nil?
|
30
|
+
params[:hwp_storage] = params.delete(:storage) unless params[:storage].nil?
|
31
|
+
params
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/models.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
# Workaround for Ruby 1.8 which does not have 'require_relative'
|
4
|
+
# method defined
|
5
|
+
#
|
6
|
+
unless Kernel.respond_to?(:require_relative)
|
7
|
+
module Kernel
|
8
|
+
def require_relative(path)
|
9
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require_relative 'client'
|
15
|
+
require_relative 'dsl'
|
16
|
+
require_relative 'task'
|
17
|
+
require_relative 'instance'
|
18
|
+
require_relative 'instance_configuration'
|
19
|
+
require_relative 'instance_definition'
|
20
|
+
require_relative 'instance_profile'
|
data/lib/task.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module Deltacloud
|
5
|
+
module DSL
|
6
|
+
|
7
|
+
class Task
|
8
|
+
|
9
|
+
attr_reader :name, :state_machine, :log
|
10
|
+
|
11
|
+
def initialize(name, &block)
|
12
|
+
@name = name
|
13
|
+
@state_machine = {}
|
14
|
+
@log = Logger.new(STDERR)
|
15
|
+
define &block
|
16
|
+
end
|
17
|
+
|
18
|
+
def define(&block)
|
19
|
+
instance_eval(&block) if block_given?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Configure group of instances that would be launched
|
23
|
+
# using specified configuration.
|
24
|
+
#
|
25
|
+
# Configuration:
|
26
|
+
#
|
27
|
+
# :driver - Deltacloud API driver to use (default: mock)
|
28
|
+
# :provider - API_PROVIDER (eg. URL to RHEV-M API)
|
29
|
+
# :username - API key (default: mockuser)
|
30
|
+
# :password - API secret (default: mockpassword)
|
31
|
+
# :url - Deltacloud API url (default: http://localhost:3001/api)
|
32
|
+
#
|
33
|
+
# The block should define single instances:
|
34
|
+
#
|
35
|
+
# instances(:driver => :ec2, :username => API_KEY, :password => API_SECRET) do
|
36
|
+
# instance 'instance-1' do
|
37
|
+
# # instance configuration here
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
def instances(configuration={}, &block)
|
42
|
+
return find_instances_by_driver(configuration) if configuration.kind_of? Symbol
|
43
|
+
@instances ||= []
|
44
|
+
@instances << Deltacloud::DSL::Instances(configuration, &block) if block_given?
|
45
|
+
@instances
|
46
|
+
end
|
47
|
+
|
48
|
+
# Declare a set of methods dynamically:
|
49
|
+
#
|
50
|
+
# find_instances_by_[attribute] => returns InstanceDefinition objects that
|
51
|
+
# match the value of attribute provided in method name
|
52
|
+
#
|
53
|
+
# [driver]_instances => return InstanceDefinition objects that correspond
|
54
|
+
# to given driver
|
55
|
+
#
|
56
|
+
# [driver]_instance => return Instance object that match with name
|
57
|
+
# eg. mock_instance 'test-mock-1' will find this
|
58
|
+
# instance.
|
59
|
+
#
|
60
|
+
# instances_[state] => return Instance objects with corresponding state
|
61
|
+
#
|
62
|
+
def method_missing(name, *args)
|
63
|
+
if name.to_s =~ /^find_instances_by_([\w_]+)$/
|
64
|
+
@instances.select { |i| i.configuration.respond_to?($1.intern) && args.include?(i.configuration.send($1.intern)) }
|
65
|
+
elsif name.to_s =~ /^(\w+)_instances$/
|
66
|
+
find_instances_by_driver($1.intern)
|
67
|
+
elsif name.to_s =~ /^(\w+)_instance$/
|
68
|
+
inst = find_instances_by_driver($1.intern).map { |instances| instances.find { |i| args.include?(i.name) } }.flatten.compact.first
|
69
|
+
yield inst if block_given?
|
70
|
+
inst
|
71
|
+
elsif name.to_s =~ /^instances_(\w+)\?$/
|
72
|
+
@instances.any? { |d| d.map { |i| (i.update! rescue true) && i.instance_state == $1.intern }.include? true }
|
73
|
+
else
|
74
|
+
super
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Start executing given task.
|
79
|
+
#
|
80
|
+
# This method will try to start all instances defined for all drivers.
|
81
|
+
# Then it will wait for instances to become running.
|
82
|
+
#
|
83
|
+
# Various callback can be provided for different state:
|
84
|
+
#
|
85
|
+
# on(:running) callback is triggered when all instances are running
|
86
|
+
# on(:instance_started) callback is triggered for every instance when become running
|
87
|
+
#
|
88
|
+
def start!
|
89
|
+
task = self
|
90
|
+
EventMachine::run do
|
91
|
+
inst_arr = []
|
92
|
+
task.instances.each do |definition|
|
93
|
+
inst_arr += definition.instances
|
94
|
+
definition.instances.each do |instance|
|
95
|
+
Thread.new do
|
96
|
+
begin
|
97
|
+
instance.create(definition).wait_for_running!
|
98
|
+
perform(:instance_started, instance)
|
99
|
+
log.info "Instance #{instance.name}[#{definition.configuration.driver}] successfully started."
|
100
|
+
rescue => e
|
101
|
+
log.error "ERROR: #{e.message}"
|
102
|
+
ensure
|
103
|
+
inst_arr.delete(instance)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
until inst_arr.empty?; end
|
109
|
+
perform(:running)
|
110
|
+
EM.stop
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Handler for callback definition:
|
115
|
+
#
|
116
|
+
# on(:running) do
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# on(:instance_started) do |instance|
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
def on(state, &block)
|
123
|
+
@state_machine[state] = block if block_given?
|
124
|
+
end
|
125
|
+
|
126
|
+
# Syntax sugar for @state_machine callbacks
|
127
|
+
#
|
128
|
+
def state(state)
|
129
|
+
@state_machine[state]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Syntax sugar for performing callbacks
|
133
|
+
#
|
134
|
+
def perform(s, item=nil)
|
135
|
+
return unless @state_machine.keys.include?(s)
|
136
|
+
state(s).call(item)
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# 1.8 compatibility fix
|
2
|
+
unless Kernel.respond_to?(:require_relative)
|
3
|
+
module Kernel
|
4
|
+
def require_relative(path)
|
5
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
require_relative '../lib/models'
|
11
|
+
require 'minitest/autorun'
|
12
|
+
require 'minitest/benchmark'
|
13
|
+
|
14
|
+
describe Deltacloud::DSL::Task do
|
15
|
+
|
16
|
+
def prepare_threaded_sample(prefix)
|
17
|
+
@threaded_sample = Deltacloud::DSL::Task('threaded pool') do
|
18
|
+
|
19
|
+
# Say we want to launch 80 instances in Mock
|
20
|
+
instances(:driver => :mock) do
|
21
|
+
1.upto(80) do |i|
|
22
|
+
instance "test-#{prefix}-#{i}" do
|
23
|
+
realm 'us'
|
24
|
+
image 'img1'
|
25
|
+
profile 'm1-large' do |p|
|
26
|
+
p.memory = 7680
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# After benchmarch destroy all instances
|
33
|
+
on(:ready) do
|
34
|
+
mock_instances.each do |d|
|
35
|
+
d.instances.each do |i|
|
36
|
+
i.stop!.wait_for_stopped!
|
37
|
+
i.destroy!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
bench_performance_linear "threaded_pool" do |n|
|
46
|
+
10.times do
|
47
|
+
threaded_sample = prepare_threaded_sample(Time.now.to_i)
|
48
|
+
threaded_sample.start!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
data/tests/dsl_test.rb
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
# 1.8 compatibility fix
|
2
|
+
unless Kernel.respond_to?(:require_relative)
|
3
|
+
module Kernel
|
4
|
+
def require_relative(path)
|
5
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
require_relative '../lib/models'
|
11
|
+
require 'minitest/autorun'
|
12
|
+
|
13
|
+
describe Deltacloud::DSL::Task do
|
14
|
+
before do
|
15
|
+
@sample = Deltacloud::DSL::Task('launch instance') do
|
16
|
+
instances(:driver => :mock) do
|
17
|
+
instance 'test-instance-1' do
|
18
|
+
realm 'us'
|
19
|
+
image 'img1'
|
20
|
+
profile('m1-large') do |p|
|
21
|
+
p.memory = 7680
|
22
|
+
end
|
23
|
+
end
|
24
|
+
instance 'test-instance-2' do
|
25
|
+
realm 'us'
|
26
|
+
image 'img1'
|
27
|
+
profile('m1-large') do |p|
|
28
|
+
p.memory = 10000
|
29
|
+
end
|
30
|
+
end
|
31
|
+
instance 'test-instance-3' do
|
32
|
+
realm 'eu'
|
33
|
+
image 'img1'
|
34
|
+
profile('m1-large') do |p|
|
35
|
+
p.memory = 10000
|
36
|
+
end
|
37
|
+
end
|
38
|
+
instance 'test-instance-4' do
|
39
|
+
realm 'us'
|
40
|
+
image 'img1'
|
41
|
+
profile('m1-large') do |p|
|
42
|
+
p.memory = 10000
|
43
|
+
end
|
44
|
+
end
|
45
|
+
instance 'test-instance-5' do
|
46
|
+
realm 'eu'
|
47
|
+
image 'img1'
|
48
|
+
profile('m1-large') do |p|
|
49
|
+
p.memory = 10000
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
on :instance_started do |i|
|
54
|
+
puts i.params.state
|
55
|
+
end
|
56
|
+
on :running do
|
57
|
+
mock_instance 'test-instance-1' do |i|
|
58
|
+
#puts "Getting IP address out of test-instance-1"
|
59
|
+
#puts i.params.public_addresses
|
60
|
+
end
|
61
|
+
mock_instance 'test-instance-2' do |i|
|
62
|
+
#puts "Destroying instance test-instance-2..."
|
63
|
+
i.stop!.wait_for_stopped!
|
64
|
+
i.destroy!
|
65
|
+
#puts i.params.state
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe Deltacloud::DSL::Task do
|
72
|
+
it 'should be constructed' do
|
73
|
+
@sample.must_be_instance_of Deltacloud::DSL::Task
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should have proper name' do
|
77
|
+
@sample.name.must_equal 'launch instance'
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should have state machine' do
|
81
|
+
@sample.state_machine.must_be_instance_of Hash
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should find instance by driver' do
|
85
|
+
@sample.find_instances_by_driver(:mock).must_be_instance_of Array
|
86
|
+
@sample.find_instances_by_driver(:mock).size.must_equal 1
|
87
|
+
@sample.find_instances_by_driver(:mock).first.must_be_instance_of Deltacloud::DSL::InstanceDefinition
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should return all mock instances' do
|
91
|
+
@sample.mock_instances.must_be_instance_of Array
|
92
|
+
@sample.mock_instances.size.must_equal 1
|
93
|
+
@sample.mock_instances.first.must_be_instance_of Deltacloud::DSL::InstanceDefinition
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should be able to find single instance by name' do
|
97
|
+
@sample.mock_instance('test-instance-1').must_be_instance_of Deltacloud::DSL::Instance
|
98
|
+
@sample.mock_instance('test-instance-1') do |i|
|
99
|
+
i.must_be_instance_of Deltacloud::DSL::Instance
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should figure out if instances are new or running' do
|
104
|
+
@sample.instances_running?.must_equal false
|
105
|
+
@sample.instances_new?.must_equal true
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should run' do
|
109
|
+
@sample.start!
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
describe Deltacloud::DSL::InstanceDefinition do
|
115
|
+
|
116
|
+
it 'should return all defined instances' do
|
117
|
+
@sample.instances.must_be_instance_of Array
|
118
|
+
@sample.instances.size.must_equal 1
|
119
|
+
@sample.instances.each do |i|
|
120
|
+
i.must_be_instance_of Deltacloud::DSL::InstanceDefinition
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should have configuration set for every instances' do
|
125
|
+
@sample.instances.first.configuration.wont_be_nil
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should have mock driver configuration' do
|
129
|
+
@sample.instances.first.configuration.driver.must_equal :mock
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should find instances using driver' do
|
133
|
+
@sample.find_instances_by_driver(:mock).must_be_instance_of Array
|
134
|
+
@sample.find_instances_by_driver(:mock).size.must_equal 1
|
135
|
+
@sample.find_instances_by_driver(:mock).first.must_be_instance_of Deltacloud::DSL::InstanceDefinition
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
describe Deltacloud::DSL::Instance do
|
141
|
+
|
142
|
+
it 'should be all valid instances' do
|
143
|
+
@sample.mock_instances.first.each do |inst|
|
144
|
+
inst.must_be_instance_of Deltacloud::DSL::Instance
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should find mock instance by name' do
|
149
|
+
@sample.mock_instance('test-instance-1') do |i|
|
150
|
+
i.wont_be_nil
|
151
|
+
i.must_be_instance_of Deltacloud::DSL::Instance
|
152
|
+
i.name.must_equal 'test-instance-1'
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should all have have valid name' do
|
157
|
+
@sample.mock_instances.first.each do |inst|
|
158
|
+
inst.name.wont_be_nil
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should have realm_id and image_id parameters defined' do
|
163
|
+
@sample.mock_instances.first.each do |inst|
|
164
|
+
['us', 'eu'].must_include inst.params.realm_id
|
165
|
+
inst.params.image_id.must_equal 'img1'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should have valid instance profile defined' do
|
170
|
+
@sample.mock_instances.first.each do |inst|
|
171
|
+
inst.instance_profile.must_be_instance_of Deltacloud::DSL::InstanceProfile
|
172
|
+
inst.instance_profile.name.wont_be_nil
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'should have memory specified in instance profile' do
|
177
|
+
@sample.mock_instances.first.each do |inst|
|
178
|
+
inst.instance_profile.memory.wont_be_nil
|
179
|
+
inst.instance_profile.memory.must_be_instance_of Fixnum
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should allow manipulation of instances' do
|
184
|
+
definition = @sample.mock_instances.first
|
185
|
+
instance = @sample.mock_instance('test-instance-3')
|
186
|
+
instance.create(definition).must_be_instance_of Deltacloud::DSL::Instance
|
187
|
+
instance.instance_owner_id.must_equal 'mockuser'
|
188
|
+
instance.params.state.must_equal :running
|
189
|
+
instance.is_running?.must_equal true
|
190
|
+
instance.is_not_running?.must_equal false
|
191
|
+
instance.is_stopped?.must_equal false
|
192
|
+
instance.stop!.must_be_instance_of Deltacloud::DSL::Instance
|
193
|
+
instance.params.state.must_equal :stopped
|
194
|
+
instance.is_running?.must_equal false
|
195
|
+
instance.is_stopped?.must_equal true
|
196
|
+
instance.destroy!.must_be_instance_of Deltacloud::DSL::Instance
|
197
|
+
instance.is_destroyed?.must_equal true
|
198
|
+
instance.params.instance_id.must_be_nil
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
data/tests/test_test.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
class Meme
|
4
|
+
def initialize
|
5
|
+
end
|
6
|
+
|
7
|
+
def i_can_has_cheezburger?
|
8
|
+
'OHAI!'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe Meme do
|
13
|
+
before do
|
14
|
+
@meme = Meme.new
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "when asked about cheeseburgers" do
|
18
|
+
it "must respond positively" do
|
19
|
+
@meme.i_can_has_cheezburger?.must_equal "OHAI!"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "when asked about blending possibilities" do
|
24
|
+
it "won't say no" do
|
25
|
+
@meme.will_it_blend?.wont_match /^no/i
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deltadsl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michal Fojtik
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: deltacloud-client
|
16
|
+
requirement: &70175076503460 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70175076503460
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: eventmachine
|
27
|
+
requirement: &70175076501840 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70175076501840
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: minitest
|
38
|
+
requirement: &70175076500080 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70175076500080
|
47
|
+
description: Deltacloud API powered DSL for creating complex deployments
|
48
|
+
email: dev@deltacloud.apache.org
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.md
|
53
|
+
files:
|
54
|
+
- README.md
|
55
|
+
- lib/client.rb
|
56
|
+
- lib/dsl.rb
|
57
|
+
- lib/instance.rb
|
58
|
+
- lib/instance_configuration.rb
|
59
|
+
- lib/instance_definition.rb
|
60
|
+
- lib/instance_profile.rb
|
61
|
+
- lib/models.rb
|
62
|
+
- lib/task.rb
|
63
|
+
- tests/deltacloud_perf_test.rb
|
64
|
+
- tests/dsl_test.rb
|
65
|
+
- tests/test_test.rb
|
66
|
+
homepage: http://www.deltacloud.org
|
67
|
+
licenses: []
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.8.15
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Deltacloud API DSL
|
90
|
+
test_files:
|
91
|
+
- tests/deltacloud_perf_test.rb
|
92
|
+
- tests/dsl_test.rb
|
93
|
+
- tests/test_test.rb
|