dynflow 0.1.0 → 0.2.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/.gitignore +6 -0
- data/.travis.yml +9 -0
- data/Gemfile +0 -10
- data/MIT-LICENSE +1 -1
- data/README.md +99 -37
- data/Rakefile +2 -6
- data/doc/images/logo.png +0 -0
- data/dynflow.gemspec +10 -1
- data/examples/generate_work_for_daemon.rb +24 -0
- data/examples/orchestrate.rb +121 -0
- data/examples/run_daemon.rb +17 -0
- data/examples/web_console.rb +29 -0
- data/lib/dynflow.rb +27 -6
- data/lib/dynflow/action.rb +185 -77
- data/lib/dynflow/action/cancellable_polling.rb +18 -0
- data/lib/dynflow/action/finalize_phase.rb +18 -0
- data/lib/dynflow/action/flow_phase.rb +44 -0
- data/lib/dynflow/action/format.rb +46 -0
- data/lib/dynflow/action/missing.rb +26 -0
- data/lib/dynflow/action/plan_phase.rb +85 -0
- data/lib/dynflow/action/polling.rb +49 -0
- data/lib/dynflow/action/presenter.rb +51 -0
- data/lib/dynflow/action/progress.rb +62 -0
- data/lib/dynflow/action/run_phase.rb +43 -0
- data/lib/dynflow/action/suspended.rb +21 -0
- data/lib/dynflow/clock.rb +133 -0
- data/lib/dynflow/daemon.rb +29 -0
- data/lib/dynflow/execution_plan.rb +285 -33
- data/lib/dynflow/execution_plan/dependency_graph.rb +29 -0
- data/lib/dynflow/execution_plan/output_reference.rb +52 -0
- data/lib/dynflow/execution_plan/steps.rb +12 -0
- data/lib/dynflow/execution_plan/steps/abstract.rb +121 -0
- data/lib/dynflow/execution_plan/steps/abstract_flow_step.rb +52 -0
- data/lib/dynflow/execution_plan/steps/error.rb +33 -0
- data/lib/dynflow/execution_plan/steps/finalize_step.rb +23 -0
- data/lib/dynflow/execution_plan/steps/plan_step.rb +81 -0
- data/lib/dynflow/execution_plan/steps/run_step.rb +21 -0
- data/lib/dynflow/executors.rb +9 -0
- data/lib/dynflow/executors/abstract.rb +32 -0
- data/lib/dynflow/executors/parallel.rb +88 -0
- data/lib/dynflow/executors/parallel/core.rb +119 -0
- data/lib/dynflow/executors/parallel/execution_plan_manager.rb +120 -0
- data/lib/dynflow/executors/parallel/flow_manager.rb +48 -0
- data/lib/dynflow/executors/parallel/pool.rb +102 -0
- data/lib/dynflow/executors/parallel/running_steps_manager.rb +63 -0
- data/lib/dynflow/executors/parallel/sequence_cursor.rb +97 -0
- data/lib/dynflow/executors/parallel/sequential_manager.rb +81 -0
- data/lib/dynflow/executors/parallel/work_queue.rb +44 -0
- data/lib/dynflow/executors/parallel/worker.rb +30 -0
- data/lib/dynflow/executors/remote_via_socket.rb +38 -0
- data/lib/dynflow/executors/remote_via_socket/core.rb +150 -0
- data/lib/dynflow/flows.rb +13 -0
- data/lib/dynflow/flows/abstract.rb +36 -0
- data/lib/dynflow/flows/abstract_composed.rb +104 -0
- data/lib/dynflow/flows/atom.rb +36 -0
- data/lib/dynflow/flows/concurrence.rb +28 -0
- data/lib/dynflow/flows/sequence.rb +13 -0
- data/lib/dynflow/future.rb +173 -0
- data/lib/dynflow/listeners.rb +7 -0
- data/lib/dynflow/listeners/abstract.rb +13 -0
- data/lib/dynflow/listeners/serialization.rb +41 -0
- data/lib/dynflow/listeners/socket.rb +88 -0
- data/lib/dynflow/logger_adapters.rb +8 -0
- data/lib/dynflow/logger_adapters/abstract.rb +30 -0
- data/lib/dynflow/logger_adapters/delegator.rb +13 -0
- data/lib/dynflow/logger_adapters/formatters.rb +8 -0
- data/lib/dynflow/logger_adapters/formatters/abstract.rb +33 -0
- data/lib/dynflow/logger_adapters/formatters/exception.rb +15 -0
- data/lib/dynflow/logger_adapters/simple.rb +59 -0
- data/lib/dynflow/micro_actor.rb +102 -0
- data/lib/dynflow/persistence.rb +53 -0
- data/lib/dynflow/persistence_adapters.rb +6 -0
- data/lib/dynflow/persistence_adapters/abstract.rb +56 -0
- data/lib/dynflow/persistence_adapters/sequel.rb +160 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/001_initial.rb +52 -0
- data/lib/dynflow/serializable.rb +66 -0
- data/lib/dynflow/simple_world.rb +18 -0
- data/lib/dynflow/stateful.rb +40 -0
- data/lib/dynflow/testing.rb +32 -0
- data/lib/dynflow/testing/assertions.rb +64 -0
- data/lib/dynflow/testing/dummy_execution_plan.rb +40 -0
- data/lib/dynflow/testing/dummy_executor.rb +29 -0
- data/lib/dynflow/testing/dummy_planned_action.rb +18 -0
- data/lib/dynflow/testing/dummy_step.rb +19 -0
- data/lib/dynflow/testing/dummy_world.rb +33 -0
- data/lib/dynflow/testing/factories.rb +83 -0
- data/lib/dynflow/testing/managed_clock.rb +23 -0
- data/lib/dynflow/testing/mimic.rb +38 -0
- data/lib/dynflow/transaction_adapters.rb +9 -0
- data/lib/dynflow/transaction_adapters/abstract.rb +26 -0
- data/lib/dynflow/transaction_adapters/active_record.rb +27 -0
- data/lib/dynflow/transaction_adapters/none.rb +12 -0
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/web_console.rb +277 -0
- data/lib/dynflow/world.rb +168 -0
- data/test/action_test.rb +89 -11
- data/test/clock_test.rb +59 -0
- data/test/code_workflow_example.rb +382 -0
- data/test/execution_plan_test.rb +195 -64
- data/test/executor_test.rb +692 -0
- data/test/persistance_adapters_test.rb +173 -0
- data/test/test_helper.rb +316 -1
- data/test/testing_test.rb +148 -0
- data/test/web_console_test.rb +38 -0
- data/web/assets/javascripts/application.js +25 -0
- data/web/assets/stylesheets/application.css +101 -0
- data/web/assets/vendor/bootstrap/css/bootstrap-responsive.css +1109 -0
- data/web/assets/vendor/bootstrap/css/bootstrap-responsive.min.css +9 -0
- data/web/assets/vendor/bootstrap/css/bootstrap.css +6167 -0
- data/web/assets/vendor/bootstrap/css/bootstrap.min.css +9 -0
- data/web/assets/vendor/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/web/assets/vendor/bootstrap/img/glyphicons-halflings.png +0 -0
- data/web/assets/vendor/bootstrap/js/bootstrap.js +2280 -0
- data/web/assets/vendor/bootstrap/js/bootstrap.min.js +6 -0
- data/web/assets/vendor/google-code-prettify/lang-basic.js +3 -0
- data/web/assets/vendor/google-code-prettify/prettify.css +1 -0
- data/web/assets/vendor/google-code-prettify/prettify.js +30 -0
- data/web/assets/vendor/google-code-prettify/run_prettify.js +34 -0
- data/web/assets/vendor/jquery/jquery.js +9807 -0
- data/web/views/flow.erb +19 -0
- data/web/views/flow_step.erb +31 -0
- data/web/views/index.erb +39 -0
- data/web/views/layout.erb +20 -0
- data/web/views/plan_step.erb +11 -0
- data/web/views/show.erb +54 -0
- metadata +250 -11
- data/examples/events.rb +0 -71
- data/examples/workflow.rb +0 -140
- data/lib/dynflow/bus.rb +0 -168
- data/lib/dynflow/dispatcher.rb +0 -36
- data/lib/dynflow/logger.rb +0 -34
- data/lib/dynflow/step.rb +0 -234
- data/test/bus_test.rb +0 -150
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -1,25 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+

