foreman_ansible 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
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
|
+
![sign up gif](http://i.imgur.com/mlnVFJj.gif)
|
23
24
|
|
24
|
-
|
25
|
+
##### Host with failed and successful reports
|
26
|
+
![reports](http://i.imgur.com/1ySO4sh.png)
|
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
|