Skip to content

Commit

Permalink
WIP: first auto-bond implementation
Browse files Browse the repository at this point in the history
refs #23851
  • Loading branch information
Thomas-Gelf committed Jun 8, 2018
1 parent 67c2fde commit 43c7b77
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
5 changes: 5 additions & 0 deletions app/models/setting/discovered.rb
Expand Up @@ -17,6 +17,7 @@ def self.load_defaults
Setting.transaction do
[
self.set('discovery_fact', N_("Fact name to use for primary interface detection"), "discovery_bootif", N_("Interface fact")),
self.set('discovery_auto_bond', N_("Automatic bond interface (if another interface is detected on the same VLAN via LLDP)"), false, N_("Create bond interfaces")),
self.set('discovery_clean_facts', N_("Clean all reported facts during provisioning (except discovery facts)"), false, N_("Clean all facts")),
self.set('discovery_hostname', N_("List of facts to use for the hostname (separated by comma, first wins)"), "discovery_bootif", N_("Hostname facts")),
self.set('discovery_auto', N_("Automatically provision newly discovered hosts, according to the provisioning rules"), false, N_("Auto provisioning")),
Expand Down Expand Up @@ -66,6 +67,10 @@ def self.discovery_hostname_fact_array
from_array Setting['discovery_hostname']
end

def self.discovery_auto_bond?
Foreman::Cast.to_bool(Setting['discovery_auto_bond'])
end

def self.discovery_lock?
Foreman::Cast.to_bool(Setting['discovery_lock'])
end
Expand Down
38 changes: 38 additions & 0 deletions app/services/foreman_discovery/host_converter.rb
@@ -1,9 +1,12 @@
require 'foreman_discovery/lldp_neighbors'

class ForemanDiscovery::HostConverter

# Converts discovered host to managed host without uptading the database.
# Record must be saved explicitly (using save! or update_attributes! or similar).
# Creates shallow copy.
def self.to_managed(original_host, set_managed = true, set_build = true, added_attributes = {})
eventually_make_bond(original_host) if Setting[:discovery_auto_bond]
host = original_host.becomes(::Host::Managed)
host.type = 'Host::Managed'
host.attributes = host.apply_inherited_attributes(added_attributes)
Expand All @@ -19,6 +22,41 @@ def self.to_managed(original_host, set_managed = true, set_build = true, added_a
host
end

def self.eventually_make_bond(host)
primary = host.primary_interface
return if primary.nil?
return if primary.type == 'Nic::Bond'

neighbors = ::ForemanDiscovery::LldpNeighbors
.from_facts(host.facts_hash)
.get_neighbors_by_interface(primary.identifier)

return if neighbors.nil?

ip = primary.ip
name = primary.name
primary.update(
:primary => false,
:provision => false,
:managed => false,
:name => nil,
:ip => nil
)

bond = Nic::Bond.create(
:identifier => "bond0",
:attached_devices => neighbors,
:primary => true,
:provision => true,
:name => name,
:ip => ip,
:host => host
)

bond.save!
host.interfaces.push bond
end

def self.set_build_clean_facts(host)
# fact cleaning
if Setting['discovery_clean_facts']
Expand Down
66 changes: 66 additions & 0 deletions lib/foreman_discovery/lldp_neighbors.rb
@@ -0,0 +1,66 @@
module ForemanDiscovery
class LldpNeighbors
def set(iface, neighbor)
interfaces[iface] = neighbor
end

def get(iface)
interfaces[iface]
end

def list_by_pvid
list = {}
interfaces.each do |name, neighbor|
next unless neighbor.has_key? 'PVID'
vlan = neighbor['PVID']
list[vlan] = [] unless list.has_key? vlan
list[vlan].push name
end

list
end

def interfaces
@interfaces ||= {}
end

def get_neighbors_by_interface(ifname)
return nil unless interfaces.has_key? ifname

interface = get(ifname)
return nil unless interface.has_key? 'PVID'

list = []
interfaces.each do |name, neighbor|
next unless neighbor.has_key? 'PVID'
list.push name if neighbor['PVID'] == interface['PVID']
end

return if list.size < 2
list
end

def self.from_facts(facts)
neighbors = self.new
interfaces = {}
facts.keys.each do |key|
key_s = key.to_s
next unless key_s.start_with? 'lldp_neighbor_'

property, iface = key_s[14..-1].split('_', 2)
if property == 'mngAddr'
protocol, iface = iface.split('_', 2)
property += '_' + protocol
end
interfaces[iface] = {} unless interfaces.has_key? iface
interfaces[iface][property] = facts[key]
end

interfaces.each do |name, properties|
neighbors.set name, properties
end

neighbors
end
end
end

0 comments on commit 43c7b77

Please sign in to comment.