|
|
2
|
+
=======
|
|
3
|
+
|
|
4
|
+
Dynflow [DYN(amic work)FLOW] is a workflow engine
|
|
5
|
+
written in Ruby that allows to:
|
|
6
|
+
|
|
7
|
+
* keep track of the progress of running process
|
|
8
|
+
* run the code asynchronously
|
|
9
|
+
* resume the process when something goes wrong, skip some steps when needed
|
|
10
|
+
* detect independent parts and run them concurrently
|
|
11
|
+
* compose simple actions into more complex scenarios
|
|
12
|
+
* extend the workflows from third-party libraries
|
|
13
|
+
* keep consistency between local transactional database and
|
|
14
|
+
external services
|
|
15
|
+
* define the input/output interface between the building blocks (planned)
|
|
16
|
+
* define rollback for the workflow (planned)
|
|
17
|
+
* have multiple workers for distributing the load (planned)
|
|
18
|
+
|
|
19
|
+
Dynflow doesn't try to choose the best tool for the jobs, as the right
|
|
20
|
+
tool depends on the context. Instead, it provides interfaces for
|
|
21
|
+
persistence, transaction layer or executor implementation, giving you
|
|
22
|
+
the last word in choosing the right one (providing default
|
|
23
|
+
implementations as well).
|
|
24
|
+
|
|
25
|
+
* [Current status](#current-status)
|
|
26
|
+
* [How it works](#how-it-works)
|
|
27
|
+
* [Glossary](#glossary)
|
|
28
|
+
* [Related projects](#related-projects)
|
|
29
|
+
|
|
30
|
+
Current status
|
|
31
|
+
-------------
|
|
32
|
+
|
|
33
|
+
Dynflow has been under heavy development for several months to be able
|
|
34
|
+
to support the services orchestration in the
|
|
35
|
+
[Katello](http://katello.org) and [Foreman](http://theforeman.org/)
|
|
36
|
+
projects, getting to production-ready state in couple of weeks.
|
|
37
|
+
|
|
38
|
+
How it works
|
|
39
|
+
------------
|
|
3
40
|
|
|
4
41
|
In traditional workflow engines, you specify a static workflow and
|
|
5
42
|
then run it with various inputs. Dynflow takes different approach.
|
|
6
|
-
|
|
7
43
|
You specify the inputs and the workflow is generated on the fly. You
|
|
8
44
|
can either specify the steps explicitly or subscribe one action to
|
|
9
45
|
another. This is suitable for plugin architecture, where you can't
|
|
10
46
|
write the whole process on one place.
|
|
11
47
|
|
|
12
48
|
Dynflow doesn't differentiate between workflow and action. Instead,
|
|
13
|
-
every action can populate another actions
|
|
14
|
-
|
|
49
|
+
every action can populate another actions. This allows composing
|
|
50
|
+
more simpler workflows into a big one.
|
|
15
51
|
|
|
16
52
|
The whole execution is done in three phases:
|
|
17
53
|
|
|
18
|
-
1. *
|
|
54
|
+
1. *Plan phase*
|
|
19
55
|
|
|
20
|
-
Construct the execution plan for the workflow.
|
|
21
|
-
|
|
22
|
-
of actions to be executed:
|
|
56
|
+
Construct the execution plan for the workflow. Two mechanisms are
|
|
57
|
+
used to get the set of actions to be executed:
|
|
23
58
|
|
|
24
59
|
a. explicit calls of `plan_action` methods in the `plan` method
|
|
25
60
|
|
|
@@ -29,7 +64,7 @@ The whole execution is done in three phases:
|
|
|
29
64
|
|
|
30
65
|
The output of this phase is a set of actions and their inputs.
|
|
31
66
|
|
|
32
|
-
2. *
|
|
67
|
+
2. *Run phase*
|
|
33
68
|
|
|
34
69
|
The plan is being executed step by step, calling the run method of
|
|
35
70
|
an action with corresponding input. The results of every action are
|
|
@@ -41,7 +76,7 @@ The output of this phase is a set of actions and their inputs.
|
|
|
41
76
|
serialized therefore the workflow itself can be persisted. This makes
|
|
42
77
|
it easy to recover from failed actions by rerunning it.
|
|
43
78
|
|
|
44
|
-
3. *
|
|
79
|
+
3. *Finalize phase*
|
|
45
80
|
|
|
46
81
|
Take the results from the execution phase and perform some additional
|
|
47
82
|
tasks. This is suitable for example for recording the results into
|
|
@@ -91,45 +126,26 @@ class Action < Dynflow::Action
|
|
|
91
126
|
plan_action SubAction, object_1
|
|
92
127
|
# we can specify, where in the workflow this action should be
|
|
93
128
|
# placed, as well as prepare the input.
|
|
94
|
-
plan_self {
|
|
129
|
+
plan_self { id: object_2.id, name: object_2.name}
|
|
95
130
|
end
|
|
96
131
|
|
|
97
132
|
# OPTIONAL: run the execution part of this action. Transform the
|
|
98
133
|
# data from +input+ to +output+. When not specified, the action is
|
|
99
134
|
# not used in the execution phase.
|
|
100
135
|
def run
|
|
101
|
-
output[
|
|
136
|
+
output[:uuid] = "#{input[:name]}-#{input[:id]}"
|
|
102
137
|
end
|
|
103
138
|
|
|
104
139
|
# OPTIONAL: finalize the action after the execution phase finishes.
|
|
105
140
|
# in the +input+ and +output+ attributes are available the data from
|
|
106
141
|
# execution phase. in the +outputs+ argument, all the execution
|
|
107
142
|
# phase actions are available, each providing its input and output.
|
|
108
|
-
def finalize
|
|
109
|
-
puts output[
|
|
143
|
+
def finalize
|
|
144
|
+
puts output[:uuid]
|
|
110
145
|
end
|
|
111
146
|
end
|
|
112
147
|
```
|
|
113
148
|
|
|
114
|
-
One can generate the execution plan for an action without actually
|
|
115
|
-
running it:
|
|
116
|
-
|
|
117
|
-
```ruby
|
|
118
|
-
pp Publish.plan(short_article).actions
|
|
119
|
-
# the expanded workflow is:
|
|
120
|
-
# [
|
|
121
|
-
# Publish: {"title"=>"Short", "body"=>"Short"} ~> {},
|
|
122
|
-
# Review: {"title"=>"Short", "body"=>"Short"} ~> {},
|
|
123
|
-
# Print: {"title"=>"Short", "body"=>"Short", "color"=>false} ~> {}
|
|
124
|
-
# ]
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Therefore it's suitable for the plan methods to not have any side
|
|
128
|
-
effects (except of database writes that can be roll-backed)
|
|
129
|
-
|
|
130
|
-
In the finalization phase, `finalize` method is called on every action
|
|
131
|
-
if defined. The order is the same as in the execution plan.
|
|
132
|
-
|
|
133
149
|
Every action should be as atomic as possible, providing better
|
|
134
150
|
granularity when manipulating the process. Since every action can be
|
|
135
151
|
subscribed by another one, adding new behaviour to an existing
|
|
@@ -140,12 +156,58 @@ that other developers can use when extending the workflows.
|
|
|
140
156
|
|
|
141
157
|
See the examples directory for more complete examples.
|
|
142
158
|
|
|
159
|
+
Glossary
|
|
160
|
+
--------
|
|
161
|
+
|
|
162
|
+
* **action** - building block for the workflows: a Ruby class
|
|
163
|
+
inherited from `Dynflow::Action`. Defines code to be run in
|
|
164
|
+
plan/run/finalize phase. It has defined input and output data.
|
|
165
|
+
* **execution plan** - definition of the workflow: product of the plan
|
|
166
|
+
phase
|
|
167
|
+
* **trigger an action** - entering the plan phase, starting with the
|
|
168
|
+
`plan` method of the action. The execution follows immediately.
|
|
169
|
+
* **plan_self** - converts the arguments of the `plan` method into
|
|
170
|
+
action input, that can be accessed from the `run`/`finalize`
|
|
171
|
+
phase.
|
|
172
|
+
* **plan_action** - includes another action into the workflow, passing
|
|
173
|
+
the arguments into the `plan` method of the action
|
|
174
|
+
* **step** - execution unit of the action. It represents the action in
|
|
175
|
+
specific phase (plan step, run step, finalize step).
|
|
176
|
+
* **flow** - definition of the run/finalize phase, holding the
|
|
177
|
+
information about steps that can run concurrently/in sequence.
|
|
178
|
+
Part of execution plan.
|
|
179
|
+
* **executor** - service that executes the run and finalize flows
|
|
180
|
+
based on the execution plan. It can run in the same process as the
|
|
181
|
+
plan phase or in different process (using the remote executor)
|
|
182
|
+
* **world** - the universe where the Dynflow runs the code: it holds
|
|
183
|
+
all needed configuration.
|
|
184
|
+
|
|
185
|
+
Related projects
|
|
186
|
+
----------------
|
|
187
|
+
|
|
188
|
+
* [Foreman](http://theforeman.org) - lifecycle management tool for
|
|
189
|
+
physical and virtual servers
|
|
190
|
+
|
|
191
|
+
* [Katello](http://katello.org) - content management plugin for
|
|
192
|
+
Foreman: integrates couple of REST services for managing the
|
|
193
|
+
software updates in the infrastructure.
|
|
194
|
+
|
|
195
|
+
* [Foreman-tasks](https://github.com/iNecas/foreman-tasks) - Foreman
|
|
196
|
+
plugin providing the tasks management with Dynflow on the back-end
|
|
197
|
+
|
|
198
|
+
* [Dyntask](https://github.com/iNecas/dyntask) - generic Rails engine
|
|
199
|
+
providing the tasks management features with Dynflow on the back-end
|
|
200
|
+
|
|
201
|
+
* [Sysflow](https://github.com/iNecas/sysflow) - set of reusable tools
|
|
202
|
+
for running system tasks with Dynflow, comes with simple Web-UI for
|
|
203
|
+
testing it
|
|
204
|
+
|
|
143
205
|
License
|
|
144
206
|
-------
|
|
145
207
|
|
|
146
208
|
MIT
|
|
147
209
|
|
|
148
|
-
|
|
149
|
-
|
|
210
|
+
Authors
|
|
211
|
+
-------
|
|
150
212
|
|
|
151
|
-
Ivan Nečas
|
|
213
|
+
Ivan Nečas, Petr Chalupa
|
data/Rakefile
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
require 'rake/testtask'
|
|
2
2
|
require 'fileutils'
|
|
3
3
|
|
|
4
|
-
desc "Generic tests"
|
|
5
4
|
Rake::TestTask.new do |t|
|
|
6
5
|
t.libs << 'lib' << 'test'
|
|
7
6
|
t.test_files = FileList['test/*_test.rb']
|
|
8
7
|
t.verbose = true
|
|
9
8
|
end
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
task :all => [:test] do
|
|
14
|
-
end
|
|
15
|
-
end
|
|
10
|
+
desc Rake::Task['test'].comment
|
|
11
|
+
task :default => :test
|
data/doc/images/logo.png
ADDED
|
Binary file
|
data/dynflow.gemspec
CHANGED
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.homepage = "http://github.com/iNecas/dynflow"
|
|
11
11
|
s.summary = "DYNamic workFLOW engine"
|
|
12
12
|
s.description = "Generate and executed workflows dynamically based "+
|
|
13
|
-
|
|
13
|
+
"on input data and leave it open for others to jump into it as well"
|
|
14
14
|
|
|
15
15
|
s.files = `git ls-files`.split("\n")
|
|
16
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
@@ -19,5 +19,14 @@ Gem::Specification.new do |s|
|
|
|
19
19
|
s.add_dependency "activesupport"
|
|
20
20
|
s.add_dependency "multi_json"
|
|
21
21
|
s.add_dependency "apipie-params"
|
|
22
|
+
s.add_dependency "algebrick", '~> 0.4.0'
|
|
23
|
+
s.add_dependency "uuidtools"
|
|
24
|
+
|
|
25
|
+
s.add_development_dependency "rack-test"
|
|
22
26
|
s.add_development_dependency "minitest"
|
|
27
|
+
s.add_development_dependency "minitest-reporters"
|
|
28
|
+
s.add_development_dependency "activerecord"
|
|
29
|
+
s.add_development_dependency "sequel"
|
|
30
|
+
s.add_development_dependency "sqlite3"
|
|
31
|
+
s.add_development_dependency "sinatra"
|
|
23
32
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
root_path = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
|
4
|
+
dynflow_path = File.join(root_path, 'lib')
|
|
5
|
+
$LOAD_PATH << dynflow_path unless $LOAD_PATH.include? dynflow_path
|
|
6
|
+
|
|
7
|
+
require 'dynflow'
|
|
8
|
+
require 'tmpdir'
|
|
9
|
+
|
|
10
|
+
socket_path = File.join(Dir.tmpdir, 'dynflow_socket')
|
|
11
|
+
persistence_adapter = Dynflow::PersistenceAdapters::Sequel.new ARGV[0] || 'sqlite://db.sqlite'
|
|
12
|
+
|
|
13
|
+
world = Dynflow::SimpleWorld.new do |world|
|
|
14
|
+
{ persistence_adapter: persistence_adapter,
|
|
15
|
+
executor: Dynflow::Executors::RemoteViaSocket.new(world, socket_path) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
load File.join(root_path, 'test', 'code_workflow_example.rb')
|
|
19
|
+
|
|
20
|
+
loop do
|
|
21
|
+
world.trigger Dynflow::CodeWorkflowExample::Slow, 1
|
|
22
|
+
sleep 0.5
|
|
23
|
+
p 'tick'
|
|
24
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Simple example on how Dynflow could be used for simple infrastructure orchestration
|
|
2
|
+
|
|
3
|
+
module Orchestrate
|
|
4
|
+
|
|
5
|
+
class CreateInfrastructure < Dynflow::Action
|
|
6
|
+
|
|
7
|
+
def plan
|
|
8
|
+
sequence do
|
|
9
|
+
concurrence do
|
|
10
|
+
plan_action(CreateMachine, 'host1', 'db')
|
|
11
|
+
plan_action(CreateMachine, 'host2', 'storage')
|
|
12
|
+
end
|
|
13
|
+
plan_action(CreateMachine,
|
|
14
|
+
'host3',
|
|
15
|
+
'web_server',
|
|
16
|
+
:db_machine => 'host1',
|
|
17
|
+
:storage_machine => 'host2')
|
|
18
|
+
end
|
|
19
|
+
sleep 2
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class CreateMachine < Dynflow::Action
|
|
24
|
+
|
|
25
|
+
def plan(name, profile, config_options = {})
|
|
26
|
+
prepare_disk = plan_action(PrepareDisk, 'name' => name)
|
|
27
|
+
create_vm = plan_action(CreateVM,
|
|
28
|
+
:name => name,
|
|
29
|
+
:disk => prepare_disk.output['path'])
|
|
30
|
+
plan_action(AddIPtoHosts, :name => name, :ip => create_vm.output[:ip])
|
|
31
|
+
plan_action(ConfigureMachine,
|
|
32
|
+
:ip => create_vm.output[:ip],
|
|
33
|
+
:profile => profile,
|
|
34
|
+
:config_options => config_options)
|
|
35
|
+
plan_self(:name => name)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def finalize
|
|
39
|
+
puts "We've create a machine #{input[:name]}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class PrepareDisk < Dynflow::Action
|
|
45
|
+
|
|
46
|
+
input_format do
|
|
47
|
+
param :name
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
output_format do
|
|
51
|
+
param :path
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def run
|
|
55
|
+
sleep(rand(5))
|
|
56
|
+
output[:path] = "/var/images/#{input[:name]}.img"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class CreateVM < Dynflow::Action
|
|
62
|
+
|
|
63
|
+
input_format do
|
|
64
|
+
param :name
|
|
65
|
+
param :disk
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
output_format do
|
|
69
|
+
param :ip
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def run
|
|
73
|
+
sleep(rand(5))
|
|
74
|
+
output[:ip] = "192.168.100.#{rand(256)}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
class AddIPtoHosts < Dynflow::Action
|
|
80
|
+
|
|
81
|
+
input_format do
|
|
82
|
+
param :ip
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def run
|
|
86
|
+
sleep(rand(5))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class ConfigureMachine < Dynflow::Action
|
|
92
|
+
|
|
93
|
+
input_format do
|
|
94
|
+
param :ip
|
|
95
|
+
param :profile
|
|
96
|
+
param :config_options
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def run
|
|
100
|
+
# for demonstration of resuming after error
|
|
101
|
+
if Orchestrate.should_fail?
|
|
102
|
+
Orchestrate.should_pass!
|
|
103
|
+
raise "temporary unavailabe"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
sleep(rand(5))
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# for simulation of the execution failing for the first time
|
|
113
|
+
def self.should_fail?
|
|
114
|
+
! @should_pass
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def self.should_pass!
|
|
118
|
+
@should_pass = true
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
root_path = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
|
4
|
+
dynflow_path = File.join(root_path, 'lib')
|
|
5
|
+
$LOAD_PATH << dynflow_path unless $LOAD_PATH.include? dynflow_path
|
|
6
|
+
|
|
7
|
+
require 'dynflow'
|
|
8
|
+
require 'tmpdir'
|
|
9
|
+
|
|
10
|
+
socket = File.join(Dir.tmpdir, 'dynflow_socket')
|
|
11
|
+
persistence_adapter = Dynflow::PersistenceAdapters::Sequel.new ARGV[0] || 'sqlite://db.sqlite'
|
|
12
|
+
world = Dynflow::SimpleWorld.new persistence_adapter: persistence_adapter
|
|
13
|
+
listener = Dynflow::Listeners::Socket.new world, socket
|
|
14
|
+
|
|
15
|
+
load File.join(root_path, 'test', 'code_workflow_example.rb')
|
|
16
|
+
|
|
17
|
+
Dynflow::Daemon.new(listener, world).run
|