Class: Actions::ProxyAction

Inherits:
Base
  • Object
show all
Includes:
Dynflow::Action::Cancellable, Dynflow::Action::Timeouts
Defined in:
app/lib/actions/proxy_action.rb

Defined Under Namespace

Classes: CallbackData

Instance Method Summary collapse

Methods inherited from Base

#already_running?, #humanized_errors, #humanized_input, #humanized_name, #humanized_output, #serializer_class, #task, #task_input, #task_output

Instance Method Details

#cancel_proxy_taskObject



71
72
73
74
75
76
77
78
79
# File 'app/lib/actions/proxy_action.rb', line 71

def cancel_proxy_task
  if output[:cancel_sent]
    error! ForemanTasks::Task::TaskCancelledException.new(_("Cancel enforced: the task might be still running on the proxy"))
  else
    proxy.cancel_task(output[:proxy_task_id])
    output[:cancel_sent] = true
    suspend
  end
end

#check_task_statusObject



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/lib/actions/proxy_action.rb', line 54

def check_task_status
  if output[:proxy_task_id]
    response = proxy.status_of_task(output[:proxy_task_id])
    if %w(stopped paused).include? response['state']
      if response['result'] == 'error'
        raise ::Foreman::Exception, _("The smart proxy task %s failed.") % (output[:proxy_task_id])
      else
        on_data(response['actions'].find { |block_action| block_action['class'] == proxy_action_name }['output'])
      end
    else
      suspend
    end
  else
    process_timeout
  end
end

#default_connection_optionsObject



144
145
146
147
148
149
150
# File 'app/lib/actions/proxy_action.rb', line 144

def default_connection_options
  # Fails if the plan is not finished within 60 seconds from the first task trigger attempt on the smart proxy
  # If the triggering fails, it retries 3 more times with 15 second delays
  { :retry_interval => Setting['foreman_tasks_proxy_action_retry_interval'] || 15,
    :retry_count    => Setting['foreman_tasks_proxy_action_retry_count' ]   || 4,
    :timeout        => Setting['foreman_tasks_proxy_action_start_timeout']  || 60 }
end

#fill_continuous_output(continuous_output) ⇒ Object

The proxy action is able to contribute to continuous output



112
113
114
115
116
117
118
# File 'app/lib/actions/proxy_action.rb', line 112

def fill_continuous_output(continuous_output)
  failed_proxy_tasks.each do |failure_data|
    message = _('Initialization error: %s') %
        "#{failure_data[:exception_class]} - #{failure_data[:exception_message]}"
    continuous_output.add_output(message, 'debug', failure_data[:timestamp])
  end
end

#metadataObject



124
125
126
127
# File 'app/lib/actions/proxy_action.rb', line 124

def 
  output[:metadata] ||= {}
  output[:metadata]
end

#metadata=(thing) ⇒ Object



129
130
131
132
# File 'app/lib/actions/proxy_action.rb', line 129

def metadata=(thing)
  output[:metadata] ||= {}
  output[:metadata] = thing
end

#on_data(data) ⇒ Object



87
88
89
# File 'app/lib/actions/proxy_action.rb', line 87

def on_data(data)
  output[:proxy_output] = data
end

#on_resumeObject



81
82
83
84
# File 'app/lib/actions/proxy_action.rb', line 81

def on_resume
  # TODO: add logic to load the data from the external action
  suspend
end

#plan(proxy, klass, options) ⇒ Object



14
15
16
17
18
# File 'app/lib/actions/proxy_action.rb', line 14

def plan(proxy, klass, options)
  options[:connection_options] ||= {}
  default_connection_options.each { |key, value| options[:connection_options][key] ||= value }
  plan_self(options.merge(:proxy_url => proxy.url, :proxy_action_name => klass.to_s))
end

#proxyObject



96
97
98
# File 'app/lib/actions/proxy_action.rb', line 96

def proxy
  ProxyAPI::ForemanDynflow::DynflowProxy.new(:url => input[:proxy_url])
end

#proxy_action_nameObject



92
93
94
# File 'app/lib/actions/proxy_action.rb', line 92

def proxy_action_name
  input[:proxy_action_name]
end

#proxy_output(live = false) ⇒ Object



100
101
102
103
104
105
106
107
108
109
# File 'app/lib/actions/proxy_action.rb', line 100

def proxy_output(live = false)
  if output.key?(:proxy_output)
    output.fetch(:proxy_output) || {}
  elsif live && output[:proxy_task_id]
    proxy_data = proxy.status_of_task(output[:proxy_task_id])['actions'].detect { |action| action['class'] == proxy_action_name }
    proxy_data.fetch('output', {})
  else
    {}
  end
end

#proxy_output=(output) ⇒ Object



120
121
122
# File 'app/lib/actions/proxy_action.rb', line 120

def proxy_output=(output)
  output[:proxy_output] = output
end

#run(event = nil) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'app/lib/actions/proxy_action.rb', line 20

def run(event = nil)
  with_connection_error_handling(event) do |event|
    case event
    when nil
      if output[:proxy_task_id]
        on_resume
      else
        trigger_proxy_task
      end
      suspend
    when ::Dynflow::Action::Skip
      # do nothing
    when ::Dynflow::Action::Cancellable::Cancel
      cancel_proxy_task
    when CallbackData
      on_data(event.data)
    when ::Dynflow::Action::Timeouts::Timeout
      check_task_status
    else
      raise "Unexpected event #{event.inspect}"
    end
  end
end

#set_timeout!Object



138
139
140
141
142
# File 'app/lib/actions/proxy_action.rb', line 138

def set_timeout!
  time = Time.now + input[:connection_options][:timeout]
  schedule_timeout(time)
  [:timeout] = time.to_s
end

#timeout_set?Boolean

Returns:

  • (Boolean)


134
135
136
# File 'app/lib/actions/proxy_action.rb', line 134

def timeout_set?
  ![:timeout].nil?
end

#trigger_proxy_taskObject



44
45
46
47
48
49
50
51
52
# File 'app/lib/actions/proxy_action.rb', line 44

def trigger_proxy_task
  suspend do |_suspended_action|
    set_timeout! unless timeout_set?
    response = proxy.trigger_task(proxy_action_name,
                                  input.merge(:callback => { :task_id => task.id,
                                                             :step_id => run_step_id }))
    output[:proxy_task_id] = response["task_id"]
  end
end