foreman_default_hostgroup 2.1.0 → 6.0.0

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