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: 3cae18690ddfd00ff1050acdefd09a621457177a
4
- data.tar.gz: bba73f69e7a760c310c712f69027cc0312b23a1a
3
+ metadata.gz: 5d9930905b911888013c949cc42e140daed748c4
4
+ data.tar.gz: 62f9e18006e75d4be30d9bf263cdb81edbbf4b05
5
5
  SHA512:
6
- metadata.gz: 2f58daf8630756494fa0f39ecf99df13cbf38694005fcf73bad1f2ec4a1e026c89ab3cde7703ca051041b41ec80469934aeb2d75d8f43360d63c6bdec6126a46
7
- data.tar.gz: 46a793766a4fd1cfd2c75e67ecacc68225410efea24d430115f452fe5f4ff9964acac8b0ef3468eab895f4fc6b5153ca1e333675cdf1070089abf11867a469be
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
- ** Warning - this project hasn't been released yet, and might change significantly. Please don't use in production. **
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
- In Foreman, you should add whatever Ansible hosts you want to submit facts from to the Setting (Administer > Settings, Puppet tab - I know..)) 'trusted_puppetmaster_hosts'.
22
+ ##### Registering a new host in Foreman
23
+ ![sign up gif](http://i.imgur.com/mlnVFJj.gif)
23
24
 
24
- #### Demo
25
+ ##### Host with failed and successful reports
26
+ ![reports](http://i.imgur.com/1ySO4sh.png)
25
27
 
26
- ![demo gif](http://i.imgur.com/mlnVFJj.gif)
28
+ ### Extra information
27
29
 
28
- ### Extra
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
- Send 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).
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' top level keys. You can see an example on test/fixtures/sample_facts.json in this repository.
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
- facts[:ansible_interfaces]
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
@@ -1,3 +1,3 @@
1
1
  module ForemanAnsible
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.1'
3
3
  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.1.1
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-02 00:00:00.000000000 Z
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