foreman_ansible 0.1.1 → 0.2.1
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.
Potentially problematic release.
This version of foreman_ansible might be problematic. Click here for more details.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d9930905b911888013c949cc42e140daed748c4
|
4
|
+
data.tar.gz: 62f9e18006e75d4be30d9bf263cdb81edbbf4b05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 468ae9f121f50e441d2d1317bd87a79f0b547aa4f7fba0c4c6ce18a63e7538813ac02301530757fedaeef7c8c7f95bb54007ad25b5c75771dfc91bd6f8ff4fd5
|
7
|
+
data.tar.gz: 676edd7606ac3c52c5d195ff2550ac0a610ad7e22b3987fdec4093a79a7bc538b71e9a7f66ef616e53a5d9e0215ced797b0ff94b2f569c16cdb221660eb42cb1
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[Foreman](http://theforeman.org) integration with Ansible. For now, it's just importing facts and not meant for general use.
|
4
4
|
|
5
|
-
**
|
5
|
+
**Warning - this project hasn't been released yet, and might change significantly. Please don't use in production**
|
6
6
|
|
7
7
|
## Basic usage
|
8
8
|
|
@@ -17,15 +17,17 @@ bin_ansible_callbacks = True
|
|
17
17
|
|
18
18
|
And copy `extras/foreman_callback.py` from this repo to `~/.ansible/plugins/callback_plugins/`. That's it!
|
19
19
|
|
20
|
-
Now, every time you run `ansible -m setup $HOSTNAME`, Ansible will automatically submit facts for $HOSTNAME to Foreman.
|
20
|
+
Now, every time you run a playbook or `ansible -m setup $HOSTNAME`, Ansible will automatically submit facts and a small report for $HOSTNAME to Foreman. See 'Extra information' below if you find any error.
|
21
21
|
|
22
|
-
|
22
|
+
##### Registering a new host in Foreman
|
23
|
+

|
23
24
|
|
24
|
-
|
25
|
+
##### Host with failed and successful reports
|
26
|
+

|
25
27
|
|
26
|
-
|
28
|
+
### Extra information
|
27
29
|
|
28
|
-
|
30
|
+
In Foreman, you should add whatever Ansible hosts you want to submit facts from to the setting `trusted_puppetmaster_hosts`. Change it at Administer > Settings, Puppet tab.
|
29
31
|
|
30
32
|
If the Foreman setting 'create_new_host_when_facts_are_uploaded' is true, and $HOSTNAME doesn't exist in Foreman, it will autocreate that host in Foreman. If it already exists, it will update the facts.
|
31
33
|
|
@@ -33,9 +35,9 @@ Similarly, the Foreman setting 'ignore_puppet_facts_for_provisioning' is set to
|
|
33
35
|
|
34
36
|
### Devs
|
35
37
|
|
36
|
-
|
38
|
+
The callback sends a POST request to /api/v2/hosts/facts with the format you can see [in the API docs](http://theforeman.org/api/1.9/apidoc/v2/hosts/facts.html).
|
37
39
|
|
38
|
-
Facts must contain the output of `ansible -m setup $HOSTNAME`, plus a '_type' and '_timestamp'
|
40
|
+
Facts must contain the output of `ansible -m setup $HOSTNAME`, plus a '_type' and '_timestamp' keys. You can see an example on test/fixtures/sample_facts.json in this repository.
|
39
41
|
|
40
42
|
After that request, you should have a host registered in Foreman with the Ansible facts. It takes into account some facter and ohai facts if these are available on the system as well.
|
41
43
|
|
@@ -7,7 +7,69 @@ module ForemanAnsible
|
|
7
7
|
def initialize(host, facts = {})
|
8
8
|
@host = host
|
9
9
|
@facts = normalize(facts[:ansible_facts])
|
10
|
+
@original_facts = FactSparser.unsparse(facts[:ansible_facts])
|
10
11
|
@counters = {}
|
11
12
|
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def add_new_facts
|
17
|
+
@counters[:added] = 0
|
18
|
+
add_missing_facts(FactSparser.unsparse(@original_facts))
|
19
|
+
logger.debug("Merging facts for '#{host}': added #{@counters[:added]} facts")
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_missing_facts(imported_facts, parent = nil, prefix = '')
|
23
|
+
imported_facts.select! { |fact_name, fact_value| !fact_value.nil? }
|
24
|
+
|
25
|
+
imported_facts.each do |imported_name, imported_value|
|
26
|
+
fact_fqn = fact_fqn(imported_name, prefix)
|
27
|
+
next unless missing_facts.include?(fact_fqn)
|
28
|
+
fact_name = find_fact_name(fact_fqn, parent)
|
29
|
+
|
30
|
+
add_fact_value(imported_value, fact_name)
|
31
|
+
add_compose_fact(imported_value, fact_name, fact_fqn)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_compose_fact(imported_values, fact_name, fact_fqn)
|
36
|
+
if imported_values.is_a?(Hash)
|
37
|
+
add_missing_facts(imported_values, fact_name, fact_fqn)
|
38
|
+
elsif imported_values.is_a?(Array)
|
39
|
+
imported_values.each do |imported_value|
|
40
|
+
next unless imported_value.is_a?(Hash)
|
41
|
+
add_missing_facts(imported_value, fact_name, fact_fqn)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def missing_facts
|
47
|
+
@missing_facts ||= (facts.keys + FactSparser.sparse(@original_facts).keys) - db_facts.keys
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns pairs [id, fact_name]
|
51
|
+
def fact_names
|
52
|
+
@fact_names ||= fact_name_class.maximum(:id, :group => 'name')
|
53
|
+
end
|
54
|
+
|
55
|
+
# Fact fully qualified name contains an unambiguous name for a fact
|
56
|
+
# e.g: ansible_lo::ipv6, ansible_virbr0::active
|
57
|
+
def fact_fqn(name, prefix)
|
58
|
+
prefix.empty? ? name : prefix + FactName::SEPARATOR + name
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_fact_name(name, parent)
|
62
|
+
return FactName.find(fact_names[name]) if fact_names[name].present?
|
63
|
+
fact_name_class.create!(:name => name,
|
64
|
+
:parent => parent,
|
65
|
+
:compose => compose)
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_fact_value(value, fact_name)
|
69
|
+
method = host.new_record? ? :build : :create!
|
70
|
+
host.fact_values.send(method, :value => value, :fact_name => fact_name)
|
71
|
+
@counters[:added] += 1
|
72
|
+
end
|
73
|
+
|
12
74
|
end
|
13
75
|
end
|
@@ -12,9 +12,7 @@ module ForemanAnsible
|
|
12
12
|
Operatingsystem.create!(args.merge(:description => os_description))
|
13
13
|
end
|
14
14
|
|
15
|
-
def environment
|
16
|
-
# Don't do anything
|
17
|
-
end
|
15
|
+
def environment; end # Don't do anything as there's no env in Ansible
|
18
16
|
|
19
17
|
def architecture
|
20
18
|
name = facts[:ansible_architecture] || facts[:facter_architecture]
|
@@ -41,7 +39,13 @@ module ForemanAnsible
|
|
41
39
|
end
|
42
40
|
|
43
41
|
def get_interfaces
|
44
|
-
|
42
|
+
# Move ansibles default interface first in the list of interfaces since
|
43
|
+
# Foreman picks the first one that is usable. If ansible has no
|
44
|
+
# preference otherwise at least sort the list.
|
45
|
+
pref = facts[:ansible_default_ipv4] &&
|
46
|
+
facts[:ansible_default_ipv4]['interface']
|
47
|
+
pref ? (facts[:ansible_interfaces] - [pref]).unshift(pref) :
|
48
|
+
facts[:ansible_interfaces].sort
|
45
49
|
end
|
46
50
|
|
47
51
|
def get_facts_for_interface(interface)
|
@@ -51,9 +55,7 @@ module ForemanAnsible
|
|
51
55
|
HashWithIndifferentAccess[interface_facts.merge(:ipaddress => ipaddress)]
|
52
56
|
end
|
53
57
|
|
54
|
-
def ipmi_interface
|
55
|
-
# ?
|
56
|
-
end
|
58
|
+
def ipmi_interface; end
|
57
59
|
|
58
60
|
private
|
59
61
|
|
@@ -64,17 +66,17 @@ module ForemanAnsible
|
|
64
66
|
|
65
67
|
def os_name
|
66
68
|
facts[:ansible_distribution] ||
|
67
|
-
facts[:ansible_lsb]['id']
|
69
|
+
facts[:ansible_lsb] && facts[:ansible_lsb]['id']
|
68
70
|
end
|
69
71
|
|
70
72
|
def os_major
|
71
73
|
facts[:ansible_distribution_major_version] ||
|
72
|
-
facts[:ansible_lsb]['major_release']
|
74
|
+
facts[:ansible_lsb] && facts[:ansible_lsb]['major_release']
|
73
75
|
end
|
74
76
|
|
75
77
|
def os_release
|
76
78
|
facts[:ansible_distribution_version] ||
|
77
|
-
facts[:ansible_lsb]['release']
|
79
|
+
facts[:ansible_lsb] && facts[:ansible_lsb]['release']
|
78
80
|
end
|
79
81
|
|
80
82
|
def os_minor
|
@@ -83,7 +85,7 @@ module ForemanAnsible
|
|
83
85
|
end
|
84
86
|
|
85
87
|
def os_description
|
86
|
-
facts[:ansible_lsb]['description']
|
88
|
+
facts[:ansible_lsb] && facts[:ansible_lsb]['description']
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ForemanAnsible
|
2
|
+
class FactSparser
|
3
|
+
class << self
|
4
|
+
def sparse(hash, options = {} )
|
5
|
+
hash.map do |k, v|
|
6
|
+
prefix = options.fetch(:prefix, []) + [k]
|
7
|
+
next sparse(v, options.merge(:prefix => prefix)) if v.is_a? Hash
|
8
|
+
{ prefix.join(options.fetch(:separator, FactName::SEPARATOR)) => v }
|
9
|
+
end.reduce(:merge) || Hash.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def unsparse(hash, options={})
|
13
|
+
ret = Hash.new
|
14
|
+
sparse(hash).each do |k, v|
|
15
|
+
current = ret
|
16
|
+
key = k.to_s.split(options.fetch(:separator, FactName::SEPARATOR))
|
17
|
+
current = (current[key.shift] ||= Hash.new) until key.size <= 1
|
18
|
+
current[key.first] = v
|
19
|
+
end
|
20
|
+
ret
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_ansible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Lobato Garcia
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- app/models/foreman_ansible/fact_name.rb
|
38
38
|
- app/services/foreman_ansible/fact_importer.rb
|
39
39
|
- app/services/foreman_ansible/fact_parser.rb
|
40
|
+
- app/services/foreman_ansible/fact_sparser.rb
|
40
41
|
- lib/foreman_ansible.rb
|
41
42
|
- lib/foreman_ansible/engine.rb
|
42
43
|
- lib/foreman_ansible/version.rb
|