floe 0.6.1 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b92b3c488e49ea77447b370e9152c49e11036e8295c6a781feda666662927f9e
4
- data.tar.gz: c553deab6491c9876e28a816cb2422a1318ac6f91a9f9f75cbfc5a144a84d248
3
+ metadata.gz: c121968c8c3f9c70edaa20c0ab3e7937206623b7c06c0cf0f300aceddcde7814
4
+ data.tar.gz: 943d9e77a9e8309a771e57fee5d6f70e5026a4d254b0da5072b768a99f427d1a
5
5
  SHA512:
6
- metadata.gz: 3f5c210d2a745aaed8e3419e228465203dcebb02ee678c1d2b47285083e1f154118c25864e51360d3d062ca0cfade9baa84f5a932804b586f26607a195acc710
7
- data.tar.gz: 238fd469915e8682c449abd26e1950f68fd4b032a32fcace11130109d46dc6962b29e4ce381734d167f5328ef16ee2fdd4bb250f844644abebc571fc001ab2dd
6
+ metadata.gz: 4fa820c364e8dc3266c2fc1eb29d682e72a9d2ab4d8f154aac3a88ff6d4c35e45e124fe714b80110b52e78a0ab654e25f956bc8a39f45f05f3990c0ab26d01ed
7
+ data.tar.gz: b62ac48c4105497c1d3dd2f2ef9d8aec60c25bcadf71046e8488175705365d0d84facde34c11f0047660b5ab2f4390f13babbe8ba2ab6becf31027f027e0b833
data/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.8.0] - 2024-01-17
8
+ ### Added
9
+ - Add CLI shorthand options for docker runner ([#147](https://github.com/ManageIQ/floe/pull/147))
10
+ - Run multiple workflows in exe/floe ([#149](https://github.com/ManageIQ/floe/pull/149))
11
+ - Add secure options for passing credentials via command-line ([#151](https://github.com/ManageIQ/floe/pull/151))
12
+ - Add a Docker Runner pull-policy option ([#155](https://github.com/ManageIQ/floe/pull/155))
13
+
14
+ ### Fixed
15
+ - Fix podman with empty output ([#150](https://github.com/ManageIQ/floe/pull/150))
16
+ - Fix run_container logger saying docker when using podman ([#154](https://github.com/ManageIQ/floe/pull/154))
17
+ - Ensure that workflow credentials is not-nil ([#156](https://github.com/ManageIQ/floe/pull/156))
18
+
19
+ ## [0.7.0] - 2023-12-18
20
+ ### Changed
21
+ - Remove the dependency on more_core_extensions in ReferencePath ([#144](https://github.com/ManageIQ/floe/pull/144))
22
+
23
+ ### Added
24
+ - Implement `ReferencePath#get` ([#144](https://github.com/ManageIQ/floe/pull/144))
25
+ - Allow a State to set a value in Credentials for subsequent states ([#145](https://github.com/ManageIQ/floe/pull/145))
26
+
7
27
  ## [0.6.1] - 2023-11-21
8
28
  ### Fixed
9
29
  - Return an error payload if run_async! fails ([#143](https://github.com/ManageIQ/floe/pull/143))
@@ -106,7 +126,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
106
126
  ### Added
107
127
  - Initial release
108
128
 
109
- [Unreleased]: https://github.com/ManageIQ/floe/compare/v0.6.1...HEAD
129
+ [Unreleased]: https://github.com/ManageIQ/floe/compare/v0.8.0...HEAD
130
+ [0.8.0]: https://github.com/ManageIQ/floe/compare/v0.7.0...v0.8.0
131
+ [0.7.0]: https://github.com/ManageIQ/floe/compare/v0.6.1...v0.7.0
110
132
  [0.6.1]: https://github.com/ManageIQ/floe/compare/v0.6.0...v0.6.1
111
133
  [0.6.0]: https://github.com/ManageIQ/floe/compare/v0.5.0...v0.6.0
112
134
  [0.5.0]: https://github.com/ManageIQ/floe/compare/v0.4.1...v0.5.0
data/README.md CHANGED
@@ -51,6 +51,48 @@ You can provide that at runtime via the `--credentials` parameter:
51
51
  bundle exec ruby exe/floe --workflow my-workflow.asl --credentials='{"roleArn": "arn:aws:iam::111122223333:role/LambdaRole"}'
52
52
  ```
53
53
 
54
+ Or if you are running the floe command programmatically you can securely provide the credentials via a stdin pipe via `--credentials=-`:
55
+ ```
56
+ echo '{"roleArn": "arn:aws:iam::111122223333:role/LambdaRole"}' | bundle exec ruby exe/floe --workflow my-workflow.asl --credentials -
57
+ ```
58
+
59
+ Or you can pass a file path with the `--credentials-file` parameter:
60
+ ```
61
+ bundle exec ruby exe/floe --workflow my-workflow.asl --credentials-file /tmp/20231218-80537-kj494t
62
+ ```
63
+
64
+ If you need to set a credential at runtime you can do that by using the `"ResultPath": "$.Credentials"` directive, for example to user a username/password to login and get a Bearer token:
65
+
66
+ ```
67
+ bundle exec ruby exe/floe --workflow my-workflow.asl --credentials='{"username": "user", "password": "pass"}'
68
+ ```
69
+
70
+ ```json
71
+ {
72
+ "StartAt": "Login",
73
+ "States": {
74
+ "Login": {
75
+ "Type": "Task",
76
+ "Resource": "docker://login:latest",
77
+ "Credentials": {
78
+ "username.$": "$.username",
79
+ "password.$": "$.password"
80
+ },
81
+ "ResultPath": "$.Credentials",
82
+ "Next": "DoSomething"
83
+ },
84
+ "DoSomething": {
85
+ "Type": "Task",
86
+ "Resource": "docker://do-something:latest",
87
+ "Credentials": {
88
+ "token.$": "$.bearer_token"
89
+ },
90
+ "End": true
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
54
96
  ### Ruby Library
55
97
 
56
98
  ```ruby
@@ -120,6 +162,7 @@ end
120
162
  Options supported by the Docker docker runner are:
121
163
 
122
164
  * `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`.
165
+ * `pull-policy` - Pull image policy. The default is missing. Allowed values: always, missing, never
123
166
 
124
167
  #### Podman
125
168
 
@@ -129,6 +172,7 @@ Options supported by the podman docker runner are:
129
172
  * `log-level=string` - Log messages above specified level (trace, debug, info, warn, warning, error, fatal, panic)
130
173
  * `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`.
131
174
  * `noout=boolean` - do not output to stdout
175
+ * `pull-policy=string` - Pull image policy. The default is missing. Allowed values: always, missing, never, newer
132
176
  * `root=string` - Path to the root directory in which data, including images, is stored
133
177
  * `runroot=string` - Path to the 'run directory' where all state information is stored
134
178
  * `runtime=string` - Path to the OCI-compatible binary used to run containers
@@ -147,6 +191,7 @@ Options supported by the kubernetes docker runner are:
147
191
  * `kubeconfig` - Path to a kubeconfig file, defaults to `KUBECONFIG` environment variable or `~/.kube/config`
148
192
  * `kubeconfig_context` - Context to use in the kubeconfig file, defaults to `"default"`
149
193
  * `namespace` - Namespace to use when creating kubernetes resources, defaults to `"default"`
194
+ * `pull-policy` - Pull image policy. The default is Always. Allowed values: IfNotPresent, Always, Never
150
195
  * `server` - A kubernetes API Server URL, overrides anything in your kubeconfig file. If set `KUBERNETES_SERVICE_HOST` and `KUBERNETES_SERVICE_PORT` will be used
151
196
  * `token` - A bearer_token to use to authenticate to the kubernetes API, overrides anything in your kubeconfig file. If present, `/run/secrets/kubernetes.io/serviceaccount/token` will be used
152
197
  * `ca_file` - Path to a certificate-authority file for the kubernetes API, only valid if server and token are passed. If present `/run/secrets/kubernetes.io/serviceaccount/ca.crt` will be used
@@ -0,0 +1,26 @@
1
+ {
2
+ "Comment": "An example showing how to set a credential.",
3
+ "StartAt": "Login",
4
+ "States": {
5
+ "Login": {
6
+ "Type": "Task",
7
+ "Resource": "docker://docker.io/agrare/echo:latest",
8
+ "Parameters": {
9
+ "ECHO": "TOKEN"
10
+ },
11
+ "ResultPath": "$.Credentials",
12
+ "ResultSelector": {
13
+ "bearer_token.$": "$.echo"
14
+ },
15
+ "Next": "DoSomething"
16
+ },
17
+ "DoSomething": {
18
+ "Type": "Task",
19
+ "Resource": "docker://docker.io/agrare/hello-world:latest",
20
+ "Credentials": {
21
+ "bearer_token.$": "$.bearer_token"
22
+ },
23
+ "End": true
24
+ }
25
+ }
26
+ }
data/exe/floe CHANGED
@@ -6,15 +6,31 @@ require "optimist"
6
6
 
7
7
  opts = Optimist.options do
8
8
  version("v#{Floe::VERSION}\n")
9
- opt :workflow, "Path to your workflow json", :type => :string, :required => true
10
- opt :input, "JSON payload to input to the workflow", :default => '{}'
11
- opt :credentials, "JSON payload with credentials", :default => "{}"
12
- opt :docker_runner, "Type of runner for docker images", :default => "docker"
13
- opt :docker_runner_options, "Options to pass to the runner", :type => :strings
9
+ usage("[options] workflow input [workflow2 input2]")
10
+
11
+ opt :workflow, "Path to your workflow json (legacy)", :type => :string
12
+ opt :input, "JSON payload to input to the workflow (legacy)", :type => :string
13
+ opt :credentials, "JSON payload with credentials", :type => :string
14
+ opt :credentials_file, "Path to a file with credentials", :type => :string
15
+ opt :docker_runner, "Type of runner for docker images", :type => :string, :short => 'r'
16
+ opt :docker_runner_options, "Options to pass to the runner", :type => :strings, :short => 'o'
17
+
18
+ opt :docker, "Use docker to run images (short for --docker_runner=docker)", :type => :boolean
19
+ opt :podman, "Use podman to run images (short for --docker_runner=podman)", :type => :boolean
20
+ opt :kubernetes, "Use kubernetes to run images (short for --docker_runner=kubernetes)", :type => :boolean
14
21
  end
15
22
 
16
23
  Optimist.die(:docker_runner, "must be one of #{Floe::Workflow::Runner::TYPES.join(", ")}") unless Floe::Workflow::Runner::TYPES.include?(opts[:docker_runner])
17
24
 
25
+ # legacy support for --workflow
26
+ args = ARGV.empty? ? [opts[:workflow], opts[:input]] : ARGV
27
+ Optimist.die(:workflow, "must be specified") if args.empty?
28
+
29
+ # shortcut support
30
+ opts[:docker_runner] ||= "docker" if opts[:docker]
31
+ opts[:docker_runner] ||= "podman" if opts[:podman]
32
+ opts[:docker_runner] ||= "kubernetes" if opts[:kubernetes]
33
+
18
34
  require "logger"
19
35
  Floe.logger = Logger.new($stdout)
20
36
 
@@ -31,10 +47,36 @@ runner_options = opts[:docker_runner_options].to_h { |opt| opt.split("=", 2) }
31
47
 
32
48
  Floe::Workflow::Runner.docker_runner = runner_klass.new(runner_options)
33
49
 
34
- context = Floe::Workflow::Context.new(:input => opts[:input])
35
- workflow = Floe::Workflow.load(opts[:workflow], context, opts[:credentials])
50
+ credentials =
51
+ if opts[:credentials_given]
52
+ opts[:credentials] == "-" ? $stdin.read : opts[:credentials]
53
+ elsif opts[:credentials_file_given]
54
+ File.read(opts[:credentials_file])
55
+ end
56
+
57
+ workflows =
58
+ args.each_slice(2).map do |workflow, input|
59
+ context = Floe::Workflow::Context.new(:input => input || opts[:input] || "{}")
60
+ Floe::Workflow.load(workflow, context, credentials)
61
+ end
62
+
63
+ # run
64
+
65
+ outstanding = workflows.dup
66
+ until outstanding.empty?
67
+ ready = outstanding.select(&:step_nonblock_ready?)
68
+ ready.map(&:run_nonblock)
69
+ outstanding -= ready.select(&:end?)
70
+ sleep(1) if !outstanding.empty?
71
+ end
72
+
73
+ # display status
74
+
75
+ workflows.each do |workflow|
76
+ puts "", "#{workflow.name}#{" (#{workflow.status})" unless workflow.context.success?}", "===" if workflows.size > 1
77
+ puts workflow.output.inspect
78
+ end
36
79
 
37
- workflow.run!
80
+ # exit status
38
81
 
39
- puts workflow.output.inspect
40
- exit workflow.status == "success" ? 0 : 1
82
+ exit workflows.all? { |workflow| workflow.context.success? } ? 0 : 1
data/floe.gemspec CHANGED
@@ -32,6 +32,5 @@ Gem::Specification.new do |spec|
32
32
  spec.add_dependency "awesome_spawn", "~>1.0"
33
33
  spec.add_dependency "jsonpath", "~>1.1"
34
34
  spec.add_dependency "kubeclient", "~>4.7"
35
- spec.add_dependency "more_core_extensions"
36
35
  spec.add_dependency "optimist", "~>3.0"
37
36
  end
data/lib/floe/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Floe
4
- VERSION = "0.6.1".freeze
4
+ VERSION = "0.8.0".freeze
5
5
  end
@@ -74,6 +74,10 @@ module Floe
74
74
  end
75
75
  end
76
76
 
77
+ def success?
78
+ status == "success"
79
+ end
80
+
77
81
  def state=(val)
78
82
  @context["State"] = val
79
83
  end
@@ -9,6 +9,8 @@ module Floe
9
9
  end
10
10
  end
11
11
 
12
+ attr_reader :payload
13
+
12
14
  def initialize(payload)
13
15
  @payload = payload
14
16
 
@@ -28,10 +30,6 @@ module Floe
28
30
 
29
31
  results.count < 2 ? results.first : results
30
32
  end
31
-
32
- private
33
-
34
- attr_reader :payload
35
33
  end
36
34
  end
37
35
  end
@@ -4,37 +4,54 @@ module Floe
4
4
  class Workflow
5
5
  class ReferencePath < Path
6
6
  class << self
7
+ def get(payload, context)
8
+ new(payload).get(context)
9
+ end
10
+
7
11
  def set(payload, context, value)
8
12
  new(payload).set(context, value)
9
13
  end
10
14
  end
11
15
 
12
- def initialize(*)
13
- require "more_core_extensions/core_ext/hash/nested"
14
- require "more_core_extensions/core_ext/array/nested"
16
+ attr_reader :path
15
17
 
18
+ def initialize(*)
16
19
  super
17
20
 
18
21
  raise Floe::InvalidWorkflowError, "Invalid Reference Path" if payload.match?(/@|,|:|\?/)
22
+ @path = JsonPath.new(payload)
23
+ .path[1..]
24
+ .map { |v| v.match(/\[(?<name>.+)\]/)["name"] }
25
+ .map { |v| v[0] == "'" ? v.delete("'") : v.to_i }
26
+ .compact
27
+ end
28
+
29
+ def get(context)
30
+ return context if path.empty?
31
+
32
+ context.dig(*path)
19
33
  end
20
34
 
21
35
  def set(context, value)
22
36
  result = context.dup
23
37
 
24
- path = JsonPath.new(payload)
25
- .path[1..]
26
- .map { |v| v.match(/\[(?<name>.+)\]/)["name"] }
27
- .map { |v| v[0] == "'" ? v.delete("'") : v.to_i }
28
- .compact
29
-
30
38
  # If the payload is '$' then merge the value into the context
31
- # otherwise use store path to set the value to a sub-key
39
+ # otherwise store the value under the path
32
40
  #
33
41
  # TODO: how to handle non-hash values, raise error if path=$ and value not a hash?
34
42
  if path.empty?
35
43
  result.merge!(value)
36
44
  else
37
- result.store_path(path, value)
45
+ child = result
46
+ keys = path.dup
47
+ last_key = keys.pop
48
+
49
+ keys.each do |key|
50
+ child[key] = {} if child[key].nil?
51
+ child = child[key]
52
+ end
53
+
54
+ child[last_key] = value
38
55
  end
39
56
 
40
57
  result
@@ -14,7 +14,8 @@ module Floe
14
14
 
15
15
  super
16
16
 
17
- @network = options.fetch("network", "bridge")
17
+ @network = options.fetch("network", "bridge")
18
+ @pull_policy = options["pull-policy"]
18
19
  end
19
20
 
20
21
  def run_async!(resource, env = {}, secrets = {})
@@ -72,7 +73,7 @@ module Floe
72
73
  def run_container(image, env, secrets_file)
73
74
  params = run_container_params(image, env, secrets_file)
74
75
 
75
- logger.debug("Running #{AwesomeSpawn.build_command_line("docker", params)}")
76
+ logger.debug("Running #{AwesomeSpawn.build_command_line(self.class::DOCKER_COMMAND, params)}")
76
77
 
77
78
  result = docker!(*params)
78
79
  result.output
@@ -83,6 +84,7 @@ module Floe
83
84
  params << :detach
84
85
  params += env.map { |k, v| [:e, "#{k}=#{v}"] }
85
86
  params << [:e, "_CREDENTIALS=/run/secrets"] if secrets_file
87
+ params << [:pull, @pull_policy] if @pull_policy
86
88
  params << [:net, "host"] if @network == "host"
87
89
  params << [:v, "#{secrets_file}:/run/secrets:z"] if secrets_file
88
90
  params << [:name, container_name(image)]
@@ -40,6 +40,7 @@ module Floe
40
40
 
41
41
  @namespace = options.fetch("namespace", "default")
42
42
 
43
+ @pull_policy = options["pull-policy"]
43
44
  @task_service_account = options["task_service_account"]
44
45
 
45
46
  super
@@ -143,6 +144,7 @@ module Floe
143
144
  }
144
145
  }
145
146
 
147
+ spec[:spec][:imagePullPolicy] = @pull_policy if @pull_policy
146
148
  spec[:spec][:serviceAccountName] = @task_service_account if @task_service_account
147
149
 
148
150
  if secret
@@ -16,6 +16,7 @@ module Floe
16
16
  @log_level = options["log-level"]
17
17
  @network = options["network"]
18
18
  @noout = options["noout"].to_s == "true" if options.key?("noout")
19
+ @pull_policy = options["pull-policy"]
19
20
  @root = options["root"]
20
21
  @runroot = options["runroot"]
21
22
  @runtime = options["runtime"]
@@ -35,7 +36,8 @@ module Floe
35
36
  params << :detach
36
37
  params += env.map { |k, v| [:e, "#{k}=#{v}"] }
37
38
  params << [:e, "_CREDENTIALS=/run/secrets/#{secret}"] if secret
38
- params << [:net, "host"] if @network == "host"
39
+ params << [:pull, @pull_policy] if @pull_policy
40
+ params << [:net, "host"] if @network == "host"
39
41
  params << [:secret, secret] if secret
40
42
  params << [:name, container_name(image)]
41
43
  params << image
@@ -33,10 +33,6 @@ module Floe
33
33
  raise Floe::InvalidWorkflowError, "State name [#{name}] must be less than or equal to 80 characters" if name.length > 80
34
34
  end
35
35
 
36
- def run!(_input = nil)
37
- wait until run_nonblock! == 0
38
- end
39
-
40
36
  def wait(timeout: 5)
41
37
  start = Time.now.utc
42
38
 
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Floe
4
+ class Workflow
5
+ module States
6
+ module InputOutputMixin
7
+ def process_input(input)
8
+ input = input_path.value(context, input)
9
+ input = parameters.value(context, input) if parameters
10
+ input
11
+ end
12
+
13
+ def process_output(input, results)
14
+ return input if results.nil?
15
+ return if output_path.nil?
16
+
17
+ results = result_selector.value(context, results) if @result_selector
18
+ if result_path.payload.start_with?("$.Credentials")
19
+ credentials = result_path.set(workflow.credentials, results)["Credentials"]
20
+ workflow.credentials.merge!(credentials)
21
+ output = input
22
+ else
23
+ output = result_path.set(input, results)
24
+ end
25
+
26
+ output_path.value(context, output)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -4,6 +4,7 @@ module Floe
4
4
  class Workflow
5
5
  module States
6
6
  class Pass < Floe::Workflow::State
7
+ include InputOutputMixin
7
8
  include NonTerminalMixin
8
9
 
9
10
  attr_reader :end, :next, :result, :parameters, :input_path, :output_path, :result_path
@@ -25,12 +26,11 @@ module Floe
25
26
 
26
27
  def start(input)
27
28
  super
28
- output = input_path.value(context, input)
29
- output = result_path.set(output, result) if result && result_path
30
- output = output_path.value(context, output)
31
29
 
30
+ input = process_input(input)
31
+
32
+ context.output = process_output(input, result)
32
33
  context.next_state = end? ? nil : @next
33
- context.output = output
34
34
  end
35
35
 
36
36
  def running?
@@ -4,6 +4,7 @@ module Floe
4
4
  class Workflow
5
5
  module States
6
6
  class Task < Floe::Workflow::State
7
+ include InputOutputMixin
7
8
  include NonTerminalMixin
8
9
 
9
10
  attr_reader :credentials, :end, :heartbeat_seconds, :next, :parameters,
@@ -49,7 +50,7 @@ module Floe
49
50
 
50
51
  if success?
51
52
  output = parse_output(output)
52
- context.state["Output"] = process_output!(output)
53
+ context.state["Output"] = process_output(context.input.dup, output)
53
54
  context.next_state = next_state
54
55
  else
55
56
  error = parse_error(output)
@@ -126,12 +127,6 @@ module Floe
126
127
  context.state["Error"] = context.output["Error"]
127
128
  end
128
129
 
129
- def process_input(input)
130
- input = input_path.value(context, input)
131
- input = parameters.value(context, input) if parameters
132
- input
133
- end
134
-
135
130
  def parse_error(output)
136
131
  return if output.nil?
137
132
  return output if output.kind_of?(Hash)
@@ -142,24 +137,14 @@ module Floe
142
137
  end
143
138
 
144
139
  def parse_output(output)
145
- return if output.nil?
146
140
  return output if output.kind_of?(Hash)
141
+ return if output.nil? || output.empty?
147
142
 
148
143
  JSON.parse(output.split("\n").last)
149
144
  rescue JSON::ParserError
150
145
  nil
151
146
  end
152
147
 
153
- def process_output!(results)
154
- output = context.input.dup
155
- return output if results.nil?
156
- return if output_path.nil?
157
-
158
- results = result_selector.value(context, results) if result_selector
159
- output = result_path.set(output, results)
160
- output_path.value(context, output)
161
- end
162
-
163
148
  def next_state
164
149
  end? ? nil : @next
165
150
  end
data/lib/floe/workflow.rb CHANGED
@@ -8,9 +8,12 @@ module Floe
8
8
  include Logging
9
9
 
10
10
  class << self
11
- def load(path_or_io, context = nil, credentials = {})
11
+ def load(path_or_io, context = nil, credentials = {}, name = nil)
12
12
  payload = path_or_io.respond_to?(:read) ? path_or_io.read : File.read(path_or_io)
13
- new(payload, context, credentials)
13
+ # default the name if it is a filename and none was passed in
14
+ name ||= path_or_io.respond_to?(:read) ? "stream" : path_or_io.split("/").last.split(".").first
15
+
16
+ new(payload, context, credentials, name)
14
17
  end
15
18
 
16
19
  def wait(workflows, timeout: 5)
@@ -31,9 +34,9 @@ module Floe
31
34
  end
32
35
  end
33
36
 
34
- attr_reader :context, :credentials, :payload, :states, :states_by_name, :start_at
37
+ attr_reader :context, :credentials, :payload, :states, :states_by_name, :start_at, :name
35
38
 
36
- def initialize(payload, context = nil, credentials = {})
39
+ def initialize(payload, context = nil, credentials = {}, name = nil)
37
40
  payload = JSON.parse(payload) if payload.kind_of?(String)
38
41
  credentials = JSON.parse(credentials) if credentials.kind_of?(String)
39
42
  context = Context.new(context) unless context.kind_of?(Context)
@@ -42,12 +45,13 @@ module Floe
42
45
  raise Floe::InvalidWorkflowError, "Missing field \"StartAt\"" if payload["StartAt"].nil?
43
46
  raise Floe::InvalidWorkflowError, "\"StartAt\" not in the \"States\" field" unless payload["States"].key?(payload["StartAt"])
44
47
 
48
+ @name = name
45
49
  @payload = payload
46
50
  @context = context
47
- @credentials = credentials
51
+ @credentials = credentials || {}
48
52
  @start_at = payload["StartAt"]
49
53
 
50
- @states = payload["States"].to_a.map { |name, state| State.build!(self, name, state) }
54
+ @states = payload["States"].to_a.map { |state_name, state| State.build!(self, state_name, state) }
51
55
  @states_by_name = @states.each_with_object({}) { |state, result| result[state.name] = state }
52
56
 
53
57
  unless context.state.key?("Name")
@@ -58,16 +62,6 @@ module Floe
58
62
  raise Floe::InvalidWorkflowError, err.message
59
63
  end
60
64
 
61
- def run!
62
- step until end?
63
- self
64
- end
65
-
66
- def step
67
- step_nonblock_wait until step_nonblock == 0
68
- self
69
- end
70
-
71
65
  def run_nonblock
72
66
  loop while step_nonblock == 0 && !end?
73
67
  self
data/lib/floe.rb CHANGED
@@ -25,6 +25,7 @@ require_relative "floe/workflow/runner/podman"
25
25
  require_relative "floe/workflow/state"
26
26
  require_relative "floe/workflow/states/choice"
27
27
  require_relative "floe/workflow/states/fail"
28
+ require_relative "floe/workflow/states/input_output_mixin"
28
29
  require_relative "floe/workflow/states/map"
29
30
  require_relative "floe/workflow/states/non_terminal_mixin"
30
31
  require_relative "floe/workflow/states/parallel"
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.6.1
4
+ version: 0.8.0
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-21 00:00:00.000000000 Z
11
+ date: 2024-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_spawn
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '4.7'
55
- - !ruby/object:Gem::Dependency
56
- name: more_core_extensions
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: optimist
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -96,6 +82,7 @@ files:
96
82
  - Gemfile
97
83
  - README.md
98
84
  - Rakefile
85
+ - examples/set-credential.asl
99
86
  - examples/workflow.asl
100
87
  - exe/floe
101
88
  - floe.gemspec
@@ -123,6 +110,7 @@ files:
123
110
  - lib/floe/workflow/state.rb
124
111
  - lib/floe/workflow/states/choice.rb
125
112
  - lib/floe/workflow/states/fail.rb
113
+ - lib/floe/workflow/states/input_output_mixin.rb
126
114
  - lib/floe/workflow/states/map.rb
127
115
  - lib/floe/workflow/states/non_terminal_mixin.rb
128
116
  - lib/floe/workflow/states/parallel.rb