floe 0.2.3 → 0.3.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -1
- data/README.md +40 -0
- data/lib/floe/version.rb +1 -1
- data/lib/floe/workflow/choice_rule/and.rb +13 -0
- data/lib/floe/workflow/choice_rule/not.rb +14 -0
- data/lib/floe/workflow/choice_rule/or.rb +13 -0
- data/lib/floe/workflow/choice_rule.rb +16 -12
- data/lib/floe/workflow/context.rb +3 -3
- data/lib/floe/workflow/payload_template.rb +54 -12
- data/lib/floe/workflow/runner/docker.rb +10 -3
- data/lib/floe/workflow/runner/kubernetes.rb +10 -16
- data/lib/floe/workflow/runner/podman.rb +47 -5
- data/lib/floe/workflow/state.rb +0 -9
- data/lib/floe/workflow/states/choice.rb +8 -0
- data/lib/floe/workflow/states/fail.rb +4 -1
- data/lib/floe/workflow/states/pass.rb +10 -1
- data/lib/floe/workflow/states/succeed.rb +8 -2
- data/lib/floe/workflow/states/task.rb +10 -1
- data/lib/floe/workflow/states/wait.rb +10 -1
- data/lib/floe/workflow.rb +2 -2
- data/lib/floe.rb +3 -1
- metadata +5 -3
- data/lib/floe/workflow/choice_rule/boolean.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae01d21cee834a23c32b89a8a1418d5c02e1a7ec825305cce2ea783c9be6fc40
|
4
|
+
data.tar.gz: df5f35ef07d199e929e7cf3bb0a73620a6ee5def9b555abf1409a9f74c6f7b9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4dcf6ccfcf37b0cd187f4dfd876d60deec4f3a1037c20f76e4b759ae61cd394f68afcb23064c3a6c30f76f56e59ff038931e1630a5e7b01393702caf339d3fa
|
7
|
+
data.tar.gz: 0c588d1eb15f71e4ccd9870df09d72e0e1914f6d31d51b0275f39fb9a7fdd68930eb54f254b4dfa13cc184d0cf9b7babae671f7b2bfa5df1f87d77661b3e5036
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,18 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
5
5
|
## [Unreleased]
|
6
6
|
|
7
|
+
## [0.3.1] - 2023-08-29
|
8
|
+
### Added
|
9
|
+
- Add more global podman runner options ([#90])(https://github.com/ManageIQ/floe/pull/90)
|
10
|
+
|
11
|
+
## [0.3.0] - 2023-08-07
|
12
|
+
### Added
|
13
|
+
- Add --network=host option to Docker/Podman runners ([#81])(https://github.com/ManageIQ/floe/pull/81)
|
14
|
+
|
15
|
+
### Fixed
|
16
|
+
- Fix PayloadTemplate value transformation rules ([#78])(https://github.com/ManageIQ/floe/pull/78)
|
17
|
+
- Move end out of the root state node ([#80])(https://github.com/ManageIQ/floe/pull/80)
|
18
|
+
|
7
19
|
## [0.2.3] - 2023-07-28
|
8
20
|
### Fixed
|
9
21
|
- Fix storing next_state in Context ([#76])(https://github.com/ManageIQ/floe/pull/76)
|
@@ -46,7 +58,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
46
58
|
### Added
|
47
59
|
- Initial release
|
48
60
|
|
49
|
-
[Unreleased]: https://github.com/ManageIQ/floe/compare/v0.
|
61
|
+
[Unreleased]: https://github.com/ManageIQ/floe/compare/v0.3.1...HEAD
|
62
|
+
[0.3.1]: https://github.com/ManageIQ/floe/compare/v0.3.0...v0.3.1
|
63
|
+
[0.3.0]: https://github.com/ManageIQ/floe/compare/v0.2.3...v0.3.0
|
64
|
+
[0.2.3]: https://github.com/ManageIQ/floe/compare/v0.2.2...v0.2.3
|
50
65
|
[0.2.2]: https://github.com/ManageIQ/floe/compare/v0.2.1...v0.2.2
|
51
66
|
[0.2.1]: https://github.com/ManageIQ/floe/compare/v0.2.0...v0.2.1
|
52
67
|
[0.2.0]: https://github.com/ManageIQ/floe/compare/v0.1.1...v0.2.0
|
data/README.md
CHANGED
@@ -36,6 +36,21 @@ bundle exec ruby exe/floe --workflow examples/workflow.asl --inputs='{"foo": 1}'
|
|
36
36
|
bundle exec ruby exe/floe --workflow examples/workflow.asl --inputs='{"foo": 1}' --docker-runner kubernetes --docker-runner-options namespace=default server=https://k8s.example.com:6443 token=my-token
|
37
37
|
```
|
38
38
|
|
39
|
+
If your workflow has `Credentials` you can provide a payload that will help resolve those credentials references at runtime.
|
40
|
+
|
41
|
+
For example if your workflow had the following Credentials field with a JSON Path property:
|
42
|
+
```json
|
43
|
+
"Credentials": {
|
44
|
+
"RoleArn.$": "$.roleArn"
|
45
|
+
}
|
46
|
+
```
|
47
|
+
|
48
|
+
You can provide that at runtime via the `--credentials` parameter:
|
49
|
+
|
50
|
+
```
|
51
|
+
bundle exec ruby exe/floe --workflow my-workflow.asl --credentials='{"roleArn": "arn:aws:iam::111122223333:role/LambdaRole"}'
|
52
|
+
```
|
53
|
+
|
39
54
|
### Ruby Library
|
40
55
|
|
41
56
|
```ruby
|
@@ -59,6 +74,31 @@ workflow.run!
|
|
59
74
|
|
60
75
|
### Docker Runner Options
|
61
76
|
|
77
|
+
#### Docker
|
78
|
+
|
79
|
+
Options supported by the Docker docker runner are:
|
80
|
+
|
81
|
+
* `network` - What docker to connect the container to, defaults to `"bridge"`. If you need access to host resources for development you can pass `network=host`.
|
82
|
+
|
83
|
+
#### Podman
|
84
|
+
|
85
|
+
Options supported by the podman docker runner are:
|
86
|
+
|
87
|
+
* `identity=string` - path to SSH identity file, (CONTAINER_SSHKEY)
|
88
|
+
* `log-level=string` - Log messages above specified level (trace, debug, info, warn, warning, error, fatal, panic)
|
89
|
+
* `network=string` - What docker to connect the container to, defaults to `"bridge"`. If you need access to host resources for development you can pass `network=host`.
|
90
|
+
* `noout=boolean` - do not output to stdout
|
91
|
+
* `root=string` - Path to the root directory in which data, including images, is stored
|
92
|
+
* `runroot=string` - Path to the 'run directory' where all state information is stored
|
93
|
+
* `runtime=string` - Path to the OCI-compatible binary used to run containers
|
94
|
+
* `runtime-flag=stringArray` - add global flags for the container runtime
|
95
|
+
* `storage-driver=string` - Select which storage driver is used to manage storage of images and containers
|
96
|
+
* `storage-opt=stringArray` - Used to pass an option to the storage driver
|
97
|
+
* `syslog=boolean` - Output logging information to syslog as well as the console
|
98
|
+
* `tmpdir=string` - Path to the tmp directory for libpod state content
|
99
|
+
* `transient-store=boolean` - Enable transient container storage
|
100
|
+
* `volumepath=string` - Path to the volume directory in which volume data is stored
|
101
|
+
|
62
102
|
#### Kubernetes
|
63
103
|
|
64
104
|
Options supported by the kubernetes docker runner are:
|
data/lib/floe/version.rb
CHANGED
@@ -4,24 +4,28 @@ module Floe
|
|
4
4
|
class Workflow
|
5
5
|
class ChoiceRule
|
6
6
|
class << self
|
7
|
-
def true?(payload, context, input)
|
8
|
-
build(payload).true?(context, input)
|
9
|
-
end
|
10
|
-
|
11
7
|
def build(payload)
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
if (sub_payloads = payload["Not"])
|
9
|
+
Floe::Workflow::ChoiceRule::Not.new(payload, build_children([sub_payloads]))
|
10
|
+
elsif (sub_payloads = payload["And"])
|
11
|
+
Floe::Workflow::ChoiceRule::And.new(payload, build_children(sub_payloads))
|
12
|
+
elsif (sub_payloads = payload["Or"])
|
13
|
+
Floe::Workflow::ChoiceRule::Or.new(payload, build_children(sub_payloads))
|
15
14
|
else
|
16
|
-
Floe::Workflow::ChoiceRule::
|
15
|
+
Floe::Workflow::ChoiceRule::Data.new(payload)
|
17
16
|
end
|
18
17
|
end
|
18
|
+
|
19
|
+
def build_children(sub_payloads)
|
20
|
+
sub_payloads.map { |payload| build(payload) }
|
21
|
+
end
|
19
22
|
end
|
20
23
|
|
21
|
-
attr_reader :next, :payload, :variable
|
24
|
+
attr_reader :next, :payload, :variable, :children
|
22
25
|
|
23
|
-
def initialize(payload)
|
24
|
-
@payload
|
26
|
+
def initialize(payload, children = nil)
|
27
|
+
@payload = payload
|
28
|
+
@children = children
|
25
29
|
|
26
30
|
@next = payload["Next"]
|
27
31
|
@variable = payload["Variable"]
|
@@ -34,7 +38,7 @@ module Floe
|
|
34
38
|
private
|
35
39
|
|
36
40
|
def variable_value(context, input)
|
37
|
-
|
41
|
+
Path.value(variable, context, input)
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
@@ -11,7 +11,7 @@ module Floe
|
|
11
11
|
"Input" => input
|
12
12
|
},
|
13
13
|
"State" => {},
|
14
|
-
"
|
14
|
+
"StateHistory" => [],
|
15
15
|
"StateMachine" => {},
|
16
16
|
"Task" => {}
|
17
17
|
}
|
@@ -29,8 +29,8 @@ module Floe
|
|
29
29
|
@context["State"] = val
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
@context["
|
32
|
+
def state_history
|
33
|
+
@context["StateHistory"]
|
34
34
|
end
|
35
35
|
|
36
36
|
def state_machine
|
@@ -4,34 +4,76 @@ module Floe
|
|
4
4
|
class Workflow
|
5
5
|
class PayloadTemplate
|
6
6
|
def initialize(payload)
|
7
|
-
@
|
7
|
+
@payload_template = parse_payload(payload)
|
8
8
|
end
|
9
9
|
|
10
10
|
def value(context, inputs = {})
|
11
|
-
|
11
|
+
interpolate_value(payload_template, context, inputs)
|
12
12
|
end
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
attr_reader :
|
16
|
+
attr_reader :payload_template
|
17
17
|
|
18
|
-
def
|
18
|
+
def parse_payload(value)
|
19
19
|
case value
|
20
|
-
when Array
|
21
|
-
|
22
|
-
when
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
when Array then parse_payload_array(value)
|
21
|
+
when Hash then parse_payload_hash(value)
|
22
|
+
when String then parse_payload_string(value)
|
23
|
+
else
|
24
|
+
value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_payload_array(value)
|
29
|
+
value.map { |val| parse_payload(val) }
|
30
|
+
end
|
26
31
|
|
32
|
+
def parse_payload_hash(value)
|
33
|
+
value.to_h do |key, val|
|
34
|
+
if key.end_with?(".$")
|
35
|
+
check_key_conflicts(key, value)
|
36
|
+
|
37
|
+
[key, parse_payload(val)]
|
38
|
+
else
|
27
39
|
[key, val]
|
28
40
|
end
|
29
|
-
|
30
|
-
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_payload_string(value)
|
45
|
+
value.start_with?("$") ? Path.new(value) : value
|
46
|
+
end
|
47
|
+
|
48
|
+
def interpolate_value(value, context, inputs)
|
49
|
+
case value
|
50
|
+
when Array then interpolate_value_array(value, context, inputs)
|
51
|
+
when Hash then interpolate_value_hash(value, context, inputs)
|
52
|
+
when Path then value.value(context, inputs)
|
31
53
|
else
|
32
54
|
value
|
33
55
|
end
|
34
56
|
end
|
57
|
+
|
58
|
+
def interpolate_value_array(value, context, inputs)
|
59
|
+
value.map { |val| interpolate_value(val, context, inputs) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def interpolate_value_hash(value, context, inputs)
|
63
|
+
value.to_h do |key, val|
|
64
|
+
if key.end_with?(".$")
|
65
|
+
[key.chomp(".$"), interpolate_value(val, context, inputs)]
|
66
|
+
else
|
67
|
+
[key, val]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_key_conflicts(key, value)
|
73
|
+
if value.key?(key.chomp(".$"))
|
74
|
+
raise Floe::InvalidWorkflowError, "both #{key} and #{key.chomp(".$")} present"
|
75
|
+
end
|
76
|
+
end
|
35
77
|
end
|
36
78
|
end
|
37
79
|
end
|
@@ -4,11 +4,13 @@ module Floe
|
|
4
4
|
class Workflow
|
5
5
|
class Runner
|
6
6
|
class Docker < Floe::Workflow::Runner
|
7
|
-
def initialize(
|
7
|
+
def initialize(options = {})
|
8
8
|
require "awesome_spawn"
|
9
9
|
require "tempfile"
|
10
10
|
|
11
11
|
super
|
12
|
+
|
13
|
+
@network = options.fetch("network", "bridge")
|
12
14
|
end
|
13
15
|
|
14
16
|
def run!(resource, env = {}, secrets = {})
|
@@ -16,7 +18,8 @@ module Floe
|
|
16
18
|
|
17
19
|
image = resource.sub("docker://", "")
|
18
20
|
|
19
|
-
params
|
21
|
+
params = ["run", :rm]
|
22
|
+
params += [[:net, "host"]] if network == "host"
|
20
23
|
params += env.map { |k, v| [:e, "#{k}=#{v}"] } if env
|
21
24
|
|
22
25
|
secrets_file = nil
|
@@ -26,7 +29,7 @@ module Floe
|
|
26
29
|
secrets_file.write(secrets.to_json)
|
27
30
|
secrets_file.flush
|
28
31
|
|
29
|
-
params << [:e, "
|
32
|
+
params << [:e, "_CREDENTIALS=/run/secrets"]
|
30
33
|
params << [:v, "#{secrets_file.path}:/run/secrets:z"]
|
31
34
|
end
|
32
35
|
|
@@ -39,6 +42,10 @@ module Floe
|
|
39
42
|
ensure
|
40
43
|
secrets_file&.close!
|
41
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :network
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|
@@ -47,27 +47,21 @@ module Floe
|
|
47
47
|
|
48
48
|
begin
|
49
49
|
create_pod!(name, image, env, secret)
|
50
|
-
|
51
|
-
|
50
|
+
loop do
|
51
|
+
case pod_info(name).dig("status", "phase")
|
52
|
+
when "Pending", "Running"
|
53
|
+
sleep(1)
|
54
|
+
when "Succeeded"
|
55
|
+
return [0, output(name)]
|
56
|
+
else
|
57
|
+
return [1, output(name)]
|
58
|
+
end
|
52
59
|
end
|
53
|
-
|
54
|
-
exit_status = success?(name) ? 0 : 1
|
55
|
-
results = output(name)
|
56
|
-
|
57
|
-
[exit_status, results]
|
58
60
|
ensure
|
59
61
|
cleanup(name, secret)
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
|
-
def running?(pod_name)
|
64
|
-
%w[Pending Running].include?(pod_info(pod_name).dig("status", "phase"))
|
65
|
-
end
|
66
|
-
|
67
|
-
def success?(pod_name)
|
68
|
-
pod_info(pod_name).dig("status", "phase") == "Succeeded"
|
69
|
-
end
|
70
|
-
|
71
65
|
def output(pod)
|
72
66
|
kubeclient.get_pod_log(pod, namespace).body
|
73
67
|
end
|
@@ -125,7 +119,7 @@ module Floe
|
|
125
119
|
]
|
126
120
|
|
127
121
|
spec[:spec][:containers][0][:env] << {
|
128
|
-
:name => "
|
122
|
+
:name => "_CREDENTIALS",
|
129
123
|
:value => "/run/secrets/#{secret}/secret"
|
130
124
|
}
|
131
125
|
|
@@ -4,11 +4,26 @@ module Floe
|
|
4
4
|
class Workflow
|
5
5
|
class Runner
|
6
6
|
class Podman < Floe::Workflow::Runner
|
7
|
-
def initialize(
|
7
|
+
def initialize(options = {})
|
8
8
|
require "awesome_spawn"
|
9
9
|
require "securerandom"
|
10
10
|
|
11
11
|
super
|
12
|
+
|
13
|
+
@identity = options["identity"]
|
14
|
+
@log_level = options["log-level"]
|
15
|
+
@network = options["network"]
|
16
|
+
@noout = options["noout"].to_s == "true" if options.key?("noout")
|
17
|
+
@root = options["root"]
|
18
|
+
@runroot = options["runroot"]
|
19
|
+
@runtime = options["runtime"]
|
20
|
+
@runtime_flag = options["runtime-flag"]
|
21
|
+
@storage_driver = options["storage-driver"]
|
22
|
+
@storage_opt = options["storage-opt"]
|
23
|
+
@syslog = options["syslog"].to_s == "true" if options.key?("syslog")
|
24
|
+
@tmpdir = options["tmpdir"]
|
25
|
+
@transient_store = !!options["transient-store"] if options.key?("transient-store")
|
26
|
+
@volumepath = options["volumepath"]
|
12
27
|
end
|
13
28
|
|
14
29
|
def run!(resource, env = {}, secrets = {})
|
@@ -16,26 +31,53 @@ module Floe
|
|
16
31
|
|
17
32
|
image = resource.sub("docker://", "")
|
18
33
|
|
19
|
-
params
|
34
|
+
params = ["run", :rm]
|
35
|
+
params += [[:net, "host"]] if @network == "host"
|
20
36
|
params += env.map { |k, v| [:e, "#{k}=#{v}"] } if env
|
21
37
|
|
22
38
|
if secrets && !secrets.empty?
|
23
39
|
secret_guid = SecureRandom.uuid
|
24
|
-
|
40
|
+
podman!("secret", "create", secret_guid, "-", :in_data => secrets.to_json)
|
25
41
|
|
26
|
-
params << [:e, "
|
42
|
+
params << [:e, "_CREDENTIALS=/run/secrets/#{secret_guid}"]
|
27
43
|
params << [:secret, secret_guid]
|
28
44
|
end
|
29
45
|
|
30
46
|
params << image
|
31
47
|
|
32
48
|
logger.debug("Running podman: #{AwesomeSpawn.build_command_line("podman", params)}")
|
33
|
-
result =
|
49
|
+
result = podman!(*params)
|
34
50
|
|
35
51
|
[result.exit_status, result.output]
|
36
52
|
ensure
|
37
53
|
AwesomeSpawn.run("podman", :params => ["secret", "rm", secret_guid]) if secret_guid
|
38
54
|
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def podman!(*args, **kwargs)
|
59
|
+
params = podman_global_options + args
|
60
|
+
|
61
|
+
AwesomeSpawn.run!("podman", :params => params, **kwargs)
|
62
|
+
end
|
63
|
+
|
64
|
+
def podman_global_options
|
65
|
+
options = []
|
66
|
+
options << [:identity, @identity] if @identity
|
67
|
+
options << [:"log-level", @log_level] if @log_level
|
68
|
+
options << :noout if @noout
|
69
|
+
options << [:root, @root] if @root
|
70
|
+
options << [:runroot, @runroot] if @runroot
|
71
|
+
options << [:runtime, @runtime] if @runtime
|
72
|
+
options << [:"runtime-flag", @runtime_flag] if @runtime_flag
|
73
|
+
options << [:"storage-driver", @storage_driver] if @storage_driver
|
74
|
+
options << [:"storage-opt", @storage_opt] if @storage_opt
|
75
|
+
options << :syslog if @syslog
|
76
|
+
options << [:tmpdir, @tmpdir] if @tmpdir
|
77
|
+
options << [:"transient-store", @transient_store] if @transient_store
|
78
|
+
options << [:volumepath, @volumepath] if @volumepath
|
79
|
+
options
|
80
|
+
end
|
39
81
|
end
|
40
82
|
end
|
41
83
|
end
|
data/lib/floe/workflow/state.rb
CHANGED
@@ -25,22 +25,13 @@ module Floe
|
|
25
25
|
@workflow = workflow
|
26
26
|
@name = name
|
27
27
|
@payload = payload
|
28
|
-
@end = !!payload["End"]
|
29
28
|
@type = payload["Type"]
|
30
29
|
@comment = payload["Comment"]
|
31
30
|
end
|
32
31
|
|
33
|
-
def end?
|
34
|
-
@end
|
35
|
-
end
|
36
|
-
|
37
32
|
def context
|
38
33
|
workflow.context
|
39
34
|
end
|
40
|
-
|
41
|
-
def status
|
42
|
-
end? ? "success" : "running"
|
43
|
-
end
|
44
35
|
end
|
45
36
|
end
|
46
37
|
end
|
@@ -10,6 +10,7 @@ module Floe
|
|
10
10
|
super
|
11
11
|
|
12
12
|
@next = payload["Next"]
|
13
|
+
@end = !!payload["End"]
|
13
14
|
@result = payload["Result"]
|
14
15
|
|
15
16
|
@parameters = PayloadTemplate.new(payload["Parameters"]) if payload["Parameters"]
|
@@ -23,7 +24,15 @@ module Floe
|
|
23
24
|
output = result_path.set(output, result) if result && result_path
|
24
25
|
output = output_path.value(context, output)
|
25
26
|
|
26
|
-
[@next, output]
|
27
|
+
[@end ? nil : @next, output]
|
28
|
+
end
|
29
|
+
|
30
|
+
def status
|
31
|
+
@end ? "success" : "running"
|
32
|
+
end
|
33
|
+
|
34
|
+
def end?
|
35
|
+
@end
|
27
36
|
end
|
28
37
|
end
|
29
38
|
end
|
@@ -13,6 +13,7 @@ module Floe
|
|
13
13
|
|
14
14
|
@heartbeat_seconds = payload["HeartbeatSeconds"]
|
15
15
|
@next = payload["Next"]
|
16
|
+
@end = !!payload["End"]
|
16
17
|
@resource = payload["Resource"]
|
17
18
|
@timeout_seconds = payload["TimeoutSeconds"]
|
18
19
|
@retry = payload["Retry"].to_a.map { |retrier| Retrier.new(retrier) }
|
@@ -33,7 +34,7 @@ module Floe
|
|
33
34
|
_exit_status, results = runner.run!(resource, input, credentials&.value({}, workflow.credentials))
|
34
35
|
|
35
36
|
output = process_output!(input, results)
|
36
|
-
[@next, output]
|
37
|
+
[@end ? nil : @next, output]
|
37
38
|
rescue => err
|
38
39
|
retrier = self.retry.detect { |r| (r.error_equals & [err.to_s, "States.ALL"]).any? }
|
39
40
|
retry if retry!(retrier)
|
@@ -44,6 +45,14 @@ module Floe
|
|
44
45
|
[catcher.next, output]
|
45
46
|
end
|
46
47
|
|
48
|
+
def status
|
49
|
+
@end ? "success" : "running"
|
50
|
+
end
|
51
|
+
|
52
|
+
def end?
|
53
|
+
@end
|
54
|
+
end
|
55
|
+
|
47
56
|
private
|
48
57
|
|
49
58
|
def retry!(retrier)
|
@@ -10,6 +10,7 @@ module Floe
|
|
10
10
|
super
|
11
11
|
|
12
12
|
@next = payload["Next"]
|
13
|
+
@end = !!payload["End"]
|
13
14
|
@seconds = payload["Seconds"].to_i
|
14
15
|
|
15
16
|
@input_path = Path.new(payload.fetch("InputPath", "$"))
|
@@ -20,7 +21,15 @@ module Floe
|
|
20
21
|
input = input_path.value(context, input)
|
21
22
|
sleep(seconds)
|
22
23
|
output = output_path.value(context, input)
|
23
|
-
[@next, output]
|
24
|
+
[@end ? nil : @next, output]
|
25
|
+
end
|
26
|
+
|
27
|
+
def status
|
28
|
+
@end ? "success" : "running"
|
29
|
+
end
|
30
|
+
|
31
|
+
def end?
|
32
|
+
@end
|
24
33
|
end
|
25
34
|
end
|
26
35
|
end
|
data/lib/floe/workflow.rb
CHANGED
@@ -55,12 +55,12 @@ module Floe
|
|
55
55
|
tock = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
56
56
|
|
57
57
|
context.state["FinishedTime"] = Time.now.utc
|
58
|
-
context.state["Duration"] =
|
58
|
+
context.state["Duration"] = tock - tick
|
59
59
|
context.state["Output"] = output
|
60
60
|
|
61
61
|
logger.info("Running state: [#{current_state.name}] with input [#{context["Input"]}]...Complete - next state: [#{next_state}] output: [#{output}]")
|
62
62
|
|
63
|
-
context.
|
63
|
+
context.state_history << context.state
|
64
64
|
|
65
65
|
@status = current_state.status
|
66
66
|
@current_state = next_state && @states_by_name[next_state]
|
data/lib/floe.rb
CHANGED
@@ -8,7 +8,9 @@ require_relative "floe/logging"
|
|
8
8
|
require_relative "floe/workflow"
|
9
9
|
require_relative "floe/workflow/catcher"
|
10
10
|
require_relative "floe/workflow/choice_rule"
|
11
|
-
require_relative "floe/workflow/choice_rule/
|
11
|
+
require_relative "floe/workflow/choice_rule/not"
|
12
|
+
require_relative "floe/workflow/choice_rule/or"
|
13
|
+
require_relative "floe/workflow/choice_rule/and"
|
12
14
|
require_relative "floe/workflow/choice_rule/data"
|
13
15
|
require_relative "floe/workflow/context"
|
14
16
|
require_relative "floe/workflow/path"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: floe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ManageIQ Developers
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_spawn
|
@@ -148,8 +148,10 @@ files:
|
|
148
148
|
- lib/floe/workflow.rb
|
149
149
|
- lib/floe/workflow/catcher.rb
|
150
150
|
- lib/floe/workflow/choice_rule.rb
|
151
|
-
- lib/floe/workflow/choice_rule/
|
151
|
+
- lib/floe/workflow/choice_rule/and.rb
|
152
152
|
- lib/floe/workflow/choice_rule/data.rb
|
153
|
+
- lib/floe/workflow/choice_rule/not.rb
|
154
|
+
- lib/floe/workflow/choice_rule/or.rb
|
153
155
|
- lib/floe/workflow/context.rb
|
154
156
|
- lib/floe/workflow/path.rb
|
155
157
|
- lib/floe/workflow/payload_template.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Floe
|
4
|
-
class Workflow
|
5
|
-
class ChoiceRule
|
6
|
-
class Boolean < Floe::Workflow::ChoiceRule
|
7
|
-
def true?(context, input)
|
8
|
-
if payload.key?("Not")
|
9
|
-
!ChoiceRule.true?(payload["Not"], context, input)
|
10
|
-
elsif payload.key?("And")
|
11
|
-
payload["And"].all? { |choice| ChoiceRule.true?(choice, context, input) }
|
12
|
-
else
|
13
|
-
payload["Or"].any? { |choice| ChoiceRule.true?(choice, context, input) }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|