-
Notifications
You must be signed in to change notification settings - Fork 45
/
Copy pathorchestrate_evented.rb
executable file
·161 lines (134 loc) · 3.99 KB
/
orchestrate_evented.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env ruby
# frozen_string_literal: true
require_relative 'example_helper'
example_description = <<DESC
Orchestrate Evented Example
===========================
This example, how the `examples/orchestrate.rb` can be updated to not block
the threads while waiting for external tasks. In this cases, we usually wait
most of the time: and we can suspend the run of the action while waiting,
for the event. Therefore we suspend the action in the run, ask the world.clock
to wake us up few seconds later, so that the thread pool can do something useful
in the meantime.
Additional benefit besides being able to do more while waiting is allowing to
send external events to the action while it's suspended. One use case is being
able to cancel the action while it's running.
Once the Sinatra web console starts, you can navigate to #{ExampleHelper::DYNFLOW_URL}
to see what's happening in the Dynflow world.
DESC
module OrchestrateEvented
class CreateInfrastructure < Dynflow::Action
def plan(get_stuck = false)
sequence do
concurrence do
plan_action(CreateMachine, 'host1', 'db', get_stuck: get_stuck)
plan_action(CreateMachine, 'host2', 'storage')
end
plan_action(CreateMachine,
'host3',
'web_server',
:db_machine => 'host1',
:storage_machine => 'host2')
end
end
end
class CreateMachine < Dynflow::Action
def plan(name, profile, config_options = {})
prepare_disk = plan_action(PrepareDisk, 'name' => name)
create_vm = plan_action(CreateVM,
:name => name,
:disk => prepare_disk.output['path'])
plan_action(AddIPtoHosts, :name => name, :ip => create_vm.output[:ip])
plan_action(ConfigureMachine,
:ip => create_vm.output[:ip],
:profile => profile,
:config_options => config_options)
plan_self(:name => name)
end
def finalize
end
end
class Base < Dynflow::Action
Finished = Algebrick.atom
def run(event = nil)
match(event,
(on Finished do
on_finish
end),
(on Dynflow::Action::Skip do
# do nothing
end),
(on nil do
suspend { |suspended_action| world.clock.ping suspended_action, rand(1), Finished }
end))
end
def on_finish
raise NotImplementedError
end
end
class PrepareDisk < Base
input_format do
param :name
end
output_format do
param :path
end
def on_finish
output[:path] = "/var/images/#{input[:name]}.img"
end
end
class CreateVM < Base
input_format do
param :name
param :disk
end
output_format do
param :ip
end
def on_finish
output[:ip] = "192.168.100.#{rand(256)}"
end
end
class AddIPtoHosts < Base
input_format do
param :ip
end
def on_finish
end
end
class ConfigureMachine < Base
# thanks to this Dynflow knows this action can be politely
# asked to get canceled
include ::Dynflow::Action::Cancellable
input_format do
param :ip
param :profile
param :config_options
end
def run(event = nil)
if event == Dynflow::Action::Cancellable::Cancel
output[:message] = "I was cancelled but we don't care"
else
super
end
end
def on_finish
if input[:config_options][:get_stuck]
puts <<-MSG.gsub(/^.*\|/, '')
| Execution plan #{execution_plan_id} got stuck
| You can cancel the stucked step at
| #{ExampleHelper::DYNFLOW_URL}/#{execution_plan_id}
MSG
# we suspend the action but don't plan the wakeup event,
# causing it to wait forever (till we cancel it)
suspend
end
end
end
end
if $0 == __FILE__
ExampleHelper.world.trigger(OrchestrateEvented::CreateInfrastructure)
ExampleHelper.world.trigger(OrchestrateEvented::CreateInfrastructure, true)
puts example_description
ExampleHelper.run_web_console
end