foreman_default_hostgroup 2.1.0 → 6.0.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 +5 -5
- data/README.md +24 -12
- data/app/models/setting/default_hostgroup.rb +10 -8
- data/default_hostgroup.yaml.example +27 -0
- data/lib/default_hostgroup_base_host_patch.rb +99 -0
- data/lib/foreman_default_hostgroup/engine.rb +19 -15
- data/lib/foreman_default_hostgroup/version.rb +1 -1
- data/lib/tasks/foreman_default_hostgroup.rake +36 -0
- data/test/test_plugin_helper.rb +3 -3
- data/test/unit/default_hostgroup_test.rb +191 -123
- metadata +12 -12
- data/lib/default_hostgroup.rake +0 -21
- data/lib/default_hostgroup_managed_host_patch.rb +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cbf9d232426c55fc207fed30c696a03c1268f02df5d481daf7bbaec627867a8b
|
4
|
+
data.tar.gz: b4e30338ca588f25c2ef0f74d383aa432357c5f94f9fae2603445107c55ae382
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 965c2c192b549c92c474af2d6074a837e8f2ef9fe1241394f083ac519730aaab34732e3ccc99897c8521e97195dc81ab6cc5517f96f5aaa5b4dff4b326ce3209
|
7
|
+
data.tar.gz: 59434c38a0e0a3da2d63160ccebf1d06b08b6b3907df95455ba8229821d1302c7cad7471adae8e44e72c88c98a8265ab4efc88e27f599493b3ae761b40fbdd93
|
data/README.md
CHANGED
@@ -5,23 +5,26 @@ a Hostgroup set.
|
|
5
5
|
|
6
6
|
## Installation
|
7
7
|
|
8
|
-
See [
|
9
|
-
for how to install Foreman plugins
|
8
|
+
See Foreman's [plugin installation documentation](https://theforeman.org/plugins/#2.Installation).
|
10
9
|
|
11
10
|
## Compatibility
|
12
11
|
|
13
12
|
| Foreman Version | Plugin Version |
|
14
|
-
| --------------- |
|
15
|
-
| <= 1.2 |
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
| --------------- | -------------: |
|
14
|
+
| <= 1.2 | 0.1.0 |
|
15
|
+
| 1.3 | 1.0.1 |
|
16
|
+
| 1.4 | 1.1.0 |
|
17
|
+
| 1.5 | 2.0.1 |
|
18
|
+
| 1.6 - 1.11 | 3.0.0 |
|
19
|
+
| >= 1.12 | 4.0.0 |
|
20
|
+
| >= 1.16 | 4.0.1 |
|
21
|
+
| >= 1.16 | 5.0.0 |
|
22
|
+
| >= 2.2.0 | 6.0.0 |
|
20
23
|
|
21
24
|
## Usage
|
22
25
|
|
23
26
|
The configuration is done inside foreman's plugin settings directory which is
|
24
|
-
|
27
|
+
`/etc/foreman/plugins/`.
|
25
28
|
|
26
29
|
You can simply copy `default_hostgroup.yaml.example` and adjust it to fit
|
27
30
|
your needs. The format is shown in the example. The simplest form would be:
|
@@ -34,14 +37,23 @@ your needs. The format is shown in the example. The simplest form would be:
|
|
34
37
|
"hostname": ".*"
|
35
38
|
```
|
36
39
|
|
40
|
+
`Default` is the host group name (more precisely title) that will be assigned if all its the rules matches.
|
41
|
+
Under the host group name, there's a list of rules. If all of them (in this example just one) is matching,
|
42
|
+
the host is assigned to the `Default` host group. The `hostname` is the name of the fact while the value `.*`
|
43
|
+
is used as a regular expression. This rule means host with any `hostname` is added to the `Default` host group.
|
44
|
+
|
45
|
+
If you are ugrading from plugin version 2.0.1 or older the format of this
|
46
|
+
file changes and you will need modify `default_hostgroup.yaml.example` to
|
47
|
+
follow the format above.
|
48
|
+
|
37
49
|
*Important Note:* You have to restart foreman in order to apply changes in
|
38
50
|
`default_hostgroup.yaml`!
|
39
51
|
|
40
52
|
There are also two more settings under `Settings -> DefaultHostgroup`
|
41
53
|
|
42
|
-
| Setting
|
43
|
-
|
|
44
|
-
| `force_hostgroup_match`
|
54
|
+
| Setting | Description |
|
55
|
+
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
56
|
+
| `force_hostgroup_match` | Setting this to `true` will perform matching even on hosts that already have a hostgroup set. Enabling this needs `force_hostgroup_match_only_new` to be `false`. Default: `false` |
|
45
57
|
| `force_hostgroup_match_only_new` | Setting this to `true` will only perform matching when a host uploads its facts for the first time, i.e. after provisioning or when adding an existing puppetmaster and thus its nodes into foreman. Default: `true` |
|
46
58
|
|
47
59
|
## TODO
|
@@ -1,19 +1,21 @@
|
|
1
|
+
# rubocop:disable Style/ClassAndModuleChildren
|
1
2
|
class Setting::DefaultHostgroup < ::Setting
|
3
|
+
# rubocop:enable Style/ClassAndModuleChildren
|
2
4
|
BLANK_ATTRS << 'default_hostgroup'
|
3
5
|
|
4
6
|
def self.load_defaults
|
5
7
|
# Check the table exists
|
8
|
+
return unless ActiveRecord::Base.connection.table_exists?('settings')
|
6
9
|
return unless super
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
Setting.transaction do
|
12
|
+
[
|
13
|
+
set('force_hostgroup_match', 'Apply hostgroup matching even if a host already has one.', false),
|
14
|
+
set('force_hostgroup_match_only_new', 'Apply hostgroup matching only on new hosts', true),
|
15
|
+
set('force_host_environment', "Apply hostgroup's environment to host even if a host already has a different one", true)
|
16
|
+
].compact.each { |s| create s.update(category: 'Setting::DefaultHostgroup') }
|
17
|
+
end
|
14
18
|
|
15
19
|
true
|
16
|
-
|
17
20
|
end
|
18
|
-
|
19
21
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Example default_hostgroup settings
|
2
|
+
#
|
3
|
+
# Must be placed in ~foreman/config/settings.plugins.d/
|
4
|
+
#
|
5
|
+
# :facts_map:
|
6
|
+
# <hostgroup>:
|
7
|
+
# <fact_name>: <regex>
|
8
|
+
#
|
9
|
+
# The Hostgroup is the full label, include any Parent Hostgroups, eg Base/Redhat
|
10
|
+
#
|
11
|
+
# The regex can be written either with or without the enclosing slashes:
|
12
|
+
# ^test$ - valid
|
13
|
+
# /^test$/ - also valid
|
14
|
+
#
|
15
|
+
# List the regexes in the order of priority, you can have as many as you like. The
|
16
|
+
# first one to match will be used. Debug statements are written to the log if you
|
17
|
+
# are getting the wrong group applied.
|
18
|
+
---
|
19
|
+
:default_hostgroup:
|
20
|
+
:facts_map:
|
21
|
+
"Redhat":
|
22
|
+
"osfamily": "RedHat"
|
23
|
+
"lsbdistcodename": "Santiago"
|
24
|
+
"Osx/Common":
|
25
|
+
"osfamily": "Darwin"
|
26
|
+
"Base":
|
27
|
+
"hostname": ".*"
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module DefaultHostgroupBaseHostPatch
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
module ManagedOverrides
|
5
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
6
|
+
def import_facts(facts, source_proxy = nil, without_alias = false)
|
7
|
+
# rubocop:enable Lint/UnusedMethodArgument
|
8
|
+
super(facts, source_proxy)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Overrides
|
13
|
+
# rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
|
14
|
+
def import_facts(facts, source_proxy = nil, without_alias = false)
|
15
|
+
# rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity
|
16
|
+
|
17
|
+
# Load the facts anyway, hook onto the end of it
|
18
|
+
result = super(facts, source_proxy)
|
19
|
+
|
20
|
+
# Module#prepend removes the import_facts_without_match_hostgroup method, so use
|
21
|
+
# a flag to return here if needed
|
22
|
+
return result if without_alias
|
23
|
+
|
24
|
+
# Check settings are created
|
25
|
+
return result unless settings_exist?
|
26
|
+
|
27
|
+
Rails.logger.debug "DefaultHostgroupMatch: performing Hostgroup match"
|
28
|
+
|
29
|
+
return result unless host_new_or_forced?
|
30
|
+
return result unless host_has_no_hostgroup_or_forced?
|
31
|
+
|
32
|
+
facts_map = SETTINGS[:default_hostgroup][:facts_map]
|
33
|
+
new_hostgroup = find_match(facts_map)
|
34
|
+
|
35
|
+
return result unless new_hostgroup
|
36
|
+
|
37
|
+
self.host.hostgroup = new_hostgroup
|
38
|
+
self.host.environment = new_hostgroup.environment if Setting[:force_host_environment] == true
|
39
|
+
self.host.save(validate: false)
|
40
|
+
Rails.logger.info "DefaultHostgroupMatch: #{facts["hostname"]} added to #{new_hostgroup}"
|
41
|
+
|
42
|
+
result
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
included do
|
47
|
+
prepend Overrides
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_match(facts_map)
|
51
|
+
facts_map.each do |group_name, facts|
|
52
|
+
hg = Hostgroup.find_by(title: group_name)
|
53
|
+
return hg if hg.present? && group_matches?(facts)
|
54
|
+
end
|
55
|
+
Rails.logger.info "No match ..."
|
56
|
+
false
|
57
|
+
end
|
58
|
+
|
59
|
+
def group_matches?(facts)
|
60
|
+
facts.each do |fact_name, fact_regex|
|
61
|
+
fact_regex.gsub!(%r{(\A/|/\z)}, "")
|
62
|
+
host_fact_value = self.host.facts[fact_name]
|
63
|
+
Rails.logger.info "Fact = #{fact_name}"
|
64
|
+
Rails.logger.info "Regex = #{fact_regex}"
|
65
|
+
return true if Regexp.new(fact_regex).match?(host_fact_value)
|
66
|
+
end
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
def settings_exist?
|
71
|
+
unless SETTINGS[:default_hostgroup] && SETTINGS[:default_hostgroup][:facts_map]
|
72
|
+
Rails.logger.warn "DefaultHostgroupMatch: Could not load :default_hostgroup map from Settings."
|
73
|
+
return false
|
74
|
+
end
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
def host_new_or_forced?
|
79
|
+
if Setting[:force_hostgroup_match_only_new]
|
80
|
+
# hosts have already been saved during import_host, so test the creation age instead
|
81
|
+
new_host = ((Time.current - self.host.created_at) < 300)
|
82
|
+
unless new_host && self.host.hostgroup.nil? && self.host.reports.empty?
|
83
|
+
Rails.logger.debug "DefaultHostgroupMatch: skipping, host exists"
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
def host_has_no_hostgroup_or_forced?
|
91
|
+
unless Setting[:force_hostgroup_match]
|
92
|
+
if self.host.hostgroup.present?
|
93
|
+
Rails.logger.debug "DefaultHostgroupMatch: skipping, host has hostgroup"
|
94
|
+
return false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
true
|
98
|
+
end
|
99
|
+
end
|
@@ -1,28 +1,32 @@
|
|
1
|
-
require
|
1
|
+
require "default_hostgroup_base_host_patch"
|
2
2
|
|
3
3
|
module ForemanDefaultHostgroup
|
4
|
-
#Inherit from the Rails module of the parent app (Foreman), not the plugin.
|
5
|
-
#Thus, inherits from ::Rails::Engine and not from Rails::Engine
|
6
4
|
class Engine < ::Rails::Engine
|
5
|
+
engine_name "foreman_default_hostgroup"
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
initializer
|
11
|
-
|
7
|
+
config.autoload_paths += Dir["#{config.root}/app/models"]
|
8
|
+
|
9
|
+
initializer "foreman_default_hostgroup.load_default_settings",
|
10
|
+
before: :load_config_initializers do
|
11
|
+
require_dependency File.expand_path(
|
12
|
+
"../../app/models/setting/default_hostgroup.rb", __dir__
|
13
|
+
)
|
12
14
|
end
|
13
15
|
|
14
|
-
initializer
|
16
|
+
initializer "foreman_default_hostgroup.register_plugin",
|
17
|
+
before: :finisher_hook do
|
15
18
|
Foreman::Plugin.register :foreman_default_hostgroup do
|
16
|
-
|
19
|
+
requires_foreman ">= 2.2"
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
23
|
config.to_prepare do
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
begin
|
25
|
+
::HostFactImporter.include DefaultHostgroupBaseHostPatch
|
26
|
+
::HostFactImporter.prepend DefaultHostgroupBaseHostPatch::ManagedOverrides
|
27
|
+
rescue StandardError => e
|
28
|
+
Rails.logger.warn "ForemanDefaultHostgroup: skipping engine hook (#{e})"
|
29
|
+
end
|
25
30
|
end
|
26
|
-
|
27
31
|
end
|
28
32
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
# Tests
|
3
|
+
namespace :test do
|
4
|
+
desc 'Test DefaultHostgroup plugin'
|
5
|
+
Rake::TestTask.new(:foreman_default_hostgroup) do |t|
|
6
|
+
test_dir = File.join(File.dirname(__FILE__), '../..', 'test')
|
7
|
+
t.libs << ['test', test_dir]
|
8
|
+
t.pattern = "#{test_dir}/**/*_test.rb"
|
9
|
+
t.verbose = true
|
10
|
+
t.warning = false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
namespace :foreman_default_hostgroup do
|
15
|
+
task :rubocop do
|
16
|
+
begin
|
17
|
+
require 'rubocop/rake_task'
|
18
|
+
RuboCop::RakeTask.new(:rubocop_foreman_default_hostgroup) do |task|
|
19
|
+
task.patterns = ["#{ForemanDefaultHostgroup::Engine.root}/app/**/*.rb",
|
20
|
+
"#{ForemanDefaultHostgroup::Engine.root}/lib/**/*.rb",
|
21
|
+
"#{ForemanDefaultHostgroup::Engine.root}/test/**/*.rb"]
|
22
|
+
end
|
23
|
+
rescue StandardError
|
24
|
+
puts 'Rubocop not loaded.'
|
25
|
+
end
|
26
|
+
|
27
|
+
Rake::Task['rubocop_foreman_default_hostgroup'].invoke
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Rake::Task[:test].enhance ['test:foreman_default_hostgroup']
|
32
|
+
|
33
|
+
load 'tasks/jenkins.rake'
|
34
|
+
if Rake::Task.task_defined?(:'jenkins:unit')
|
35
|
+
Rake::Task['jenkins:unit'].enhance ['test:foreman_default_hostgroup', 'foreman_default_hostgroup:rubocop']
|
36
|
+
end
|
data/test/test_plugin_helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This calls the main test_helper in Foreman-core
|
2
2
|
require 'test_helper'
|
3
3
|
|
4
|
-
# Add plugin to
|
5
|
-
|
6
|
-
|
4
|
+
# Add plugin to FactoryBot's paths
|
5
|
+
FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
|
6
|
+
FactoryBot.reload
|
@@ -1,155 +1,223 @@
|
|
1
1
|
require 'test_plugin_helper'
|
2
2
|
|
3
|
+
# Tests for the plugin
|
3
4
|
class DefaultHostgroupTest < ActiveSupport::TestCase
|
5
|
+
include FactImporterIsolation
|
6
|
+
|
7
|
+
allow_transactions_for_any_importer
|
8
|
+
|
4
9
|
setup do
|
5
10
|
disable_orchestration
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def parse_json_fixture(relative_path)
|
10
|
-
return JSON.parse(File.read(File.expand_path(File.dirname(__FILE__) + relative_path)))
|
11
|
+
set_admin
|
12
|
+
setup_hostgroup_matchers
|
13
|
+
setup_host_and_facts
|
11
14
|
end
|
12
15
|
|
13
|
-
def
|
16
|
+
def setup_hostgroup_matchers
|
14
17
|
# The settings.yml fixture in Core wipes out the Setting table,
|
15
|
-
# so we use
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
# so we use FactoryBot to re-create it
|
19
|
+
FactoryBot.create(:setting,
|
20
|
+
name: 'force_hostgroup_match',
|
21
|
+
category: 'Setting::DefaultHostgroup')
|
22
|
+
FactoryBot.create(:setting,
|
23
|
+
name: 'force_hostgroup_match_only_new',
|
24
|
+
category: 'Setting::DefaultHostgroup')
|
25
|
+
FactoryBot.create(:setting,
|
26
|
+
name: 'force_host_environment',
|
27
|
+
category: 'Setting::DefaultHostgroup')
|
28
|
+
# Set the defaults
|
22
29
|
Setting[:force_hostgroup_match] = false
|
23
30
|
Setting[:force_hostgroup_match_only_new] = true
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
SETTINGS[:default_hostgroup][:facts_map] = {
|
30
|
-
|
31
|
-
|
32
|
-
raw = parse_json_fixture('/facts.json')
|
33
|
-
|
34
|
-
assert Host.import_host_and_facts(raw['name'], raw['facts'])
|
35
|
-
assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
|
31
|
+
Setting[:force_host_environment] = true
|
32
|
+
|
33
|
+
# Mimic plugin config fron config file
|
34
|
+
FactoryBot.create(:hostgroup, :with_environment, name: 'Test Default')
|
35
|
+
SETTINGS[:default_hostgroup] = {}
|
36
|
+
SETTINGS[:default_hostgroup][:facts_map] = {
|
37
|
+
'Test Default' => { 'hostname' => '.*' }
|
38
|
+
}
|
36
39
|
end
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
raw = parse_json_fixture('/facts.json')
|
44
|
-
|
45
|
-
assert Host.import_host_and_facts(raw['name'], raw['facts'])
|
46
|
-
assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
|
41
|
+
def setup_host_and_facts
|
42
|
+
raw = JSON.parse(File.read(File.expand_path(File.dirname(__FILE__) + '/facts.json')))
|
43
|
+
@name = raw['name']
|
44
|
+
@host = Host.import_host(raw['name'], 'puppet')
|
45
|
+
@facts = raw['facts']
|
47
46
|
end
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
context 'import_facts_with_match_hostgroup' do
|
49
|
+
test 'matched host is saved with new hostgroup' do
|
50
|
+
assert @host.import_facts(@facts)
|
51
|
+
assert_equal Hostgroup.find_by(name: 'Test Default'), Host.find_by(name: @name).hostgroup
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
|
54
|
+
test 'matched host not updated if host already has a hostgroup' do
|
55
|
+
hostgroup = FactoryBot.create(:hostgroup)
|
56
|
+
@host.hostgroup = hostgroup
|
57
|
+
@host.save(validate: false)
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
assert @host.import_facts(@facts)
|
60
|
+
assert_equal hostgroup, Host.find_by(name: @name).hostgroup
|
61
|
+
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
test 'hostgroup is not updated if host is not new' do
|
64
|
+
@host.created_at = Time.current - 1000
|
65
|
+
@host.save(validate: false)
|
63
66
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
assert Host.import_host_and_facts(raw['name'], raw['facts'])
|
68
|
-
assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
|
67
|
+
assert @host.import_facts(@facts)
|
68
|
+
assert_not Host.find_by(name: @name).hostgroup
|
69
|
+
end
|
69
70
|
end
|
70
71
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
72
|
+
context 'force host environment setting' do
|
73
|
+
test 'environment is updated if enabled' do
|
74
|
+
h = FactoryBot.create(:host, :with_environment, created_at: Time.current)
|
75
|
+
h.import_facts(@facts)
|
76
|
+
assert_equal Hostgroup.find_by(name: 'Test Default').environment, h.environment
|
77
|
+
end
|
78
|
+
|
79
|
+
test 'environment not updated if disabled' do
|
80
|
+
Setting[:force_host_environment] = false
|
81
|
+
h = FactoryBot.create(:host, :with_environment, created_at: Time.current)
|
82
|
+
h.import_facts(@facts)
|
83
|
+
assert_not_equal Hostgroup.find_by(name: 'Test Default').environment, h.environment
|
84
|
+
end
|
80
85
|
end
|
81
86
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
context 'find_match' do
|
88
|
+
# takes a config map, returns a group or false
|
89
|
+
test 'match a single hostgroup' do
|
90
|
+
facts_map = SETTINGS[:default_hostgroup][:facts_map]
|
91
|
+
assert @host.import_facts(@facts, nil, true)
|
92
|
+
assert_equal Hostgroup.find_by(name: 'Test Default'), @host.find_match(facts_map)
|
93
|
+
end
|
94
|
+
|
95
|
+
test 'returns false for no match' do
|
96
|
+
facts_map = SETTINGS[:default_hostgroup][:facts_map] = {
|
97
|
+
'Test Default' => { 'hostname' => 'nosuchhost' }
|
98
|
+
}
|
99
|
+
assert @host.import_facts(@facts, nil, true)
|
100
|
+
assert_not @host.find_match(facts_map)
|
101
|
+
end
|
102
|
+
|
103
|
+
test 'matches first available hostgroup' do
|
104
|
+
facts_map = SETTINGS[:default_hostgroup][:facts_map] = {
|
105
|
+
'Test Default' => { 'hostname' => '.*' },
|
106
|
+
'Some Other Group' => { 'hostname' => '/\.lan$/' }
|
107
|
+
}
|
108
|
+
assert @host.import_facts(@facts, nil, true)
|
109
|
+
assert_equal Hostgroup.find_by(name: 'Test Default'), @host.find_match(facts_map)
|
110
|
+
end
|
111
|
+
|
112
|
+
test 'nonexistant groups are ignored' do
|
113
|
+
facts_map = SETTINGS[:default_hostgroup][:facts_map] = {
|
114
|
+
'Some Other Group' => { 'hostname' => '.*' },
|
115
|
+
'Test Default' => { 'hostname' => '/\.lan$/' }
|
116
|
+
}
|
117
|
+
assert @host.import_facts(@facts, nil, true)
|
118
|
+
assert_equal Hostgroup.find_by(name: 'Test Default'), @host.find_match(facts_map)
|
119
|
+
end
|
91
120
|
end
|
92
121
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
122
|
+
context 'group_matches?' do
|
123
|
+
# passing a hash of (group_name, regex) pairs
|
124
|
+
test 'full regex matches' do
|
125
|
+
regex = { 'hostname' => '^sinn1636.lan$' }
|
126
|
+
assert @host.import_facts(@facts, nil, true)
|
127
|
+
assert @host.group_matches?(regex)
|
128
|
+
end
|
129
|
+
|
130
|
+
test 'partial regex matches' do
|
131
|
+
regex = { 'hostname' => '.lan$' }
|
132
|
+
assert @host.import_facts(@facts, nil, true)
|
133
|
+
assert @host.group_matches?(regex)
|
134
|
+
end
|
135
|
+
|
136
|
+
test 'regex slashes are stripped' do
|
137
|
+
regex = { 'hostname' => '/\.lan$/' }
|
138
|
+
assert @host.import_facts(@facts, nil, true)
|
139
|
+
assert @host.group_matches?(regex)
|
140
|
+
end
|
141
|
+
|
142
|
+
test 'invalid keys are ignored' do
|
143
|
+
regex = { 'nosuchfact' => '.*' }
|
144
|
+
assert @host.import_facts(@facts, nil, true)
|
145
|
+
assert_not @host.group_matches?(regex)
|
146
|
+
end
|
147
|
+
|
148
|
+
test 'unmatched values are ignored' do
|
149
|
+
regex = { 'hostname' => 'nosuchname' }
|
150
|
+
assert @host.import_facts(@facts, nil, true)
|
151
|
+
assert_not @host.group_matches?(regex)
|
152
|
+
end
|
153
|
+
|
154
|
+
test 'multiple entries with invalid keys / values match' do
|
155
|
+
regex = {
|
156
|
+
'nosuchfact' => '.*',
|
157
|
+
'osfamily' => 'nosuchos',
|
158
|
+
'hostname' => '.lan$'
|
159
|
+
}
|
160
|
+
assert @host.import_facts(@facts, nil, true)
|
161
|
+
assert @host.group_matches?(regex)
|
162
|
+
end
|
102
163
|
end
|
103
164
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
assert Host.import_host_and_facts(raw['name'], raw['facts'])
|
117
|
-
assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
|
165
|
+
context 'settings_exist?' do
|
166
|
+
test 'true when Settings exist' do
|
167
|
+
h = FactoryBot.create(:host)
|
168
|
+
assert h.settings_exist?
|
169
|
+
end
|
170
|
+
|
171
|
+
test 'false when Settings are missing' do
|
172
|
+
SETTINGS[:default_hostgroup] = {}
|
173
|
+
h = FactoryBot.create(:host)
|
174
|
+
assert_not h.settings_exist?
|
175
|
+
end
|
118
176
|
end
|
119
177
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
host
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
178
|
+
context 'host_new_or_forced?' do
|
179
|
+
test 'true when host is new' do
|
180
|
+
h = FactoryBot.create(:host, created_at: Time.current)
|
181
|
+
assert h.host_new_or_forced?
|
182
|
+
end
|
183
|
+
|
184
|
+
test 'false when host has existed for > 300s' do
|
185
|
+
h = FactoryBot.create(:host, created_at: Time.current - 1000)
|
186
|
+
assert_not h.host_new_or_forced?
|
187
|
+
end
|
188
|
+
|
189
|
+
test 'false when host has a hostgroup' do
|
190
|
+
h = FactoryBot.create(:host, :with_hostgroup, created_at: Time.current)
|
191
|
+
assert_not h.host_new_or_forced?
|
192
|
+
end
|
193
|
+
|
194
|
+
test 'false when host has reports' do
|
195
|
+
h = FactoryBot.create(:host, :with_reports, created_at: Time.current)
|
196
|
+
assert_not h.host_new_or_forced?
|
197
|
+
end
|
198
|
+
|
199
|
+
test 'true when setting is forced' do
|
200
|
+
Setting[:force_hostgroup_match_only_new] = false
|
201
|
+
h = FactoryBot.create(:host, :with_hostgroup, created_at: Time.current)
|
202
|
+
assert h.host_new_or_forced?
|
203
|
+
end
|
136
204
|
end
|
137
205
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
host
|
150
|
-
|
151
|
-
|
152
|
-
|
206
|
+
context 'host_has_no_hostgroup_or_forced?' do
|
207
|
+
test 'true if host has no hostgroup' do
|
208
|
+
h = FactoryBot.create(:host)
|
209
|
+
assert h.host_has_no_hostgroup_or_forced?
|
210
|
+
end
|
211
|
+
|
212
|
+
test 'false if host has hostgroup' do
|
213
|
+
h = FactoryBot.create(:host, :with_hostgroup)
|
214
|
+
assert_not h.host_has_no_hostgroup_or_forced?
|
215
|
+
end
|
216
|
+
|
217
|
+
test 'true if host has hostgroup and setting forced' do
|
218
|
+
Setting[:force_hostgroup_match] = true
|
219
|
+
h = FactoryBot.create(:host, :with_hostgroup)
|
220
|
+
assert h.host_has_no_hostgroup_or_forced?
|
221
|
+
end
|
153
222
|
end
|
154
|
-
|
155
223
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_default_hostgroup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Sutcliffe
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Adds the option to specify a default hostgroup for new hosts created
|
14
14
|
from facts/reports
|
@@ -22,19 +22,20 @@ files:
|
|
22
22
|
- LICENSE
|
23
23
|
- README.md
|
24
24
|
- app/models/setting/default_hostgroup.rb
|
25
|
-
-
|
26
|
-
- lib/
|
25
|
+
- default_hostgroup.yaml.example
|
26
|
+
- lib/default_hostgroup_base_host_patch.rb
|
27
27
|
- lib/foreman_default_hostgroup.rb
|
28
28
|
- lib/foreman_default_hostgroup/engine.rb
|
29
29
|
- lib/foreman_default_hostgroup/version.rb
|
30
|
+
- lib/tasks/foreman_default_hostgroup.rake
|
30
31
|
- test/test_plugin_helper.rb
|
31
32
|
- test/unit/default_hostgroup_test.rb
|
32
33
|
- test/unit/facts.json
|
33
|
-
homepage:
|
34
|
+
homepage: https://github.com/theforeman/foreman_default_hostgroup
|
34
35
|
licenses:
|
35
|
-
- GPL-3
|
36
|
+
- GPL-3.0
|
36
37
|
metadata: {}
|
37
|
-
post_install_message:
|
38
|
+
post_install_message:
|
38
39
|
rdoc_options: []
|
39
40
|
require_paths:
|
40
41
|
- lib
|
@@ -49,12 +50,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
50
|
- !ruby/object:Gem::Version
|
50
51
|
version: '0'
|
51
52
|
requirements: []
|
52
|
-
|
53
|
-
|
54
|
-
signing_key:
|
53
|
+
rubygems_version: 3.0.3
|
54
|
+
signing_key:
|
55
55
|
specification_version: 4
|
56
56
|
summary: Default Hostgroup Plugin for Foreman
|
57
57
|
test_files:
|
58
58
|
- test/test_plugin_helper.rb
|
59
|
-
- test/unit/default_hostgroup_test.rb
|
60
59
|
- test/unit/facts.json
|
60
|
+
- test/unit/default_hostgroup_test.rb
|
data/lib/default_hostgroup.rake
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
namespace :test do
|
2
|
-
desc "Test DefaultHostgroup plugin"
|
3
|
-
Rake::TestTask.new(:default_hostgroup) do |t|
|
4
|
-
test_dir = File.join(File.dirname(__FILE__), '..', 'test')
|
5
|
-
t.libs << ["test",test_dir]
|
6
|
-
t.pattern = "#{test_dir}/**/*_test.rb"
|
7
|
-
t.verbose = true
|
8
|
-
end
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
Rake::Task[:test].enhance do
|
13
|
-
Rake::Task['test:default_hostgroup'].invoke
|
14
|
-
end
|
15
|
-
|
16
|
-
load 'tasks/jenkins.rake'
|
17
|
-
if Rake::Task.task_defined?(:'jenkins:setup')
|
18
|
-
Rake::Task["jenkins:unit"].enhance do
|
19
|
-
Rake::Task['test:default_hostgroup'].invoke
|
20
|
-
end
|
21
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
module DefaultHostgroupManagedHostPatch
|
2
|
-
def self.included(base)
|
3
|
-
base.extend ClassMethods
|
4
|
-
base.class_eval do
|
5
|
-
class << self
|
6
|
-
alias_method_chain :import_host_and_facts, :match_hostgroup
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def import_host_and_facts_with_match_hostgroup hostname, facts, certname = nil, proxy_id = nil
|
13
|
-
@host, result = import_host_and_facts_without_match_hostgroup(hostname, facts, certname, proxy_id)
|
14
|
-
|
15
|
-
unless SETTINGS[:default_hostgroup] && SETTINGS[:default_hostgroup][:facts_map]
|
16
|
-
Rails.logger.warn "DefaultHostgroupMatch: Could not load default_hostgroup map from settings, check config."
|
17
|
-
return @host, result
|
18
|
-
end
|
19
|
-
|
20
|
-
Rails.logger.debug "DefaultHostgroupMatch: performing Hostgroup match"
|
21
|
-
|
22
|
-
if Setting[:force_hostgroup_match_only_new]
|
23
|
-
# host.new_record? will only test for the early return in the core method, a real host
|
24
|
-
# will have already been saved at least once.
|
25
|
-
unless @host.present? && !@host.new_record? && @host.hostgroup.nil? && @host.reports.empty?
|
26
|
-
|
27
|
-
Rails.logger.debug "DefaultHostgroupMatch: skipping, host exists"
|
28
|
-
return @host, result
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
unless Setting[:force_hostgroup_match]
|
33
|
-
if @host.hostgroup.present?
|
34
|
-
Rails.logger.debug "DefaultHostgroupMatch: skipping, host has hostgroup"
|
35
|
-
return @host, result
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
facts_map = SETTINGS[:default_hostgroup][:facts_map]
|
40
|
-
new_hostgroup = find_match(facts_map)
|
41
|
-
|
42
|
-
return @host, result unless new_hostgroup
|
43
|
-
|
44
|
-
@host.hostgroup = new_hostgroup
|
45
|
-
@host.save(:validate => false)
|
46
|
-
Rails.logger.info "DefaultHostgroupMatch: #{hostname} added to #{new_hostgroup}"
|
47
|
-
|
48
|
-
return @host, result
|
49
|
-
end
|
50
|
-
|
51
|
-
def group_matches?(fact)
|
52
|
-
fact.each do |fact_name, fact_regex|
|
53
|
-
fact_regex.gsub!(/(\A\/|\/\z)/, '')
|
54
|
-
host_fact_value = @host.facts_hash[fact_name]
|
55
|
-
Rails.logger.info "Fact = #{fact_name}"
|
56
|
-
Rails.logger.info "Regex = #{fact_regex}"
|
57
|
-
return true if Regexp.new(fact_regex).match(host_fact_value)
|
58
|
-
end
|
59
|
-
return false
|
60
|
-
end
|
61
|
-
|
62
|
-
def find_match(facts_map)
|
63
|
-
facts_map.each do |group_name, facts|
|
64
|
-
return Hostgroup.find_by_title(group_name) if group_matches?(facts) and valid_hostgroup?(group_name)
|
65
|
-
end
|
66
|
-
Rails.logger.info "No match ..."
|
67
|
-
return false
|
68
|
-
end
|
69
|
-
|
70
|
-
def valid_hostgroup?(hostgroup)
|
71
|
-
Hostgroup.find_by_title(hostgroup) ? true : false
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|