foreman-tasks 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e52c285f1d8c6c98cc334d7d1028b190cebca6ea
4
- data.tar.gz: 3d924a2162dfa1085a7d22c470184c0b5cebed61
3
+ metadata.gz: b55e0faa2c0c85d85d432c28bd50b9fea076a338
4
+ data.tar.gz: eb3840f629fe5b52380423e0ca0821f7d1562f95
5
5
  SHA512:
6
- metadata.gz: f8f42b585c90c6a2b5af2f57022a0bc8bd8c87367007f7dede5ed39c37431cdc84d553de1c3fb0e1876d34b667f31445e9f6afa191b85346e7ac92cad1ac4e21
7
- data.tar.gz: 4397ef5b4c91c7598eb67edd6591341d44b725a955b2d048505e06c34a02d7ca3c670949fe7e196c6aa5963e667ef41fdf18a7ca71bdcda5af9baddb76ee7bc4
6
+ metadata.gz: ddb0a9efe1b688fd922970c6ba03a7ee39518221696c553428d00946ec27ac56bd356b788b808317ce5b6caa346fe2bc830f04c36991ea5cf413ade2e5e4c95c
7
+ data.tar.gz: 05b76b8b00ea367e193d30b404ef17b824f890ca362938b680bc3a55beb7f3162b21c1221859beb613abde70241312b9419d3e23c1bef9b4c12ad4e4a63445da
@@ -20,7 +20,9 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
20
20
  DESC
21
21
 
22
22
  s.files = `git ls-files`.split("\n").reject do |file|
23
- file.end_with? "test.rake"
23
+ file.end_with?("test.rake") ||
24
+ file.start_with?('lib/foreman_tasks_core') ||
25
+ file == 'foreman-tasks-core.gemspec'
24
26
  end
25
27
 
26
28
  s.test_files = `git ls-files test`.split("\n")
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = "0.8.1"
2
+ VERSION = "0.8.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman-tasks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-07 00:00:00.000000000 Z
11
+ date: 2016-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: foreman-tasks-core
@@ -204,7 +204,6 @@ files:
204
204
  - deploy/foreman-tasks.service
205
205
  - deploy/foreman-tasks.sysconfig
206
206
  - extra/dynflow-executor.example
207
- - foreman-tasks-core.gemspec
208
207
  - foreman-tasks.gemspec
209
208
  - lib/foreman-tasks.rb
210
209
  - lib/foreman_tasks.rb
@@ -223,17 +222,6 @@ files:
223
222
  - lib/foreman_tasks/test_extensions.rb
224
223
  - lib/foreman_tasks/triggers.rb
225
224
  - lib/foreman_tasks/version.rb
226
- - lib/foreman_tasks_core.rb
227
- - lib/foreman_tasks_core/continuous_output.rb
228
- - lib/foreman_tasks_core/runner.rb
229
- - lib/foreman_tasks_core/runner/action.rb
230
- - lib/foreman_tasks_core/runner/base.rb
231
- - lib/foreman_tasks_core/runner/command_runner.rb
232
- - lib/foreman_tasks_core/runner/dispatcher.rb
233
- - lib/foreman_tasks_core/runner/update.rb
234
- - lib/foreman_tasks_core/settings_loader.rb
235
- - lib/foreman_tasks_core/shareable_action.rb
236
- - lib/foreman_tasks_core/version.rb
237
225
  - lib/tasks/gettext.rake
238
226
  - locale/Makefile
239
227
  - locale/action_names.rb
