dynflow 0.8.11 → 0.8.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/dynflow.gemspec +1 -0
- data/lib/dynflow/action.rb +4 -4
- data/lib/dynflow/coordinator.rb +28 -4
- data/lib/dynflow/middleware.rb +3 -0
- data/lib/dynflow/middleware/stack.rb +1 -1
- data/lib/dynflow/middleware/world.rb +1 -1
- data/lib/dynflow/persistence.rb +4 -2
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/web/console_helpers.rb +1 -1
- data/lib/dynflow/world.rb +5 -1
- data/test/coordinator_test.rb +6 -0
- data/test/middleware_test.rb +51 -0
- data/test/support/middleware_example.rb +33 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74ac597ce9af73467ae1ecbf398a2929f1595b14
|
4
|
+
data.tar.gz: 22cb74c9aef05391f93d8652888c9806fd9edde5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aec52cb41798f0730ef950e88195a3973b3d879f584b0e3341e8900147d66ff1b5642d394683894c4a0c33a1eb1d119296c08840dbbb8fb9a90d1b760d8fe0ef
|
7
|
+
data.tar.gz: 5e5908f5ad7938c036c948a1d925c23d714ea2384f3ef6ac0e1a40aa12c97ee71c044c598898e00e2942e04d4473738f975ceaa3b35ce0294b2a00ea0a969ede
|
data/Gemfile
CHANGED
data/dynflow.gemspec
CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_dependency "concurrent-ruby-edge", '~> 0.2'
|
26
26
|
s.add_dependency "sequel"
|
27
27
|
|
28
|
+
s.add_development_dependency "rake"
|
28
29
|
s.add_development_dependency "rack-test"
|
29
30
|
s.add_development_dependency "minitest"
|
30
31
|
s.add_development_dependency "minitest-reporters"
|
data/lib/dynflow/action.rb
CHANGED
@@ -92,8 +92,8 @@ module Dynflow
|
|
92
92
|
|
93
93
|
@phase = Type! attributes.fetch(:phase), Phase
|
94
94
|
@world = Type! world, World
|
95
|
-
@step = Type!
|
96
|
-
|
95
|
+
@step = Type! attributes.fetch(:step), ExecutionPlan::Steps::Abstract, NilClass
|
96
|
+
raise ArgumentError, 'Step reference missing' if phase?(Executable) && @step.nil?
|
97
97
|
@execution_plan_id = Type! attributes.fetch(:execution_plan_id), String
|
98
98
|
@id = Type! attributes.fetch(:id), Integer
|
99
99
|
@plan_step_id = Type! attributes.fetch(:plan_step_id), Integer
|
@@ -240,7 +240,7 @@ module Dynflow
|
|
240
240
|
end
|
241
241
|
|
242
242
|
def state
|
243
|
-
|
243
|
+
raise "state data not available" if @step.nil?
|
244
244
|
@step.state
|
245
245
|
end
|
246
246
|
|
@@ -251,7 +251,7 @@ module Dynflow
|
|
251
251
|
end
|
252
252
|
|
253
253
|
def error
|
254
|
-
|
254
|
+
raise "error data not available" if @step.nil?
|
255
255
|
@step.error
|
256
256
|
end
|
257
257
|
|
data/lib/dynflow/coordinator.rb
CHANGED
@@ -146,6 +146,14 @@ module Dynflow
|
|
146
146
|
@data.merge!(owner_id: "world:#{world.id}", world_id: world.id)
|
147
147
|
end
|
148
148
|
|
149
|
+
def self.lock_id(*args)
|
150
|
+
raise NoMethodError
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.unique_filter(*args)
|
154
|
+
{ :class => self.name, :id => lock_id(*args) }
|
155
|
+
end
|
156
|
+
|
149
157
|
def validate!
|
150
158
|
super
|
151
159
|
raise Errors::InactiveWorldError.new(@world) if @world.terminating?
|
@@ -171,33 +179,49 @@ module Dynflow
|
|
171
179
|
class DelayedExecutorLock < LockByWorld
|
172
180
|
def initialize(world)
|
173
181
|
super
|
174
|
-
@data[:id] =
|
182
|
+
@data[:id] = self.class.lock_id
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.lock_id
|
186
|
+
"delayed-executor"
|
175
187
|
end
|
176
188
|
end
|
177
189
|
|
178
190
|
class WorldInvalidationLock < LockByWorld
|
179
191
|
def initialize(world, invalidated_world)
|
180
192
|
super(world)
|
181
|
-
@data[:id] =
|
193
|
+
@data[:id] = self.class.lock_id(invalidated_world.id)
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.lock_id(invalidated_world_id)
|
197
|
+
"world-invalidation:#{invalidated_world_id}"
|
182
198
|
end
|
183
199
|
end
|
184
200
|
|
185
201
|
class AutoExecuteLock < LockByWorld
|
186
202
|
def initialize(*args)
|
187
203
|
super
|
188
|
-
@data[:id] =
|
204
|
+
@data[:id] = self.class.lock_id
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.lock_id
|
208
|
+
"auto-execute"
|
189
209
|
end
|
190
210
|
end
|
191
211
|
|
192
212
|
class ExecutionLock < LockByWorld
|
193
213
|
def initialize(world, execution_plan_id, client_world_id, request_id)
|
194
214
|
super(world)
|
195
|
-
@data.merge!(id:
|
215
|
+
@data.merge!(id: self.class.lock_id(execution_plan_id),
|
196
216
|
execution_plan_id: execution_plan_id,
|
197
217
|
client_world_id: client_world_id,
|
198
218
|
request_id: request_id)
|
199
219
|
end
|
200
220
|
|
221
|
+
def self.lock_id(execution_plan_id)
|
222
|
+
"execution-plan:#{execution_plan_id}"
|
223
|
+
end
|
224
|
+
|
201
225
|
# we need to store the following data in case of
|
202
226
|
# invalidation of the lock from outside (after
|
203
227
|
# the owner world terminated unexpectedly)
|
data/lib/dynflow/middleware.rb
CHANGED
@@ -14,7 +14,7 @@ module Dynflow
|
|
14
14
|
@middleware_class = Child! middleware_class, Middleware
|
15
15
|
@middleware = middleware_class.new self
|
16
16
|
@action = Type! action, Dynflow::Action, NilClass
|
17
|
-
@method = Match! method, :delay, :plan, :run, :finalize, :plan_phase, :finalize_phase
|
17
|
+
@method = Match! method, :delay, :plan, :run, :finalize, :plan_phase, :finalize_phase, :present
|
18
18
|
@next_stack = Type! next_stack, Middleware::Stack, Proc
|
19
19
|
end
|
20
20
|
|
@@ -14,7 +14,7 @@ module Dynflow
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def execute(method, action_or_class, *args, &block)
|
17
|
-
Match! method, :delay, :plan, :run, :finalize, :plan_phase, :finalize_phase
|
17
|
+
Match! method, :delay, :plan, :run, :finalize, :plan_phase, :finalize_phase, :present
|
18
18
|
if Child? action_or_class, Dynflow::Action
|
19
19
|
action = nil
|
20
20
|
action_class = action_or_class
|
data/lib/dynflow/persistence.rb
CHANGED
@@ -21,9 +21,11 @@ module Dynflow
|
|
21
21
|
return Action.from_hash(attributes, step.world)
|
22
22
|
end
|
23
23
|
|
24
|
-
def load_action_for_presentation(execution_plan, action_id)
|
24
|
+
def load_action_for_presentation(execution_plan, action_id, step = nil)
|
25
25
|
attributes = adapter.load_action(execution_plan.id, action_id)
|
26
|
-
Action.from_hash(attributes.update(phase: Action::Present, execution_plan: execution_plan), @world)
|
26
|
+
Action.from_hash(attributes.update(phase: Action::Present, execution_plan: execution_plan, step: step), @world).tap do |present_action|
|
27
|
+
@world.middleware.execute(:present, present_action) {}
|
28
|
+
end
|
27
29
|
end
|
28
30
|
|
29
31
|
def save_action(execution_plan_id, action)
|
data/lib/dynflow/version.rb
CHANGED
data/lib/dynflow/world.rb
CHANGED
@@ -354,7 +354,11 @@ module Dynflow
|
|
354
354
|
coordinator.acquire(Coordinator::AutoExecuteLock.new(self)) do
|
355
355
|
planned_execution_plans =
|
356
356
|
self.persistence.find_execution_plans filters: { 'state' => %w(planned paused), 'result' => (ExecutionPlan.results - [:error]).map(&:to_s) }
|
357
|
-
planned_execution_plans.map
|
357
|
+
planned_execution_plans.map do |ep|
|
358
|
+
if coordinator.find_locks(Dynflow::Coordinator::ExecutionLock.unique_filter(ep.id)).empty?
|
359
|
+
execute(ep.id)
|
360
|
+
end
|
361
|
+
end.compact
|
358
362
|
end
|
359
363
|
end
|
360
364
|
|
data/test/coordinator_test.rb
CHANGED
@@ -32,6 +32,12 @@ module Dynflow
|
|
32
32
|
tester.finish
|
33
33
|
end
|
34
34
|
|
35
|
+
it 'supports checking about locks' do
|
36
|
+
world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world))
|
37
|
+
locks = world.coordinator.find_locks(Coordinator::AutoExecuteLock.unique_filter)
|
38
|
+
locks.map(&:world_id).must_equal([world.id])
|
39
|
+
end
|
40
|
+
|
35
41
|
it 'deserializes the data from the adapter when searching for locks' do
|
36
42
|
lock = Coordinator::AutoExecuteLock.new(world)
|
37
43
|
world.coordinator.acquire(lock)
|
data/test/middleware_test.rb
CHANGED
@@ -132,6 +132,57 @@ module Dynflow
|
|
132
132
|
'run',
|
133
133
|
'output#message:finished']
|
134
134
|
end
|
135
|
+
|
136
|
+
describe 'Presnet middleware' do
|
137
|
+
let(:world_with_middleware) do
|
138
|
+
WorldFactory.create_world.tap do |world|
|
139
|
+
world.middleware.use(Support::MiddlewareExample::FilterSensitiveData)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
let :execution_plan do
|
144
|
+
result = world.trigger(Support::CodeWorkflowExample::IncomingIssue, issue_data)
|
145
|
+
result.must_be :planned?
|
146
|
+
result.finished.value
|
147
|
+
end
|
148
|
+
|
149
|
+
let :execution_plan_2 do
|
150
|
+
result = world.trigger(Support::MiddlewareExample::SecretAction)
|
151
|
+
result.must_be :planned?
|
152
|
+
result.finished.value
|
153
|
+
end
|
154
|
+
|
155
|
+
let :filtered_execution_plan do
|
156
|
+
world_with_middleware.persistence.load_execution_plan(execution_plan.id)
|
157
|
+
end
|
158
|
+
|
159
|
+
let :issue_data do
|
160
|
+
{ 'author' => 'Harry Potter', 'text' => 'Lord Voldemort is comming' }
|
161
|
+
end
|
162
|
+
|
163
|
+
let :presenter do
|
164
|
+
filtered_execution_plan.root_plan_step.action filtered_execution_plan
|
165
|
+
end
|
166
|
+
|
167
|
+
let :presenter_2 do
|
168
|
+
execution_plan_2.root_plan_step.action execution_plan_2
|
169
|
+
end
|
170
|
+
|
171
|
+
let :presenter_without_middleware do
|
172
|
+
execution_plan.root_plan_step.action execution_plan
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'filters the data ===' do
|
176
|
+
presenter.input['text'].must_equal('You-Know-Who is comming')
|
177
|
+
presenter_2.output['spell'].must_equal('***')
|
178
|
+
end
|
179
|
+
|
180
|
+
it "doesn't affect stored data" do
|
181
|
+
presenter.input['text'].must_equal('You-Know-Who is comming')
|
182
|
+
presenter_without_middleware.input['text'].must_equal('Lord Voldemort is comming')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
135
186
|
end
|
136
187
|
end
|
137
188
|
end
|
@@ -70,6 +70,39 @@ module Support
|
|
70
70
|
class AnotherLogRunMiddleware < LogRunMiddleware
|
71
71
|
end
|
72
72
|
|
73
|
+
class FilterSensitiveData < Dynflow::Middleware
|
74
|
+
def present
|
75
|
+
if action.respond_to?(:filter_sensitive_data)
|
76
|
+
action.filter_sensitive_data
|
77
|
+
end
|
78
|
+
filter_sensitive_data(action.input)
|
79
|
+
filter_sensitive_data(action.output)
|
80
|
+
end
|
81
|
+
|
82
|
+
def filter_sensitive_data(data)
|
83
|
+
case data
|
84
|
+
when Hash
|
85
|
+
data.values.each { |value| filter_sensitive_data(value) }
|
86
|
+
when Array
|
87
|
+
data.each { |value| filter_sensitive_data(value) }
|
88
|
+
when String
|
89
|
+
data.gsub!('Lord Voldemort', 'You-Know-Who')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class SecretAction < Dynflow::Action
|
95
|
+
middleware.use(FilterSensitiveData)
|
96
|
+
|
97
|
+
def run
|
98
|
+
output[:spell] = 'Wingardium Leviosa'
|
99
|
+
end
|
100
|
+
|
101
|
+
def filter_sensitive_data
|
102
|
+
output[:spell] = '***'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
73
106
|
class LoggingAction < Dynflow::Action
|
74
107
|
|
75
108
|
middleware.use LogMiddleware
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Necas
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-07-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -95,6 +95,20 @@ dependencies:
|
|
95
95
|
- - ">="
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: rake
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
98
112
|
- !ruby/object:Gem::Dependency
|
99
113
|
name: rack-test
|
100
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -528,7 +542,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
528
542
|
version: '0'
|
529
543
|
requirements: []
|
530
544
|
rubyforge_project:
|
531
|
-
rubygems_version: 2.4.
|
545
|
+
rubygems_version: 2.4.8
|
532
546
|
signing_key:
|
533
547
|
specification_version: 4
|
534
548
|
summary: DYNamic workFLOW engine
|
@@ -557,3 +571,4 @@ test_files:
|
|
557
571
|
- test/testing_test.rb
|
558
572
|
- test/web_console_test.rb
|
559
573
|
- test/world_test.rb
|
574
|
+
has_rdoc:
|