From 133a4bb92bd792d09c8fd76259b46cfeaa9683d2 Mon Sep 17 00:00:00 2001 From: Bogdan Irimie Date: Fri, 19 Jun 2020 17:13:55 +0300 Subject: [PATCH] (FACT-2656) Add Solaris networking facts --- README.md | 14 +- lib/facter/facts/solaris/dhcp_servers.rb | 27 ++++ lib/facter/facts/solaris/interfaces.rb | 16 ++ .../facts/solaris/ipaddress6_interfaces.rb | 20 +++ .../facts/solaris/ipaddress_interfaces.rb | 20 +++ .../facts/solaris/macaddress_interfaces.rb | 20 +++ lib/facter/facts/solaris/mtu_interfaces.rb | 20 +++ .../facts/solaris/netmask6_interfaces.rb | 20 +++ .../facts/solaris/netmask_interfaces.rb | 20 +++ .../facts/solaris/network6_interfaces.rb | 20 +++ .../facts/solaris/network_interfaces.rb | 20 +++ lib/facter/facts/solaris/networking/dhcp.rb | 17 ++ .../facts/solaris/networking/interfaces.rb | 16 ++ lib/facter/facts/solaris/networking/ip6.rb | 18 +++ lib/facter/facts/solaris/networking/mac.rb | 18 +++ lib/facter/facts/solaris/networking/mtu.rb | 17 ++ .../facts/solaris/networking/netmask.rb | 18 +++ .../facts/solaris/networking/netmask6.rb | 18 +++ .../facts/solaris/networking/network.rb | 18 +++ .../facts/solaris/networking/network6.rb | 18 +++ .../facts/solaris/networking/primary.rb | 17 ++ lib/facter/resolvers/solaris/ffi/ffi.rb | 25 +++ lib/facter/resolvers/solaris/ffi/functions.rb | 30 ++++ lib/facter/resolvers/solaris/ffi/structs.rb | 117 ++++++++++++++ .../resolvers/solaris/networking_resolver.rb | 150 ++++++++++++++++++ .../facter/facts/solaris/dhcp_servers_spec.rb | 41 +++++ spec/facter/facts/solaris/interfaces_spec.rb | 32 ++++ .../solaris/ipaddress6_interfaces_spec.rb | 34 ++++ .../solaris/ipaddress_interfaces_spec.rb | 34 ++++ .../solaris/macaddress_interfaces_spec.rb | 34 ++++ .../facts/solaris/mtu_interfaces_spec.rb | 32 ++++ .../facts/solaris/netmask6_interfaces_spec.rb | 37 +++++ .../facts/solaris/netmask_interfaces_spec.rb | 34 ++++ .../facts/solaris/network6_interfaces_spec.rb | 34 ++++ .../facts/solaris/network_interfaces_spec.rb | 34 ++++ .../facts/solaris/networking/dhcp_spec.rb | 33 ++++ .../solaris/networking/interfaces_spec.rb | 45 ++++++ .../facts/solaris/networking/ip6_spec.rb | 34 ++++ .../facts/solaris/networking/mac_spec.rb | 34 ++++ .../facts/solaris/networking/mtu_spec.rb | 33 ++++ .../facts/solaris/networking/netmask6_spec.rb | 34 ++++ .../facts/solaris/networking/netmask_spec.rb | 34 ++++ .../facts/solaris/networking/network6_spec.rb | 34 ++++ .../facts/solaris/networking/network_spec.rb | 34 ++++ .../facts/solaris/networking/primary_spec.rb | 33 ++++ spec/mocks/ffi_mock.rb | 4 +- 46 files changed, 1404 insertions(+), 8 deletions(-) create mode 100644 lib/facter/facts/solaris/dhcp_servers.rb create mode 100644 lib/facter/facts/solaris/interfaces.rb create mode 100644 lib/facter/facts/solaris/ipaddress6_interfaces.rb create mode 100644 lib/facter/facts/solaris/ipaddress_interfaces.rb create mode 100644 lib/facter/facts/solaris/macaddress_interfaces.rb create mode 100644 lib/facter/facts/solaris/mtu_interfaces.rb create mode 100644 lib/facter/facts/solaris/netmask6_interfaces.rb create mode 100644 lib/facter/facts/solaris/netmask_interfaces.rb create mode 100644 lib/facter/facts/solaris/network6_interfaces.rb create mode 100644 lib/facter/facts/solaris/network_interfaces.rb create mode 100644 lib/facter/facts/solaris/networking/dhcp.rb create mode 100644 lib/facter/facts/solaris/networking/interfaces.rb create mode 100644 lib/facter/facts/solaris/networking/ip6.rb create mode 100644 lib/facter/facts/solaris/networking/mac.rb create mode 100644 lib/facter/facts/solaris/networking/mtu.rb create mode 100644 lib/facter/facts/solaris/networking/netmask.rb create mode 100644 lib/facter/facts/solaris/networking/netmask6.rb create mode 100644 lib/facter/facts/solaris/networking/network.rb create mode 100644 lib/facter/facts/solaris/networking/network6.rb create mode 100644 lib/facter/facts/solaris/networking/primary.rb create mode 100644 lib/facter/resolvers/solaris/ffi/ffi.rb create mode 100644 lib/facter/resolvers/solaris/ffi/functions.rb create mode 100644 lib/facter/resolvers/solaris/ffi/structs.rb create mode 100644 lib/facter/resolvers/solaris/networking_resolver.rb create mode 100644 spec/facter/facts/solaris/dhcp_servers_spec.rb create mode 100644 spec/facter/facts/solaris/interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/ipaddress6_interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/ipaddress_interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/macaddress_interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/mtu_interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/netmask6_interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/netmask_interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/network6_interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/network_interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/networking/dhcp_spec.rb create mode 100644 spec/facter/facts/solaris/networking/interfaces_spec.rb create mode 100644 spec/facter/facts/solaris/networking/ip6_spec.rb create mode 100644 spec/facter/facts/solaris/networking/mac_spec.rb create mode 100644 spec/facter/facts/solaris/networking/mtu_spec.rb create mode 100644 spec/facter/facts/solaris/networking/netmask6_spec.rb create mode 100644 spec/facter/facts/solaris/networking/netmask_spec.rb create mode 100644 spec/facter/facts/solaris/networking/network6_spec.rb create mode 100644 spec/facter/facts/solaris/networking/network_spec.rb create mode 100644 spec/facter/facts/solaris/networking/primary_spec.rb diff --git a/README.md b/README.md index 9065e2f72e..c5aa6781f9 100644 --- a/README.md +++ b/README.md @@ -21,30 +21,30 @@ Facter is a command-line tool that gathers basic facts about nodes (systems) suc * Ruby 2.3+ ## Basic concepts -The project has three main parts, the framework, facts and resolvers. +The project has three main parts, the framework, facts and resolvers. In the framework we implement functionality that is agnostic of specific facts like parsing user input, formatting output, etc. Facts are the nuggets of information that will be provided by facter e.g. `os.name`, `networking.interfaces`, etc. -Resolvers have the role of gathering data from the system. -For example a resolver can execute a command on the system, can read a file or any operation that retries some data from a single source on the system. +Resolvers have the role of gathering data from the system. +For example a resolver can execute a command on the system, can read a file or any operation that retries some data from a single source on the system. ![Facter user interaction](docs/diagrams/facter_user_interaction.png?raw=true) ## Getting started After cloning the project, run `bundle install` to install all dependencies. -You can run facter by executing `./bin/facter`. +You can run facter by executing `./bin/facter`. The command will output all the facts that facter detected for the current os. In order to generate a fact, we can use the rake task `rake 'create_fact[,]'` e.g. `rake 'create_fact[ubuntu,facterversion]'` When generating a fact, the unit test for that fact is also generated. Facts should call on or more resolvers in order to obtain the data they need. -The implementation can be validated locally by running the `./check.sh` script. +The implementation can be validated locally by running the `./check.sh` script. ## Goals - fast, easy, compatible -* Gain performance similar to the C++ version of Facter. We plan to achieve this goal by gathering multiple facts with only one call and by using the faster Win32 API rather than WMI for the Windows implementation. -* Facilitate community contribution. At the moment, C++ presents a possible impediment for community contributions. +* Gain performance similar to the C++ version of Facter. We plan to achieve this goal by gathering multiple facts with only one call and by using the faster Win32 API rather than WMI for the Windows implementation. +* Facilitate community contribution. At the moment, C++ presents a possible impediment for community contributions. * Enable native integration with other Ruby-based projects such as Bolt and puppet. * Enable native integration for custom facts. * Provide 100% compatibility with C++ Facter (drop-in replacement). diff --git a/lib/facter/facts/solaris/dhcp_servers.rb b/lib/facter/facts/solaris/dhcp_servers.rb new file mode 100644 index 0000000000..3ee29568e1 --- /dev/null +++ b/lib/facter/facts/solaris/dhcp_servers.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class DhcpServers + FACT_NAME = 'dhcp_servers' + + def call_the_resolver + fact_value = construct_addresses_hash + fact_value = !fact_value || fact_value.empty? ? nil : fact_value + Facter::ResolvedFact.new(FACT_NAME, fact_value, :legacy) + end + + private + + def construct_addresses_hash + primary_dhcp = Facter::Resolvers::Solaris::Networking.resolve(:dhcp) + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + return unless interfaces + + servers = { system: primary_dhcp } + interfaces&.each { |interface_name, info| servers[interface_name] = info[:dhcp] if info[:dhcp] } + servers + end + end + end +end diff --git a/lib/facter/facts/solaris/interfaces.rb b/lib/facter/facts/solaris/interfaces.rb new file mode 100644 index 0000000000..3baa8e06d7 --- /dev/null +++ b/lib/facter/facts/solaris/interfaces.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class Interfaces + FACT_NAME = 'interfaces' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + + Facter::ResolvedFact.new(FACT_NAME, fact_value && !fact_value.empty? ? fact_value.keys.sort.join(',') : nil, + :legacy) + end + end + end +end diff --git a/lib/facter/facts/solaris/ipaddress6_interfaces.rb b/lib/facter/facts/solaris/ipaddress6_interfaces.rb new file mode 100644 index 0000000000..bf937fda5f --- /dev/null +++ b/lib/facter/facts/solaris/ipaddress6_interfaces.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class Ipaddress6Interfaces + FACT_NAME = 'ipaddress6_.*' + TYPE = :legacy + + def call_the_resolver + arr = [] + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + interfaces&.each do |interface_name, info| + arr << Facter::ResolvedFact.new("ipaddress6_#{interface_name}", info[:ip6], :legacy) if info[:ip6] + end + + arr + end + end + end +end diff --git a/lib/facter/facts/solaris/ipaddress_interfaces.rb b/lib/facter/facts/solaris/ipaddress_interfaces.rb new file mode 100644 index 0000000000..4db28141fe --- /dev/null +++ b/lib/facter/facts/solaris/ipaddress_interfaces.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class IpaddressInterfaces + FACT_NAME = 'ipaddress_.*' + TYPE = :legacy + + def call_the_resolver + arr = [] + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + interfaces&.each do |interface_name, info| + arr << Facter::ResolvedFact.new("ipaddress_#{interface_name}", info[:ip], :legacy) if info[:ip] + end + + arr + end + end + end +end diff --git a/lib/facter/facts/solaris/macaddress_interfaces.rb b/lib/facter/facts/solaris/macaddress_interfaces.rb new file mode 100644 index 0000000000..da6cfc6a52 --- /dev/null +++ b/lib/facter/facts/solaris/macaddress_interfaces.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class MacaddressInterfaces + FACT_NAME = 'macaddress_.*' + TYPE = :legacy + + def call_the_resolver + arr = [] + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + interfaces&.each do |interface_name, info| + arr << Facter::ResolvedFact.new("macaddress_#{interface_name}", info[:mac], :legacy) if info[:mac] + end + + arr + end + end + end +end diff --git a/lib/facter/facts/solaris/mtu_interfaces.rb b/lib/facter/facts/solaris/mtu_interfaces.rb new file mode 100644 index 0000000000..cae18860f1 --- /dev/null +++ b/lib/facter/facts/solaris/mtu_interfaces.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class MtuInterfaces + FACT_NAME = 'mtu_.*' + TYPE = :legacy + + def call_the_resolver + arr = [] + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + interfaces&.each do |interface_name, info| + arr << Facter::ResolvedFact.new("mtu_#{interface_name}", info[:mtu], :legacy) if info[:mtu] + end + + arr + end + end + end +end diff --git a/lib/facter/facts/solaris/netmask6_interfaces.rb b/lib/facter/facts/solaris/netmask6_interfaces.rb new file mode 100644 index 0000000000..0df8bb6bea --- /dev/null +++ b/lib/facter/facts/solaris/netmask6_interfaces.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class Netmask6Interfaces + FACT_NAME = 'netmask6_.*' + TYPE = :legacy + + def call_the_resolver + arr = [] + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + interfaces&.each do |interface_name, info| + arr << Facter::ResolvedFact.new("netmask6_#{interface_name}", info[:netmask6], :legacy) if info[:netmask6] + end + + arr + end + end + end +end diff --git a/lib/facter/facts/solaris/netmask_interfaces.rb b/lib/facter/facts/solaris/netmask_interfaces.rb new file mode 100644 index 0000000000..e6af897ae5 --- /dev/null +++ b/lib/facter/facts/solaris/netmask_interfaces.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class NetmaskInterfaces + FACT_NAME = 'netmask_.*' + TYPE = :legacy + + def call_the_resolver + arr = [] + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + interfaces&.each do |interface_name, info| + arr << Facter::ResolvedFact.new("netmask_#{interface_name}", info[:netmask], :legacy) if info[:netmask] + end + + arr + end + end + end +end diff --git a/lib/facter/facts/solaris/network6_interfaces.rb b/lib/facter/facts/solaris/network6_interfaces.rb new file mode 100644 index 0000000000..e92f84ec1e --- /dev/null +++ b/lib/facter/facts/solaris/network6_interfaces.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class Network6Interfaces + FACT_NAME = 'network6_.*' + TYPE = :legacy + + def call_the_resolver + arr = [] + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + interfaces&.each do |interface_name, info| + arr << Facter::ResolvedFact.new("network6_#{interface_name}", info[:network6], :legacy) if info[:network6] + end + + arr + end + end + end +end diff --git a/lib/facter/facts/solaris/network_interfaces.rb b/lib/facter/facts/solaris/network_interfaces.rb new file mode 100644 index 0000000000..15b2dd7b76 --- /dev/null +++ b/lib/facter/facts/solaris/network_interfaces.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class NetworkInterfaces + FACT_NAME = 'network_.*' + TYPE = :legacy + + def call_the_resolver + arr = [] + interfaces = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + interfaces&.each do |interface_name, info| + arr << Facter::ResolvedFact.new("network_#{interface_name}", info[:network], :legacy) if info[:network] + end + + arr + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/dhcp.rb b/lib/facter/facts/solaris/networking/dhcp.rb new file mode 100644 index 0000000000..218a2b723b --- /dev/null +++ b/lib/facter/facts/solaris/networking/dhcp.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Dhcp + FACT_NAME = 'networking.dhcp' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:dhcp) + + Facter::ResolvedFact.new(FACT_NAME, fact_value) + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/interfaces.rb b/lib/facter/facts/solaris/networking/interfaces.rb new file mode 100644 index 0000000000..79eab935dd --- /dev/null +++ b/lib/facter/facts/solaris/networking/interfaces.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Interfaces + FACT_NAME = 'networking.interfaces' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:interfaces) + Facter::ResolvedFact.new(FACT_NAME, fact_value) + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/ip6.rb b/lib/facter/facts/solaris/networking/ip6.rb new file mode 100644 index 0000000000..22bee32ba0 --- /dev/null +++ b/lib/facter/facts/solaris/networking/ip6.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Ip6 + FACT_NAME = 'networking.ip6' + ALIASES = 'ipaddress6' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:ip6) + + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/mac.rb b/lib/facter/facts/solaris/networking/mac.rb new file mode 100644 index 0000000000..3cf5bd769d --- /dev/null +++ b/lib/facter/facts/solaris/networking/mac.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Mac + FACT_NAME = 'networking.mac' + ALIASES = 'macaddress' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:mac) + + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/mtu.rb b/lib/facter/facts/solaris/networking/mtu.rb new file mode 100644 index 0000000000..95c48300e5 --- /dev/null +++ b/lib/facter/facts/solaris/networking/mtu.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Mtu + FACT_NAME = 'networking.mtu' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:mtu) + + Facter::ResolvedFact.new(FACT_NAME, fact_value) + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/netmask.rb b/lib/facter/facts/solaris/networking/netmask.rb new file mode 100644 index 0000000000..3b7e41381d --- /dev/null +++ b/lib/facter/facts/solaris/networking/netmask.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Netmask + FACT_NAME = 'networking.netmask' + ALIASES = 'netmask' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:netmask) + + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/netmask6.rb b/lib/facter/facts/solaris/networking/netmask6.rb new file mode 100644 index 0000000000..389796890d --- /dev/null +++ b/lib/facter/facts/solaris/networking/netmask6.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Netmask6 + FACT_NAME = 'networking.netmask6' + ALIASES = 'netmask6' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:netmask6) + + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/network.rb b/lib/facter/facts/solaris/networking/network.rb new file mode 100644 index 0000000000..ba316c3562 --- /dev/null +++ b/lib/facter/facts/solaris/networking/network.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Network + FACT_NAME = 'networking.network' + ALIASES = 'network' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:network) + + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/network6.rb b/lib/facter/facts/solaris/networking/network6.rb new file mode 100644 index 0000000000..d0d014d8ad --- /dev/null +++ b/lib/facter/facts/solaris/networking/network6.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Network6 + FACT_NAME = 'networking.network6' + ALIASES = 'network6' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:network6) + + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facter/facts/solaris/networking/primary.rb b/lib/facter/facts/solaris/networking/primary.rb new file mode 100644 index 0000000000..c26535b5ad --- /dev/null +++ b/lib/facter/facts/solaris/networking/primary.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Networking + class Primary + FACT_NAME = 'networking.primary' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Networking.resolve(:primary_interface) + + Facter::ResolvedFact.new(FACT_NAME, fact_value) + end + end + end + end +end diff --git a/lib/facter/resolvers/solaris/ffi/ffi.rb b/lib/facter/resolvers/solaris/ffi/ffi.rb new file mode 100644 index 0000000000..b72371b74b --- /dev/null +++ b/lib/facter/resolvers/solaris/ffi/ffi.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'ffi' +require_relative 'structs.rb' +require_relative 'functions.rb' + +module Facter + module Resolvers + module Solaris + module FFI + SIOCGLIFNUM = -1_072_928_382 + SIOCGLIFCONF = -1_072_666_203 + SIOCGLIFMTU = -1_065_850_502 + SIOCGLIFNETMASK = -1_065_850_499 + SIOCGARP = -1_071_355_617 + AF_INET = 2 + AF_INET6 = 26 + AF_UNSPEC = 0 + SOCK_DGRAM = 1 + INET_ADDRSTRLEN = 16 + INET6_ADDRSTRLEN = 46 + end + end + end +end diff --git a/lib/facter/resolvers/solaris/ffi/functions.rb b/lib/facter/resolvers/solaris/ffi/functions.rb new file mode 100644 index 0000000000..088be50d32 --- /dev/null +++ b/lib/facter/resolvers/solaris/ffi/functions.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Facter + module Resolvers + module Solaris + module FFI + module Socket + extend ::FFI::Library + ffi_lib '/usr/lib/libsocket.so' + attach_function :open, :socket, %i[int int int], :int + attach_function :close, :shutdown, %i[int int], :int + attach_function :inet_ntop, %i[int pointer pointer uint], :string + end + + module Ioctl + extend ::FFI::Library + ffi_lib ::FFI::Library::LIBC + attach_function :ioctl_base, :ioctl, %i[int int pointer], :int + + def self.ioctl(call_const, pointer, address_family = AF_INET) + fd = Socket.open(address_family, SOCK_DGRAM, 0) + result = ioctl_base(fd, call_const, pointer) + Socket.close(fd, 2) + result + end + end + end + end + end +end diff --git a/lib/facter/resolvers/solaris/ffi/structs.rb b/lib/facter/resolvers/solaris/ffi/structs.rb new file mode 100644 index 0000000000..aaa6a8e30d --- /dev/null +++ b/lib/facter/resolvers/solaris/ffi/structs.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +module Facter + module Resolvers + module Solaris + module FFI + class SockaddrStorage < ::FFI::Struct + layout :ss_family, :int16, + :pad, [:char, 254] + end + + class Sockaddr < ::FFI::Struct + layout :sa_family, :sa_family_t, + :sa_data, [:uchar, 14] + end + + class Lifnum < ::FFI::Struct + layout :lifn_family, :sa_family_t, + :lifn_flags, :int, + :lifn_count, :int + end + + class Arpreq < ::FFI::Struct + layout :arp_pa, Sockaddr, + :arp_ha, Sockaddr, + :arp_flags, :int + + def sa_data_to_mac + self[:arp_ha][:sa_data].entries[0, 6].map do |s| + s.to_s(16).rjust(2, '0') + end.join ':' + end + + def self.new_for_ioctl(lifreq) + arp = Arpreq.new + arp_addr = SockaddrIn.new(arp[:arp_pa].to_ptr) + arp_addr[:sin_addr][:s_addr] = SockaddrIn.new(lifreq.lifru_addr.to_ptr).s_addr + + arp + end + end + + class Lifru1 < ::FFI::Union + layout :lifru_addrlen, :int, + :lifru_ppa, :uint_t + end + + class Lifru < ::FFI::Union + layout :lifru_addr, SockaddrStorage, + :lifru_dstaddr, SockaddrStorage, + :lifru_broadaddr, SockaddrStorage, + :lifru_token, SockaddrStorage, + :lifru_subnet, SockaddrStorage, + :lifru_flags, :uint64, + :lifru_metric, :int, + :pad, [:char, 80] + end + + class Lifreq < ::FFI::Struct + layout :lifr_name, [:char, 32], + :lifr_lifru1, Lifru1, + :lifr_movetoindex, :int, + :lifr_lifru, Lifru, + :pad, [:char, 80] + + def name + self[:lifr_name].to_s + end + + def ss_family + self[:lifr_lifru][:lifru_addr][:ss_family] + end + + def lifru_addr + self[:lifr_lifru][:lifru_addr] + end + end + + class Lifconf < ::FFI::Struct + layout :lifc_family, :uint, + :lifc_flags, :int, + :lifc_len, :int, + :lifc_buf, :pointer + + def self.new_for_ioctl(interface_count) + lifconf = new + lifconf[:lifc_family] = 0 + lifconf[:lifc_flags] = 0 + lifconf[:lifc_len] = interface_count * Lifreq.size + lifconf[:lifc_buf] = ::FFI::MemoryPointer.new(Lifreq, interface_count) + lifconf + end + end + + class Lifcu < ::FFI::Union + layout :lifcu_buf, :caddr_t, + :lifcu_req, Lifreq + end + + class InAddr < ::FFI::Struct + layout :s_addr, :uint32_t + end + + class SockaddrIn < ::FFI::Struct + layout :sin_family, :sa_family_t, + :sin_port, :in_port_t, + :sin_addr, InAddr, + :sin_zero, [:char, 8] + + def s_addr + self[:sin_addr][:s_addr] + end + end + end + end + end +end diff --git a/lib/facter/resolvers/solaris/networking_resolver.rb b/lib/facter/resolvers/solaris/networking_resolver.rb new file mode 100644 index 0000000000..c7561cf979 --- /dev/null +++ b/lib/facter/resolvers/solaris/networking_resolver.rb @@ -0,0 +1,150 @@ +# frozen_string_literal: true + +require_relative 'ffi/ffi.rb' +require 'ipaddr' + +module Facter + module Resolvers + module Solaris + class Networking < BaseResolver + @log = Facter::Log.new(self) + @semaphore = Mutex.new + @fact_list ||= {} + + BINDINGS_KEY = { + FFI::AF_INET => :bindings, + FFI::AF_INET6 => :bindings6 + }.freeze + + class << self + private + + def post_resolve(fact_name) + @fact_list.fetch(fact_name) { read_facts(fact_name) } + end + + def read_facts(fact_name) + lifreqs = load_interfaces + + lifreqs.each do |lifreq| + @fact_list[lifreq.name] ||= {} + + add_mac(lifreq) + add_bindings(lifreq) + add_mtu(lifreq) + add_dhcp(lifreq.name) + end + + @fact_list = { interfaces: @fact_list } + primary_interface + + ::Resolvers::Utils::Networking.expand_main_bindings(@fact_list) + + @fact_list[fact_name] + end + + def add_mac(lifreq) + arp = FFI::Arpreq.new_for_ioctl(lifreq) + + ioctl = FFI::Ioctl.ioctl(FFI::SIOCGARP, arp, lifreq.ss_family) + + @log.debug("Error! #{::FFI::LastError.error}") if ioctl == -1 + + mac = arp.sa_data_to_mac + @fact_list[lifreq.name][:mac] ||= mac if mac.count('0') < 12 + end + + def add_bindings(lifreq) + ip = inet_ntop(lifreq, lifreq.ss_family) + _netmask, netmask_length = load_netmask(lifreq) + + bindings = ::Resolvers::Utils::Networking.build_binding(ip, netmask_length) + + bindings_key = BINDINGS_KEY[lifreq.ss_family] + @fact_list[lifreq.name][bindings_key] ||= [] + @fact_list[lifreq.name][bindings_key] << bindings + end + + def add_mtu(lifreq) + ioctl = FFI::Ioctl.ioctl(FFI::SIOCGLIFMTU, lifreq, lifreq.ss_family) + + @log.debug("Error! #{::FFI::LastError.error}") if ioctl == -1 + + @fact_list[lifreq.name][:mtu] = lifreq[:lifr_lifru][:lifru_metric] + end + + def load_netmask(lifreq) + netmask_lifreq = FFI::Lifreq.new(lifreq.to_ptr) + + ioctl = FFI::Ioctl.ioctl(FFI::SIOCGLIFNETMASK, netmask_lifreq, lifreq.ss_family) + + if ioctl == -1 + @log.debug("Error! #{::FFI::LastError.error}") + else + netmask = inet_ntop(netmask_lifreq, lifreq.ss_family) + [netmask, calculate_mask_length(netmask)] + end + end + + def inet_ntop(lifreq, ss_family) + sockaddr = FFI::Sockaddr.new(lifreq.lifru_addr.to_ptr) + sockaddr_in = FFI::SockaddrIn.new(sockaddr.to_ptr) + ip = FFI::InAddr.new(sockaddr_in[:sin_addr].to_ptr) + buffer_size = FFI::INET_ADDRSTRLEN + buffer_size = FFI::INET6_ADDRSTRLEN if ss_family == FFI::AF_INET6 + buffer = ::FFI::MemoryPointer.new(:char, buffer_size) + + FFI::Socket.inet_ntop(ss_family, ip.to_ptr, buffer.to_ptr, buffer.size) + end + + def count_interfaces + lifnum = FFI::Lifnum.new + lifnum[:lifn_family] = FFI::AF_UNSPEC + lifnum[:lifn_flags] = 0 + lifnum[:lifn_count] = 0 + + ioctl = FFI::Ioctl.ioctl(FFI::SIOCGLIFNUM, lifnum) + + @log.debug("Error! #{::FFI::LastError.error}") if ioctl == -1 + + lifnum[:lifn_count] + end + + def load_interfaces + interface_count = count_interfaces + + lifconf = FFI::Lifconf.new_for_ioctl(interface_count) + + ioctl = FFI::Ioctl.ioctl(FFI::SIOCGLIFCONF, lifconf) + + @log.debug("Error! #{::FFI::LastError.error}") if ioctl == -1 + + interfaces = [] + interface_count.times do |i| + interfaces << FFI::Lifreq.new(lifconf[:lifc_buf] + (i * FFI::Lifreq.size)) + end + + interfaces + end + + def calculate_mask_length(netmask) + ipaddr = IPAddr.new(netmask) + ipaddr.to_i.to_s(2).count('1') + end + + def primary_interface + result = Facter::Core::Execution.execute('route -n get default', logger: log) + + @fact_list[:primary_interface] = result.match(/interface: (.+)/)&.captures&.first + end + + def add_dhcp(interface_name) + result = Facter::Core::Execution.execute("dhcpinfo -i #{interface_name} ServerID", logger: log) + + @fact_list[interface_name][:dhcp] = result.chomp + end + end + end + end + end +end diff --git a/spec/facter/facts/solaris/dhcp_servers_spec.rb b/spec/facter/facts/solaris/dhcp_servers_spec.rb new file mode 100644 index 0000000000..b0e0a783e8 --- /dev/null +++ b/spec/facter/facts/solaris/dhcp_servers_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +describe Facts::Solaris::DhcpServers do + subject(:fact) { Facts::Solaris::DhcpServers.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:dhcp).and_return(dhcp) + end + + describe '#call_the_resolver' do + let(:value) { { 'system' => '10.16.122.163', 'eth0' => '10.16.122.163', 'en1' => '10.32.10.163' } } + let(:interfaces) { { 'eth0' => { dhcp: '10.16.122.163' }, 'en1' => { dhcp: '10.32.10.163' } } } + let(:dhcp) { '10.16.122.163' } + + it 'calls Facter::Resolvers::Solaris::Networking with interfaces' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'calls Facter::Resolvers::Solaris::Networking with dhcp' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:dhcp) + end + + it 'returns dhcp_servers' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'dhcp_servers', value: value, type: :legacy) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + let(:dhcp) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'dhcp_servers', value: nil, type: :legacy) + end + end +end diff --git a/spec/facter/facts/solaris/interfaces_spec.rb b/spec/facter/facts/solaris/interfaces_spec.rb new file mode 100644 index 0000000000..468a901be8 --- /dev/null +++ b/spec/facter/facts/solaris/interfaces_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Interfaces do + subject(:fact) { Facts::Solaris::Interfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) { { 'eth0' => { ip6: 'fe80::99bf:da20:ad3:9bfe' }, 'en1' => { ip6: 'fe80::99bf:da20:ad3:9bfe' } } } + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns interfaces names' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'interfaces', value: interfaces.keys.sort.join(','), type: :legacy) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'interfaces', value: interfaces, type: :legacy) + end + end +end diff --git a/spec/facter/facts/solaris/ipaddress6_interfaces_spec.rb b/spec/facter/facts/solaris/ipaddress6_interfaces_spec.rb new file mode 100644 index 0000000000..525e299a05 --- /dev/null +++ b/spec/facter/facts/solaris/ipaddress6_interfaces_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Ipaddress6Interfaces do + subject(:fact) { Facts::Solaris::Ipaddress6Interfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) { { 'eth0' => { ip6: 'fe80::99bf:da20:ad3:9bfe' }, 'en1' => { ip6: 'fe80::99bf:da20:ad3:9bfe' } } } + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns legacy facts with names ipaddress6_' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'ipaddress6_eth0', + value: interfaces['eth0'][:ip6], type: :legacy), + an_object_having_attributes(name: 'ipaddress6_en1', + value: interfaces['en1'][:ip6], type: :legacy)) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and contain_exactly + end + end +end diff --git a/spec/facter/facts/solaris/ipaddress_interfaces_spec.rb b/spec/facter/facts/solaris/ipaddress_interfaces_spec.rb new file mode 100644 index 0000000000..e2b11bd591 --- /dev/null +++ b/spec/facter/facts/solaris/ipaddress_interfaces_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::IpaddressInterfaces do + subject(:fact) { Facts::Solaris::IpaddressInterfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) { { 'eth0' => { ip: '10.16.117.100' }, 'en1' => { ip: '10.16.117.255' } } } + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns legacy facts with names ipaddress_' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'ipaddress_eth0', + value: interfaces['eth0'][:ip], type: :legacy), + an_object_having_attributes(name: 'ipaddress_en1', + value: interfaces['en1'][:ip], type: :legacy)) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and contain_exactly + end + end +end diff --git a/spec/facter/facts/solaris/macaddress_interfaces_spec.rb b/spec/facter/facts/solaris/macaddress_interfaces_spec.rb new file mode 100644 index 0000000000..56826102ca --- /dev/null +++ b/spec/facter/facts/solaris/macaddress_interfaces_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::MacaddressInterfaces do + subject(:fact) { Facts::Solaris::MacaddressInterfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) { { 'eth0' => { mac: '10.16.117.100' }, 'en1' => { mac: '10.16.117.255' } } } + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns legacy facts with names macaddress_' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'macaddress_eth0', + value: interfaces['eth0'][:mac], type: :legacy), + an_object_having_attributes(name: 'macaddress_en1', + value: interfaces['en1'][:mac], type: :legacy)) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and contain_exactly + end + end +end diff --git a/spec/facter/facts/solaris/mtu_interfaces_spec.rb b/spec/facter/facts/solaris/mtu_interfaces_spec.rb new file mode 100644 index 0000000000..ae69170327 --- /dev/null +++ b/spec/facter/facts/solaris/mtu_interfaces_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +describe Facts::Solaris::MtuInterfaces do + subject(:fact) { Facts::Solaris::MtuInterfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) { { 'eth0' => { mtu: 1500 }, 'en1' => { mtu: 1500 } } } + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns legacy facts with names mtu_' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'mtu_eth0', value: interfaces['eth0'][:mtu], type: :legacy), + an_object_having_attributes(name: 'mtu_en1', value: interfaces['en1'][:mtu], type: :legacy)) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and contain_exactly + end + end +end diff --git a/spec/facter/facts/solaris/netmask6_interfaces_spec.rb b/spec/facter/facts/solaris/netmask6_interfaces_spec.rb new file mode 100644 index 0000000000..3189649fda --- /dev/null +++ b/spec/facter/facts/solaris/netmask6_interfaces_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Netmask6Interfaces do + subject(:fact) { Facts::Solaris::Netmask6Interfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) do + { 'eth0' => { netmask6: 'fe80::99bf:da20:ad3:9bfe' }, + 'en1' => { netmask6: 'fe80::99bf:da20:ad3:9bfe' } } + end + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns legacy facts with names netmask6_' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'netmask6_eth0', + value: interfaces['eth0'][:netmask6], type: :legacy), + an_object_having_attributes(name: 'netmask6_en1', + value: interfaces['en1'][:netmask6], type: :legacy)) + end + end + + describe '#call_the_resolver when resolver return nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and contain_exactly + end + end +end diff --git a/spec/facter/facts/solaris/netmask_interfaces_spec.rb b/spec/facter/facts/solaris/netmask_interfaces_spec.rb new file mode 100644 index 0000000000..043d7a7e8b --- /dev/null +++ b/spec/facter/facts/solaris/netmask_interfaces_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::NetmaskInterfaces do + subject(:fact) { Facts::Solaris::NetmaskInterfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) { { 'eth0' => { netmask: '10.255.255.255' }, 'en1' => { netmask: '10.17.255.255' } } } + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns legacy facts with names netmask_' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'netmask_eth0', + value: interfaces['eth0'][:netmask], type: :legacy), + an_object_having_attributes(name: 'netmask_en1', + value: interfaces['en1'][:netmask], type: :legacy)) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and contain_exactly + end + end +end diff --git a/spec/facter/facts/solaris/network6_interfaces_spec.rb b/spec/facter/facts/solaris/network6_interfaces_spec.rb new file mode 100644 index 0000000000..1279fe7052 --- /dev/null +++ b/spec/facter/facts/solaris/network6_interfaces_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Network6Interfaces do + subject(:fact) { Facts::Solaris::Network6Interfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) { { 'eth0' => { network6: '::1' }, 'en1' => { network6: 'fe80::' } } } + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns legacy facts with names network6_' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'network6_eth0', + value: interfaces['eth0'][:network6], type: :legacy), + an_object_having_attributes(name: 'network6_en1', + value: interfaces['en1'][:network6], type: :legacy)) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and contain_exactly + end + end +end diff --git a/spec/facter/facts/solaris/network_interfaces_spec.rb b/spec/facter/facts/solaris/network_interfaces_spec.rb new file mode 100644 index 0000000000..d57ae861c7 --- /dev/null +++ b/spec/facter/facts/solaris/network_interfaces_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::NetworkInterfaces do + subject(:fact) { Facts::Solaris::NetworkInterfaces.new } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(interfaces) + end + + describe '#call_the_resolver' do + let(:interfaces) { { 'eth0' => { network: '10.255.255.255' }, 'en1' => { network: '10.17.255.255' } } } + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns legacy facts with names network_' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'network_eth0', + value: interfaces['eth0'][:network], type: :legacy), + an_object_having_attributes(name: 'network_en1', + value: interfaces['en1'][:network], type: :legacy)) + end + end + + describe '#call_the_resolver when resolver returns nil' do + let(:interfaces) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and contain_exactly + end + end +end diff --git a/spec/facter/facts/solaris/networking/dhcp_spec.rb b/spec/facter/facts/solaris/networking/dhcp_spec.rb new file mode 100644 index 0000000000..ad4aa941f4 --- /dev/null +++ b/spec/facter/facts/solaris/networking/dhcp_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Dhcp do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Dhcp.new } + + let(:value) { '10.16.122.163' } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:dhcp).and_return(value) + end + + it 'calls Facter::Resolvers::NetworkingLinux with dhcp' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:dhcp) + end + + it 'returns dhcp fact' do + expect(fact.call_the_resolver) + .to be_an_instance_of(Facter::ResolvedFact) + .and have_attributes(name: 'networking.dhcp', value: value) + end + + context 'when dhcp can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver) + .to be_an_instance_of(Facter::ResolvedFact).and have_attributes(name: 'networking.dhcp', value: value) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/interfaces_spec.rb b/spec/facter/facts/solaris/networking/interfaces_spec.rb new file mode 100644 index 0000000000..3de3847e1b --- /dev/null +++ b/spec/facter/facts/solaris/networking/interfaces_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Interfaces do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Interfaces.new } + + let(:value) do + { + 'ens160' => { + 'bindings' => [ + { + 'address' => '10.16.116.8', + 'netmask' => '255.255.240.0', + 'network' => '10.16.112.0' + } + ] + } + } + end + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:interfaces).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:interfaces) + end + + it 'returns networking.interfaces fact' do + expect(fact.call_the_resolver) + .to be_an_instance_of(Facter::ResolvedFact) + .and have_attributes(name: 'networking.interfaces', value: value) + end + + context 'when interfaces can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver) + .to be_an_instance_of(Facter::ResolvedFact).and have_attributes(name: 'networking.interfaces', value: value) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/ip6_spec.rb b/spec/facter/facts/solaris/networking/ip6_spec.rb new file mode 100644 index 0000000000..b6c8203cfa --- /dev/null +++ b/spec/facter/facts/solaris/networking/ip6_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Ip6 do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Ip6.new } + + let(:value) { 'fe80::5989:97ff:75ae:dae7' } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:ip6).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking with ip6' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:ip6) + end + + it 'returns ipv6 address fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.ip6', value: value), + an_object_having_attributes(name: 'ipaddress6', value: value, type: :legacy)) + end + + context 'when ip6 can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.ip6', value: value), + an_object_having_attributes(name: 'ipaddress6', value: value, type: :legacy)) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/mac_spec.rb b/spec/facter/facts/solaris/networking/mac_spec.rb new file mode 100644 index 0000000000..c385daa368 --- /dev/null +++ b/spec/facter/facts/solaris/networking/mac_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Mac do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Mac.new } + + let(:value) { '64:5a:ed:ea:c3:25' } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:mac).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking with mac' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:mac) + end + + it 'return macaddress fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.mac', value: value), + an_object_having_attributes(name: 'macaddress', value: value, type: :legacy)) + end + + context 'when mac can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.mac', value: value), + an_object_having_attributes(name: 'macaddress', value: value, type: :legacy)) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/mtu_spec.rb b/spec/facter/facts/solaris/networking/mtu_spec.rb new file mode 100644 index 0000000000..79e59c1686 --- /dev/null +++ b/spec/facter/facts/solaris/networking/mtu_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Mtu do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Mtu.new } + + let(:value) { 1500 } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:mtu).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking with mtu' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:mtu) + end + + it 'return mtu fact' do + expect(fact.call_the_resolver) + .to be_an_instance_of(Facter::ResolvedFact) + .and have_attributes(name: 'networking.mtu', value: value) + end + + context 'when mtu can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver) + .to be_an_instance_of(Facter::ResolvedFact).and have_attributes(name: 'networking.mtu', value: value) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/netmask6_spec.rb b/spec/facter/facts/solaris/networking/netmask6_spec.rb new file mode 100644 index 0000000000..4607816559 --- /dev/null +++ b/spec/facter/facts/solaris/networking/netmask6_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Netmask6 do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Netmask6.new } + + let(:value) { 'fe80::5989:97ff:75ae:dae7' } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:netmask6).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking with netmask6' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:netmask6) + end + + it 'returns netmask6 fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.netmask6', value: value), + an_object_having_attributes(name: 'netmask6', value: value, type: :legacy)) + end + + context 'when netmask6 can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.netmask6', value: value), + an_object_having_attributes(name: 'netmask6', value: value, type: :legacy)) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/netmask_spec.rb b/spec/facter/facts/solaris/networking/netmask_spec.rb new file mode 100644 index 0000000000..32af5e5062 --- /dev/null +++ b/spec/facter/facts/solaris/networking/netmask_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Netmask do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Netmask.new } + + let(:value) { '10.16.122.163' } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:netmask).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking with netmask' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:netmask) + end + + it 'returns netmask fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array) + .and contain_exactly(an_object_having_attributes(name: 'networking.netmask', value: value), + an_object_having_attributes(name: 'netmask', value: value, type: :legacy)) + end + + context 'when netmask can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.netmask', value: value), + an_object_having_attributes(name: 'netmask', value: value, type: :legacy)) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/network6_spec.rb b/spec/facter/facts/solaris/networking/network6_spec.rb new file mode 100644 index 0000000000..d5a1e08acc --- /dev/null +++ b/spec/facter/facts/solaris/networking/network6_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Network6 do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Network6.new } + + let(:value) { 'fe80::5989:97ff:75ae:dae7' } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:network6).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking with network6' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:network6) + end + + it 'returns network6 fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.network6', value: value), + an_object_having_attributes(name: 'network6', value: value, type: :legacy)) + end + + context 'when network6 can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.network6', value: value), + an_object_having_attributes(name: 'network6', value: value, type: :legacy)) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/network_spec.rb b/spec/facter/facts/solaris/networking/network_spec.rb new file mode 100644 index 0000000000..a8f943a4c6 --- /dev/null +++ b/spec/facter/facts/solaris/networking/network_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Network do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Network.new } + + let(:value) { '10.16.122.163' } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:network).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking with network' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:network) + end + + it 'returns network fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array) + .and contain_exactly(an_object_having_attributes(name: 'networking.network', value: value), + an_object_having_attributes(name: 'network', value: value, type: :legacy)) + end + + context 'when network can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'networking.network', value: value), + an_object_having_attributes(name: 'network', value: value, type: :legacy)) + end + end + end +end diff --git a/spec/facter/facts/solaris/networking/primary_spec.rb b/spec/facter/facts/solaris/networking/primary_spec.rb new file mode 100644 index 0000000000..418f95bdcd --- /dev/null +++ b/spec/facter/facts/solaris/networking/primary_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Networking::Primary do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Networking::Primary.new } + + let(:value) { 'ens160' } + + before do + allow(Facter::Resolvers::Solaris::Networking).to receive(:resolve).with(:primary_interface).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Networking' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Networking).to have_received(:resolve).with(:primary_interface) + end + + it 'returns networking.primary fact' do + expect(fact.call_the_resolver) + .to be_an_instance_of(Facter::ResolvedFact) + .and have_attributes(name: 'networking.primary', value: value) + end + + context 'when primary interface can not be retrieved' do + let(:value) { nil } + + it 'returns nil' do + expect(fact.call_the_resolver) + .to be_an_instance_of(Facter::ResolvedFact).and have_attributes(name: 'networking.primary', value: value) + end + end + end +end diff --git a/spec/mocks/ffi_mock.rb b/spec/mocks/ffi_mock.rb index 45610b4f57..06e5c066d0 100644 --- a/spec/mocks/ffi_mock.rb +++ b/spec/mocks/ffi_mock.rb @@ -19,11 +19,13 @@ def self.define_errno(arg) def self.type_size(arg); end module Library + LIBC = 'libc' + def ffi_convention(arg); end def ffi_lib(arg); end - def attach_function(function, args, return_type); end + def attach_function(*); end def enum(*); end