foreman_salt 1.0.0 → 1.1.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 +4 -4
- data/app/controllers/foreman_salt/api/v2/jobs_controller.rb +65 -0
- data/app/lib/actions/foreman_salt/report_import.rb +29 -0
- data/app/models/foreman_salt/concerns/host_managed_extensions.rb +1 -1
- data/app/services/foreman_salt/report_importer.rb +152 -0
- data/config/routes.rb +4 -0
- data/lib/foreman_salt.rb +7 -1
- data/lib/foreman_salt/engine.rb +10 -0
- data/lib/foreman_salt/version.rb +1 -1
- data/test/unit/highstate.json +196 -0
- data/test/unit/report_importer_test.rb +32 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 763554c758fd70adb3a4feef13ceb720c6711caa
|
4
|
+
data.tar.gz: 0b86628a2277d95a26cc75bf6ef45070361c35d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d874dcf278f82b3b5bce1da5373bc37ccd758a5ee3ab9cccca65bc7cd8e0518a74a4cb9580d47e9d3187b4b2191e9b5d4b69b102cb420b4815719344eae35de
|
7
|
+
data.tar.gz: 5fd385f82b6dd1a8f9fef3d8061e221e127123176afeda78ea07b1075092b62ac7cab162d8b143a60f4bb6f88c991657fcf3c5511602977b825fa1aa9127d37e
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module ForemanSalt
|
4
|
+
module Api
|
5
|
+
module V2
|
6
|
+
class JobsController < ::Api::V2::BaseController
|
7
|
+
include ::Api::Version2
|
8
|
+
include ::Foreman::Controller::SmartProxyAuth
|
9
|
+
include ForemanSalt::Concerns::SmartProxyAuthExtensions
|
10
|
+
|
11
|
+
add_puppetmaster_filters :upload
|
12
|
+
|
13
|
+
resource_description do
|
14
|
+
api_base_url "/salt/api"
|
15
|
+
end
|
16
|
+
|
17
|
+
def_param_group :job do
|
18
|
+
param :job, Hash, :required => true, :action_aware => true do
|
19
|
+
param :job_id, Integer, :required => true, :desc => N_("JID")
|
20
|
+
param :function, String, :required => true, :desc => N_("Function")
|
21
|
+
param :result, Hash, :required => true, :desc => N_("Result")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
api :POST, '/upload/', N_('Upload a Job')
|
26
|
+
param_group :job, :as => :upload
|
27
|
+
|
28
|
+
def upload
|
29
|
+
Rails.logger.info("Processing job #{params[:job][:job_id]} from Salt.")
|
30
|
+
case params[:job][:function]
|
31
|
+
when 'state.highstate'
|
32
|
+
# Dynflowize the action if we can, otherwise we'll do it live
|
33
|
+
if defined? ForemanTasks
|
34
|
+
task = ForemanTasks.async_task(::Actions::ForemanSalt::ReportImport, params[:job], detected_proxy.try(:id))
|
35
|
+
render :json => {:task_id => task.id}
|
36
|
+
else
|
37
|
+
reports = ForemanSalt::ReportImporter.import(params[:job][:result], detected_proxy.try(:id))
|
38
|
+
render :json => {:message => "Imported #{reports.count} new reports."}
|
39
|
+
end
|
40
|
+
else
|
41
|
+
render :json => {:message => 'Unsupported function'}, :status => :unprocessable_entity
|
42
|
+
end
|
43
|
+
rescue ::Foreman::Exception => e
|
44
|
+
render :json => {:message => e.to_s}, :status => :unprocessable_entity
|
45
|
+
end
|
46
|
+
|
47
|
+
def resource_class
|
48
|
+
::Report
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def action_permission
|
54
|
+
case params[:action]
|
55
|
+
when 'upload'
|
56
|
+
:create
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Actions
|
2
|
+
module ForemanSalt
|
3
|
+
if defined? ForemanTasks
|
4
|
+
class ReportImport < Actions::EntryAction
|
5
|
+
|
6
|
+
def resource_locks
|
7
|
+
:report_import
|
8
|
+
end
|
9
|
+
|
10
|
+
def plan(job, proxy_id)
|
11
|
+
plan_self(:job_id => job[:job_id], :report => job[:result], :proxy_id => proxy_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
::User.as_anonymous_admin do
|
16
|
+
reports = ::ForemanSalt::ReportImporter.import(input[:report], input[:proxy_id])
|
17
|
+
|
18
|
+
output[:state] = {:message => "Imported #{reports.count} new reports"}
|
19
|
+
output[:hosts] = reports.map { |report| report.host.name }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def humanized_name
|
24
|
+
_("Process Highstate Report: #{input[:job_id]}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -51,7 +51,7 @@ module ForemanSalt
|
|
51
51
|
|
52
52
|
def set_hostgroup_defaults_with_salt_proxy
|
53
53
|
return unless hostgroup
|
54
|
-
assign_hostgroup_attributes(%w{salt_proxy_id})
|
54
|
+
assign_hostgroup_attributes(%w{salt_proxy_id salt_environment_id})
|
55
55
|
set_hostgroup_defaults_without_salt_proxy
|
56
56
|
end
|
57
57
|
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module ForemanSalt
|
2
|
+
class ReportImporter
|
3
|
+
delegate :logger, :to => :Rails
|
4
|
+
attr_reader :report
|
5
|
+
|
6
|
+
def self.import(raw, proxy_id = nil)
|
7
|
+
raise ::Foreman::Exception.new(_('Invalid report')) unless raw.is_a?(Hash)
|
8
|
+
raw.map do |host, report|
|
9
|
+
importer = ForemanSalt::ReportImporter.new(host, report, proxy_id)
|
10
|
+
importer.import
|
11
|
+
importer.report
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(host, raw, proxy_id = nil)
|
16
|
+
@host = find_or_create_host(host)
|
17
|
+
@raw = raw
|
18
|
+
@proxy_id = proxy_id
|
19
|
+
end
|
20
|
+
|
21
|
+
def import
|
22
|
+
logger.info "processing report for #{@host}"
|
23
|
+
logger.debug { "Report: #{@raw.inspect}" }
|
24
|
+
|
25
|
+
if @host.new_record? && !Setting[:create_new_host_when_report_is_uploaded]
|
26
|
+
logger.info("skipping report for #{@host} as its an unknown host and create_new_host_when_report_is_uploaded setting is disabled")
|
27
|
+
return Report.new
|
28
|
+
end
|
29
|
+
|
30
|
+
@host.salt_proxy_id ||= @proxy_id
|
31
|
+
@host.last_report = start_time
|
32
|
+
|
33
|
+
if @raw.is_a? Array
|
34
|
+
process_failures # If Salt sends us only an array, it's a list of fatal failures
|
35
|
+
else
|
36
|
+
process_normal
|
37
|
+
end
|
38
|
+
|
39
|
+
@host.save(:validate => false)
|
40
|
+
logger.info("Imported report for #{@host} in #{(Time.now - start_time).round(2)} seconds")
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def find_or_create_host(host)
|
46
|
+
@host ||= Host::Base.find_by_name(host)
|
47
|
+
|
48
|
+
unless @host
|
49
|
+
new = Host::Managed.new(:name => host)
|
50
|
+
new.save(:validate => false)
|
51
|
+
@host = new
|
52
|
+
end
|
53
|
+
|
54
|
+
@host
|
55
|
+
end
|
56
|
+
|
57
|
+
def import_log_messages
|
58
|
+
@raw.each do |resource, result|
|
59
|
+
level = if result['changes'].blank? && result['result']
|
60
|
+
:info
|
61
|
+
elsif result['result'] == false
|
62
|
+
:err
|
63
|
+
else
|
64
|
+
:notice
|
65
|
+
end
|
66
|
+
|
67
|
+
source = Source.find_or_create(resource)
|
68
|
+
|
69
|
+
message = if result['changes']['diff']
|
70
|
+
result['changes']['diff']
|
71
|
+
elsif !result['comment'].blank?
|
72
|
+
result['comment']
|
73
|
+
else
|
74
|
+
'No message available'
|
75
|
+
end
|
76
|
+
|
77
|
+
message = Message.find_or_create(message)
|
78
|
+
Log.create(:message_id => message.id, :source_id => source.id, :report => @report, :level => level)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def calculate_metrics
|
83
|
+
success = 0
|
84
|
+
failed = 0
|
85
|
+
changed = 0
|
86
|
+
restarted = 0
|
87
|
+
restarted_failed = 0
|
88
|
+
|
89
|
+
time = {}
|
90
|
+
|
91
|
+
@raw.each do |resource, result|
|
92
|
+
next unless result.is_a? Hash
|
93
|
+
|
94
|
+
if result['result'] == true
|
95
|
+
success += 1
|
96
|
+
if resource.match(/^service_/) && result['comment'].include?('restarted')
|
97
|
+
restarted += 1
|
98
|
+
elsif !result['changes'].blank?
|
99
|
+
changed += 1
|
100
|
+
end
|
101
|
+
elsif result['result'] == false
|
102
|
+
if resource.match(/^service_/) && result['comment'].include?('restarted')
|
103
|
+
restarted_failed += 1
|
104
|
+
else
|
105
|
+
failed += 1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
time[resource] = result['duration'] if result['duration']
|
110
|
+
end
|
111
|
+
|
112
|
+
time[:total] = time.values.inject(&:+)
|
113
|
+
events = {:total => changed + failed + restarted + restarted_failed, :success => success + restarted, :failure => failed + restarted_failed}
|
114
|
+
|
115
|
+
changes = {:total => changed + restarted}
|
116
|
+
|
117
|
+
resources = {'total' => @raw.size, 'applied' => changed, 'restarted' => restarted, 'failed' => failed,
|
118
|
+
'failed_restarts' => restarted_failed, 'skipped' => 0, 'scheduled' => 0}
|
119
|
+
|
120
|
+
{:events => events, :resources => resources, :changes => changes, :time => time}
|
121
|
+
end
|
122
|
+
|
123
|
+
def process_normal
|
124
|
+
metrics = calculate_metrics
|
125
|
+
status = ReportStatusCalculator.new(:counters => metrics[:resources].slice(*::Report::METRIC)).calculate
|
126
|
+
|
127
|
+
@host.puppet_status = status
|
128
|
+
|
129
|
+
@report = Report.new(:host => @host, :reported_at => start_time, :status => status, :metrics => metrics)
|
130
|
+
return @report unless @report.save
|
131
|
+
import_log_messages
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def process_failures
|
136
|
+
status = ReportStatusCalculator.new({:counters => {'failed' => @raw.size}}).calculate
|
137
|
+
@report = Report.create(:host => @host, :reported_at => Time.now, :status => status, :metrics => {})
|
138
|
+
|
139
|
+
@host.puppet_status = status
|
140
|
+
|
141
|
+
source = Source.find_or_create('Salt')
|
142
|
+
@raw.each do |failure|
|
143
|
+
message = Message.find_or_create(failure)
|
144
|
+
Log.create(:message_id => message.id, :source_id => source.id, :report => @report, :level => :err)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def start_time
|
149
|
+
@start_time ||= Time.now
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/config/routes.rb
CHANGED
@@ -14,6 +14,10 @@ Rails.application.routes.draw do
|
|
14
14
|
get 'auto_complete_search'
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
scope :api, :defaults => {:format => 'json'}, :constraints => ApiConstraints.new(:version => 2) do
|
19
|
+
match 'api/v2/jobs/upload' => 'foreman_salt/api/v2/jobs#upload', :via => :post
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
23
|
constraints(:smart_proxy_id => /[^\/]+/) do
|
data/lib/foreman_salt.rb
CHANGED
data/lib/foreman_salt/engine.rb
CHANGED
@@ -10,6 +10,12 @@ module ForemanSalt
|
|
10
10
|
config.autoload_paths += Dir["#{config.root}/app/services"]
|
11
11
|
config.autoload_paths += Dir["#{config.root}/app/lib"]
|
12
12
|
|
13
|
+
if defined? ForemanTasks
|
14
|
+
initializer "foreman_salt.require_dynflow", :before => "foreman_tasks.initialize_dynflow" do |app|
|
15
|
+
ForemanTasks.dynflow.require!
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
13
19
|
# Add any db migrations
|
14
20
|
initializer "foreman_salt.load_app_instance_data" do |app|
|
15
21
|
app.config.paths['db/migrate'] += ForemanSalt::Engine.paths['db/migrate'].existent
|
@@ -66,6 +72,10 @@ module ForemanSalt
|
|
66
72
|
permission :view_smart_proxies_salt_autosign, {:'foreman_salt/salt_autosign' => [:index]}, :resource_type => "SmartProxy"
|
67
73
|
end
|
68
74
|
|
75
|
+
security_block :api do |map|
|
76
|
+
permission :create_reports, {:'foreman_salt/api/v2/jobs' => [:upload]}, :resource_type => "Report"
|
77
|
+
end
|
78
|
+
|
69
79
|
role "Salt admin", [:saltrun_hosts, :create_salt_modules, :view_salt_modules, :edit_salt_modules, :destroy_salt_modules,
|
70
80
|
:view_smart_proxies_salt_keys, :destroy_smart_proxies_salt_keys, :edit_smart_proxies_salt_keys,
|
71
81
|
:create_smart_proxies_salt_autosign, :view_smart_proxies_salt_autosign, :destroy_smart_proxies_salt_autosign,
|
data/lib/foreman_salt/version.rb
CHANGED
@@ -0,0 +1,196 @@
|
|
1
|
+
{
|
2
|
+
"saltclient713.example.com": {
|
3
|
+
"pkg_|-postfix_|-postfix_|-installed": {
|
4
|
+
"comment": "Package postfix is already installed.",
|
5
|
+
"name": "postfix",
|
6
|
+
"start_time": "00:18:06.518702",
|
7
|
+
"result": true,
|
8
|
+
"duration": 1.575,
|
9
|
+
"__run_num__": 13,
|
10
|
+
"changes": {
|
11
|
+
},
|
12
|
+
"retcode": 2
|
13
|
+
},
|
14
|
+
"file_|-mysql_config_|-/etc/my.cnf_|-managed": {
|
15
|
+
"comment": "File /etc/my.cnf updated",
|
16
|
+
"name": "/etc/my.cnf",
|
17
|
+
"start_time": "00:18:00.901791",
|
18
|
+
"result": true,
|
19
|
+
"duration": 978.938,
|
20
|
+
"__run_num__": 6,
|
21
|
+
"changes": {
|
22
|
+
"diff": "--- \n+++ \n@@ -1,10 +1,39 @@\n-[mysqld]\n-datadir=/var/lib/mysql\n-socket=/var/lib/mysql/mysql.sock\n-user=mysql\n-# Disabling symbolic-links is recommended to prevent assorted security risks\n-symbolic-links=0\n+# DO NOT CHANGE THIS FILE!\n+# This config is generated by SALTSTACK\n+# and all change will be overrided on next salt call\n+\n+\n+[myisampack]\n+\n+[mysqlimport]\n+\n+[mysqlcheck]\n \n [mysqld_safe]\n-log-error=/var/log/mysqld.log\n-pid-file=/var/run/mysqld/mysqld.pid\n+log-error = /var/log/mysqld.log\n+pid-file = /var/run/mysqld/mysqld.pid\n+\n+[mysqladmin]\n+\n+[mysqlshow]\n+\n+[myisamchk]\n+\n+[client]\n+\n+[mysqlhotcopy]\n+\n+[mysqldump]\n+\n+[mysql]\n+\n+[mysqld]\n+bind-address = 127.0.0.1\n+datadir = /var/lib/mysql\n+port = 3306\n+socket = /var/lib/mysql/mysql.sock\n+symbolic-links = 0\n+user = mysql\n+\n+[isamchk]\n+\n"
|
23
|
+
},
|
24
|
+
"retcode": 2
|
25
|
+
},
|
26
|
+
"mysql_database_|-mysql remove test database_|-test_|-absent": {
|
27
|
+
"comment": "Database test has been removed",
|
28
|
+
"name": "test",
|
29
|
+
"start_time": "00:18:06.511324",
|
30
|
+
"result": true,
|
31
|
+
"duration": 7.266,
|
32
|
+
"__run_num__": 12,
|
33
|
+
"changes": {
|
34
|
+
"test": "Absent"
|
35
|
+
},
|
36
|
+
"retcode": 2
|
37
|
+
},
|
38
|
+
"service_|-postfix_|-postfix_|-running": {
|
39
|
+
"comment": "Service postfix is already enabled, and is in the desired state",
|
40
|
+
"name": "postfix",
|
41
|
+
"start_time": "00:18:06.520605",
|
42
|
+
"result": true,
|
43
|
+
"duration": 53.025,
|
44
|
+
"__run_num__": 14,
|
45
|
+
"changes": {
|
46
|
+
}
|
47
|
+
},
|
48
|
+
"mysql_user_|-mysql_delete_anonymous_user_saltclient713.example.com_|-_|-absent": {
|
49
|
+
"comment": "An exception occurred in this state: Traceback (most recent call last):\n File \"/usr/lib/python2.6/site-packages/salt/state.py\", line 1533, in call\n **cdata['kwargs'])\n File \"/usr/lib/python2.6/site-packages/salt/states/mysql_user.py\", line 239, in absent\n if __salt__['mysql.user_exists'](name, host, **connection_args):\n File \"/usr/lib/python2.6/site-packages/salt/modules/mysql.py\", line 1023, in user_exists\n dbc = _connect(**connection_args)\n File \"/usr/lib/python2.6/site-packages/salt/modules/mysql.py\", line 287, in _connect\n dbc = MySQLdb.connect(**connargs)\n File \"/usr/lib64/python2.6/site-packages/MySQLdb/__init__.py\", line 81, in Connect\n return Connection(*args, **kwargs)\n File \"/usr/lib64/python2.6/site-packages/MySQLdb/connections.py\", line 187, in __init__\n super(Connection, self).__init__(*args, **kwargs2)\nTypeError: connect() argument 3 must be string, not int\n",
|
50
|
+
"name": "",
|
51
|
+
"start_time": "00:18:06.510447",
|
52
|
+
"result": false,
|
53
|
+
"duration": 0.752,
|
54
|
+
"__run_num__": 11,
|
55
|
+
"changes": {
|
56
|
+
}
|
57
|
+
},
|
58
|
+
"mysql_user_|-mysql_delete_anonymous_user_localhost_|-_|-absent": {
|
59
|
+
"comment": "An exception occurred in this state: Traceback (most recent call last):\n File \"/usr/lib/python2.6/site-packages/salt/state.py\", line 1533, in call\n **cdata['kwargs'])\n File \"/usr/lib/python2.6/site-packages/salt/states/mysql_user.py\", line 239, in absent\n if __salt__['mysql.user_exists'](name, host, **connection_args):\n File \"/usr/lib/python2.6/site-packages/salt/modules/mysql.py\", line 1023, in user_exists\n dbc = _connect(**connection_args)\n File \"/usr/lib/python2.6/site-packages/salt/modules/mysql.py\", line 287, in _connect\n dbc = MySQLdb.connect(**connargs)\n File \"/usr/lib64/python2.6/site-packages/MySQLdb/__init__.py\", line 81, in Connect\n return Connection(*args, **kwargs)\n File \"/usr/lib64/python2.6/site-packages/MySQLdb/connections.py\", line 187, in __init__\n super(Connection, self).__init__(*args, **kwargs2)\nTypeError: connect() argument 3 must be string, not int\n",
|
60
|
+
"_stamp": "2014-11-16T01:18:06.783560",
|
61
|
+
"return": "Error: mysql_user.absent",
|
62
|
+
"name": "",
|
63
|
+
"success": false,
|
64
|
+
"start_time": "00:18:06.488962",
|
65
|
+
"jid": "20141116011706024672",
|
66
|
+
"duration": 19.798,
|
67
|
+
"result": false,
|
68
|
+
"fun": "state.highstate",
|
69
|
+
"__run_num__": 9,
|
70
|
+
"changes": {
|
71
|
+
},
|
72
|
+
"id": "saltclient713.example.com",
|
73
|
+
"retcode": 2
|
74
|
+
},
|
75
|
+
"service_|-mysqld_|-mysqld_|-running": {
|
76
|
+
"comment": "Service mysqld has been enabled, and is running",
|
77
|
+
"name": "mysqld",
|
78
|
+
"start_time": "00:18:01.881541",
|
79
|
+
"result": true,
|
80
|
+
"duration": 4566.262,
|
81
|
+
"__run_num__": 7,
|
82
|
+
"changes": {
|
83
|
+
"mysqld": true
|
84
|
+
}
|
85
|
+
},
|
86
|
+
"mysql_user_|-mysql_delete_anonymous_user_localhost.localdomain_|-_|-absent": {
|
87
|
+
"comment": "An exception occurred in this state: Traceback (most recent call last):\n File \"/usr/lib/python2.6/site-packages/salt/state.py\", line 1533, in call\n **cdata['kwargs'])\n File \"/usr/lib/python2.6/site-packages/salt/states/mysql_user.py\", line 239, in absent\n if __salt__['mysql.user_exists'](name, host, **connection_args):\n File \"/usr/lib/python2.6/site-packages/salt/modules/mysql.py\", line 1023, in user_exists\n dbc = _connect(**connection_args)\n File \"/usr/lib/python2.6/site-packages/salt/modules/mysql.py\", line 287, in _connect\n dbc = MySQLdb.connect(**connargs)\n File \"/usr/lib64/python2.6/site-packages/MySQLdb/__init__.py\", line 81, in Connect\n return Connection(*args, **kwargs)\n File \"/usr/lib64/python2.6/site-packages/MySQLdb/connections.py\", line 187, in __init__\n super(Connection, self).__init__(*args, **kwargs2)\nTypeError: connect() argument 3 must be string, not int\n",
|
88
|
+
"name": "",
|
89
|
+
"start_time": "00:18:06.509230",
|
90
|
+
"result": false,
|
91
|
+
"duration": 0.8,
|
92
|
+
"__run_num__": 10,
|
93
|
+
"changes": {
|
94
|
+
}
|
95
|
+
},
|
96
|
+
"pkg_|-mysqld_|-mysql-server_|-installed": {
|
97
|
+
"comment": "The following packages were installed/updated: mysql-server.",
|
98
|
+
"name": "mysql-server",
|
99
|
+
"start_time": "00:17:41.058929",
|
100
|
+
"result": true,
|
101
|
+
"duration": 19842.654,
|
102
|
+
"__run_num__": 5,
|
103
|
+
"changes": {
|
104
|
+
"perl-DBI": {
|
105
|
+
"new": "1.609-4.el6",
|
106
|
+
"old": ""
|
107
|
+
},
|
108
|
+
"perl-DBD-MySQL": {
|
109
|
+
"new": "4.013-3.el6",
|
110
|
+
"old": ""
|
111
|
+
},
|
112
|
+
"mysql-server": {
|
113
|
+
"new": "5.1.73-3.el6_5",
|
114
|
+
"old": ""
|
115
|
+
},
|
116
|
+
"mysql": {
|
117
|
+
"new": "5.1.73-3.el6_5",
|
118
|
+
"old": ""
|
119
|
+
}
|
120
|
+
}
|
121
|
+
},
|
122
|
+
"cmd_|-mysql_root_password_|-mysqladmin --user root password '434510094'_|-run": {
|
123
|
+
"comment": "Command \"mysqladmin --user root password '434510094'\" run",
|
124
|
+
"name": "mysqladmin --user root password '434510094'",
|
125
|
+
"start_time": "00:18:06.448367",
|
126
|
+
"result": true,
|
127
|
+
"duration": 39.196,
|
128
|
+
"__run_num__": 8,
|
129
|
+
"changes": {
|
130
|
+
"pid": 2709,
|
131
|
+
"retcode": 0,
|
132
|
+
"stderr": "",
|
133
|
+
"stdout": ""
|
134
|
+
}
|
135
|
+
},
|
136
|
+
"pkg_|-mysql_python_|-MySQL-python_|-installed": {
|
137
|
+
"comment": "The following packages were installed/updated: MySQL-python.",
|
138
|
+
"name": "MySQL-python",
|
139
|
+
"start_time": "00:17:14.059753",
|
140
|
+
"result": true,
|
141
|
+
"duration": 26997.765,
|
142
|
+
"__run_num__": 4,
|
143
|
+
"changes": {
|
144
|
+
"MySQL-python": {
|
145
|
+
"new": "1.2.3-0.3.c1.1.el6",
|
146
|
+
"old": ""
|
147
|
+
}
|
148
|
+
},
|
149
|
+
"retcode": 2
|
150
|
+
},
|
151
|
+
"file_|-enable_epel_|-/etc/yum.repos.d/epel.repo_|-sed": {
|
152
|
+
"comment": "sed ran without error",
|
153
|
+
"name": "/etc/yum.repos.d/epel.repo",
|
154
|
+
"start_time": "00:17:14.024416",
|
155
|
+
"result": true,
|
156
|
+
"duration": 35.098,
|
157
|
+
"__run_num__": 3,
|
158
|
+
"changes": {
|
159
|
+
"diff": "--- \n+++ \n@@ -12,7 +12,7 @@\n #baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch/debug\n mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch\n failovermethod=priority\n-enabled=0\n+enabled=1\n gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6\n gpgcheck=1\n \n@@ -21,6 +21,6 @@\n #baseurl=http://download.fedoraproject.org/pub/epel/6/SRPMS\n mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-6&arch=$basearch\n failovermethod=priority\n-enabled=0\n+enabled=1\n gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6\n gpgcheck=1\n"
|
160
|
+
}
|
161
|
+
},
|
162
|
+
"pkg_|-epel_release_|-epel_release_|-installed": {
|
163
|
+
"comment": "All specified packages are already installed.",
|
164
|
+
"name": "epel_release",
|
165
|
+
"start_time": "00:17:13.178528",
|
166
|
+
"result": true,
|
167
|
+
"duration": 845.684,
|
168
|
+
"__run_num__": 2,
|
169
|
+
"changes": {
|
170
|
+
}
|
171
|
+
},
|
172
|
+
"file_|-/etc/motd_|-/etc/motd_|-managed": {
|
173
|
+
"comment": "File /etc/motd updated",
|
174
|
+
"name": "/etc/motd",
|
175
|
+
"start_time": "00:17:11.971247",
|
176
|
+
"result": true,
|
177
|
+
"duration": 163.144,
|
178
|
+
"__run_num__": 0,
|
179
|
+
"changes": {
|
180
|
+
"diff": "--- \n+++ \n@@ -1,0 +1,7 @@\n+_| _| _| _| _|\n+_|_|_| _|_|_|_| _|_|_| _|_|_|\n+_| _| _| _| _| _| _| _| _|\n+_| _| _| _| _| _| _| _| _|\n+_|_|_| _| _|_| _|_|_| _| _| _|\n+\n+saltclient713.example.com\n"
|
181
|
+
}
|
182
|
+
},
|
183
|
+
"file_|-install_pubkey_|-/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL_|-managed": {
|
184
|
+
"comment": "File /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL updated",
|
185
|
+
"name": "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL",
|
186
|
+
"start_time": "00:17:12.134782",
|
187
|
+
"result": true,
|
188
|
+
"duration": 1042.983,
|
189
|
+
"__run_num__": 1,
|
190
|
+
"changes": {
|
191
|
+
"diff": "New file",
|
192
|
+
"mode": "0644"
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
|
3
|
+
module ForemanSalt
|
4
|
+
class ReportImporterTest < ActiveSupport::TestCase
|
5
|
+
setup do
|
6
|
+
User.current = User.find_by_login 'admin'
|
7
|
+
Setting[:create_new_host_when_facts_are_uploaded] = true
|
8
|
+
|
9
|
+
@report = JSON.parse(File.read(File.join(Engine.root, 'test', 'unit', 'highstate.json')))
|
10
|
+
|
11
|
+
@host = 'saltclient713.example.com'
|
12
|
+
end
|
13
|
+
|
14
|
+
test 'importing report creates a host' do
|
15
|
+
refute Host.find_by_name(@host)
|
16
|
+
ForemanSalt::ReportImporter.import(@report)
|
17
|
+
assert Host.find_by_name(@host)
|
18
|
+
end
|
19
|
+
|
20
|
+
test "importing report updates host status" do
|
21
|
+
ForemanSalt::ReportImporter.import(@report)
|
22
|
+
assert_equal Host.find_by_name(@host).host_status, 'Error'
|
23
|
+
end
|
24
|
+
|
25
|
+
test 'importing report has correct status' do
|
26
|
+
ForemanSalt::ReportImporter.import(@report)
|
27
|
+
status = Host.find_by_name(@host).reports.last.status
|
28
|
+
assert_equal status['applied'], 9
|
29
|
+
assert_equal status['failed'], 3
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_salt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Benjamin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deface
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- app/views/foreman_salt/salt_autosign/new.html.erb
|
53
53
|
- app/views/foreman_salt/salt_autosign/_form.html.erb
|
54
54
|
- app/services/foreman_salt/smart_proxies/salt_keys.rb
|
55
|
+
- app/services/foreman_salt/report_importer.rb
|
55
56
|
- app/services/foreman_salt/fact_importer.rb
|
56
57
|
- app/models/foreman_salt/salt_module.rb
|
57
58
|
- app/models/foreman_salt/concerns/hostgroup_extensions.rb
|
@@ -67,8 +68,10 @@ files:
|
|
67
68
|
- app/controllers/foreman_salt/concerns/smart_proxy_auth_extensions.rb
|
68
69
|
- app/controllers/foreman_salt/concerns/hosts_controller_extensions.rb
|
69
70
|
- app/controllers/foreman_salt/concerns/unattended_controller_extensions.rb
|
71
|
+
- app/controllers/foreman_salt/api/v2/jobs_controller.rb
|
70
72
|
- app/controllers/foreman_salt/salt_environments_controller.rb
|
71
73
|
- app/lib/proxy_api/salt.rb
|
74
|
+
- app/lib/actions/foreman_salt/report_import.rb
|
72
75
|
- config/routes.rb
|
73
76
|
- db/seeds.d/75-salt-seeds.rb
|
74
77
|
- db/migrate/20140920232200_create_salt_environments.rb
|
@@ -90,8 +93,10 @@ files:
|
|
90
93
|
- test/unit/grains_centos.json
|
91
94
|
- test/unit/host_extensions_test.rb
|
92
95
|
- test/unit/salt_modules_test.rb
|
96
|
+
- test/unit/highstate.json
|
93
97
|
- test/unit/grains_importer_test.rb
|
94
98
|
- test/unit/hostgroup_extensions_test.rb
|
99
|
+
- test/unit/report_importer_test.rb
|
95
100
|
- test/test_plugin_helper.rb
|
96
101
|
- test/factories/foreman_salt_factories.rb
|
97
102
|
- test/functional/hosts_controller_test.rb
|
@@ -128,8 +133,10 @@ test_files:
|
|
128
133
|
- test/unit/grains_centos.json
|
129
134
|
- test/unit/host_extensions_test.rb
|
130
135
|
- test/unit/salt_modules_test.rb
|
136
|
+
- test/unit/highstate.json
|
131
137
|
- test/unit/grains_importer_test.rb
|
132
138
|
- test/unit/hostgroup_extensions_test.rb
|
139
|
+
- test/unit/report_importer_test.rb
|
133
140
|
- test/test_plugin_helper.rb
|
134
141
|
- test/factories/foreman_salt_factories.rb
|
135
142
|
- test/functional/hosts_controller_test.rb
|