foreman_salt 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|