@@ -1,20 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
-
4
- # Maintain your gem's version:
5
- require "foreman_tasks_core/version"
6
-
7
- # Describe your gem and declare its dependencies:
8
- Gem::Specification.new do |s|
9
- s.name = "foreman-tasks-core"
10
- s.version = ForemanTasksCore::VERSION
11
- s.authors = ["Ivan Nečas"]
12
- s.email = ["inecas@redhat.com"]
13
- s.homepage = "https://github.com/theforeman/foreman-tasks"
14
- s.summary = "Common code used both at Forman and Foreman proxy regarding tasks"
15
- s.description = <<DESC
16
- Common code used both at Forman and Foreman proxy regarding tasks
17
- DESC
18
-
19
- s.files = Dir['lib/foreman_tasks_core/**/*'] + ['lib/foreman_tasks_core.rb']
20
- end
@@ -1,19 +0,0 @@
1
- # The goal of ForemanTasksCore is to collect parts of foreman-tasks
2
- # that can be shared by the Foreman server and Foreman proxy
3
-
4
- require 'foreman_tasks_core/settings_loader'
5
-
6
- module ForemanTasksCore
7
- def self.dynflow_world
8
- raise "Dynflow world not set. Call initialize first" unless @dynflow_world
9
- @dynflow_world
10
- end
11
-
12
- def self.dynflow_present?
13
- defined? Dynflow
14
- end
15
-
16
- def self.dynflow_setup(dynflow_world)
17
- @dynflow_world = dynflow_world
18
- end
19
- end
@@ -1,50 +0,0 @@
1
- module ForemanTasksCore
2
- class ContinuousOutput
3
- attr_accessor :raw_outputs
4
-
5
- def initialize(raw_outputs = [])
6
- @raw_outputs = []
7
- raw_outputs.each { |raw_output| add_raw_output(raw_output) }
8
- end
9
-
10
- def add_raw_output(raw_output)
11
- missing_args = %w[output_type output timestamp] - raw_output.keys
12
- unless missing_args.empty?
13
- raise ArgumentError, "Missing args for raw output: #{missing_args.inspect}"
14
- end
15
- @raw_outputs << raw_output
16
- end
17
-
18
- def empty?
19
- @raw_outputs.empty?
20
- end
21
-
22
- def last_timestamp
23
- return if @raw_outputs.empty?
24
- @raw_outputs.last.fetch('timestamp')
25
- end
26
-
27
- def sort!
28
- @raw_outputs.sort_by! { |record| record['timestamp'].to_f }
29
- end
30
-
31
- def humanize
32
- sort!
33
- raw_outputs.map { |output| output['output'] }.join("\n")
34
- end
35
-
36
- def add_exception(context, exception, timestamp = Time.now.getlocal)
37
- add_output(context + ": #{exception.class} - #{exception.message}", 'debug', timestamp)
38
- end
39
-
40
- def add_output(*args)
41
- add_raw_output(self.class.format_output(*args))
42
- end
43
-
44
- def self.format_output(message, type = 'debug', timestamp = Time.now.getlocal)
45
- { 'output_type' => type,
46
- 'output' => message,
47
- 'timestamp' => timestamp.to_f }
48
- end
49
- end
50
- end
@@ -1,9 +0,0 @@
1
- module ForemanTasksCore
2
- module Runner
3
- end
4
- end
5
-
6
- require 'foreman_tasks_core/runner/update'
7
- require 'foreman_tasks_core/runner/base'
8
- require 'foreman_tasks_core/runner/dispatcher'
9
- require 'foreman_tasks_core/runner/action'
@@ -1,69 +0,0 @@
1
- require 'foreman_tasks_core/shareable_action'
2
- module ForemanTasksCore
3
- module Runner
4
- class Action < ::ForemanTasksCore::ShareableAction
5
- include ::Dynflow::Action::Cancellable
6
-
7
- def run(event = nil)
8
- case event
9
- when nil
10
- init_run
11
- when Runner::Update
12
- process_update(event)
13
- when ::Dynflow::Action::Cancellable::Cancel
14
- kill_run
15
- else
16
- raise "Unexpected event #{event.inspect}"
17
- end
18
- rescue => e
19
- action_logger.error(e)
20
- process_update(Runner::Update.encode_exception("Proxy error", e))
21
- end
22
-
23
- def finalize
24
- # To mark the task as a whole as failed
25
- error! "Script execution failed" if failed_run?
26
- end
27
-
28
- def rescue_strategy_for_self
29
- ::Dynflow::Action::Rescue::Fail
30
- end
31
-
32
- def initiate_runner
33
- raise NotImplementedError
34
- end
35
-
36
- def init_run
37
- output[:result] = []
38
- output[:runner_id] = runner_dispatcher.start(suspended_action, initiate_runner)
39
- suspend
40
- end
41
-
42
- def runner_dispatcher
43
- Runner::Dispatcher.instance
44
- end
45
-
46
- def kill_run
47
- runner_dispatcher.kill(output[:runner_id])
48
- suspend
49
- end
50
-
51
- def finish_run(update)
52
- output[:exit_status] = update.exit_status
53
- end
54
-
55
- def process_update(update)
56
- output[:result].concat(update.continuous_output.raw_outputs)
57
- if update.exit_status
58
- finish_run(update)
59
- else
60
- suspend
61
- end
62
- end
63
-
64
- def failed_run?
65
- output[:exit_status] != 0
66
- end
67
- end
68
- end
69
- end
@@ -1,60 +0,0 @@
1
- module ForemanTasksCore
2
- module Runner
3
- # Runner is an object that is able to initiate some action and
4
- # provide update data on refresh call.
5
- class Base
6
- attr_reader :id
7
- attr_accessor :logger
8
-
9
- def initialize(*args)
10
- @id = SecureRandom.uuid
11
- @continuous_output = ::ForemanTasksCore::ContinuousOutput.new
12
- end
13
-
14
- def logger
15
- @logger ||= Logger.new(STDERR)
16
- end
17
-
18
- def run_refresh
19
- logger.debug("refreshing runner")
20
- refresh
21
- new_data = @continuous_output
22
- @continuous_output = ForemanTasksCore::ContinuousOutput.new
23
- if !new_data.empty? || @exit_status
24
- return Runner::Update.new(new_data, @exit_status)
25
- end
26
- end
27
-
28
- def start
29
- raise NotImplementedError
30
- end
31
-
32
- def refresh
33
- raise NotImplementedError
34
- end
35
-
36
- def kill
37
- # Override when you can kill the runner in the middle
38
- end
39
-
40
- def close
41
- # if cleanup is needed
42
- end
43
-
44
- def publish_data(data, type)
45
- @continuous_output.add_output(data, type)
46
- end
47
-
48
- def publish_exception(context, exception, fatal = true)
49
- logger.error("#{context} - #{exception.class} #{exception.message}:\n" + \
50
- exception.backtrace.join("\n"))
51
- @continuous_output.add_exception(context, exception)
52
- publish_exit_status('EXCEPTION') if fatal
53
- end
54
-
55
- def publish_exit_status(status)
56
- @exit_status = status
57
- end
58
- end
59
- end
60
- end
@@ -1,41 +0,0 @@
1
- require 'io/wait'
2
- require 'pty'
3
-
4
- module ForemanTasksCore
5
- module Runner
6
- class CommandRunner < Runner::Base
7
- def initialize_command(*command)
8
- @command_out, @command_in, @command_pid = PTY.spawn(*command)
9
- end
10
-
11
- def refresh
12
- return if @command_out.nil?
13
- ready_outputs, * = IO.select([@command_out], nil, nil, 0.1)
14
- if ready_outputs
15
- if @command_out.nread > 0
16
- lines = @command_out.read_nonblock(@command_out.nread)
17
- else
18
- close_io
19
- Process.wait(@command_pid)
20
- publish_exit_status($?.exitstatus)
21
- end
22
- publish_data(lines, 'stdout') if lines && !lines.empty?
23
- end
24
- end
25
-
26
- def close
27
- close_io
28
- end
29
-
30
- private
31
-
32
- def close_io
33
- @command_out.close if @command_out && !@command_out.closed?
34
- @command_out = nil
35
-
36
- @command_in.close if @command_in && !@command_in.closed?
37
- @command_in = nil
38
- end
39
- end
40
- end
41
- end
@@ -1,158 +0,0 @@
1
- module ForemanTasksCore
2
- module Runner
3
- class Dispatcher
4
- def self.instance
5
- return @instance if @instance
6
- @instance = self.new(ForemanTasksCore.dynflow_world.clock,
7
- ForemanTasksCore.dynflow_world.logger)
8
- end
9
-
10
- class RunnerActor < ::Dynflow::Actor
11
- def initialize(dispatcher, suspended_action, runner, clock, logger, options = {})
12
- @dispatcher = dispatcher
13
- @clock = clock
14
- @logger = logger
15
- @suspended_action = suspended_action
16
- @runner = runner
17
- @finishing = false
18
- @refresh_interval = options[:refresh_interval] || 1
19
- end
20
-
21
- def on_envelope(*args)
22
- super
23
- rescue => e
24
- handle_exception(e)
25
- end
26
-
27
- def start_runner
28
- @logger.debug("start runner #{@runner.id}")
29
- @runner.start
30
- refresh_runner
31
- ensure
32
- plan_next_refresh
33
- end
34
-
35
- def refresh_runner
36
- @logger.debug("refresh runner #{@runner.id}")
37
- if update = @runner.run_refresh
38
- @suspended_action << update
39
- finish if update.exit_status
40
- end
41
- ensure
42
- @refresh_planned = false
43
- plan_next_refresh
44
- end
45
-
46
- def kill
47
- @logger.debug("kill runner #{@runner.id}")
48
- @runner.kill
49
- rescue => e
50
- handle_exception(e, false)
51
- end
52
-
53
- def finish
54
- @logger.debug("finish runner #{@runner.id}")
55
- @finishing = true
56
- @dispatcher.finish(@runner.id)
57
- end
58
-
59
- def start_termination(*args)
60
- @logger.debug("terminate #{@runner.id}")
61
- super
62
- @runner.close
63
- finish_termination
64
- end
65
-
66
- private
67
-
68
- def plan_next_refresh
69
- if !@finishing && !@refresh_planned
70
- @logger.debug("planning to refresh #{@runner.id}")
71
- @clock.ping(reference, Time.now + @refresh_interval, :refresh_runner)
72
- @refresh_planned = true
73
- end
74
- end
75
-
76
- def handle_exception(exception, fatal = true)
77
- @dispatcher.handle_command_exception(@runner.id, exception, fatal)
78
- end
79
- end
80
-
81
- def initialize(clock, logger)
82
- @mutex = Mutex.new
83
- @clock = clock
84
- @logger = logger
85
- @runner_actors = {}
86
- @runner_suspended_actions = {}
87
- end
88
-
89
- def synchronize(&block)
90
- @mutex.synchronize(&block)
91
- end
92
-
93
- def start(suspended_action, runner)
94
- synchronize do
95
- begin
96
- raise "Actor with runner id #{runner.id} already exists" if @runner_actors[runner.id]
97
- runner.logger = @logger
98
- runner_actor = RunnerActor.spawn("runner-actor-#{runner.id}", self, suspended_action, runner, @clock, @logger)
99
- @runner_actors[runner.id] = runner_actor
100
- @runner_suspended_actions[runner.id] = suspended_action
101
- runner_actor.tell(:start_runner)
102
- return runner.id
103
- rescue => exception
104
- _handle_command_exception(runner.id, exception)
105
- return nil
106
- end
107
- end
108
- end
109
-
110
- def kill(runner_id)
111
- synchronize do
112
- begin
113
- runner_actor = @runner_actors[runner_id]
114
- runner_actor.tell(:kill) if runner_actor
115
- rescue => exception
116
- _handle_command_exception(runner_id, exception, false)
117
- end
118
- end
119
- end
120
-
121
- def finish(runner_id)
122
- synchronize do
123
- begin
124
- _finish(runner_id)
125
- rescue => exception
126
- _handle_command_exception(runner_id, exception, false)
127
- end
128
- end
129
- end
130
-
131
- def handle_command_exception(*args)
132
- synchronize { _handle_command_exception(*args) }
133
- end
134
-
135
- private
136
-
137
- def _finish(runner_id)
138
- runner_actor = @runner_actors.delete(runner_id)
139
- return unless runner_actor
140
- @logger.debug("closing session for command [#{runner_id}]," +
141
- "#{@runner_actors.size} actors left ")
142
- runner_actor.tell([:start_termination, Concurrent.future])
143
- ensure
144
- @runner_suspended_actions.delete(runner_id)
145
- end
146
-
147
- def _handle_command_exception(runner_id, exception, fatal = true)
148
- @logger.error("error while dispatching request to runner #{runner_id}:"\
149
- "#{exception.class} #{exception.message}:\n #{exception.backtrace.join("\n")}")
150
- suspended_action = @runner_suspended_actions[runner_id]
151
- if suspended_action
152
- suspended_action << Runner::Update.encode_exception("Runner error", exception, fatal)
153
- end
154
- _finish(runner_id) if fatal
155
- end
156
- end
157
- end
158
- end
@@ -1,21 +0,0 @@
1
- require 'foreman_tasks_core/continuous_output'
2
-
3
- module ForemanTasksCore
4
- module Runner
5
- # Runner::Update represents chunk of data produced by runner that
6
- # can be consumed by other components, such as RunnerAction
7
- class Update
8
- attr_reader :continuous_output, :exit_status
9
- def initialize(continuous_output, exit_status)
10
- @continuous_output = continuous_output
11
- @exit_status = exit_status
12
- end
13
-
14
- def self.encode_exception(context, exception, fatal = true)
15
- continuous_output = ::ForemanTasksCore::ContinuousOutput.new
16
- continuous_output.add_exception(context, exception)
17
- return self.new(continuous_output, fatal ? 'EXCEPTION' : nil)
18
- end
19
- end
20
- end
21
- end
@@ -1,53 +0,0 @@
1
- module ForemanTasksCore
2
- module SettingsLoader
3
- def self.settings_registry
4
- @settings_registry ||= {}
5
- end
6
-
7
- def self.name_to_settings
8
- @name_to_settings ||= {}
9
- end
10
-
11
- def self.settings_keys
12
- @settings_keys ||= []
13
- end
14
-
15
- def self.settings_registered?(name)
16
- name_to_settings.key?(name)
17
- end
18
-
19
- def self.register_settings(names, object)
20
- names = [names] unless names.is_a? Array
21
- names.each do |name|
22
- raise "settings name has to be a symbol" unless name.is_a? Symbol
23
- raise "settings #{name} already registered" if SettingsLoader.settings_registered?(name)
24
- name_to_settings[name] = object
25
- end
26
- settings_registry[names] = object
27
- end
28
-
29
- def self.setup_settings(name, settings)
30
- raise "Settings for #{name} were not registered" unless settings_registered?(name)
31
- name_to_settings[name].initialize_settings(settings)
32
- end
33
-
34
- def register_settings(names, defaults = {})
35
- SettingsLoader.register_settings(names, self)
36
- @defaults = defaults
37
- end
38
-
39
- def initialize_settings(settings = {})
40
- @settings = @defaults.merge(settings)
41
- validate_settings!
42
- end
43
-
44
- def settings
45
- raise "Settings for #{self} not initalized" unless @settings
46
- @settings
47
- end
48
-
49
- def validate_settings!
50
- raise "Only symbols expected in keys" unless @settings.keys.all? { |key| key.is_a? Symbol }
51
- end
52
- end
53
- end
@@ -1,19 +0,0 @@
1
- module ForemanTasksCore
2
- class ShareableAction < ::Dynflow::Action
3
- def plan(input)
4
- input = input.dup
5
- callback = input.delete('callback')
6
- if callback
7
- input[:task_id] = callback['task_id']
8
- else
9
- input[:task_id] ||= SecureRandom.uuid
10
- end
11
-
12
- planned_action = plan_self(input)
13
- # code only applicable, when run with SmartProxyDynflowCore in place
14
- if defined?(SmartProxyDynflowCore::Callback) && callback
15
- plan_action(SmartProxyDynflowCore::Callback::Action, callback, planned_action.output)
16
- end
17
- end
18
- end
19
- end
@@ -1,3 +0,0 @@
1
- module ForemanTasksCore
2
- VERSION = '0.1.0'
3
- end