| 
 | 1 | +# frozen_string_literal: true  | 
 | 2 | + | 
 | 3 | +module Facter  | 
 | 4 | +  module Resolvers  | 
 | 5 | +    module Linux  | 
 | 6 | +      class Containers < BaseResolver  | 
 | 7 | +        # :virtual  | 
 | 8 | +        # :hypervisor  | 
 | 9 | + | 
 | 10 | +        init_resolver  | 
 | 11 | + | 
 | 12 | +        INFO = { 'docker' => 'id', 'lxc' => 'name' }.freeze  | 
 | 13 | + | 
 | 14 | +        class << self  | 
 | 15 | +          private  | 
 | 16 | + | 
 | 17 | +          def post_resolve(fact_name, _options)  | 
 | 18 | +            @fact_list.fetch(fact_name) do  | 
 | 19 | +              read_environ(fact_name) || read_cgroup(fact_name)  | 
 | 20 | +            end  | 
 | 21 | +          end  | 
 | 22 | + | 
 | 23 | +          def read_cgroup(fact_name)  | 
 | 24 | +            output_cgroup = Facter::Util::FileHelper.safe_read('/proc/1/cgroup', nil)  | 
 | 25 | +            return unless output_cgroup  | 
 | 26 | + | 
 | 27 | +            output_docker = %r{docker/(.+)}.match(output_cgroup)  | 
 | 28 | +            output_lxc = %r{^/lxc/([^/]+)}.match(output_cgroup)  | 
 | 29 | + | 
 | 30 | +            info, vm = extract_vm_and_info(output_docker, output_lxc)  | 
 | 31 | +            @fact_list[:vm] = vm  | 
 | 32 | +            @fact_list[:hypervisor] = { vm.to_sym => info } if vm  | 
 | 33 | +            @fact_list[fact_name]  | 
 | 34 | +          end  | 
 | 35 | + | 
 | 36 | +          def read_environ(fact_name)  | 
 | 37 | +            begin  | 
 | 38 | +              container = Facter::Util::Linux::Proc.getenv_for_pid(1, 'container')  | 
 | 39 | +            rescue StandardError => e  | 
 | 40 | +              log.warn("Unable to getenv for pid 1, '#{e}'")  | 
 | 41 | +              return nil  | 
 | 42 | +            end  | 
 | 43 | +            return if container.nil? || container.empty?  | 
 | 44 | + | 
 | 45 | +            info = {}  | 
 | 46 | +            case container  | 
 | 47 | +            when 'lxc'  | 
 | 48 | +              vm = 'lxc'  | 
 | 49 | +            when 'podman'  | 
 | 50 | +              vm = 'podman'  | 
 | 51 | +            when 'crio'  | 
 | 52 | +              vm = 'crio'  | 
 | 53 | +            when 'systemd-nspawn'  | 
 | 54 | +              vm = 'systemd_nspawn'  | 
 | 55 | +              info = { 'id' => Facter::Util::FileHelper.safe_read('/etc/machine-id', nil).strip }  | 
 | 56 | +            else  | 
 | 57 | +              vm = 'container_other'  | 
 | 58 | +              log.warn("Container runtime, '#{container}', is unsupported, setting to '#{vm}'")  | 
 | 59 | +            end  | 
 | 60 | +            @fact_list[:vm] = vm  | 
 | 61 | +            @fact_list[:hypervisor] = { vm.to_sym => info } if vm  | 
 | 62 | +            @fact_list[fact_name]  | 
 | 63 | +          end  | 
 | 64 | + | 
 | 65 | +          def extract_vm_and_info(output_docker, output_lxc)  | 
 | 66 | +            vm = nil  | 
 | 67 | +            if output_docker  | 
 | 68 | +              vm = 'docker'  | 
 | 69 | +              info = output_docker[1]  | 
 | 70 | +            elsif output_lxc  | 
 | 71 | +              vm = 'lxc'  | 
 | 72 | +              info = output_lxc[1]  | 
 | 73 | +            end  | 
 | 74 | + | 
 | 75 | +            [info ? { INFO[vm] => info } : {}, vm]  | 
 | 76 | +          end  | 
 | 77 | +        end  | 
 | 78 | +      end  | 
 | 79 | +    end  | 
 | 80 | +  end  | 
 | 81 | +end  | 
0 commit comments