foreman_remote_execution 1.4.1 → 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +11 -9
- data/.rubocop_todo.yml +146 -116
- data/app/controllers/api/v2/job_invocations_controller.rb +6 -1
- data/app/controllers/api/v2/job_templates_controller.rb +0 -1
- data/app/controllers/job_invocations_controller.rb +6 -1
- data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
- data/app/models/concerns/foreman_remote_execution/errors_flattener.rb +3 -0
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +1 -1
- data/app/models/concerns/foreman_remote_execution/subnet_extensions.rb +1 -1
- data/app/models/foreign_input_set.rb +1 -1
- data/app/models/job_invocation.rb +1 -1
- data/app/models/job_invocation_composer.rb +2 -2
- data/app/models/job_invocation_task_group.rb +1 -1
- data/app/models/job_template.rb +3 -3
- data/app/models/job_template_effective_user.rb +1 -1
- data/app/models/remote_execution_feature.rb +1 -1
- data/app/models/target_remote_execution_proxy.rb +1 -1
- data/app/models/targeting.rb +2 -2
- data/app/models/targeting_host.rb +1 -1
- data/app/models/template_input.rb +1 -1
- data/app/models/template_invocation.rb +1 -1
- data/app/models/template_invocation_input_value.rb +1 -1
- data/db/migrate/20150612121541_add_job_template_to_template.rb +1 -1
- data/db/migrate/20150616080015_create_template_input.rb +1 -1
- data/db/migrate/20150708133241_add_targeting.rb +1 -1
- data/db/migrate/20150708133242_add_invocation.rb +1 -1
- data/db/migrate/20150708133305_add_template_invocation.rb +1 -1
- data/db/migrate/20150812110800_add_resolved_at_to_targeting.rb +1 -1
- data/db/migrate/20150812145900_add_last_task_id_to_job_invocation.rb +1 -1
- data/db/migrate/20150826191632_create_target_remote_execution_proxies.rb +1 -1
- data/db/migrate/20150827144500_change_targeting_search_query_type.rb +1 -1
- data/db/migrate/20150827152730_add_options_to_template_input.rb +1 -1
- data/db/migrate/20150903192731_add_execution_to_interface.rb +2 -2
- data/db/migrate/20150923125825_add_job_invocation_task_group.rb +1 -1
- data/db/migrate/20151013135415_add_pub_key_to_smart_proxy.rb +1 -1
- data/db/migrate/20151022105508_rename_last_task_id_column.rb +1 -1
- data/db/migrate/20151116105412_add_triggering_to_job_invocation.rb +1 -1
- data/db/migrate/20151120171100_add_effective_user_to_template_invocation.rb +1 -1
- data/db/migrate/20151124162300_create_job_template_effective_users.rb +1 -1
- data/db/migrate/20151203100824_add_description_to_job_invocation.rb +1 -1
- data/db/migrate/20151215114631_add_host_id_to_template_invocation.rb +2 -2
- data/db/migrate/20151217092555_migrate_to_task_groups.rb +2 -2
- data/db/migrate/20160108134600_create_template_input_sets.rb +1 -1
- data/db/migrate/20160108141144_make_job_name_default_to_something.rb +1 -1
- data/db/migrate/20160111113032_upcase_ssh_feature.rb +2 -2
- data/db/migrate/20160113161916_add_run_host_job_task_id_to_template_invocation.rb +1 -1
- data/db/migrate/20160113162007_expand_all_template_invocations.rb +3 -3
- data/db/migrate/20160114120200_rename_job_categories.rb +1 -1
- data/db/migrate/20160114125628_rename_job_name_to_job_category.rb +1 -1
- data/db/migrate/20160118124600_create_remote_execution_features.rb +1 -1
- data/db/migrate/20160125155108_make_job_template_name_unique.rb +1 -1
- data/db/migrate/20160127134031_add_advanced_to_template_input.rb +1 -1
- data/db/migrate/20160127162711_reword_puppet_template_description.rb +1 -1
- data/db/migrate/20160203104056_add_concurrency_options_to_job_invocation.rb +1 -1
- data/db/migrate/20160926225841_update_template_input_value.rb +1 -1
- data/db/migrate/20170110145641_add_host_action_button_to_remote_execution_feature.rb +1 -1
- data/db/migrate/20170613101039_add_timeout_to_job_templates_and_job_invocations.rb +1 -1
- data/db/migrate/20180110104432_rename_template_invocation_permission.rb +25 -0
- data/db/migrate/20180112125015_fix_taxable_taxonomies_job_template.rb +14 -0
- data/db/seeds.d/90-bookmarks.rb +1 -1
- data/foreman_remote_execution.gemspec +2 -1
- data/lib/foreman_remote_execution/engine.rb +3 -3
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/benchmark/run_hosts_job_benchmark.rb +10 -10
- data/test/benchmark/targeting_benchmark.rb +6 -6
- data/test/factories/foreman_remote_execution_factories.rb +14 -14
- data/test/functional/api/v2/foreign_input_sets_controller_test.rb +10 -15
- data/test/functional/api/v2/job_invocations_controller_test.rb +19 -8
- data/test/functional/api/v2/job_templates_controller_test.rb +12 -16
- data/test/functional/api/v2/remote_execution_features_controller_test.rb +3 -4
- data/test/functional/api/v2/template_inputs_controller_test.rb +8 -13
- data/test/test_plugin_helper.rb +4 -4
- data/test/unit/actions/run_hosts_job_test.rb +3 -3
- data/test/unit/concerns/exportable_test.rb +1 -1
- data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +2 -2
- data/test/unit/concerns/host_extensions_test.rb +20 -20
- data/test/unit/concerns/nic_extensions_test.rb +1 -1
- data/test/unit/input_template_renderer_test.rb +86 -86
- data/test/unit/job_invocation_composer_test.rb +17 -16
- data/test/unit/job_invocation_test.rb +10 -10
- data/test/unit/job_template_effective_user_test.rb +2 -2
- data/test/unit/job_template_importer_test.rb +3 -3
- data/test/unit/job_template_test.rb +15 -15
- data/test/unit/remote_execution_feature_test.rb +3 -3
- data/test/unit/remote_execution_provider_test.rb +15 -15
- data/test/unit/targeting_test.rb +3 -3
- data/test/unit/template_input_test.rb +1 -1
- data/test/unit/template_invocation_input_value_test.rb +17 -17
- metadata +19 -77
- data/doc/.gitignore +0 -7
- data/doc/Gemfile +0 -7
- data/doc/Rakefile +0 -41
- data/doc/_config.yml +0 -33
- data/doc/plugins/alert_block.rb +0 -27
- data/doc/plugins/div_tag.rb +0 -24
- data/doc/plugins/graphviz.rb +0 -121
- data/doc/plugins/plantuml.rb +0 -84
- data/doc/plugins/play.rb +0 -13
- data/doc/plugins/tags.rb +0 -137
- data/doc/plugins/toc.rb +0 -19
- data/doc/source/.nojekyll +0 -0
- data/doc/source/404.md +0 -6
- data/doc/source/_includes/footer.html +0 -21
- data/doc/source/_includes/header.html +0 -59
- data/doc/source/_includes/tocify.html +0 -6
- data/doc/source/_layouts/default.html +0 -9
- data/doc/source/_layouts/page.html +0 -25
- data/doc/source/atom.xml +0 -32
- data/doc/source/design/index.md +0 -1322
- data/doc/source/design/wireframes.pdf +0 -0
- data/doc/source/index.md +0 -18
- data/doc/source/static/css/bootstrap-responsive.min.css +0 -9
- data/doc/source/static/css/bootstrap.min.css +0 -866
- data/doc/source/static/css/jquery.tocify.css +0 -128
- data/doc/source/static/css/style.css +0 -285
- data/doc/source/static/css/syntax.css +0 -60
- data/doc/source/static/images/foreman.png +0 -0
- data/doc/source/static/images/glyphicons-halflings-white.png +0 -0
- data/doc/source/static/images/glyphicons-halflings.png +0 -0
- data/doc/source/static/js/bootstrap.min.js +0 -7
- data/doc/source/static/js/jquery-ui-1.9.2.custom.min.js +0 -6
- data/doc/source/static/js/jquery.js +0 -2
- data/doc/source/static/js/jquery.tocify.min.js +0 -3
- data/doc/source/static/js/scroll.js +0 -24
data/doc/plugins/play.rb
DELETED
data/doc/plugins/tags.rb
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
require 'nuggets/range/quantile'
|
2
|
-
require 'erb'
|
3
|
-
|
4
|
-
module Jekyll
|
5
|
-
|
6
|
-
class Tagger < Generator
|
7
|
-
|
8
|
-
safe true
|
9
|
-
|
10
|
-
attr_accessor :site
|
11
|
-
|
12
|
-
@types = [:page, :feed]
|
13
|
-
|
14
|
-
class << self; attr_accessor :types, :site; end
|
15
|
-
|
16
|
-
def generate(site)
|
17
|
-
self.class.site = self.site = site
|
18
|
-
|
19
|
-
generate_tag_pages
|
20
|
-
add_tag_cloud
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
# Generates a page per tag and adds them to all the pages of +site+.
|
26
|
-
# A <tt>tag_page_layout</tt> have to be defined in your <tt>_config.yml</tt>
|
27
|
-
# to use this.
|
28
|
-
def generate_tag_pages
|
29
|
-
active_tags.each { |tag, posts| new_tag(tag, posts) }
|
30
|
-
end
|
31
|
-
|
32
|
-
def new_tag(tag, posts)
|
33
|
-
self.class.types.each do |type|
|
34
|
-
if layout = site.config["tag_#{type}_layout"]
|
35
|
-
data = { 'layout' => layout, 'posts' => posts.sort.reverse!, 'tag' => tag, 'title' => tag }
|
36
|
-
|
37
|
-
name = yield data if block_given?
|
38
|
-
name ||= tag
|
39
|
-
|
40
|
-
tag_dir = site.config["tag_#{type}_dir"]
|
41
|
-
tag_dir = File.join(tag_dir, (pretty? ? name : ''))
|
42
|
-
|
43
|
-
page_name = "#{pretty? ? 'index' : name}#{site.layouts[data['layout']].ext}"
|
44
|
-
|
45
|
-
site.pages << TagPage.new(
|
46
|
-
site, site.source, tag_dir, page_name, data
|
47
|
-
)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def add_tag_cloud(num = 5, name = 'tag_data')
|
53
|
-
s, t = site, { name => calculate_tag_cloud(num) }
|
54
|
-
s.respond_to?(:add_payload) ? s.add_payload(t) : s.config.update(t)
|
55
|
-
end
|
56
|
-
|
57
|
-
# Calculates the css class of every tag for a tag cloud. The possible
|
58
|
-
# classes are: set-1..set-5.
|
59
|
-
#
|
60
|
-
# [[<TAG>, <CLASS>], ...]
|
61
|
-
def calculate_tag_cloud(num = 5)
|
62
|
-
range = 0
|
63
|
-
|
64
|
-
tags = active_tags.map do |tag, posts|
|
65
|
-
[tag.to_s, range < (size = posts.size) ? range = size : size]
|
66
|
-
end
|
67
|
-
|
68
|
-
range = 1..range
|
69
|
-
|
70
|
-
tags.sort!.map! { |tag, size| [tag, range.quantile(size, num)] }
|
71
|
-
end
|
72
|
-
|
73
|
-
def active_tags
|
74
|
-
return site.tags unless site.config['ignored_tags']
|
75
|
-
site.tags.reject { |t| site.config['ignored_tags'].include? t[0] }
|
76
|
-
end
|
77
|
-
|
78
|
-
def pretty?
|
79
|
-
@pretty ||= (site.permalink_style == :pretty || site.config['tag_permalink_style'] == 'pretty')
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
class TagPage < Page
|
85
|
-
|
86
|
-
def initialize(site, base, dir, name, data = {})
|
87
|
-
self.content = data.delete('content') || ''
|
88
|
-
self.data = data
|
89
|
-
|
90
|
-
super(site, base, dir[-1, 1] == '/' ? dir : '/' + dir, name)
|
91
|
-
end
|
92
|
-
|
93
|
-
def read_yaml(*)
|
94
|
-
# Do nothing
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
module Filters
|
100
|
-
|
101
|
-
def tag_cloud(site)
|
102
|
-
active_tag_data.map do |tag, set|
|
103
|
-
tag_link(tag, tag_url(tag), :class => "set-#{set} label label-default")
|
104
|
-
end.join(' ')
|
105
|
-
end
|
106
|
-
|
107
|
-
def tag_link(tag, url = tag_url(tag), html_opts = nil)
|
108
|
-
html_opts &&= ' ' << html_opts.map { |k, v| %Q{#{k}="#{v}"} }.join(' ')
|
109
|
-
%Q{<a href="#{url}"#{html_opts}>#{tag}</a>}
|
110
|
-
end
|
111
|
-
|
112
|
-
def tag_url(tag, type = :page, site = Tagger.site)
|
113
|
-
# FIXME generate full url for atom.xml page
|
114
|
-
url = File.join('', site.config["tag_#{type}_dir"], ERB::Util.u(tag))
|
115
|
-
site.permalink_style == :pretty || site.config['tag_permalink_style'] == 'pretty' ? url : url << '.html'
|
116
|
-
end
|
117
|
-
|
118
|
-
def tags(obj)
|
119
|
-
tags = obj['tags'].dup
|
120
|
-
tags.map! { |t| t.first } if tags.first.is_a?(Array)
|
121
|
-
tags.map! { |t| tag_link(t, tag_url(t), rel: 'tag', class: 'label label-default') if t.is_a?(String) }.compact!
|
122
|
-
tags.join(' ')
|
123
|
-
end
|
124
|
-
|
125
|
-
def keywords(obj)
|
126
|
-
return '' if not obj['tags']
|
127
|
-
tags = obj['tags'].dup
|
128
|
-
tags.join(',')
|
129
|
-
end
|
130
|
-
|
131
|
-
def active_tag_data(site = Tagger.site)
|
132
|
-
return site.config['tag_data'] unless site.config['ignored_tags']
|
133
|
-
site.config['tag_data'].reject { |tag, set| site.config['ignored_tags'].include? tag }
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
data/doc/plugins/toc.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Jekyll
|
2
|
-
module FancyToCFilter
|
3
|
-
def fancytoc(input)
|
4
|
-
converter = @context.registers[:site].converters.find { |c| c.is_a? Jekyll::Converters::Markdown }
|
5
|
-
extensions = converter.instance_variable_get(:@parser).instance_variable_get(:@redcarpet_extensions)
|
6
|
-
toc_generator = Redcarpet::Markdown.new(Redcarpet::Render::HTML_TOC, extensions)
|
7
|
-
toc = toc_generator.render(input)
|
8
|
-
|
9
|
-
<<-HTML unless toc.empty?
|
10
|
-
<div class="toc well" data-spy="affix" data-offset-top="0" data-offset-bottom="0">
|
11
|
-
<h4>Table of content</h4>
|
12
|
-
#{toc}
|
13
|
-
</div>
|
14
|
-
HTML
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
Liquid::Template.register_filter(Jekyll::FancyToCFilter)
|
data/doc/source/.nojekyll
DELETED
File without changes
|
data/doc/source/404.md
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
<div class="footer">
|
2
|
-
<div class="container">
|
3
|
-
<p>This web site is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>. Source available: <a xmlns:dct="http://purl.org/dc/terms/" href="https://github.com/theforeman/theforeman.org" rel="dct:source">github/theforeman/theforeman.org</a>.</p>
|
4
|
-
<a href="https://plus.google.com/102496134326414788199" rel="publisher">Google+ community</a>
|
5
|
-
</div>
|
6
|
-
</div>
|
7
|
-
|
8
|
-
<script type="text/javascript">
|
9
|
-
var _gaq = _gaq || [];
|
10
|
-
_gaq.push(['_setAccount', 'UA-2134730-5']);
|
11
|
-
_gaq.push(['_trackPageview']);
|
12
|
-
|
13
|
-
(function() {
|
14
|
-
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
15
|
-
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
16
|
-
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
17
|
-
})();
|
18
|
-
</script>
|
19
|
-
|
20
|
-
</body>
|
21
|
-
</html>
|
@@ -1,59 +0,0 @@
|
|
1
|
-
<!doctype html>
|
2
|
-
<html itemscope itemtype="http://schema.org/Organization" lang="en">
|
3
|
-
<head>
|
4
|
-
<base href="{{ site.baseurl }}">
|
5
|
-
{% if page.sitename != nil %}
|
6
|
-
{% assign sitename = page.sitename %}
|
7
|
-
{% else %}
|
8
|
-
{% assign sitename = site.sitename %}
|
9
|
-
{% endif %}
|
10
|
-
|
11
|
-
{% if page.pagename != nil %}
|
12
|
-
{% assign pagename = true %}
|
13
|
-
{% endif %}
|
14
|
-
<title>{{ sitename }}{% if pagename %} :: {{ page.pagename }}{% endif %}</title>
|
15
|
-
|
16
|
-
<script type="text/javascript" src="{{ site.baseurl }}static/js/jquery.js"></script>
|
17
|
-
<script type="text/javascript" src="{{ site.baseurl }}static/js/bootstrap.min.js"></script>
|
18
|
-
<script type="text/javascript" src="{{ site.baseurl }}static/js/jquery-ui-1.9.2.custom.min.js"></script>
|
19
|
-
<script type="text/javascript" src="{{ site.baseurl }}static/js/jquery.tocify.min.js"></script>
|
20
|
-
<script type="text/javascript" src="{{ site.baseurl }}static/js/scroll.js"></script>
|
21
|
-
|
22
|
-
<link rel="stylesheet" media="all" href="{{ site.baseurl }}static/css/bootstrap.min.css"/>
|
23
|
-
<link rel="stylesheet" media="all" href="{{ site.baseurl }}static/css/bootstrap-responsive.min.css"/>
|
24
|
-
<link rel="stylesheet" media="all" href="{{ site.baseurl }}static/css/jquery.tocify.css"/>
|
25
|
-
<link rel="stylesheet" media="all" href="{{ site.baseurl }}static/css/syntax.css" />
|
26
|
-
<link rel="stylesheet" media="all" href="{{ site.baseurl }}static/css/style.css"/>
|
27
|
-
<meta name="apple-mobile-web-app-capable" content="yes">
|
28
|
-
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0;" />
|
29
|
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
30
|
-
</head>
|
31
|
-
|
32
|
-
<body>
|
33
|
-
<div class="navbar navbar-fixed-top">
|
34
|
-
<div class="navbar-inner">
|
35
|
-
<div class="container">
|
36
|
-
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
37
|
-
<span class="icon-bar"></span>
|
38
|
-
<span class="icon-bar"></span>
|
39
|
-
<span class="icon-bar"></span>
|
40
|
-
</button>
|
41
|
-
<img alt="Foreman" class="logo" src="{{ site.baseurl }}static/images/foreman.png" />
|
42
|
-
<div class="brand">
|
43
|
-
<a href="{{ site.baseurl }}">Foreman</a>
|
44
|
-
<a class="subtitle" href="{{ site.baseurl }}">Remote Execution</a>
|
45
|
-
</div>
|
46
|
-
<div class="nav-collapse collapse">
|
47
|
-
<ul class="nav">
|
48
|
-
<li><a href="{{ site.baseurl }}">About</a></li>
|
49
|
-
<li><a href="{{ site.baseurl }}design/">Design</a></li>
|
50
|
-
</ul>
|
51
|
-
</div>
|
52
|
-
</div>
|
53
|
-
</div>
|
54
|
-
</div>
|
55
|
-
<script>
|
56
|
-
$(function(){
|
57
|
-
$('.nav > li a[href="'+window.location.pathname+'"]').parents('.nav > li').addClass('active')
|
58
|
-
})
|
59
|
-
</script>
|
@@ -1,25 +0,0 @@
|
|
1
|
-
---
|
2
|
-
pagename: Foreman Remote Execution
|
3
|
-
---
|
4
|
-
{% include header.html %}
|
5
|
-
|
6
|
-
<div id="main">
|
7
|
-
<div id="content" class="container">
|
8
|
-
<div class="row">
|
9
|
-
<div id="toc" class="span3">
|
10
|
-
</div>
|
11
|
-
<div id="doc" class="offset3 span9">
|
12
|
-
{{ content }}
|
13
|
-
</div>
|
14
|
-
</div>
|
15
|
-
</div>
|
16
|
-
</div>
|
17
|
-
|
18
|
-
<script type="text/javascript">
|
19
|
-
$(function() {
|
20
|
-
//Calls the tocify method on your HTML div.
|
21
|
-
$("#toc").tocify({context: '#doc', scrollTo: '60', selectors: "h1,h2,h3"});
|
22
|
-
});
|
23
|
-
</script>
|
24
|
-
|
25
|
-
{% include footer.html %}
|
data/doc/source/atom.xml
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
---
|
2
|
-
# Front matter comment to ensure Jekyll properly reads file.
|
3
|
-
---
|
4
|
-
|
5
|
-
<?xml version="1.0" encoding="utf-8"?>
|
6
|
-
<feed xmlns="http://www.w3.org/2005/Atom">
|
7
|
-
|
8
|
-
<title><![CDATA[{{ site.title }}]]></title>
|
9
|
-
<link href="{{ site.url }}/atom.xml" rel="self"/>
|
10
|
-
<link href="{{ site.url }}/"/>
|
11
|
-
<updated>{{ site.time | date_to_xmlschema }}</updated>
|
12
|
-
<id>{{ site.url }}/</id>
|
13
|
-
<author>
|
14
|
-
<name><![CDATA[{{ site.author | strip_html }}]]></name>
|
15
|
-
{% if site.email %}<email><![CDATA[{{ site.email }}]]></email>{% endif %}
|
16
|
-
</author>
|
17
|
-
|
18
|
-
{% for post in site.posts %}
|
19
|
-
<entry>
|
20
|
-
<title type="html"><![CDATA[{{ post.title | cdata_escape }}]]></title>
|
21
|
-
<link href="{{ site.url }}{{ post.url }}"/>
|
22
|
-
<updated>{{ post.date | date_to_xmlschema }}</updated>
|
23
|
-
<id>{{ site.url }}{{ post.id }}</id>
|
24
|
-
<!--<content type="html">-->
|
25
|
-
<!--<!– FIXME full urls–>-->
|
26
|
-
<!--<![CDATA[-->
|
27
|
-
<!--Tags: {{ post | tags }}-->
|
28
|
-
<!--]]>-->
|
29
|
-
<!--</content>-->
|
30
|
-
</entry>
|
31
|
-
{% endfor %}
|
32
|
-
</feed>
|
data/doc/source/design/index.md
DELETED
@@ -1,1322 +0,0 @@
|
|
1
|
-
---
|
2
|
-
layout: page
|
3
|
-
title: Design
|
4
|
-
countheads: true
|
5
|
-
toc: true
|
6
|
-
comments: true
|
7
|
-
---
|
8
|
-
|
9
|
-
Remote Execution Technology
|
10
|
-
===========================
|
11
|
-
|
12
|
-
User Stories
|
13
|
-
------------
|
14
|
-
|
15
|
-
- As a user I want to run jobs in parallel across large number of
|
16
|
-
hosts
|
17
|
-
|
18
|
-
- As a user I want to run jobs on a host in a different network
|
19
|
-
segment (the host doesn't see the Foreman server/the Foreman server
|
20
|
-
doesn't see the host directly)
|
21
|
-
|
22
|
-
- As a user I want to manage a host without installing an agent on it
|
23
|
-
(just plain old ssh)
|
24
|
-
|
25
|
-
- As a community user I want to already existing remote execution
|
26
|
-
technologies in combination with the Foreman
|
27
|
-
|
28
|
-
Design
|
29
|
-
------
|
30
|
-
|
31
|
-
Although specific providers are mentioned in the design, it's used
|
32
|
-
mainly for distinguishing different approaches to the remote execution
|
33
|
-
than to choose specific technologies
|
34
|
-
|
35
|
-
### Ssh Single Host Push
|
36
|
-
|
37
|
-
{% plantuml %}
|
38
|
-
actor User
|
39
|
-
participant "Foreman Server" as Foreman
|
40
|
-
participant "Foreman Proxy" as Proxy
|
41
|
-
participant "Host" as Host
|
42
|
-
|
43
|
-
autonumber
|
44
|
-
User -> Foreman : JobInvocation
|
45
|
-
Foreman -> Proxy : ProxyCommand
|
46
|
-
Proxy -> Host : SshScript
|
47
|
-
Activate Host
|
48
|
-
Host --> Proxy : ProgressReport[1, Running]
|
49
|
-
Host --> Proxy : ProgressReport[2, Running]
|
50
|
-
Proxy --> Foreman : AccumulatedProgressReport[1, Running]
|
51
|
-
Host --> Proxy : ProgressReport[3, Running]
|
52
|
-
Host --> Proxy : ProgressReport[4, Finished]
|
53
|
-
Deactivate Host
|
54
|
-
Proxy --> Foreman : AccumulatedProgressReport[2, Finished]
|
55
|
-
{% endplantuml %}
|
56
|
-
|
57
|
-
JobInvocation: see see [scheduling](design#job-invocation)
|
58
|
-
|
59
|
-
ProxyCommand:
|
60
|
-
|
61
|
-
* host: host.example.com
|
62
|
-
* provider: ssh
|
63
|
-
* input: "yum install -y vim-X11"
|
64
|
-
|
65
|
-
SSHScript:
|
66
|
-
|
67
|
-
* host: host.example.com
|
68
|
-
* input: "yum install -y vim-X11"
|
69
|
-
|
70
|
-
ProgressReport[1, Running]:
|
71
|
-
|
72
|
-
* output: "Resolving depednencies"
|
73
|
-
|
74
|
-
ProgressReport[2, Running]:
|
75
|
-
|
76
|
-
* output: "installing libXt"
|
77
|
-
|
78
|
-
AccumulatedProgressReport[1, Running]:
|
79
|
-
|
80
|
-
* output: { stdout: "Resolving depednencies\ninstalling libXt" }
|
81
|
-
|
82
|
-
ProgressReport[3, Running]:
|
83
|
-
|
84
|
-
* output: "installing vim-X11"
|
85
|
-
|
86
|
-
ProgressReport[4, Finished]:
|
87
|
-
|
88
|
-
* output: "operation finished successfully"
|
89
|
-
* exit_code: 0
|
90
|
-
|
91
|
-
AccumulatedProgressReport[2, Finished]:
|
92
|
-
|
93
|
-
* output: { stdout: "installing vim-X11\noperation finished successfully", exit_code: 0 }
|
94
|
-
* success: true
|
95
|
-
|
96
|
-
### Ssh Single Host Check-in
|
97
|
-
|
98
|
-
This case allows to handle the case, when the host is offline by the
|
99
|
-
time of job invocation: the list of jobs for the host is stored on the
|
100
|
-
Foreman server side for running once the host is online.
|
101
|
-
|
102
|
-
This approach is not limited to the ssh provider only.
|
103
|
-
|
104
|
-
{% plantuml %}
|
105
|
-
actor User
|
106
|
-
participant "Foreman Server" as Foreman
|
107
|
-
participant "Foreman Proxy" as Proxy
|
108
|
-
participant "Host" as Host
|
109
|
-
|
110
|
-
autonumber
|
111
|
-
User -> Foreman : JobInvocation
|
112
|
-
Host -> Proxy : CheckIn
|
113
|
-
Proxy -> Foreman : CheckIn
|
114
|
-
Foreman -> Proxy : ProxyCommand
|
115
|
-
Proxy -> Host : SshScript
|
116
|
-
{% endplantuml %}
|
117
|
-
|
118
|
-
### Ssh Multi Host
|
119
|
-
|
120
|
-
{% plantuml %}
|
121
|
-
actor User
|
122
|
-
participant "Foreman Server" as Foreman
|
123
|
-
participant "Foreman Proxy" as Proxy
|
124
|
-
participant "Host 1" as Host1
|
125
|
-
participant "Host 2" as Host2
|
126
|
-
|
127
|
-
autonumber
|
128
|
-
User -> Foreman : JobInvocation
|
129
|
-
Foreman -> Proxy : ProxyCommand[host1]
|
130
|
-
Foreman -> Proxy : ProxyCommand[host2]
|
131
|
-
Proxy -> Host1 : SSHScript
|
132
|
-
Proxy -> Host2 : SSHScript
|
133
|
-
{% endplantuml %}
|
134
|
-
|
135
|
-
ProxyCommand[host1]:
|
136
|
-
|
137
|
-
* host: host-1.example.com
|
138
|
-
* provider: ssh
|
139
|
-
* input: "yum install -y vim-X11"
|
140
|
-
|
141
|
-
ProxyCommand[host2]:
|
142
|
-
|
143
|
-
* host: host-2.example.com
|
144
|
-
* provider: ssh
|
145
|
-
* input: "yum install -y vim-X11"
|
146
|
-
|
147
|
-
{% info_block %}
|
148
|
-
we might want to optimize the communication between server and
|
149
|
-
the proxy (sending collection of ProxyCommands in bulk, as well as
|
150
|
-
the AccumulatedProgerssReports). That would could also be utilized
|
151
|
-
by the Ansible implementation, where there might be optimization
|
152
|
-
on the invoking the ansible commands at once (the same might apply
|
153
|
-
to mcollective). On the other hand, this is more an optimization,
|
154
|
-
not required to be implemented from the day one: but it's good to have
|
155
|
-
this in mind
|
156
|
-
{% endinfo_block %}
|
157
|
-
|
158
|
-
### MCollective Single Host
|
159
|
-
|
160
|
-
{% plantuml %}
|
161
|
-
actor User
|
162
|
-
participant "Foreman Server" as Foreman
|
163
|
-
participant "Foreman Proxy" as Proxy
|
164
|
-
participant "AMQP" as AMQP
|
165
|
-
participant "Host" as Host
|
166
|
-
|
167
|
-
autonumber
|
168
|
-
User -> Foreman : JobInvocation
|
169
|
-
Foreman -> Proxy : ProxyCommand
|
170
|
-
Proxy -> AMQP : MCOCommand
|
171
|
-
AMQP -> Host : MCOCommand
|
172
|
-
Activate Host
|
173
|
-
Host --> AMQP : ProgressReport[Finished]
|
174
|
-
Deactivate Host
|
175
|
-
AMQP --> Proxy : ProgressReport[Finished]
|
176
|
-
Proxy --> Foreman : AccumulatedProgressReport[Finished]
|
177
|
-
{% endplantuml %}
|
178
|
-
|
179
|
-
JobInvocation:
|
180
|
-
|
181
|
-
* hosts: [host.example.com]
|
182
|
-
* template: install-packages-mco
|
183
|
-
* input: { packages: ['vim-X11'] }
|
184
|
-
|
185
|
-
ProxyCommand:
|
186
|
-
|
187
|
-
* host: host.example.com
|
188
|
-
* provider: mcollective
|
189
|
-
* input: { agent: package, args: { package => 'vim-X11' } }
|
190
|
-
|
191
|
-
MCOCommand:
|
192
|
-
|
193
|
-
* host: host.example.com
|
194
|
-
* input: { agent: package, args: { package => 'vim-X11' } }
|
195
|
-
|
196
|
-
ProgressReport[Finished]:
|
197
|
-
|
198
|
-
* output: [ {"name":"vim-X11","tries":1,"version":"7.4.160-1","status":0,"release":"1.el7"},
|
199
|
-
{"name":"libXt","tries":1,"version":"1.1.4-6","status":0,"release":"1.el7"} ]
|
200
|
-
|
201
|
-
AccumulatedProgressReport[Finished]:
|
202
|
-
|
203
|
-
* output: [ {"name":"vim-X11","tries":1,"version":"7.4.160-1","status":0,"release":"1.el7"},
|
204
|
-
{"name":"libXt","tries":1,"version":"1.1.4-6","status":0,"release":"1.el7"} ]
|
205
|
-
* success: true
|
206
|
-
|
207
|
-
### Ansible Single Host
|
208
|
-
|
209
|
-
{% plantuml %}
|
210
|
-
actor User
|
211
|
-
participant "Foreman Server" as Foreman
|
212
|
-
participant "Foreman Proxy" as Proxy
|
213
|
-
participant "Host" as Host
|
214
|
-
|
215
|
-
autonumber
|
216
|
-
User -> Foreman : JobInvocation
|
217
|
-
Foreman -> Proxy : ProxyCommand
|
218
|
-
Proxy -> Host : AnsibleCommand
|
219
|
-
Activate Host
|
220
|
-
Host --> Proxy : ProgressReport[Finished]
|
221
|
-
Deactivate Host
|
222
|
-
Proxy --> Foreman : AccumulatedProgressReport[Finished]
|
223
|
-
|
224
|
-
{% endplantuml %}
|
225
|
-
|
226
|
-
JobInvocation:
|
227
|
-
|
228
|
-
* hosts: [host.example.com]
|
229
|
-
* template: install-packages-ansible
|
230
|
-
* input: { packages: ['vim-X11'] }
|
231
|
-
|
232
|
-
ProxyCommand:
|
233
|
-
|
234
|
-
* host: host.example.com
|
235
|
-
* provider: ansible
|
236
|
-
* input: { module: yum, args: { name: 'vim-X11', state: installed } }
|
237
|
-
|
238
|
-
AnsibleCommand:
|
239
|
-
|
240
|
-
* host: host.example.com
|
241
|
-
* provider: ansible
|
242
|
-
* input: { module: yum, args: { name: 'vim-X11', state: installed } }
|
243
|
-
|
244
|
-
ProgressReport[Finished]:
|
245
|
-
|
246
|
-
* output: { changed: true,
|
247
|
-
rc: 0,
|
248
|
-
results: ["Resolving depednencies\ninstalling libXt\ninstalling vim-X11\noperation finished successfully"] }
|
249
|
-
|
250
|
-
AccumulatedProgressReport[Finished]:
|
251
|
-
|
252
|
-
* output: { changed: true,
|
253
|
-
rc: 0,
|
254
|
-
results: ["Resolving depednencies\ninstalling libXt\ninstalling vim-X11\noperation finished successfully"] }
|
255
|
-
* success: true
|
256
|
-
|
257
|
-
|
258
|
-
Job Preparation
|
259
|
-
===============
|
260
|
-
|
261
|
-
User Stories
|
262
|
-
------------
|
263
|
-
|
264
|
-
- As a user I want to be able to create a template to run some command for a given remote execution provider for a specific job
|
265
|
-
|
266
|
-
- As a user these job templates should be audited and versioned
|
267
|
-
|
268
|
-
- As a user I want to be able to define inputs into the template that consist of user input at execution time. I should be able to use these inputs within my template.
|
269
|
-
|
270
|
-
- As a user I want to be able to define an input for a template that uses a particular fact about the host being executed on at execution time.
|
271
|
-
|
272
|
-
- As a user I want to be able to define an input for a template that uses a particular smart variable that is resolved at execution time.
|
273
|
-
|
274
|
-
- As a user I want to be able to define a description of each input in order to help describe the format and meaning of an input.
|
275
|
-
|
276
|
-
- As a user I want to be able to specify default number of tries per job template.
|
277
|
-
|
278
|
-
- As a user I want to be able to specify default retry interval per job template.
|
279
|
-
|
280
|
-
- As a user I want to be able to specify default splay time per job template.
|
281
|
-
|
282
|
-
- As a user I want to setup default timeout per job template.
|
283
|
-
|
284
|
-
- As a user I want to preview a rendered job template for a host (providing needed inputs)
|
285
|
-
|
286
|
-
Scenarios
|
287
|
-
---------
|
288
|
-
**Creating a job template**
|
289
|
-
|
290
|
-
1. given I'm on new template form
|
291
|
-
1. I select from a list of existing job names or fill in a new job name
|
292
|
-
1. I select some option to add an input
|
293
|
-
1. Give the input a name
|
294
|
-
1. Select the type 'user input'
|
295
|
-
1. Give the input a description (space separated package list)
|
296
|
-
1. I select from a list of known providers (ssh, mco, salt, ansible)
|
297
|
-
1. I am shown an example of how to use the input in the template
|
298
|
-
1. I am able to see some simple example for the selected provider??
|
299
|
-
1. I fill in the template
|
300
|
-
1. I select one or more organizations and locations (if enabled)
|
301
|
-
1. I click save
|
302
|
-
|
303
|
-
|
304
|
-
**Creating a smart variable based input**
|
305
|
-
|
306
|
-
1. given i am creating or editing a job template
|
307
|
-
1. I select to add a new input
|
308
|
-
1. Give the input a name
|
309
|
-
1. Define a smart variable name
|
310
|
-
|
311
|
-
Design
|
312
|
-
------
|
313
|
-
|
314
|
-
{% plantuml %}
|
315
|
-
|
316
|
-
class JobTemplate {
|
317
|
-
name:string
|
318
|
-
job_name: string
|
319
|
-
retry_count: integer
|
320
|
-
retry_interval: integer
|
321
|
-
splay: integer
|
322
|
-
provider_type: string
|
323
|
-
==
|
324
|
-
has_and_belongs_to_many :taxonomies
|
325
|
-
has_many :inputs
|
326
|
-
has_many :audits
|
327
|
-
}
|
328
|
-
|
329
|
-
class ConfigTemplateInput {
|
330
|
-
name: string
|
331
|
-
required: bool
|
332
|
-
input_type: USER_INPUT | FACT | SMART_VARIABLE
|
333
|
-
fact_name: string
|
334
|
-
smart_variable_name: string
|
335
|
-
description: string
|
336
|
-
==
|
337
|
-
has_one :job_template
|
338
|
-
}
|
339
|
-
|
340
|
-
ConfigTemplate "1" -- "N" ConfigTemplateInput
|
341
|
-
{% endplantuml %}
|
342
|
-
|
343
|
-
|
344
|
-
Job Invocation
|
345
|
-
==============
|
346
|
-
|
347
|
-
User Stories
|
348
|
-
------------
|
349
|
-
|
350
|
-
- As a user I would like to invoke a job on a single host
|
351
|
-
|
352
|
-
- As a user I would like to invoke a job on a set of hosts, based on
|
353
|
-
search filter
|
354
|
-
|
355
|
-
- As a user I want to be able to reuse existing bookmarks for job
|
356
|
-
invocation
|
357
|
-
|
358
|
-
- As a user, when setting a job in future, I want to decide if the
|
359
|
-
search criteria should be evaluated now or on the execution time
|
360
|
-
|
361
|
-
- As a user I want to reuse the target of previous jobs for next execution
|
362
|
-
|
363
|
-
- As a CLI user I want to be able to invoke a job via hammer CLI
|
364
|
-
|
365
|
-
- As a user, I want to be able to invoke the job on a specific set of hosts
|
366
|
-
(by using checkboxes in the hosts table)
|
367
|
-
|
368
|
-
- As a user, when planning future job execution, I want to see a
|
369
|
-
warning with the info about unreachable hosts
|
370
|
-
|
371
|
-
- As a user I want to be able to override default values like (number
|
372
|
-
of tries, retry interval, splay time, timeout, effective user...) when I plan an execution of command.
|
373
|
-
|
374
|
-
- As a user I expect to see a the description of an input whenever i am being requested to
|
375
|
-
provide the value for the input.
|
376
|
-
|
377
|
-
- As a user I want to be able to re-invoke the jobs based on
|
378
|
-
success/failure of previous task
|
379
|
-
|
380
|
-
Scenarios
|
381
|
-
---------
|
382
|
-
|
383
|
-
**Fill in target for a job**
|
384
|
-
|
385
|
-
1. when I'm on job invocation form
|
386
|
-
1. then I can specify the target of the job using the scoped search
|
387
|
-
syntax
|
388
|
-
1. the target might influence the list of providers available for the
|
389
|
-
invocation: although, in delayed execution and dynamic targeting the
|
390
|
-
current list of providers based on the hosts might not be final and
|
391
|
-
we should count on that.
|
392
|
-
|
393
|
-
**Fill in template inputs for a job**
|
394
|
-
|
395
|
-
1. given I'm on job invocation form
|
396
|
-
1. when I choose the job to execute
|
397
|
-
1. then I'm given a list of providers that I have enabled and has a
|
398
|
-
template available for the job
|
399
|
-
1. and each provider allows to choose which template to use for this
|
400
|
-
invocation (if more templates for the job and provider are available)
|
401
|
-
1. and every template has input fields generated based on the input
|
402
|
-
defined on the template (such as list of packages for install package
|
403
|
-
job)
|
404
|
-
|
405
|
-
**See the calculated template inputs for a job**
|
406
|
-
|
407
|
-
1. given I'm on job invocation form
|
408
|
-
1. when I choose the job to execute
|
409
|
-
1. and I'm using a template with inputs calculated base on fact data
|
410
|
-
template available for the job
|
411
|
-
1. then the preview of the current value for this input should be displayed
|
412
|
-
1. but for the execution the value that the fact has by the time of
|
413
|
-
execution will be used.
|
414
|
-
|
415
|
-
**Fill in job description for the execution**
|
416
|
-
|
417
|
-
1. given I'm on job invocation form
|
418
|
-
1. there should be a field for task description, that will be used for
|
419
|
-
listing the jobs
|
420
|
-
1. the description value should be pregenerated based on the job name
|
421
|
-
and specified input (something like "Package install: zsh")
|
422
|
-
|
423
|
-
**Fill in execution properties of the job**
|
424
|
-
|
425
|
-
1. when I'm on job invocation form
|
426
|
-
1. I can override the default values for number of tries, retry
|
427
|
-
interval, splay time, timeout, effective user...
|
428
|
-
1. the overrides are common for all the templates
|
429
|
-
|
430
|
-
**Set the execution time into future** (see [scheduling](design#scheduling)
|
431
|
-
for more scenarios)
|
432
|
-
|
433
|
-
1. when I'm on a job invocation form
|
434
|
-
1. then I can specify the time to start the execution at (now by
|
435
|
-
default)
|
436
|
-
1. and I can specify if the targeting should be calculated now or
|
437
|
-
postponed to the execution time
|
438
|
-
|
439
|
-
**Run a job from host detail**
|
440
|
-
|
441
|
-
1. given I'm on a host details page
|
442
|
-
1. when I click "Run job"
|
443
|
-
1. then a user dialog opens with job invocation form, with pre-filled
|
444
|
-
targeting pointing to this particular host
|
445
|
-
|
446
|
-
**Run a job from host index**
|
447
|
-
|
448
|
-
1. given I'm on a host index page
|
449
|
-
1. when I click "Run job"
|
450
|
-
1. then a user dialog opens with job invocation form, with prefiled
|
451
|
-
targeting using the same search that was used in the host index page
|
452
|
-
|
453
|
-
**Invoke a job with single remote execution provider**
|
454
|
-
|
455
|
-
1. given I have only one provider available in my installation
|
456
|
-
1. and I'm on job invocation form
|
457
|
-
1. when I choose the job to execute
|
458
|
-
1. then only the template for this provider is available to run and
|
459
|
-
asking for user inputs
|
460
|
-
|
461
|
-
**Invoke a job with hammer**
|
462
|
-
|
463
|
-
1. given I'm using CLI
|
464
|
-
1. then I can run a job with ability to specify:
|
465
|
-
- targeting with scoped search or bookmark_id
|
466
|
-
- job name to run
|
467
|
-
- templates to use for the job
|
468
|
-
- inputs on per-template basis
|
469
|
-
- execution properties as overrides for the defaults coming from the template
|
470
|
-
- ``start_at`` value for execution in future
|
471
|
-
- in case of the start_at value, if the targeting should be static
|
472
|
-
vs. dynamic
|
473
|
-
- whether to wait for the job or exit after invocation (--async
|
474
|
-
option)
|
475
|
-
|
476
|
-
**Re-invoke a job**
|
477
|
-
|
478
|
-
1. given I'm in job details page
|
479
|
-
1. when I choose re-run
|
480
|
-
1. then a user dialog opens with job invocation form, with prefiled
|
481
|
-
targeting parameters from the previous execution
|
482
|
-
1 and I can override all the values (including targeting, job,
|
483
|
-
templates and inputs)
|
484
|
-
|
485
|
-
**Re-invoke a job for failed hosts**
|
486
|
-
|
487
|
-
1. given I'm in job details page
|
488
|
-
1. when I choose re-run
|
489
|
-
1. then a user dialog opens with job invocation form, with prefiled
|
490
|
-
targeting parameters from the previous execution
|
491
|
-
1 and I can override all the values (including targeting, job,
|
492
|
-
templates and inputs)
|
493
|
-
1. I can choose in the targeting to only run on hosts that failed with
|
494
|
-
the job previously
|
495
|
-
|
496
|
-
**Edit a bookmark referenced by pending job invocation**
|
497
|
-
|
498
|
-
1. given I have a pending execution task which targeting was created
|
499
|
-
from a bookmark
|
500
|
-
2. when I edit the bookmark
|
501
|
-
3. then I should be notified about the existence of the pending tasks
|
502
|
-
with ability to update the targeting (or cancel and recreate the
|
503
|
-
invocation)
|
504
|
-
|
505
|
-
**Email notification: opt in**
|
506
|
-
|
507
|
-
1. given I haven't configured to send email notifications about my executions
|
508
|
-
1. then the job invocation should have the 'send email notification'
|
509
|
-
turned off by default
|
510
|
-
|
511
|
-
**Email notification: opt out**
|
512
|
-
|
513
|
-
1. given I haven't configured to send email notifications about my executions
|
514
|
-
1. then the job invocation should have the 'send email notification'
|
515
|
-
turned off by default
|
516
|
-
|
517
|
-
Design
|
518
|
-
------
|
519
|
-
|
520
|
-
Class diagram of Foreman classes
|
521
|
-
|
522
|
-
{% plantuml %}
|
523
|
-
|
524
|
-
class Bookmark {
|
525
|
-
name:string
|
526
|
-
query:string
|
527
|
-
controller:string
|
528
|
-
public:bool
|
529
|
-
owner_id:integer
|
530
|
-
owner_type:string
|
531
|
-
}
|
532
|
-
|
533
|
-
class Targeting {
|
534
|
-
query: string
|
535
|
-
dynamic: bool
|
536
|
-
}
|
537
|
-
|
538
|
-
class Host
|
539
|
-
class User
|
540
|
-
|
541
|
-
class TemplateInvocation {
|
542
|
-
inputs
|
543
|
-
}
|
544
|
-
|
545
|
-
class JobInvocation {
|
546
|
-
tries
|
547
|
-
retry_interval
|
548
|
-
splay
|
549
|
-
concurrency
|
550
|
-
effective_user
|
551
|
-
email_notification: bool
|
552
|
-
}
|
553
|
-
|
554
|
-
class JobTask {
|
555
|
-
start_at: datetime
|
556
|
-
}
|
557
|
-
|
558
|
-
Bookmark "1" - "N" Targeting
|
559
|
-
Targeting "M" - "N" Host : (polymorphic)
|
560
|
-
Targeting "N" -- "1" User
|
561
|
-
JobInvocation "1" -- "1" Targeting
|
562
|
-
JobInvocation "1" -- "N" TemplateInvocation
|
563
|
-
TemplateInvocation "N" -- "1" JobTemplate
|
564
|
-
JobInvocation "1" -- "N" JobTask
|
565
|
-
|
566
|
-
{% endplantuml %}
|
567
|
-
|
568
|
-
Query is copied to Targeting, we don't want to propagate any later
|
569
|
-
changes to Bookmark to already planned job executions.
|
570
|
-
|
571
|
-
We can store link to original bookmark to be able to
|
572
|
-
compare changes later.
|
573
|
-
|
574
|
-
For JobInvocation we forbid later editing of Targeting.
|
575
|
-
|
576
|
-
Open questions
|
577
|
-
--------------
|
578
|
-
|
579
|
-
* should we unify the common inputs in all templates to specify them
|
580
|
-
only once or scoping the input by template?
|
581
|
-
|
582
|
-
* Maybe an inputs catalog (with both defined name and semantic) might
|
583
|
-
help with keeping the inputs consistent across templates/providers
|
584
|
-
|
585
|
-
|
586
|
-
Job Execution
|
587
|
-
=============
|
588
|
-
|
589
|
-
User Stories
|
590
|
-
------------
|
591
|
-
|
592
|
-
- As a user I want to be able to cancel job which hasn't been started yet.
|
593
|
-
|
594
|
-
- As a user I want to be able to cancel job which is in progress
|
595
|
-
(if supported by specific provider…)
|
596
|
-
|
597
|
-
- As a user I want job execution to fail after timeout limit.
|
598
|
-
|
599
|
-
- As a user I want to job execution to be re-tried
|
600
|
-
based on the tries and retry interval values given in the invocation
|
601
|
-
|
602
|
-
- As a user I want to job execution on multiple hosts to be spread
|
603
|
-
using the splay time value: the execution of the jobs will be spread
|
604
|
-
randomly across the time interval
|
605
|
-
|
606
|
-
- As a user I want to job execution on multiple hosts to be limited
|
607
|
-
by a concurrency level: the number of concurrently running jobs will
|
608
|
-
not exceed the limit.
|
609
|
-
|
610
|
-
- As a user I want the job execution to be performed as a user that
|
611
|
-
was specified on the job invocation
|
612
|
-
|
613
|
-
- As a user I want an ability to retry the job execution when the host
|
614
|
-
checks in (support of hosts that are offline by the time the
|
615
|
-
execution).
|
616
|
-
|
617
|
-
Scenarios
|
618
|
-
---------
|
619
|
-
|
620
|
-
**Cancel pending bulk task: all at once**
|
621
|
-
|
622
|
-
1. given I've set a job to run in future on multiple hosts
|
623
|
-
1. when I click 'cancel' on the corresponding bulk task
|
624
|
-
1. then the whole task should be canceled (including all the sub-tasks
|
625
|
-
on all the hosts)
|
626
|
-
|
627
|
-
**Cancel pending bulk task: task on specific host**
|
628
|
-
|
629
|
-
1. given I've set a job to run in future on multiple hosts
|
630
|
-
1. when I show the task representation on a host details page
|
631
|
-
1. when I click 'cancel' on the task
|
632
|
-
1. then I should be offered whether I should cancel just this
|
633
|
-
instance or the whole bulk task on all hosts
|
634
|
-
|
635
|
-
**Fail after timeout**
|
636
|
-
|
637
|
-
1. given I've invoked a job
|
638
|
-
1. when the job fails to start in given specified timeout
|
639
|
-
1. then the job should be marked as failed due to timeout
|
640
|
-
|
641
|
-
**Retried task**
|
642
|
-
|
643
|
-
1. given I've invoked a job
|
644
|
-
1. when the job fails to start at first attemt
|
645
|
-
1. then the executor should wait for retry_timeout period
|
646
|
-
1. and it should reiterate with the attempt based on the tries number
|
647
|
-
1. and I should see the information about the number of retries
|
648
|
-
|
649
|
-
Design
|
650
|
-
------
|
651
|
-
|
652
|
-
Class diagram for jobs running on multiple hosts
|
653
|
-
|
654
|
-
{% plantuml %}
|
655
|
-
|
656
|
-
|
657
|
-
class Host {
|
658
|
-
get_provider(type)
|
659
|
-
}
|
660
|
-
|
661
|
-
class BulkJobTask {
|
662
|
-
state: $TaskState
|
663
|
-
start_at: datetime
|
664
|
-
started_at: datetime
|
665
|
-
ended_at datetime
|
666
|
-
cancel()
|
667
|
-
}
|
668
|
-
|
669
|
-
class JobTask {
|
670
|
-
retry: integer
|
671
|
-
retry_interval: integer
|
672
|
-
timeout: integer
|
673
|
-
splay: integer
|
674
|
-
concurrency: integer
|
675
|
-
type: string
|
676
|
-
state: $TaskState
|
677
|
-
start_at: datetime
|
678
|
-
started_at: datetime
|
679
|
-
tried_count: integer
|
680
|
-
ended_at datetime
|
681
|
-
{abstract} support_cancel?()
|
682
|
-
{abstract} proxy_endpoint()
|
683
|
-
cancel()
|
684
|
-
}
|
685
|
-
|
686
|
-
abstract class ProxyCommand {
|
687
|
-
}
|
688
|
-
|
689
|
-
class SSHProxyCommand {
|
690
|
-
{static} support_cancel?()
|
691
|
-
proxy_endpoint():string
|
692
|
-
}
|
693
|
-
|
694
|
-
class MCollectiveProxyCommand {
|
695
|
-
{static} support_cancel?()
|
696
|
-
proxy_endpoint():string
|
697
|
-
}
|
698
|
-
|
699
|
-
BulkJobTask "N" - "1" JobInvocation
|
700
|
-
BulkJobTask "1" -- "N" JobTask
|
701
|
-
TemplateInvocation "N" - "1" JobInvocation
|
702
|
-
TemplateInvocation "1" --- "N" JobTask
|
703
|
-
JobTask "1" -- "1" ProxyCommand
|
704
|
-
JobTask "N" -- "1" Host
|
705
|
-
|
706
|
-
ProxyCommand <|-- SSHProxyCommand
|
707
|
-
ProxyCommand <|-- MCollectiveProxyCommand
|
708
|
-
|
709
|
-
{% endplantuml %}
|
710
|
-
|
711
|
-
Class diagram for jobs running a single host
|
712
|
-
|
713
|
-
{% plantuml %}
|
714
|
-
|
715
|
-
class Host {
|
716
|
-
get_provider(type)
|
717
|
-
}
|
718
|
-
|
719
|
-
class JobTask {
|
720
|
-
retry: integer
|
721
|
-
retry_interval: integer
|
722
|
-
timeout: integer
|
723
|
-
splay: integer
|
724
|
-
concurrency: integer
|
725
|
-
type: string
|
726
|
-
state: $TaskState
|
727
|
-
started_at: datetime
|
728
|
-
start_at: datetime
|
729
|
-
tried_count: integer
|
730
|
-
ended_at datetime
|
731
|
-
cancel()
|
732
|
-
{abstract} support_cancel?()
|
733
|
-
{abstract} proxy_endpoint()
|
734
|
-
plan()
|
735
|
-
cancel()
|
736
|
-
}
|
737
|
-
|
738
|
-
class ProxyCommand {
|
739
|
-
}
|
740
|
-
|
741
|
-
JobTask "N" - "1" JobInvocation
|
742
|
-
TemplateInvocation "N" - "1" JobInvocation
|
743
|
-
TemplateInvocation "1" - "N" JobTask
|
744
|
-
JobTask "1" -- "1" ProxyCommand
|
745
|
-
JobTask "1" -- "1" Host
|
746
|
-
{% endplantuml %}
|
747
|
-
|
748
|
-
Reporting
|
749
|
-
=========
|
750
|
-
|
751
|
-
User Stories
|
752
|
-
------------
|
753
|
-
|
754
|
-
- As a user I would like to monitor the current state of the job
|
755
|
-
running against a single host, including the output and exit status
|
756
|
-
|
757
|
-
- As a user I would like to monitor the status of bulk job,
|
758
|
-
including the number of successful, failed and pending tasks
|
759
|
-
|
760
|
-
- As a user I would like to see the history of all job run on a
|
761
|
-
host
|
762
|
-
|
763
|
-
- As a user I would like to see the history of all tasks that I've
|
764
|
-
invoked
|
765
|
-
|
766
|
-
- As a user I would like to be able to get an email notification with
|
767
|
-
execution report
|
768
|
-
|
769
|
-
Scenarios
|
770
|
-
---------
|
771
|
-
|
772
|
-
**Track the job running on a set of hosts**
|
773
|
-
|
774
|
-
1. given I've set a job to run in future on multiple hosts
|
775
|
-
1. then I can watch the progress of the job (number of
|
776
|
-
successful/failed/pending tasks)
|
777
|
-
1. and I can get to the list of jobs per host
|
778
|
-
1. and I'm able to filter on the host that it was run against and
|
779
|
-
state
|
780
|
-
|
781
|
-
**Track the job running on a single host**
|
782
|
-
|
783
|
-
1. given I've set a job to run on a specific host
|
784
|
-
1. when I show the task representation page
|
785
|
-
1. then I can watch the progress of the job (updated log), status
|
786
|
-
|
787
|
-
**History of jobs run on a host**
|
788
|
-
|
789
|
-
1. given I'm on host jobs page
|
790
|
-
1. when I can see all the jobs run against the host
|
791
|
-
1. and I'm able to filter on the host that it was run against and
|
792
|
-
state, owner etc.
|
793
|
-
|
794
|
-
**History of invoked jobs**
|
795
|
-
|
796
|
-
1. given I'm on job invocation history page
|
797
|
-
1. when I can see all the jobs invoked in the system
|
798
|
-
1. scoped by a taxonomy (based on the hosts the jobs were run against)
|
799
|
-
1. and I'm able to filter on the host that it was run against and
|
800
|
-
state, owner etc.
|
801
|
-
|
802
|
-
**Email notification: send after finish**
|
803
|
-
|
804
|
-
1. given I've invoked a job with email notification turned on
|
805
|
-
1. when the job finishes
|
806
|
-
1. then I should get the email with report from the job after it finishes
|
807
|
-
|
808
|
-
Design
|
809
|
-
------
|
810
|
-
|
811
|
-
Class diagram for jobs running on multiple hosts
|
812
|
-
|
813
|
-
{% plantuml %}
|
814
|
-
|
815
|
-
|
816
|
-
class Host {
|
817
|
-
}
|
818
|
-
|
819
|
-
class JobInvocation {
|
820
|
-
email_notification: bool
|
821
|
-
}
|
822
|
-
|
823
|
-
class BulkJobTask {
|
824
|
-
state: $TaskState
|
825
|
-
start_at: datetime
|
826
|
-
started_at: datetime
|
827
|
-
ended_at datetime
|
828
|
-
}
|
829
|
-
|
830
|
-
class JobTask {
|
831
|
-
type: string
|
832
|
-
state: $TaskState
|
833
|
-
start_at: datetime
|
834
|
-
started_at: datetime
|
835
|
-
ended_at datetime
|
836
|
-
tried_count: integer
|
837
|
-
command: string
|
838
|
-
output: string
|
839
|
-
exit_code: string
|
840
|
-
}
|
841
|
-
|
842
|
-
BulkJobTask "N" - "1" JobInvocation
|
843
|
-
BulkJobTask "1" -- "N" JobTask
|
844
|
-
JobTask "1" -- "1" Host
|
845
|
-
|
846
|
-
{% endplantuml %}
|
847
|
-
|
848
|
-
Scheduling
|
849
|
-
==========
|
850
|
-
|
851
|
-
User Stories
|
852
|
-
------------
|
853
|
-
|
854
|
-
- As a user I want to be able go execute a job at future time
|
855
|
-
|
856
|
-
- As a user I want to set the job to reoccur with specified
|
857
|
-
frequency
|
858
|
-
|
859
|
-
Scenarios
|
860
|
-
---------
|
861
|
-
|
862
|
-
**Job set for the future**
|
863
|
-
|
864
|
-
1. given I've invoked a job at future time
|
865
|
-
1. when the time comes
|
866
|
-
1. the job gets executed
|
867
|
-
|
868
|
-
**Creating reoccurring job**
|
869
|
-
|
870
|
-
1. given I'm in job invocation form
|
871
|
-
1. when I check 'reoccurring job'
|
872
|
-
1. then I can set the frequency and valid until date
|
873
|
-
|
874
|
-
**Showing the tasks with reoccurring logic**
|
875
|
-
|
876
|
-
1. when I list the jobs
|
877
|
-
1. I can see the information about the reoccurring logic at every job
|
878
|
-
1. and I can filter the jobs for those with the reoccurring logic
|
879
|
-
|
880
|
-
**Canceling the reoccurring job**
|
881
|
-
|
882
|
-
1. given I have reoccurring job configured
|
883
|
-
1. when I cancel the next instance of the job
|
884
|
-
1. then I'm offered to cancel the reoccurring of the job in the future
|
885
|
-
|
886
|
-
Design
|
887
|
-
------
|
888
|
-
|
889
|
-
{% plantuml %}
|
890
|
-
|
891
|
-
class Schedule {
|
892
|
-
start_at: datetime
|
893
|
-
end_at: datetime
|
894
|
-
cronline: string
|
895
|
-
}
|
896
|
-
|
897
|
-
class JobTask {
|
898
|
-
}
|
899
|
-
|
900
|
-
JobTask "N" -- "1" JobInvocation
|
901
|
-
JobInvocation "1" -- "1" Schedule
|
902
|
-
|
903
|
-
{% endplantuml %}
|
904
|
-
|
905
|
-
Developer API
|
906
|
-
=============
|
907
|
-
|
908
|
-
User Stories
|
909
|
-
------------
|
910
|
-
|
911
|
-
- As a Foreman developer, I want to be able to use remote execution
|
912
|
-
plugin to help with other Foreman features such as:
|
913
|
-
- puppet run
|
914
|
-
- grubby reprovision
|
915
|
-
- content actions (package install/update/remove/downgrade, group
|
916
|
-
install/uninstall, package profile refresh)
|
917
|
-
- subscription actions (refresh)
|
918
|
-
- OpenSCAP content update
|
919
|
-
|
920
|
-
Scenarios
|
921
|
-
---------
|
922
|
-
|
923
|
-
**Defining a predefined job without provided inputs**
|
924
|
-
|
925
|
-
1. given I'm a Foreman developer
|
926
|
-
1. and I want to expose 'puppet run' feature to the user
|
927
|
-
1. then define the 'Puppet Run' as predefined job in the code
|
928
|
-
1. and specify the default job name to be used for the mapping
|
929
|
-
|
930
|
-
**Defining a predefined job with provided inputs**
|
931
|
-
|
932
|
-
1. given I'm a Katello developer
|
933
|
-
1. and I want to expose 'package install' feature to the user
|
934
|
-
1. then I define the 'Package Install' predefined job with list of
|
935
|
-
packages as provided input in the code
|
936
|
-
1. and I specify default job name to be used for the mapping
|
937
|
-
1. and I specify default mapping of the provided inputs to template
|
938
|
-
inputs
|
939
|
-
|
940
|
-
**Preseeding the predefined jobs**
|
941
|
-
|
942
|
-
1. given I've defined the 'Package Install' predefined job
|
943
|
-
1. when the seed script is run as part of the Foreman installation
|
944
|
-
1. the systems tries to create the default mapping from the predefined job to
|
945
|
-
the existing templates based on the developer-provided defaults
|
946
|
-
|
947
|
-
**Configuring the predefined jobs mapping**
|
948
|
-
|
949
|
-
1. given I'm the administrator of the Foreman instance
|
950
|
-
1. then I can see all the predefined jobs mapping
|
951
|
-
1. when I edit existing mapping
|
952
|
-
1. then I can choose job name, template and provided input -> template
|
953
|
-
inputs mapping
|
954
|
-
|
955
|
-
**Configuring the predefined jobs mapping with organizations**
|
956
|
-
|
957
|
-
1. given I'm the administrator of the Foreman instance
|
958
|
-
1. then I can scope the mapping of the predefined job to a specific
|
959
|
-
organization
|
960
|
-
1. and the system doesn't let me to create two mappings for the same
|
961
|
-
predefined job and provider visible in one organization
|
962
|
-
|
963
|
-
**Using the predefined jobs without provided inputs**
|
964
|
-
|
965
|
-
1. given I'm a Foreman user
|
966
|
-
1. when I'm on host details page
|
967
|
-
1. and I press 'Puppet Run'
|
968
|
-
1. the job is invoked on the host based on the predefined mapping
|
969
|
-
|
970
|
-
**Using the predefined jobs with provided inputs**
|
971
|
-
|
972
|
-
1. given I'm a Katello user
|
973
|
-
1. when I'm on host applicable errata list
|
974
|
-
1. and I select a set of errata to install on the host
|
975
|
-
1. and I click 'Install errata'
|
976
|
-
1. the job will be invoked to install the packages belonging to this
|
977
|
-
errata
|
978
|
-
|
979
|
-
**Using the predefined jobs with customization**
|
980
|
-
|
981
|
-
1. given I'm a Katello user
|
982
|
-
1. when I'm on host applicable errata list
|
983
|
-
1. and I select a set of errata to install on the host
|
984
|
-
1. and I click 'Install errata (customize)'
|
985
|
-
1. then the job invocation form will be opened with pre-filled values
|
986
|
-
based on the mapping
|
987
|
-
1. and I can update the values, including setting the start_at time or
|
988
|
-
reoccurring logic
|
989
|
-
|
990
|
-
Design
|
991
|
-
------
|
992
|
-
|
993
|
-
{% plantuml %}
|
994
|
-
|
995
|
-
class PredefinedJob {
|
996
|
-
predefined_job_name: string
|
997
|
-
==
|
998
|
-
has_and_belongs_to_many :taxonomies
|
999
|
-
}
|
1000
|
-
|
1001
|
-
class PredefinedJobInputMapping {
|
1002
|
-
provided_input_name: string
|
1003
|
-
}
|
1004
|
-
|
1005
|
-
PredefinedJob "1" -- "N" PredefinedJobInputMapping
|
1006
|
-
PredefinedJobInputMapping "N" -- "1" ConfigTemplateInput
|
1007
|
-
PredefinedJob "M" -- "N" JobTemplate
|
1008
|
-
note on link #red: 1:1 per organization and provider
|
1009
|
-
|
1010
|
-
{% endplantuml %}
|
1011
|
-
|
1012
|
-
|
1013
|
-
Security
|
1014
|
-
========
|
1015
|
-
|
1016
|
-
User Stories
|
1017
|
-
------------
|
1018
|
-
|
1019
|
-
- As a user I want to be able to plan job invocation for any host that I
|
1020
|
-
can view (view_host permission).
|
1021
|
-
|
1022
|
-
- As a user I want to be able to plan a job invocation of job that I can
|
1023
|
-
view (view_job permission)
|
1024
|
-
|
1025
|
-
- As a user I want to restrict other users which combination of host and job
|
1026
|
-
name they can execute (execute permission on job_task resource).
|
1027
|
-
|
1028
|
-
- As a user I want to be warned if I planned job invocation on hosts on
|
1029
|
-
which the execution of this job is not allowed to me.
|
1030
|
-
|
1031
|
-
- As a user I want to see refused job invocations (based on permissions) as
|
1032
|
-
failed when they are executed.
|
1033
|
-
|
1034
|
-
- As a user I want to set limit filter with execute permission by host attributes
|
1035
|
-
such as hostgroup, environment, fqdn, id, lifecycle environment (if applicable),
|
1036
|
-
content view (if applicable).
|
1037
|
-
|
1038
|
-
- As a user I want to specify effective_user for JobInvocation if at least one
|
1039
|
-
provider supports it.
|
1040
|
-
|
1041
|
-
- As a user I want to restrict other users to execute job under specific user
|
1042
|
-
as a part of filter condition. If the provider does not allow this, execution
|
1043
|
-
should be refused.
|
1044
|
-
|
1045
|
-
- As a job template provider I want to be able to specify default effective user
|
1046
|
-
|
1047
|
-
Scenarios
|
1048
|
-
---------
|
1049
|
-
|
1050
|
-
**Allow user A to invoke package installation on host B**
|
1051
|
-
|
1052
|
-
1. given user A can view all hosts and job templates
|
1053
|
-
1. when he invoke package installation job on host B
|
1054
|
-
1. then his job task fails because he does not have execution
|
1055
|
-
permission for such job task
|
1056
|
-
|
1057
|
-
**Allow user A to run package installation on host B**
|
1058
|
-
|
1059
|
-
1. given I've permissions to assign other user permissions
|
1060
|
-
1. and user A can view all hosts and job templates
|
1061
|
-
1. and user A can create job invocations
|
1062
|
-
1. when I grant user A execution permission on resource JobTask
|
1063
|
-
1. and I set related filter condition to "host_name = B and job_name = package_install"
|
1064
|
-
1. and user A invokes package install execution on hosts B and C
|
1065
|
-
1. then the job gets executed successfully on host B
|
1066
|
-
1. and job execution will fail on host C
|
1067
|
-
|
1068
|
-
**User can set effective user**
|
1069
|
-
|
1070
|
-
1. given the provider of job template supports changing effective user
|
1071
|
-
1. when user invokes a job
|
1072
|
-
1. then he can set effective user under which job is executed on target host
|
1073
|
-
|
1074
|
-
**User can disallow running job as different effective user**
|
1075
|
-
|
1076
|
-
1. given I've permissions to assign other user permissions
|
1077
|
-
1. and user A can view all hosts and job templates
|
1078
|
-
1. and user A can create job invocations
|
1079
|
-
1. when I grant user A execution permission on resource JobTask
|
1080
|
-
1. and I set related filter condition to "effective_user = user_a"
|
1081
|
-
1. and user A invokes job execution with effective user set to different user (e.g. root)
|
1082
|
-
1. then the job execution fails
|
1083
|
-
|
1084
|
-
New permissions introduced
|
1085
|
-
--------------------------
|
1086
|
-
|
1087
|
-
- JobInvocation
|
1088
|
-
- Create
|
1089
|
-
- View
|
1090
|
-
- Cancel
|
1091
|
-
- Edit (Schedule, never can change targetting)
|
1092
|
-
- JobTask
|
1093
|
-
- Execute
|
1094
|
-
- (filter can be: effective_user = 'joe' and host_id = 1 or host_id = 2 and script_name = 'foobar')
|
1095
|
-
|
1096
|
-
|
1097
|
-
Design
|
1098
|
-
------
|
1099
|
-
|
1100
|
-
{% plantuml %}
|
1101
|
-
|
1102
|
-
class JobTemplate {
|
1103
|
-
effective_user: string
|
1104
|
-
}
|
1105
|
-
|
1106
|
-
class JobInvocation {
|
1107
|
-
effective_user: string
|
1108
|
-
}
|
1109
|
-
|
1110
|
-
{% endplantuml %}
|
1111
|
-
|
1112
|
-
Katello Client Utilities
|
1113
|
-
========================
|
1114
|
-
|
1115
|
-
Design
|
1116
|
-
------
|
1117
|
-
|
1118
|
-
katello-agent provides three main functions aside from remote management:
|
1119
|
-
|
1120
|
-
* package profile yum plugin - pushes a new package profile after any yum transaction
|
1121
|
-
* Split out into its own package (yum-plugin-katello-profile)
|
1122
|
-
* enabled repository monitoring
|
1123
|
-
* monitors /etc/yum.repos.d/redhat.repo file for changes and sends newly enabled repos whenever it does change
|
1124
|
-
* Split out into its own package (katello-errata-profile) with a service to do the same
|
1125
|
-
* On the capsule, goferd runs to recieve commands to sync repositories, possible solutions:
|
1126
|
-
* katello-agent can remain (but possibly renamed), with a lot of the existing functionality removed
|
1127
|
-
* pulp changes to a rest api method for initiating capsule syncs, katello needs to store some auth credentials per capsule
|
1128
|
-
|
1129
|
-
Orchestration
|
1130
|
-
=============
|
1131
|
-
|
1132
|
-
User Stories
|
1133
|
-
------------
|
1134
|
-
|
1135
|
-
- As a user I want to group a number of jobs together and treat them
|
1136
|
-
as an executable unit. (i.e. run this script to stop the app, install
|
1137
|
-
these errata, reboot the system)
|
1138
|
-
|
1139
|
-
- As a user I want to run a set of jobs in a rolling fashion.
|
1140
|
-
(i.e.,patch server 1, reboot it, if it succeeds, proceed to server 2
|
1141
|
-
& repeat. Otherwise raise exception)
|
1142
|
-
|
1143
|
-
- As a user I want to define a rollback job in case the execution
|
1144
|
-
fails
|
1145
|
-
|
1146
|
-
- As a sysadmin I would like to orchestrate several actions across a
|
1147
|
-
collection of machines. (e.g. install a DB on this machine, and pass
|
1148
|
-
the ip address into an install of a web server on another machine)
|
1149
|
-
|
1150
|
-
Design
|
1151
|
-
------
|
1152
|
-
|
1153
|
-
- TBD after the simple support is implemented, possible cooperation with
|
1154
|
-
multi-host deployments feature
|
1155
|
-
|
1156
|
-
- Some of the features might be solved by advanced remote execution
|
1157
|
-
technology integration (such as ansible playbook)
|
1158
|
-
|
1159
|
-
|
1160
|
-
Design: the whole picture
|
1161
|
-
======================
|
1162
|
-
|
1163
|
-
{% plantuml %}
|
1164
|
-
class Host {
|
1165
|
-
get_provider(type)
|
1166
|
-
}
|
1167
|
-
|
1168
|
-
package "Job Preparation" {
|
1169
|
-
class JobTemplate {
|
1170
|
-
name: string
|
1171
|
-
job_name: string
|
1172
|
-
retry_count: integer
|
1173
|
-
retry_interval: integer
|
1174
|
-
splay: integer
|
1175
|
-
provider_type: string
|
1176
|
-
effective_user: string
|
1177
|
-
==
|
1178
|
-
has_and_belongs_to_many :taxonomies
|
1179
|
-
has_many :inputs
|
1180
|
-
has_many :audits
|
1181
|
-
}
|
1182
|
-
|
1183
|
-
class ConfigTemplateInput {
|
1184
|
-
name: string
|
1185
|
-
required: bool
|
1186
|
-
input_type: USER_INPUT | FACT | SMART_VARIABLE
|
1187
|
-
fact_name: string
|
1188
|
-
smart_variable_name: string
|
1189
|
-
description: string
|
1190
|
-
==
|
1191
|
-
has_one :job_template
|
1192
|
-
}
|
1193
|
-
|
1194
|
-
JobTemplate "1" -- "N" ConfigTemplateInput
|
1195
|
-
}
|
1196
|
-
|
1197
|
-
package "Job Invocation" {
|
1198
|
-
class Bookmark {
|
1199
|
-
name:string
|
1200
|
-
query:string
|
1201
|
-
controller:string
|
1202
|
-
public:bool
|
1203
|
-
owner_id:integer
|
1204
|
-
owner_type:string
|
1205
|
-
}
|
1206
|
-
|
1207
|
-
class Targeting {
|
1208
|
-
query: string
|
1209
|
-
dynamic: bool
|
1210
|
-
}
|
1211
|
-
|
1212
|
-
class TemplateInvocation {
|
1213
|
-
inputs
|
1214
|
-
}
|
1215
|
-
|
1216
|
-
class JobInvocation {
|
1217
|
-
tries
|
1218
|
-
retry_interval
|
1219
|
-
splay
|
1220
|
-
concurrency
|
1221
|
-
email_notification: bool
|
1222
|
-
effective_user: string
|
1223
|
-
}
|
1224
|
-
|
1225
|
-
class User
|
1226
|
-
|
1227
|
-
Bookmark "1" -DOWN- "N" Targeting
|
1228
|
-
Targeting "M" -DOWN- "N" Host
|
1229
|
-
Targeting "N" -UP- "1" User
|
1230
|
-
JobInvocation "1" -LEFT- "1" Targeting
|
1231
|
-
JobInvocation "1" -DOWN- "N" TemplateInvocation
|
1232
|
-
TemplateInvocation "N" -LEFT- "1" JobTemplate
|
1233
|
-
|
1234
|
-
}
|
1235
|
-
|
1236
|
-
package "Scheduling" {
|
1237
|
-
class Schedule {
|
1238
|
-
start_at: datetime
|
1239
|
-
end_at: datetime
|
1240
|
-
cronline: string
|
1241
|
-
}
|
1242
|
-
|
1243
|
-
JobInvocation "1" -UP- "0..1" Schedule
|
1244
|
-
}
|
1245
|
-
|
1246
|
-
package "Execution" {
|
1247
|
-
class BulkJobTask {
|
1248
|
-
state: $TaskState
|
1249
|
-
start_at: datetime
|
1250
|
-
started_at: datetime
|
1251
|
-
ended_at datetime
|
1252
|
-
cancel()
|
1253
|
-
}
|
1254
|
-
|
1255
|
-
class JobTask {
|
1256
|
-
state: $TaskState
|
1257
|
-
start_at: datetime
|
1258
|
-
started_at: datetime
|
1259
|
-
tried_count: integer
|
1260
|
-
ended_at datetime
|
1261
|
-
retry: integer
|
1262
|
-
retry_interval: integer
|
1263
|
-
timeout: integer
|
1264
|
-
splay: integer
|
1265
|
-
concurrency: integer
|
1266
|
-
provider: string
|
1267
|
-
|
1268
|
-
command: string
|
1269
|
-
output: string
|
1270
|
-
exit_code: string
|
1271
|
-
|
1272
|
-
{abstract} support_cancel?()
|
1273
|
-
{abstract} proxy_endpoint()
|
1274
|
-
cancel()
|
1275
|
-
}
|
1276
|
-
|
1277
|
-
abstract class ProxyCommand {
|
1278
|
-
}
|
1279
|
-
|
1280
|
-
class SSHProxyCommand {
|
1281
|
-
{static} support_cancel?()
|
1282
|
-
proxy_endpoint():string
|
1283
|
-
}
|
1284
|
-
|
1285
|
-
class MCollectiveProxyCommand {
|
1286
|
-
{static} support_cancel?()
|
1287
|
-
proxy_endpoint():string
|
1288
|
-
}
|
1289
|
-
|
1290
|
-
BulkJobTask "N" -LEFT- "1" JobInvocation
|
1291
|
-
BulkJobTask "1" -- "N" JobTask
|
1292
|
-
TemplateInvocation "1" -- "N" JobTask
|
1293
|
-
JobTask "1" -RIGHT- "1" ProxyCommand
|
1294
|
-
JobTask "N" -UP- "1" Host
|
1295
|
-
}
|
1296
|
-
|
1297
|
-
|
1298
|
-
ProxyCommand <|-- SSHProxyCommand
|
1299
|
-
ProxyCommand <|-- MCollectiveProxyCommand
|
1300
|
-
|
1301
|
-
package "Developer API" {
|
1302
|
-
class PredefinedJob {
|
1303
|
-
predefined_job_name: string
|
1304
|
-
==
|
1305
|
-
has_and_belongs_to_many :taxonomies
|
1306
|
-
}
|
1307
|
-
|
1308
|
-
class PredefinedJobInputMapping {
|
1309
|
-
provided_input_name: string
|
1310
|
-
}
|
1311
|
-
|
1312
|
-
PredefinedJob "1" -- "N" PredefinedJobInputMapping
|
1313
|
-
PredefinedJobInputMapping "N" -RIGHT- "1" ConfigTemplateInput
|
1314
|
-
PredefinedJob "M" -RIGHT- "N" JobTemplate
|
1315
|
-
}
|
1316
|
-
|
1317
|
-
{% endplantuml %}
|
1318
|
-
|
1319
|
-
Wireframes
|
1320
|
-
===========
|
1321
|
-
|
1322
|
-
Here are [wireframes PDF](/foreman_remote_execution/design/wireframes.pdf) from 2015-08-14 which we follow where underlaying backends allow us.
|