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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5d454d40d36c903cdb01917607ff7bb5a95ec18f
4
- data.tar.gz: a620ee8b99e5bf30147d2266378462473b326628
2
+ SHA256:
3
+ metadata.gz: cbf9d232426c55fc207fed30c696a03c1268f02df5d481daf7bbaec627867a8b
4
+ data.tar.gz: b4e30338ca588f25c2ef0f74d383aa432357c5f94f9fae2603445107c55ae382
5
5
  SHA512:
6
- metadata.gz: 79200d8486340a22124c1f4b8f7df6645db83fc0c4933cf7f0a9b1269acc5a11648b810718c1dd8a97a9f9a4b0d0bf98fc0bfb638b56616c530cb28e0a1d150b
7
- data.tar.gz: 6e49893a8db8af0cde5e8dc7dd242e7de90569182555cfb3232a2c2eb7b01b7bade2ec248ac932714752fb3b7f14830f4acf6ecf4a6920af68faf7cf126afac6
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 [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
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 | 0.1.0 |
16
- | 1.3 | 1.0.1 |
17
- | 1.4 | 1.1.0 |
18
- | 1.5 | 2.0.1 |
19
- | >= 1.6 | 2.1.0 |
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
- `~foreman/config/settings.plugins.d/`.
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 | Description |
43
- | ------- | ----------- |
44
- | `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` |
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
- Setting.transaction do
9
- [
10
- self.set('force_hostgroup_match', 'Apply hostgroup matching even if a host already has one.', false),
11
- self.set('force_hostgroup_match_only_new', 'Apply hostgroup matching only on new hosts', true),
12
- ].compact.each { |s| self.create s.update(:category => 'Setting::DefaultHostgroup')}
13
- end
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 'default_hostgroup_managed_host_patch'
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
- # Load this before the Foreman config initizializers, so that the Setting.descendants
9
- # list includes the plugin STI setting class
10
- initializer 'foreman_discovery.load_default_settings', :before => :load_config_initializers do |app|
11
- require_dependency File.expand_path("../../../app/models/setting/default_hostgroup.rb", __FILE__) if (Setting.table_exists? rescue(false))
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 'foreman_default_hostgroup.register_plugin', :after=> :finisher_hook do |app|
16
+ initializer "foreman_default_hostgroup.register_plugin",
17
+ before: :finisher_hook do
15
18
  Foreman::Plugin.register :foreman_default_hostgroup do
16
- end if (Rails.env == "development" or defined? Foreman::Plugin)
19
+ requires_foreman ">= 2.2"
20
+ end
17
21
  end
18
22
 
19
23
  config.to_prepare do
20
- ::Host::Managed.send :include, DefaultHostgroupManagedHostPatch
21
- end
22
-
23
- rake_tasks do
24
- load "default_hostgroup.rake"
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
@@ -1,3 +1,3 @@
1
1
  module ForemanDefaultHostgroup
2
- VERSION = "2.1.0"
2
+ VERSION = '6.0.0'.freeze
3
3
  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
@@ -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 FactoryGirl's paths
5
- FactoryGirl.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
6
- FactoryGirl.reload
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
- User.current = User.find_by_login "admin"
7
- end
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 setup_hostgroup_match
16
+ def setup_hostgroup_matchers
14
17
  # The settings.yml fixture in Core wipes out the Setting table,
15
- # so we use FactoryGirl to re-create it
16
- FactoryGirl.create(:setting,
17
- :name => 'force_hostgroup_match',
18
- :category => 'Setting::DefaultHostgroup')
19
- FactoryGirl.create(:setting,
20
- :name => 'force_hostgroup_match_only_new',
21
- :category => 'Setting::DefaultHostgroup')
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
- SETTINGS[:default_hostgroup] = Hash.new
25
- end
26
-
27
- test "full matching regex not enclosed in /" do
28
- setup_hostgroup_match
29
- SETTINGS[:default_hostgroup][:facts_map] = { "Test Full" => {'hostname' =>'^sinn1636.lan$'} }
30
-
31
- hostgroup = Hostgroup.create(:name => "Test Full")
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
- test "partial matching regex enclosed in /" do
39
- setup_hostgroup_match
40
- SETTINGS[:default_hostgroup][:facts_map] = { "Test Partial" => {'hostname' => '/\.lan$/' }}
41
-
42
- hostgroup = Hostgroup.create(:name => "Test Partial")
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
- test "invalid hostgroup name is ignored" do
50
- setup_hostgroup_match
51
- SETTINGS[:default_hostgroup][:facts_map] = { "Nonexistent Group" => {'hostname' => '.*'}, "Existent Group" => {'hostname' => '/\.lan$/'} }
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
- hostgroup = Hostgroup.create(:name => "Existent Group")
54
- raw = parse_json_fixture('/facts.json')
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
- assert Host.import_host_and_facts(raw['name'], raw['facts'])
57
- assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
58
- end
59
+ assert @host.import_facts(@facts)
60
+ assert_equal hostgroup, Host.find_by(name: @name).hostgroup
61
+ end
59
62
 
60
- test "first matching hostgroup is used" do
61
- setup_hostgroup_match
62
- SETTINGS[:default_hostgroup][:facts_map] = { "First Group" => {'hostname' => '.*'}, "Second Group" => {'hostname' => '.*'} }
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
- hostgroup = Hostgroup.create(:name => "First Group")
65
- raw = parse_json_fixture('/facts.json')
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
- test "invalid keys ignored" do
72
- setup_hostgroup_match
73
- SETTINGS[:default_hostgroup][:facts_map] = { "First Group" => {'nosuchfact' => '.*', 'hostname' => '.*'} }
74
-
75
- hostgroup = Hostgroup.create(:name => "First Group")
76
- raw = parse_json_fixture('/facts.json')
77
-
78
- assert Host.import_host_and_facts(raw['name'], raw['facts'])
79
- assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
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
- test "unmatched values ignored" do
83
- setup_hostgroup_match
84
- SETTINGS[:default_hostgroup][:facts_map] = { "First Group" => {'hostname' => 'nosuchname', 'osfamily' => '.*'} }
85
-
86
- hostgroup = Hostgroup.create(:name => "First Group")
87
- raw = parse_json_fixture('/facts.json')
88
-
89
- assert Host.import_host_and_facts(raw['name'], raw['facts'])
90
- assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
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
- test "default hostgroup" do
94
- setup_hostgroup_match
95
- SETTINGS[:default_hostgroup][:facts_map] = { "Test Default" => {'hostname' =>'.*'} }
96
-
97
- hostgroup = Hostgroup.create(:name => "Test Default")
98
- raw = parse_json_fixture('/facts.json')
99
-
100
- assert Host.import_host_and_facts(raw['name'], raw['facts'])
101
- assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
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
- test "host already has a hostgroup" do
105
- setup_hostgroup_match
106
- SETTINGS[:default_hostgroup][:facts_map] = { "Test Default" => {'hostname' => '.*'} }
107
-
108
- hostgroup = Hostgroup.create(:name => "Test Group")
109
- Hostgroup.create(:name => "Test Default")
110
- raw = parse_json_fixture('/facts.json')
111
-
112
- host, result = Host.import_host_and_facts_without_match_hostgroup(raw['name'], raw['facts'])
113
- host.hostgroup = hostgroup
114
- host.save(:validate => false)
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
- test "force hostgroup match on host with existing hostgroup" do
121
- setup_hostgroup_match
122
- Setting[:force_hostgroup_match] = true
123
- Setting[:force_hostgroup_match_only_new] = false
124
- SETTINGS[:default_hostgroup][:facts_map] = { "Test Default" => {'hostname' => '.*'} }
125
-
126
- hostgroup = Hostgroup.create(:name => "Test Group")
127
- default = Hostgroup.create(:name => "Test Default")
128
- raw = parse_json_fixture('/facts.json')
129
-
130
- host, result = Host.import_host_and_facts_without_match_hostgroup(raw['name'], raw['facts'])
131
- host.hostgroup = hostgroup
132
- host.save(:validate => false)
133
-
134
- assert Host.import_host_and_facts(raw['name'], raw['facts'])
135
- assert_equal default, Host.find_by_name('sinn1636.lan').hostgroup
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
- test "hostgroup is not updated if host is not new" do
139
- setup_hostgroup_match
140
- Setting[:force_hostgroup_match] = true
141
- SETTINGS[:default_hostgroup][:facts_map] = { "Test Default" => {'hostname' => '.*'} }
142
-
143
- hostgroup = Hostgroup.create(:name => "Test Group")
144
- Hostgroup.create(:name => "Test Default")
145
- raw = parse_json_fixture('/facts.json')
146
-
147
- host, result = Host.import_host_and_facts_without_match_hostgroup(raw['name'], raw['facts'])
148
- host.hostgroup = hostgroup
149
- host.save(:validate => false)
150
-
151
- assert Host.import_host_and_facts(raw['name'], raw['facts'])
152
- assert_equal hostgroup, Host.find_by_name('sinn1636.lan').hostgroup
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: 2.1.0
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: 2014-12-15 00:00:00.000000000 Z
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
- - lib/default_hostgroup.rake
26
- - lib/default_hostgroup_managed_host_patch.rb
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: http://github.com/GregSutcliffe/foreman_default_hostgroup
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
- rubyforge_project:
53
- rubygems_version: 2.2.2
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
@@ -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