├── root ├── opt │ └── extension │ │ ├── .gitkeep │ │ ├── bin │ │ └── .gitkeep │ │ ├── facts │ │ └── .gitkeep │ │ ├── lib │ │ └── ruby │ │ │ └── .gitkeep │ │ └── autostart.d │ │ └── .gitkeep ├── usr │ ├── share │ │ ├── locale │ │ │ └── fdi │ │ │ │ ├── cs_CZ │ │ │ │ ├── LC_MESSAGES │ │ │ │ │ └── foreman-discovery-image.mo │ │ │ │ └── foreman-discovery-image.po │ │ │ │ ├── Makefile │ │ │ │ └── foreman-discovery-image.pot │ │ ├── fdi │ │ │ ├── facts │ │ │ │ ├── efi.rb │ │ │ │ ├── pcicards.rb │ │ │ │ ├── ethtool.rb │ │ │ │ ├── disks_partition_table.rb │ │ │ │ ├── openlldp.rb │ │ │ │ └── discovery-facts.rb │ │ │ ├── commonfunc.sh │ │ │ └── script-helpers.sh │ │ └── ruby │ │ │ └── vendor_ruby │ │ │ ├── discovery │ │ │ ├── screen │ │ │ │ ├── info.rb │ │ │ │ ├── ssh.rb │ │ │ │ ├── welcome.rb │ │ │ │ ├── network.rb │ │ │ │ ├── countdown.rb │ │ │ │ ├── foreman.rb │ │ │ │ ├── facts.rb │ │ │ │ ├── status.rb │ │ │ │ └── primary_iface.rb │ │ │ └── menu.rb │ │ │ └── discovery.rb │ └── bin │ │ ├── enable-lldp │ │ ├── discovery-script │ │ ├── discovery-menu │ │ ├── discovery-fetch-extensions │ │ ├── discovery-debug │ │ ├── find-missing-libs │ │ ├── generate-proxy-cert │ │ ├── nm-prepare │ │ ├── discovery-start-extensions │ │ ├── discovery-register │ │ └── nm-configure └── etc │ ├── default │ └── discovery │ ├── systemd │ └── system │ │ ├── discovery-start-extensions.service │ │ ├── enable-lldp@.service │ │ ├── nm-prepare.service │ │ ├── discovery-script-pxe.service │ │ ├── discovery-register.service │ │ ├── journalctl.service │ │ ├── discovery-fetch-extensions.service │ │ ├── enable-promiscuous-mode@.service │ │ ├── discovery-fetch-extensions.path │ │ ├── discovery-script-pxeless.service │ │ └── discovery-menu.service │ ├── rc.d │ └── rc.local │ ├── profile.d │ └── discovery.sh │ └── NetworkManager │ └── dispatcher.d │ └── 15-get-zip-server ├── example_zip ├── lib │ ├── your-libs-go-here │ └── ruby │ │ ├── your-rubylibs-go-here │ │ └── discovery_extension.rb ├── bin │ └── your-binaries-go-here ├── your-custom-facts-go-here ├── facts │ └── discovery_extension.rb └── autostart.d │ └── 01_zip.sh ├── aux ├── vagrant-build │ ├── .gitignore │ ├── .ruby-version │ ├── Vagrantfile │ └── build_image.sh ├── basescript-examples │ ├── configure-bond.sh │ └── README ├── discovery-script-creator ├── remaster │ └── discovery-remaster └── livecd-iso-to-pxeboot ├── .rubocop.yml ├── clean-cache ├── extract-strings ├── fdi-stream9.ks ├── .tx └── config ├── 00-repos-stream9.ks ├── .gitignore ├── 10-header.ks ├── .github └── workflows │ └── build.yml ├── 20-packages.ks ├── 25-minimize.ks ├── 22-discovery.ks ├── README.md ├── LICENSE └── .rubocop_todo.yml /root/opt/extension/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example_zip/lib/your-libs-go-here: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/opt/extension/bin/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/opt/extension/facts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example_zip/bin/your-binaries-go-here: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example_zip/your-custom-facts-go-here: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/opt/extension/lib/ruby/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /aux/vagrant-build/.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | -------------------------------------------------------------------------------- /aux/vagrant-build/.ruby-version: -------------------------------------------------------------------------------- 1 | system 2 | -------------------------------------------------------------------------------- /example_zip/lib/ruby/your-rubylibs-go-here: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/opt/extension/autostart.d/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | -------------------------------------------------------------------------------- /clean-cache: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo rm -rf /var/cache/build-fdi 3 | -------------------------------------------------------------------------------- /extract-strings: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | TARGET=${1:-extract} 3 | make -C root/usr/share/locale/fdi/ $TARGET 4 | -------------------------------------------------------------------------------- /example_zip/facts/discovery_extension.rb: -------------------------------------------------------------------------------- 1 | Facter.add("discovery_extension") do 2 | setcode do 3 | "installed" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /example_zip/lib/ruby/discovery_extension.rb: -------------------------------------------------------------------------------- 1 | module Discovery 2 | class Extension 3 | def self.confirm 4 | true 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /fdi-stream9.ks: -------------------------------------------------------------------------------- 1 | %include 10-header.ks 2 | %include 00-repos-stream9.ks 3 | %include 20-packages.ks 4 | %include fdi-install.ks 5 | %include 22-discovery.ks 6 | %include 25-minimize.ks 7 | -------------------------------------------------------------------------------- /aux/basescript-examples/configure-bond.sh: -------------------------------------------------------------------------------- 1 | no_tui 2 | fact via_script 1 3 | clean_nm 4 | cfg_bond bond0 5 | for DEV in eth0 eth1; do cfg_slave bond0 $DEV; done 6 | reload_nm 7 | sleep 30 8 | discover_now 9 | -------------------------------------------------------------------------------- /root/usr/share/locale/fdi/cs_CZ/LC_MESSAGES/foreman-discovery-image.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theforeman/foreman-discovery-image/HEAD/root/usr/share/locale/fdi/cs_CZ/LC_MESSAGES/foreman-discovery-image.mo -------------------------------------------------------------------------------- /root/etc/default/discovery: -------------------------------------------------------------------------------- 1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/extension/bin 2 | FACTERLIB=/usr/share/fdi/facts:/opt/extension/facts 3 | LD_LIBRARY_PATH=/opt/extension/lib 4 | RUBYLIB=/usr/share/ruby/vendor_ruby/ 5 | -------------------------------------------------------------------------------- /example_zip/autostart.d/01_zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Discovery Extension zipfile loaded" > /tmp/discovery-extension.log 4 | 5 | # This example shows the RUBYLIB extension working 6 | /usr/bin/ruby -rdiscovery_extension -e'puts Discovery::Extension.confirm' 7 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [foreman.foreman-discovery-image] 5 | file_filter = root/usr/share/locale/fdi//foreman-discovery-image.edit.po 6 | source_file = root/usr/share/locale/fdi/foreman-discovery-image.pot 7 | source_lang = en 8 | type = PO 9 | -------------------------------------------------------------------------------- /root/etc/systemd/system/discovery-start-extensions.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Start downloaded extension scripts 3 | Before=discovery-register.service foreman-proxy.service 4 | 5 | [Service] 6 | Type=oneshot 7 | EnvironmentFile=/etc/default/discovery 8 | RemainAfterExit=yes 9 | ExecStart=/usr/bin/discovery-start-extensions 10 | -------------------------------------------------------------------------------- /root/etc/systemd/system/enable-lldp@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Configures LLDP for %i 3 | After=lldpad.service 4 | Requires=lldpad.service 5 | 6 | [Service] 7 | Type=oneshot 8 | RemainAfterExit=yes 9 | ExecStart=/usr/bin/enable-lldp %i 10 | SyslogIdentifier=enable-lldp 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /aux/discovery-script-creator: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT="fdi.script=$(cat - | gzip -9 | base64 -w0)" 3 | LENGTH=${#SCRIPT} 4 | MAX=310 5 | echo $SCRIPT 6 | echo "Maximum length: $MAX (512 limit - current options)" 7 | echo "Actual length: $LENGTH" 8 | if [[ $LENGTH -gt $MAX ]]; then 9 | echo "Consider shell minifier or stage2 script downloaded from network." 10 | fi 11 | -------------------------------------------------------------------------------- /root/etc/systemd/system/nm-prepare.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Prepares NetworkManager configuration for primary interface 3 | Wants=basic.target 4 | Before=NetworkManager.service 5 | ConditionKernelCommandLine=BOOTIF 6 | 7 | [Service] 8 | Type=oneshot 9 | RemainAfterExit=yes 10 | ExecStart=/usr/bin/nm-configure primary 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /00-repos-stream9.ks: -------------------------------------------------------------------------------- 1 | url --url https://mirror.stream.centos.org/9-stream/BaseOS/$basearch/os/ 2 | repo --name="AppStream" --baseurl=https://mirror.stream.centos.org/9-stream/AppStream/$basearch/os/ 3 | repo --name="foreman-el9" --baseurl=http://yum.theforeman.org/releases/nightly/el9/$basearch/ 4 | repo --name="foreman-plugins-el9" --baseurl=http://yum.theforeman.org/plugins/nightly/el9/$basearch/ 5 | 6 | -------------------------------------------------------------------------------- /root/etc/systemd/system/discovery-script-pxe.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Script PXE 3 | Wants=basic.target 4 | After=foreman-proxy.service NetworkManager.service 5 | ConditionKernelCommandLine=BOOTIF 6 | 7 | [Service] 8 | Type=oneshot 9 | EnvironmentFile=/etc/default/discovery 10 | RemainAfterExit=yes 11 | ExecStart=/usr/bin/discovery-script 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /root/etc/systemd/system/discovery-register.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Register this host in Foreman 3 | Wants=network-online.target 4 | After=basic.target network-online.target nss-lookup.target foreman-proxy.service 5 | 6 | [Service] 7 | Type=simple 8 | EnvironmentFile=/etc/default/discovery 9 | ExecStart=/usr/bin/discovery-register 10 | ExecReload=/bin/kill -HUP $MAINPID 11 | KillMode=process 12 | Restart=always 13 | -------------------------------------------------------------------------------- /root/etc/systemd/system/journalctl.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Display journal on tty2 3 | Wants=basic.target 4 | After=basic.target 5 | ConditionPathExists=/dev/tty2 6 | 7 | [Service] 8 | Type=idle 9 | ExecStart=/usr/bin/journalctl --full --all --follow --merge --no-pager 10 | KillMode=process 11 | StandardOutput=tty 12 | StandardError=tty 13 | TTYPath=/dev/tty2 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /root/etc/systemd/system/discovery-fetch-extensions.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Download zip extensions to this image 3 | Wants=network-online.target discovery-start-extensions.service 4 | Before=discovery-start-extensions.service 5 | After=network-online.target 6 | 7 | [Service] 8 | Type=oneshot 9 | EnvironmentFile=-/etc/default/discovery-zip-server 10 | RemainAfterExit=yes 11 | ExecStart=/usr/bin/discovery-fetch-extensions 12 | -------------------------------------------------------------------------------- /root/usr/bin/enable-lldp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [[ -z "$1" ]] && echo "Usage: $0 interface" && exit 1 4 | [[ "$1" == "lo" ]] && exit 0 5 | 6 | echo -n "Setting LLDP parameter on interface $1: " 7 | /usr/sbin/lldptool -L -i $1 adminstatus=rxtx 8 | for var in portDesc sysName sysDesc sysCap; do 9 | echo -n "Setting LLDP TLV $var on interface $1: " 10 | /usr/sbin/lldptool -i $1 -T -V $var enableTx=yes 11 | done 12 | 13 | exit 0 14 | -------------------------------------------------------------------------------- /root/etc/systemd/system/enable-promiscuous-mode@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Control promiscuous mode for interface %i 3 | After=network-online.target 4 | Wants=network-online.target 5 | ConditionKernelCommandLine=!fdi.nopromis 6 | 7 | [Service] 8 | Type=oneshot 9 | ExecStart=/sbin/ip link set promisc on dev %i 10 | ExecStop=/sbin/ip link set promisc off dev %i 11 | RemainAfterExit=yes 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /root/etc/systemd/system/discovery-fetch-extensions.path: -------------------------------------------------------------------------------- 1 | [Unit] 2 | # Network-Manager-wait-online doesn't seem to wait *quite* long enough 3 | # for the custom post-up command to write the next-server environment 4 | # file. So we use a path target to wait for it to be written. 5 | Description=Waiting for ZIP_SERVER environment file to be created 6 | 7 | [Path] 8 | PathExists=/etc/default/discovery-zip-server 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /root/etc/systemd/system/discovery-script-pxeless.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Script PXE-less 3 | Wants=basic.target 4 | Before=foreman-proxy.service NetworkManager.service 5 | After=nm-prepare.service systemd-journald.service 6 | ConditionKernelCommandLine=!BOOTIF 7 | 8 | [Service] 9 | Type=oneshot 10 | EnvironmentFile=/etc/default/discovery 11 | RemainAfterExit=yes 12 | ExecStart=/usr/bin/discovery-script 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /root/usr/share/fdi/facts/efi.rb: -------------------------------------------------------------------------------- 1 | # (c) Pat Riehecky 2016, Apache Public License 2.0 2 | # 3 | # Fact: efi 4 | # 5 | # Purpose: Set 'true' if system is booted into EFI 6 | # 7 | # Resolution: 8 | # if /sys/firmware/efi exists this is true, else false 9 | # 10 | # Notes: 11 | # The result is boolean 12 | # 13 | require 'facter' 14 | 15 | Facter.add(:efi) do 16 | confine :kernel => "Linux" 17 | 18 | setcode do 19 | File.directory?('/sys/firmware/efi') 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /fdi-image.ks 2 | /fdi-install.ks 3 | /root/usr/share/fdi/VERSION 4 | /root/usr/share/fdi/RELEASE 5 | /*.tar 6 | /*.iso 7 | /*.log 8 | /tftpboot 9 | /fdi-image 10 | /anaconda 11 | /build-local 12 | /root/opt/extension/autostart.d/* 13 | /root/opt/extension/facts/* 14 | /root/opt/extension/lib/ruby/* 15 | /root/opt/extension/lib/* 16 | /root/opt/extension/bin/* 17 | /root/usr/share/locale/fdi/*/*.pox 18 | /00-repos-rhel*.ks 19 | /fdi-rhel*.ks 20 | /build-livecd-root.conf.sh 21 | /result/* 22 | -------------------------------------------------------------------------------- /aux/basescript-examples/README: -------------------------------------------------------------------------------- 1 | Example scripts which can be run from kernel commandline. To encode them do: 2 | 3 | # cat aux/basescript-examples/myscript | gzip -9 | base64 -w0 4 | fdi.script=H4sIAK4hZ1oCA0tNzshXUA/JyCxWAKJEhZLU4hJ1LgA92U9qFgAAAA== 5 | 6 | And append. Keep in mind that kernel command line length is very limited. 7 | 8 | There are couple of helper shell functions which can be used defined in: 9 | 10 | root/usr/bin/discovery-script 11 | 12 | Send patches with more functions for more options. 13 | -------------------------------------------------------------------------------- /root/usr/bin/discovery-script: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /etc/default/discovery 3 | source /usr/share/fdi/commonfunc.sh 4 | exportKCL 5 | [ -d /tmp/facts ] || mkdir /tmp/facts 6 | defaultscript=${KCL_FDI_SCRIPT:-H4sIAOj1ZloCA0tNzshXUPLLVyhOLsosKFEoSCwuTk1R4gIAIbwTwhgAAAA=} 7 | basescript=${1:-$defaultscript} 8 | cat /usr/share/fdi/script-helpers.sh > /tmp/discovery-script 9 | echo "$basescript" | base64 -d | gunzip >> /tmp/discovery-script 10 | [[ $? -eq 0 ]] && ( bash /tmp/discovery-script | tee /tmp/discovery-script.log ) 11 | rm /tmp/discovery-script 12 | -------------------------------------------------------------------------------- /10-header.ks: -------------------------------------------------------------------------------- 1 | network --bootproto=dhcp 2 | lang en_US.UTF-8 3 | keyboard us 4 | timezone --utc Etc/UTC 5 | selinux --permissive 6 | bootloader --timeout=1 --append="acpi=force" 7 | # root password is "redhat" but account is locked - use fdi.rootpw kernel option 8 | rootpw --iscrypted $1$_redhat_$i3.3Eg7ko/Peu/7Q/1.wJ/ 9 | clearpart --all --initlabel 10 | services --disabled=network,sshd --enabled=NetworkManager 11 | # required for lorax 12 | shutdown 13 | # the image currently needs 2.1 GiB but this has been only growing 14 | part / --size 3000 --fstype ext4 15 | -------------------------------------------------------------------------------- /root/etc/rc.d/rc.local: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /usr/share/fdi/commonfunc.sh 4 | exportKCL 5 | 6 | # setup root password 7 | if [[ ! -z "$KCL_FDI_ROOTPW" ]]; then 8 | # remove possible double and/or single quotes surrounding password string 9 | KCL_FDI_ROOTPW=`echo $KCL_FDI_ROOTPW | sed -e "s/^'\(.*\)'$/\1/" -e 's/^"\(.*\)"$/\1/'` 10 | # if password starts with dollar sign, set an encrypted flag 11 | if [[ "$KCL_FDI_ROOTPW" =~ ^\$.* ]]; then 12 | FLAG="-e" 13 | fi 14 | echo "root:$KCL_FDI_ROOTPW" | chpasswd $FLAG >/dev/null 15 | fi 16 | 17 | # enable ssh 18 | if [ "$KCL_FDI_SSH" == "1" ]; then 19 | systemctl start sshd 20 | fi 21 | -------------------------------------------------------------------------------- /root/etc/systemd/system/discovery-menu.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Discovery TUI 3 | Wants=basic.target 4 | After=basic.target network-online.target nss-lookup.target 5 | ConditionPathExists=/dev/tty1 6 | 7 | [Service] 8 | Type=idle 9 | EnvironmentFile=/etc/default/discovery 10 | ExecStart=/usr/bin/discovery-menu 11 | ExecStartPre=/usr/sbin/sysctl -w kernel.printk=0 12 | ExecReload=/bin/kill -HUP $MAINPID 13 | Restart=always 14 | RestartSec=5 15 | KillMode=process 16 | TimeoutStopSec=5 17 | StandardInput=tty 18 | StandardError=tty 19 | StandardOutput=tty 20 | TTYPath=/dev/tty1 21 | RemainAfterExit=yes 22 | 23 | [Install] 24 | WantedBy=multi-user.target 25 | -------------------------------------------------------------------------------- /root/usr/bin/discovery-menu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | exit(0) if File.exist?('/tmp/disable-menu') 4 | 5 | 6 | require 'discovery/menu' 7 | require 'discovery/screen/countdown' 8 | require 'discovery/screen/facts' 9 | require 'discovery/screen/foreman' 10 | require 'discovery/screen/network' 11 | require 'discovery/screen/primary_iface' 12 | require 'discovery/screen/ssh' 13 | require 'discovery/screen/status' 14 | require 'discovery/screen/welcome' 15 | require 'discovery/screen/info' 16 | 17 | # Disable GC until https://github.com/theforeman/ruby-newt/issues/2 is fixed, 18 | # see also: http://projects.theforeman.org/issues/11623 19 | GC.disable 20 | 21 | main_loop 22 | -------------------------------------------------------------------------------- /aux/vagrant-build/Vagrantfile: -------------------------------------------------------------------------------- 1 | # vim: sw=2:ts=2:et:ft=ruby 2 | 3 | SHELLARGS = [] 4 | SHELLARGS << (ENV['repoowner'] || '') 5 | SHELLARGS << (ENV['branch'] || '') 6 | SHELLARGS << (ENV['proxy_repo'] || '') 7 | 8 | Vagrant.configure("2") do |config| 9 | config.vm.define "fdi-builder", primary: true do |machine| 10 | machine.vm.hostname = "fdi-builder-vm" 11 | machine.vm.provision :shell, :path => 'build_image.sh', :args => SHELLARGS 12 | machine.vm.synced_folder ".", "/vagrant", disabled: true 13 | 14 | config.vm.provider :libvirt do |domain, cfg| 15 | cfg.vm.box = 'centos/stream9' 16 | domain.memory = 7990 17 | domain.cpus = 2 18 | domain.nested = true 19 | domain.disk_driver :cache => 'unsafe' 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /root/etc/profile.d/discovery.sh: -------------------------------------------------------------------------------- 1 | # /etc/profile.d/discovery.sh - shell extensions for discovery 2 | 3 | # Parse the systemd EnvironmentFile(s) and export the values for use 4 | # in normal shells 5 | 6 | filename="/etc/default/discovery" 7 | if test -f $filename 8 | then 9 | while read -r line 10 | do 11 | if [[ $line =~ ^# ]] ; then 12 | continue 13 | elif [[ $line =~ .*=.* ]] ; then 14 | export $line 15 | else 16 | continue 17 | fi 18 | done < "$filename" 19 | fi 20 | 21 | filename="/etc/default/discovery-zip-server" 22 | if test -f $filename 23 | then 24 | while read -r line 25 | do 26 | if [[ $line =~ ^# ]] ; then 27 | continue 28 | elif [[ $line =~ .*=.* ]] ; then 29 | export $line 30 | else 31 | continue 32 | fi 33 | done < "$filename" 34 | fi 35 | -------------------------------------------------------------------------------- /root/usr/bin/discovery-fetch-extensions: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Use a commandline option, fdi.zips=zip1.zip,zip2.zip,etc and 4 | # get the zips from the TFTP server. Try zipserver passed on kernel 5 | # cmdline first and fall back to DHCP next-server passed in through 6 | # ENV 7 | 8 | extdir="/opt/extension" 9 | 10 | source /usr/share/fdi/commonfunc.sh 11 | exportKCL 12 | 13 | for zip in ${KCL_FDI_ZIPS//,/ } 14 | do 15 | tempfile="$(mktemp)" 16 | URL="tftp://${ZIP_SERVER}/${zip}" 17 | echo "Downloading $URL" 18 | curl --fail --silent "$URL" -o "${tempfile}" 19 | curl_rc="$?" 20 | if [ "${curl_rc}" -ne 0 ] 21 | then 22 | echo "CURL error downloading ${zip} via tftp: ${curl_rc}" 23 | echo "Problem downloading zipfile ${zip}" >&2 24 | else 25 | unzip "${tempfile}" -d "${extdir}" 26 | fi 27 | rm "${tempfile}" 28 | done 29 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/screen/info.rb: -------------------------------------------------------------------------------- 1 | def screen_info action_proc, message, error_message, success_screen, failure_screen 2 | text_help, tw, th = Newt.reflow_text(message, 60, 5, 5) 3 | t = Newt::Textbox.new(-1, -1, tw, th, Newt::FLAG_WRAP) 4 | t.set_text(text_help) 5 | 6 | main_grid = Newt::Grid.new(1, 1) 7 | main_grid.set_field(0, 0, Newt::GRID_COMPONENT, t, 0, 0, 0, 1, 0, 0) 8 | main_grid.wrapped_window(_("Waiting for operation to complete")) 9 | 10 | f = Newt::Form.new 11 | f.add(t) 12 | f.draw 13 | 14 | # facter sometimes leaves messages on stdout, refresh before/after 15 | Newt::Screen.refresh 16 | result = action_proc.call 17 | Newt::Screen.refresh 18 | 19 | if result 20 | success_screen 21 | else 22 | Newt::Screen.win_message(_("Operation failed"), _("OK"), error_message) 23 | failure_screen 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /root/usr/bin/discovery-debug: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /etc/default/discovery 4 | export FACTERLIB 5 | 6 | echo "* LOOPBACK ISO IMAGE CHECK" 7 | checkisomd5 /dev/loop0 8 | 9 | echo "* KERNEL COMMAND LINE *" 10 | cat /proc/cmdline 11 | 12 | echo "* PROCESSES *" 13 | ps axww 14 | 15 | echo "* PACKAGES" 16 | cat /usr/PACKAGES-LIST 17 | 18 | echo "* NETWORK CONFIGURATION *" 19 | nmcli con 20 | for C in /etc/NetworkManager/system-connections/*; do 21 | echo $C; cat $C; echo 22 | done 23 | 24 | echo "* IP ADDRESSES *" 25 | ip addr show 26 | 27 | echo "* ROUTES *" 28 | ip route 29 | 30 | echo "* NEIGHBOURS *" 31 | ip neigh 32 | 33 | echo "* DHCP LEASES *" 34 | cat /var/lib/NetworkManager/dhclient-*.lease 35 | 36 | echo "* DNS *" 37 | cat /etc/resolv.conf 38 | 39 | echo "* IMAGE VERSION" 40 | cat /usr/share/fdi/VERSION /usr/share/fdi/RELEASE 41 | 42 | echo "* FACTER *" 43 | facter --json 44 | 45 | echo "* JOURNAL (last 500 lines) *" 46 | journalctl -n300 -ocat 47 | -------------------------------------------------------------------------------- /root/usr/share/fdi/commonfunc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/echo This file is meant to be sourced not to be executed: 2 | 3 | # Common functions used in FDI scripts. 4 | 5 | # normalize MAC address to use lowercase and : as separator 6 | function normalizeHwAddr() { 7 | /usr/bin/tr 'A-F-' 'a-f:' <<< "${1}" 8 | } 9 | 10 | # parse /proc/cmdline and export parameters into env (KCL_*) 11 | function exportKCL() { 12 | local -a cmdline 13 | local param 14 | IFS=" " read -a cmdline < /proc/cmdline 15 | for param in "${cmdline[@]}" 16 | do 17 | # sanitize variable name to contain only _ and alpha nummeric chars. 18 | local name="$(/usr/bin/tr -c '[:alnum:]_\n' '_' <<< "${param%%=*}")" 19 | local value="${param#*=}" 20 | export "KCL_${name^^}"="${value}" 21 | done 22 | if [ -n "${KCL_BOOTIF}" ] 23 | then 24 | # strip out leading arp type (01-) of KCL_BOOTIF 25 | # and provide BOOTMAC in environment 26 | export BOOTMAC="${KCL_BOOTIF#*-}" 27 | fi 28 | } 29 | -------------------------------------------------------------------------------- /aux/vagrant-build/build_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: sw=2:ts=2:et 3 | set -x 4 | export repoowner=${1:-theforeman} 5 | export branch=${2:-master} 6 | export proxy_repo=${3:-nightly} 7 | KERNEL_CMDLINE="nomodeset nokaslr" 8 | NAME=foreman-discovery-image 9 | 10 | echo "Short sleep to allow things to settle down" 11 | sleep 10 12 | ping -c1 8.8.8.8 2>&1 >/dev/null && echo NET OK || echo NET FAILURE 13 | sudo setenforce 0 14 | 15 | # There are several options with lorax. Recommended is building from ISO in 16 | # qemu, this requires nested virtualization and it is extremely slow on CI. 17 | # Building in mock did not work at all, therefore building directly on the host 18 | # VM is the approach. 19 | 20 | sudo dnf -y install pykickstart git wget lorax anaconda 21 | 22 | [ -d $NAME ] || git clone https://github.com/$repoowner/$NAME.git 23 | pushd $NAME 24 | git fetch origin $branch 25 | git checkout FETCH_HEAD 26 | 27 | version=$(git describe --abbrev=0 --tags) 28 | 29 | ./build-kickstart fdi-stream9.ks $proxy_repo && sudo ./build-livecd-root "$version" . "$KERNEL_CMDLINE" novirt 30 | 31 | find . 32 | popd 33 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Build 3 | 4 | on: 5 | pull_request: 6 | 7 | concurrency: 8 | group: ${{ github.ref_name }}-${{ github.workflow }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-24.04 14 | steps: 15 | - uses: actions/checkout@v5 16 | - name: Setup libvirt for Vagrant 17 | uses: voxpupuli/setup-vagrant@v0 18 | - name: Build image 19 | run: repoowner=theforeman branch=${{ github.ref }} proxy_repo=nightly vagrant up fdi-builder 20 | working-directory: aux/vagrant-build 21 | - name: Copy image 22 | run: | 23 | vagrant ssh-config fdi-builder | tee vagrant-ssh-config.tmp 24 | mkdir result 25 | scp -F vagrant-ssh-config.tmp fdi-builder:foreman-discovery-image/fdi*tar result/ 26 | scp -F vagrant-ssh-config.tmp fdi-builder:foreman-discovery-image/fdi*iso result/ 27 | working-directory: aux/vagrant-build 28 | - name: Archive image 29 | uses: actions/upload-artifact@v5 30 | with: 31 | name: fdi 32 | path: aux/vagrant-build/result/*.iso 33 | retention-days: 15 34 | -------------------------------------------------------------------------------- /root/usr/bin/find-missing-libs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # vim: ts=2:sw=2:et 4 | # 5 | # Copyright (C) 2013 Red Hat, Inc. 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; version 2 of the License. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | # MA 02110-1301, USA. A copy of the GNU General Public License is 20 | # also available at http://www.gnu.org/copyleft/gpl.html. 21 | 22 | ifs=$IFS 23 | IFS=':' 24 | 25 | files=$(find /usr -type f) 26 | IFS=$ifs 27 | for i in $files 28 | do 29 | if [ `file $i | grep -c 'ELF'` -ne 0 ]; then 30 | if [ `ldd $i 2>/dev/null | grep -c 'not found'` -ne 0 ]; then 31 | echo "$i:" 32 | ldd $i 2>/dev/null | grep 'not found' 33 | fi 34 | fi 35 | done 36 | -------------------------------------------------------------------------------- /root/usr/bin/generate-proxy-cert: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # When booted from ISO, foreman-proxy starts up by default but since 4 | # network is not yet configured, we cannot continue. This makes 5 | # the service to fail. 6 | [ -f /etc/NetworkManager/system-connections/primary ] || exit 101 7 | 8 | source /usr/share/fdi/commonfunc.sh 9 | exportKCL 10 | 11 | DIR=/etc/foreman-proxy 12 | DAYS=${KCL_FDI_PROXY_CERT_DAYS:-999} 13 | WAIT=${KCL_FDI_IPWAIT:-120} 14 | SECONDS=0 15 | while (( SECONDS < $WAIT )); do 16 | sleep 1 17 | COMMON_NAME=$(nmcli -w 1 -t -f IP4.ADDRESS con show primary 2>/dev/null | cut -f2 -d: | cut -f1 -d/) 18 | [ ! -z "$COMMON_NAME" ] && break 19 | COMMON_NAME=$(nmcli -w 1 -t -f IP6.ADDRESS con show primary 2>/dev/null | cut -f2 -d: | cut -f1 -d/) 20 | [ ! -z "$COMMON_NAME" ] && break 21 | logger "Waiting for IP address to generate SSL cert ($SECONDS/$WAIT)" 22 | done 23 | 24 | # Don't fail when IP address was not provided (HTTP can be still used). 25 | [ -z "$COMMON_NAME" ] && COMMON_NAME=discovered 26 | 27 | openssl req -x509 \ 28 | -newkey rsa:2048 \ 29 | -keyout $DIR/key.pem \ 30 | -out $DIR/cert.pem \ 31 | -nodes \ 32 | -subj "/CN=$COMMON_NAME" \ 33 | -rand /dev/urandom \ 34 | -batch \ 35 | -days $DAYS 36 | 37 | chown root:foreman-proxy $DIR/key.pem $DIR/cert.pem 38 | chmod 640 $DIR/key.pem $DIR/cert.pem 39 | -------------------------------------------------------------------------------- /root/usr/bin/nm-prepare: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Deploys NetworkManager configuration according to the kernel command line 4 | # options for bootif/initnet options. When executed with parameter (device 5 | # name) it only configures the particular (secondary) device, otherwise all are 6 | # configured. The script is executed via udev for all secondary network devices and 7 | # via systemd (nm-prepare) for primary interface. 8 | 9 | source /usr/share/fdi/commonfunc.sh 10 | exportKCL 11 | bootif="$(normalizeHwAddr "${BOOTMAC}")" 12 | 13 | configure_secondary_device() { 14 | # device name can still change after configuration is deployed - we don't use it 15 | dev=$(basename $1) 16 | [[ "$dev" == "lo" ]] && return 17 | [[ -f /sys/class/net/$dev/address ]] || return 18 | read mac < "/sys/class/net/$dev/address" 19 | mac="$(normalizeHwAddr "$mac")" 20 | [[ "$mac" == "$bootif" ]] && return 21 | if [[ "${KCL_FDI_INITNET,,}" == "all" ]]; then 22 | autoconnect=true 23 | else 24 | autoconnect=false 25 | fi 26 | echo "Configuring secondary interface via udev script: $mac" 27 | /usr/bin/nm-configure secondary "$mac" "$autoconnect" 28 | } 29 | 30 | if [[ -z "$1" ]]; then 31 | for device in /sys/class/net/*; do 32 | configure_secondary_device $device 33 | done 34 | else 35 | configure_secondary_device $1 36 | fi 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /root/etc/NetworkManager/dispatcher.d/15-get-zip-server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to extract the NEXT_SERVER value from the incoming DHCP lease 4 | # and write it to a place where systemd/profile.d can source it 5 | 6 | # This is only run when the interface is going "up" so we don't interfere 7 | # with the next-server settings on "down" 8 | 9 | zipserver="" 10 | 11 | # create/replace file using a tempfile. 12 | # This allows us to trigger on PathExists inside systemd.path units. 13 | function tmpwriter { 14 | tmpfile="$(TMPDIR="${1%/*}" mktemp)" 15 | cat > "${tmpfile}" 16 | mv "${tmpfile}" "${1}" 17 | } 18 | 19 | if [ $# -ne 2 ] 20 | then 21 | echo "usage: $0 " >&2 22 | echo ' Only action "up" is used by this script.' >&2 23 | exit 1 24 | fi 25 | 26 | if [ "${2}" != "up" ] 27 | then 28 | exit 29 | fi 30 | 31 | iface="${1}" 32 | 33 | read hwaddr < "/sys/class/net/${iface}/address" 34 | 35 | source /usr/share/fdi/commonfunc.sh 36 | exportKCL 37 | 38 | zipserver="${KCL_FDI_ZIPSERVER}" 39 | bootif="$(normalizeHwAddr "${BOOTMAC}")" 40 | 41 | # we process the interface we have booted PXELINUX from 42 | if [ "${hwaddr}" == "${bootif}" ] 43 | then 44 | # kernel cmdline takes precedence over DHCP supplied next-server 45 | if [ -z "${zipserver}" -a -n "${DHCP4_NEXT_SERVER}" ] 46 | then 47 | zipserver="${DHCP4_NEXT_SERVER}" 48 | fi 49 | echo "ZIP_SERVER=${zipserver}" | tmpwriter /etc/default/discovery-zip-server 50 | fi 51 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/screen/ssh.rb: -------------------------------------------------------------------------------- 1 | def screen_ssh 2 | t_desc = Newt::Textbox.new(-1, -1, 39, 3, Newt::FLAG_WRAP) 3 | t_desc.set_text _("Enter root password to unlock the account and enable SSH service:") 4 | e_password = Newt::Entry.new(-1, -1, "", 39, Newt::FLAG_PASSWORD) 5 | b_enable = Newt::Button.new(-1, -1, _("Set and Enable")) 6 | b_disable = Newt::Button.new(-1, -1, _("Disable")) 7 | b_cancel = Newt::Button.new(-1, -1, _("Cancel")) 8 | 9 | main_grid = Newt::Grid.new(1, 3) 10 | but_grid = Newt::Grid.new(3, 1) 11 | 12 | but_grid.set_field(0, 0, Newt::GRID_COMPONENT, b_enable, 0, 0, 0, 0, 0, 0) 13 | but_grid.set_field(1, 0, Newt::GRID_COMPONENT, b_disable, 0, 0, 0, 0, 0, 0) 14 | but_grid.set_field(2, 0, Newt::GRID_COMPONENT, b_cancel, 0, 0, 0, 0, 0, 0) 15 | 16 | main_grid.set_field(0, 0, Newt::GRID_COMPONENT, t_desc, 0, 0, 0, 0, 0, 0) 17 | main_grid.set_field(0, 1, Newt::GRID_COMPONENT, e_password, 0, 0, 0, 0, 0, 0) 18 | main_grid.set_field(0, 2, Newt::GRID_SUBGRID, but_grid, 0, 1, 0, 0, 0, Newt::GRID_FLAG_GROWX) 19 | main_grid.wrapped_window(_("Secure Shell access")) 20 | 21 | f = Newt::Form.new 22 | f.add(t_desc, e_password, b_enable, b_disable, b_cancel) 23 | answer = f.run() 24 | if answer == b_enable 25 | enable_root_account(e_password.get) 26 | elsif answer == b_disable 27 | command("systemctl stop sshd.service") 28 | elsif answer == b_cancel 29 | :screen_welcome 30 | end 31 | :screen_status 32 | end 33 | -------------------------------------------------------------------------------- /root/usr/bin/discovery-start-extensions: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # vim: ts=2:sw=2:et 4 | # 5 | # Copyright (C) 2012-2014 Red Hat, Inc. 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; version 2 of the License. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | # MA 02110-1301, USA. A copy of the GNU General Public License is 20 | # also available at http://www.gnu.org/copyleft/gpl.html. 21 | 22 | # Simple bash script to check for and start the downloaded extension(s) 23 | 24 | # Since we allow multiple zipfile extensions, we require users to put 25 | # autostart scripts in autostart.d, which will then be executed in 26 | # POSIX order, in blocking mode so that they can complete before the 27 | # host is registered. Users are responsible for backgrounding long tasks 28 | # in their own startup scripts. 29 | 30 | if test -d /opt/extension/autostart.d; then 31 | for script in /opt/extension/autostart.d/*; do 32 | test -x "$script" && $script 33 | done 34 | unset script 35 | fi 36 | exit 0 37 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/screen/welcome.rb: -------------------------------------------------------------------------------- 1 | def screen_welcome 2 | text_help, tw, th = Newt.reflow_text(_('Select Manual network setup to select primary interface, configure network (no DHCP required), setup server credentials, add custom facts and trigger auto-provisioning via Discovery rules. This will lead to kernel reload (kexec) into installer. Select Discover with DHCP to select primary interface and proceed with DHCP configuration and standard discovery without any custom facts. This will reboot the host once the system is provisioned either manually or via Discovery rules.'), 60, 5, 5) 3 | t_welcome = Newt::Textbox.new(-1, -1, tw, th, Newt::FLAG_WRAP) 4 | t_welcome.set_text(text_help) 5 | 6 | b_proceed = Newt::Button.new(-1, -1, _("Manual network setup")) 7 | b_discover = Newt::Button.new(-1, -1, _("Discover with DHCP")) 8 | 9 | main_grid = Newt::Grid.new(1, 2) 10 | but_grid = Newt::Grid.new(2, 1) 11 | 12 | but_grid.set_field(0, 0, Newt::GRID_COMPONENT, b_proceed, 0, 0, 0, 0, 0, 0) 13 | but_grid.set_field(1, 0, Newt::GRID_COMPONENT, b_discover, 0, 0, 0, 0, 0, 0) 14 | 15 | main_grid.set_field(0, 0, Newt::GRID_COMPONENT, t_welcome, 0, 0, 0, 1, 0, 0) 16 | main_grid.set_field(0, 1, Newt::GRID_SUBGRID, but_grid, 0, 0, 0, 0, 0, Newt::GRID_FLAG_GROWX) 17 | main_grid.wrapped_window(_("Manual/PXE-less provisioning workflow")) 18 | 19 | f = Newt::Form.new 20 | f.add(t_welcome, b_proceed, b_discover) 21 | answer = f.run() 22 | if answer == b_discover 23 | [:screen_primary_iface, true] 24 | elsif answer == b_proceed 25 | :screen_primary_iface 26 | else 27 | :quit 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /root/usr/share/fdi/facts/pcicards.rb: -------------------------------------------------------------------------------- 1 | # PCI Card Enumeration Script 2 | 3 | # This is what lspci output looks like: 4 | # [empty line] 5 | # Slot: 01:00.0 6 | # Class: RAID bus controller 7 | # Vendor: LSI Logic / Symbios Logic 8 | # Device: MegaRAID SAS-3 3108 [Invader] 9 | # SVendor: IBM 10 | # SDevice: Device 0454 11 | # PhySlot: 4 12 | # Rev: 02 13 | # NUMANode: 0 14 | # [empty line] 15 | # [another section] 16 | 17 | # Expected output: 18 | # pci_device_0 => NetXtreme BCM5719 Gigabit Ethernet PCIe 19 | # pci_device_1 => SFC9220 10/40G Ethernet Controller 20 | # pci_device_2 => SFC9220 10/40G Ethernet Controller 21 | # pci_device_4 => MegaRAID SAS-3 3108 [Invader] 22 | 23 | require 'facter' 24 | 25 | # Read lspci 26 | begin 27 | lspci_output = %x{lspci -mm -v} 28 | rescue => e 29 | warn "Invocation of lspci failed: #{e}" 30 | lspci_output = '' 31 | end 32 | 33 | # Filter relevant data 34 | all_devices = {} 35 | current_element = {} 36 | lspci_output.each_line do |line| 37 | line.chomp! 38 | # Newline triggers evaluation of values read earlier 39 | if line == '' then 40 | # Only store PCI devices that report a physical PCI slot 41 | if current_element.has_key?('physlot') then 42 | all_devices[current_element['physlot']] = current_element['device'] 43 | end 44 | 45 | # Clear values, process next PCI device 46 | current_element = {} 47 | next 48 | end 49 | 50 | key, value = line.split(/:\t/, 2) 51 | key.downcase! 52 | 53 | current_element[key] = value 54 | end 55 | 56 | # Convert stored data to facts: 57 | all_devices.each do |slot, model| 58 | Facter.add("pci_device_#{slot}") do 59 | setcode { model.chomp } 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /root/usr/share/fdi/script-helpers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /etc/default/discovery 3 | source /usr/share/fdi/commonfunc.sh 4 | exportKCL 5 | 6 | # helper functions 7 | clean_nm() { 8 | rm -f /etc/NetworkManager/system-connections/* 9 | } 10 | 11 | no_tui() { 12 | touch /tmp/disable-menu 13 | } 14 | 15 | reload_nm() { 16 | # in PXE-less mode NM is not yet started - this will fail 17 | nmcli connection reload 2>/dev/null || true 18 | } 19 | 20 | discover_now() { 21 | nohup /usr/bin/discovery-register &> /tmp/discovery-script-register.log & 22 | } 23 | 24 | enable_discovery() { 25 | systemctl enable discovery-register 26 | } 27 | 28 | hwaddr() { 29 | HWADDR=$(cat /sys/class/net/$1/address) 30 | } 31 | 32 | cfg_eth() { 33 | DEVICE=${1:-eth0} 34 | NAME=${2:-$DEVICE} 35 | cat >/etc/sysconfig/network-scripts/ifcfg-$DEVICE </etc/sysconfig/network-scripts/ifcfg-$DEVICE </etc/sysconfig/network-scripts/ifcfg-slave-$DEV < "/tmp/facts/$1" 95 | } 96 | 97 | set +x 98 | -------------------------------------------------------------------------------- /root/usr/share/fdi/facts/ethtool.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # Quickfix for regression introduced in FDI 3.7.0 4 | # See: https://community.theforeman.org/t/foreman-discovery-image-3-7/21642 5 | # 6 | # To test: 7 | # $ FACTERLIB=/usr/share/fdi/facts facter 8 | 9 | require 'facter' 10 | 11 | Facter.add(:ethtool, :timeout => 10) do 12 | confine kernel: "Linux" 13 | 14 | confine :networking do |value| 15 | value && value['interfaces'] 16 | end 17 | 18 | confine do 19 | Facter::Core::Execution.which('ethtool') != nil 20 | end 21 | 22 | setcode do 23 | interface_info = {} 24 | Facter.value(:networking)['interfaces'].keys.each do |interface| 25 | Facter.debug("Running ethtool on interface #{interface}") 26 | output = Facter::Core::Execution.exec("ethtool #{interface} 2>/dev/null") 27 | if output.nil? 28 | Facter.debug("Execution of ethtool on interface #{interface} failed") 29 | else 30 | attributes = {} 31 | output.each_line do |line| 32 | next if line.nil? or line == "" 33 | case line.strip 34 | when /Speed: (.*)Mb/ 35 | attributes[:speed] = $1 36 | when /Duplex: (.*)/ 37 | attributes[:duplex] = $1.downcase 38 | when /Port: (.*)/ 39 | attributes[:port] = $1 40 | when /Auto-negotiation: (.*)/ 41 | attributes[:auto_negotiation] = ($1 == 'on').to_s 42 | when /^Wake-on: (.*)/ 43 | attributes[:wol] = $1.include?('g') 44 | when /Link detected: (.*)/ 45 | attributes[:link] = ($1 == 'yes').to_s 46 | end 47 | end 48 | 49 | if attributes.keys.empty? 50 | Facter.debug("Running ethtool on #{interface} didn't give any information") 51 | else 52 | interface_info[interface] = attributes 53 | end 54 | end 55 | end 56 | interface_info 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/screen/network.rb: -------------------------------------------------------------------------------- 1 | def screen_network mac, vlan_id, ip = cmdline('fdi.pxip', ''), gw = cmdline('fdi.pxgw', ''), dns = cmdline('fdi.pxdns', '') 2 | Newt::Screen.centered_window(75, 20, _("Network configuration")) 3 | f = Newt::Form.new 4 | t_desc = Newt::Textbox.new(2, 2, 70, 6, Newt::FLAG_WRAP) 5 | t_desc.set_text _("Provide network configuration for the selected primary interface. Use CIDR netmask notation (e.g. 192.168.1.1/24) for the IPv4 or IPv6 address.") 6 | l_ip = Newt::Label.new(2, 8, _("Address:")) 7 | l_gw = Newt::Label.new(2, 10, _("Gateway:")) 8 | l_dns = Newt::Label.new(2, 12, _("DNS:")) 9 | t_ip = Newt::Entry.new(16, 8, ip.to_s, 55, Newt::FLAG_SCROLL) 10 | t_gw = Newt::Entry.new(16, 10, gw.to_s, 55, Newt::FLAG_SCROLL) 11 | t_dns = Newt::Entry.new(16, 12, dns.to_s, 55, Newt::FLAG_SCROLL) 12 | b_ok = Newt::Button.new(24, 15, _("Next")) 13 | b_cancel = Newt::Button.new(36, 15, _("Cancel")) 14 | items = [t_desc, l_ip, l_gw, l_dns, t_ip, t_gw, t_dns] 15 | if cmdline('fdi.pxip') 16 | f.add(b_ok, b_cancel, *items) 17 | else 18 | f.add(*items, b_ok, b_cancel) 19 | end 20 | answer = f.run 21 | if answer == b_ok 22 | ip = t_ip.get 23 | gw = t_gw.get 24 | dns = t_dns.get 25 | begin 26 | IPAddr.new(ip); IPAddr.new(gw); IPAddr.new(dns) 27 | rescue Exception => e 28 | Newt::Screen.win_message(_("Invalid IP"), _("OK"), _("Provide valid CIDR ipaddress with a netmask, gateway and one DNS server")) 29 | return [:screen_network, mac, vlan_id, ip, gw, dns] 30 | end 31 | action = Proc.new { configure_network true, mac, ip, gw, dns, vlan_id } 32 | [:screen_info, action, _("Configuring network. This operation can take several minutes to complete."), _("Unable to bring up network"), 33 | [:screen_foreman, mac, gw], 34 | [:screen_network, mac, vlan_id, ip, gw, dns]] 35 | else 36 | :screen_welcome 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /root/usr/share/locale/fdi/Makefile: -------------------------------------------------------------------------------- 1 | # vim: noet:ts=4:sw=4 filetype=make 2 | # 3 | # make build (default) - generate MO files 4 | # make check - check translations using translate-tool 5 | # make update - download and merge translations from Transifex 6 | # 7 | DOMAIN = foreman-discovery-image 8 | VERSION = $(shell git describe --abbrev=0 --tags) 9 | POTFILE = $(DOMAIN).pot 10 | MOFILE = $(DOMAIN).mo 11 | POFILES = $(shell find . -name '$(DOMAIN).po') 12 | MOFILES = $(patsubst %.po,%.mo,$(POFILES)) 13 | POXFILES = $(patsubst %.po,%.pox,$(POFILES)) 14 | EDITFILES = $(patsubst %.po,%.edit.po,$(POFILES)) 15 | 16 | %.mo: %.po 17 | mkdir -p $(shell dirname $@)/LC_MESSAGES 18 | msgfmt -o $(shell dirname $@)/LC_MESSAGES/$(MOFILE) $< 19 | touch $(shell dirname $@)/LC_MESSAGES/$(MOFILE) 20 | 21 | build: $(MOFILES) 22 | 23 | %.pox: %.po 24 | msgfmt -c $< 25 | pofilter --nofuzzy -t variables -t blank -t urls -t emails -t long -t newlines \ 26 | -t endwhitespace -t endpunc -t puncspacing -t options -t printf -t validchars --gnome $< > $@ 27 | cat $@ 28 | ! grep -q msgid $@ 29 | 30 | %.edit.po: 31 | touch $@ 32 | 33 | check: $(POXFILES) 34 | 35 | uniq-po: 36 | for f in $(shell find ./ -name "*.po") ; do \ 37 | msguniq $$f -o $$f ; \ 38 | done 39 | 40 | tx-pull: $(EDITFILES) 41 | tx pull -f 42 | for f in $(EDITFILES) ; do \ 43 | sed -i 's/^\("Project-Id-Version: \).*$$/\1$(DOMAIN) $(VERSION)\\n"/' $$f; \ 44 | done 45 | 46 | update: tx-pull $(MOFILES) 47 | git add $(POFILES) $(POTFILE) */LC_MESSAGES 48 | git commit -m "i18n - pulling from tx" 49 | @echo 50 | @echo Changes commited! 51 | @echo 52 | 53 | extract: 54 | rxgettext \ 55 | --sort-output \ 56 | --sort-by-msgid \ 57 | --no-wrap \ 58 | --no-location \ 59 | -o ${DOMAIN}.pot \ 60 | --package-name=${DOMAIN} \ 61 | --package-version="${VERSION}" \ 62 | --msgid-bugs-address=foreman-dev@googlegroups.com \ 63 | --copyright-holder="Foreman developers" \ 64 | --copyright-year=$(shell date +%Y) \ 65 | $(shell find ../../ruby/vendor_ruby -type f -name \*.rb -o -name \*.erb) 66 | -------------------------------------------------------------------------------- /root/usr/share/fdi/facts/disks_partition_table.rb: -------------------------------------------------------------------------------- 1 | # 2 | # $ FACTERLIB=/usr/share/fdi/facts tfm-ruby /opt/theforeman/tfm/root/usr/bin/facter 3 | # 4 | 5 | require 'facter' 6 | 7 | class PartedInfo 8 | 9 | attr_accessor :units, :size, :transport_type, :logical_sector_size, :physical_sector_size, :partition_table_type, :model_name, :flags 10 | 11 | def initialize(disk) 12 | parted_lines = `parted --machine --script /dev/#{disk} print 2>/dev/null`.split("\n", -1) 13 | # https://git.savannah.gnu.org/cgit/parted.git/tree/parted/parted.c?h=v3.5#n1116 14 | if parted_lines.length >= 2 && 15 | /^(?CHS|CYL|BYT);$/ =~ parted_lines[0] && 16 | /^\/.+?:(?.+?):(?.+?):(?\d+):(?\d+):(?.+?):(?.+?):(?.*?);$/ =~ parted_lines[1] 17 | @units = units 18 | @size = size 19 | @transport_type = transport_type 20 | @logical_sector_size = logical_sector_size.to_i 21 | @physical_sector_size = physical_sector_size.to_i 22 | @partition_table_type = partition_table_type 23 | @model_name = model_name 24 | @flags = flags.length > 0 ? flags : nil 25 | end 26 | end 27 | end 28 | 29 | Facter.add(:disks_partition_table) do 30 | confine kernel: "Linux" 31 | 32 | confine :disks do |value| 33 | value != nil 34 | end 35 | 36 | confine :identity do |identity| 37 | identity['uid'] === 0 38 | end 39 | 40 | setcode do 41 | hash = {} 42 | Facter.value(:disks).each_key do |disk| 43 | parted_info = PartedInfo.new(disk) 44 | hash[disk] = { 45 | :units => parted_info.units, 46 | :size => parted_info.size, 47 | :transport_type => parted_info.transport_type, 48 | :logical_sector_size => parted_info.logical_sector_size, 49 | :physical_sector_size => parted_info.physical_sector_size, 50 | :partition_table_type => parted_info.partition_table_type, 51 | :model_name => parted_info.model_name, 52 | :flags => parted_info.flags 53 | } 54 | end 55 | hash 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb: -------------------------------------------------------------------------------- 1 | def screen_countdown discovery_only = false 2 | text_help, tw, th = Newt.reflow_text(_('This system will attempt to configure all interfaces via DHCP and discover itself by sending hardware facts to Foreman instance. To interrupt this behavior, press a key to be able to do manual network configuration and additional provisioning settings.'), 60, 5, 5) 3 | t = Newt::Textbox.new(-1, -1, tw, th, Newt::FLAG_WRAP) 4 | t.set_text(text_help) 5 | 6 | secs = cmdline("fdi.countdown", 45).to_i rescue 45 7 | l_press = Newt::Label.new(-1, -1, "< " + _('Press any key') + " (#{secs}s) >") 8 | 9 | main_grid = Newt::Grid.new(1, 2) 10 | but_grid = Newt::Grid.new(1, 1) 11 | 12 | but_grid.set_field(0, 0, Newt::GRID_COMPONENT, l_press, 0, 0, 0, 0, 0, 0) 13 | 14 | main_grid.set_field(0, 0, Newt::GRID_COMPONENT, t, 0, 0, 0, 1, 0, 0) 15 | main_grid.set_field(0, 1, Newt::GRID_SUBGRID, but_grid, 0, 0, 0, 0, 0, Newt::GRID_FLAG_GROWX) 16 | main_grid.wrapped_window(_("Welcome to Foreman Discovery")) 17 | 18 | f = Newt::Form.new 19 | f.add(t, l_press) 20 | f.draw 21 | key_was_pressed = false 22 | unless discovery_only 23 | sec = secs 24 | while sec > 0 25 | l_press.set_text("< " + _('Press any key') + " ... (#{sec}s) >") 26 | sec = sec - 1 27 | Newt::Screen.refresh 28 | if (STDIN.read_nonblock(1) rescue nil) 29 | key_was_pressed = true 30 | break 31 | end 32 | sleep 1 33 | end 34 | end 35 | 36 | if key_was_pressed 37 | :screen_welcome 38 | else 39 | start_discovery_service 40 | # additional countdown to let discovery-register do its work 41 | sec = secs 42 | while sec > 0 43 | l_press.set_text("< " + _('Discovery') + " ... (#{sec}s) >") 44 | sec = sec - 1 45 | Newt::Screen.refresh 46 | # break countdown on keypress or IPC 47 | break if (STDIN.read_nonblock(1) rescue nil) 48 | break if File.exist?("/tmp/discovery-http-success") 49 | break if File.exist?("/tmp/discovery-http-failure") 50 | sleep 1 51 | end 52 | :screen_status 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/screen/foreman.rb: -------------------------------------------------------------------------------- 1 | def screen_foreman mac = nil, gw = nil, proxy_url = cmdline('proxy.url'), proxy_type = cmdline('proxy.type') 2 | Newt::Screen.centered_window(59, 20, _("Credentials")) 3 | 4 | f = Newt::Form.new 5 | 6 | t_desc = Newt::Textbox.new(2, 2, 54, 6, Newt::FLAG_WRAP) 7 | t_desc.set_text _("Provide full URL (http(s)://host:PORT) to the Server or Foreman Proxy according to the type selected. Ports are usually 443, 8443, 8448 or 9090 according to configuration.") 8 | 9 | l_url = Newt::Label.new(2, 8, _("Server URL:")) 10 | l_type = Newt::Label.new(2, 10, _("Connection type:")) 11 | 12 | t_url = Newt::Entry.new(20, 8, "", 36, Newt::FLAG_SCROLL) 13 | 14 | r_server = Newt::RadioButton.new(20, 10, _("Server"), 0, nil) 15 | r_proxy = Newt::RadioButton.new(32, 10, _("Foreman Proxy"), 1, r_server) 16 | b_ok = Newt::Button.new(34, 15, _("Next")) 17 | b_cancel = Newt::Button.new(46, 15, _("Cancel")) 18 | proxy_type ||= 'foreman' 19 | t_url.set(proxy_url, 1) if proxy_url 20 | 21 | if proxy_type == 'proxy' 22 | r_proxy.set_current 23 | else 24 | r_server.set_current 25 | end 26 | 27 | items = [t_desc, l_type, l_url, t_url, r_server, r_proxy] 28 | 29 | if proxy_url 30 | f.add(b_ok, b_cancel, *items) 31 | else 32 | f.add(*items, b_ok, b_cancel) 33 | end 34 | 35 | answer = f.run 36 | 37 | if answer == b_ok 38 | begin 39 | proxy_type = r_server.get_current == r_server ? 'foreman' : 'proxy' 40 | url = t_url.get 41 | 42 | raise _("No URL was provided") if url.size < 1 43 | 44 | proxy_url = URI.parse(url) 45 | 46 | unless [443, 3000, 5000, 8443, 8448, 9090].include? proxy_url.port 47 | Newt::Screen.win_message(_("Warning"), _("OK"), _("Port %s is likely not correct, expected ports are 443, 8443 or 9090") % proxy_url.port) 48 | end 49 | rescue Exception => e 50 | Newt::Screen.win_message(_("Invalid URL"), _("OK"), _("Not a valid URL") + ": #{url} (#{e})") 51 | return [:screen_foreman, mac, gw, url, proxy_type] 52 | end 53 | [:screen_facts, mac, proxy_url, proxy_type] 54 | else 55 | :screen_welcome 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/screen/facts.rb: -------------------------------------------------------------------------------- 1 | def screen_facts mac, proxy_url, proxy_type 2 | custom_facts = new_custom_facts(mac) 3 | 4 | b_confirm = Newt::Button.new(-1, -1, _("Confirm")) 5 | b_cancel = Newt::Button.new(-1, -1, _("Cancel")) 6 | 7 | top_grid = Newt::Grid.new(1, 2) 8 | facts_grid = Newt::Grid.new(4, 9) 9 | but_grid = Newt::Grid.new(2, 1) 10 | 11 | but_grid.set_field(0, 0, Newt::GRID_COMPONENT, b_confirm, 0, 0, 2, 0, 0, 0) 12 | but_grid.set_field(1, 0, Newt::GRID_COMPONENT, b_cancel, 0, 0, 2, 0, 0, 0) 13 | 14 | names = []; values = []; labels = []; labels_sep = [] 15 | (0..8).each_with_index do |ix, _| 16 | labels[ix] = Newt::Label.new(-1, -1, (_("Fact %s name") % ('#' + (ix + 1).to_s)) + ' ') 17 | labels_sep[ix] = Newt::Label.new(-1, -1, ' ' + _('value') + ' ') 18 | names[ix] = Newt::Entry.new(-1, -1, cmdline("fdi.pxfactname#{ix + 1}").to_s, 15, Newt::FLAG_SCROLL) 19 | values[ix] = Newt::Entry.new(-1, -1, cmdline("fdi.pxfactvalue#{ix + 1}").to_s, 15, Newt::FLAG_SCROLL) 20 | facts_grid.set_field(0, ix, Newt::GRID_COMPONENT, labels[ix], 0, 0, 0, 0, 0, 0) 21 | facts_grid.set_field(1, ix, Newt::GRID_COMPONENT, names[ix], 0, 0, 0, 0, 0, 0) 22 | facts_grid.set_field(2, ix, Newt::GRID_COMPONENT, labels_sep[ix], 0, 0, 0, 0, 0, 0) 23 | facts_grid.set_field(3, ix, Newt::GRID_COMPONENT, values[ix], 0, 0, 0, 0, 0, 0) 24 | end 25 | 26 | top_grid.set_field(0, 0, Newt::GRID_SUBGRID, facts_grid, 0, 0, 0, 0, 0, 0) 27 | top_grid.set_field(0, 1, Newt::GRID_SUBGRID, but_grid, 0, 2, 0, 0, 0, 0) 28 | 29 | top_grid.wrapped_window(_("Custom facts")) 30 | 31 | f = Newt::Form.new 32 | f.add(b_confirm, b_cancel) 33 | (0..8).each_with_index do |ix, _| 34 | f.add(labels[ix], names[ix], labels_sep[ix], values[ix]) 35 | end 36 | answer = f.run 37 | if answer == b_confirm 38 | (0..8).each_with_index do |ix, _| 39 | custom_facts[names[ix].get] = values[ix].get if names[ix].get && values[ix].get 40 | end 41 | if perform_upload(proxy_url, proxy_type, custom_facts) 42 | [:screen_status, generate_info(' - ' + _('awaiting kexec into installer'))] 43 | else 44 | [:screen_status, generate_info(' - ' + _('fact upload failed'))] 45 | end 46 | else 47 | :screen_welcome 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /20-packages.ks: -------------------------------------------------------------------------------- 1 | %packages --excludedocs --inst-langs en_US.utf8 2 | # from lorax examples 3 | @core 4 | kernel 5 | kernel-modules 6 | kernel-modules-extra 7 | grub2-efi 8 | grub2 9 | shim 10 | syslinux 11 | dracut-config-generic 12 | -dracut-config-rescue 13 | dracut-network 14 | dracut-squash 15 | tar 16 | isomd5sum 17 | 18 | # required by lorax 19 | dracut-live 20 | # required by bootloader 21 | centos-logos 22 | memtest86+ 23 | biosdevname 24 | vim-minimal 25 | 26 | # Facter 27 | rubygem-facter 28 | ethtool 29 | lldpad 30 | net-tools 31 | dmidecode 32 | virt-what 33 | 34 | # Foreman proxy 35 | foreman-discovery-image-service 36 | curl 37 | wget 38 | passwd 39 | sudo 40 | OpenIPMI 41 | ipmitool 42 | openssl 43 | elfutils-libs 44 | 45 | # Interactive discovery 46 | foreman-discovery-image-service-tui 47 | kexec-tools 48 | kbd 49 | 50 | # Debugging support 51 | less 52 | file 53 | 54 | # SSH access 55 | openssh-clients 56 | openssh-server 57 | 58 | # Starts all interfaces automatically for us 59 | NetworkManager 60 | 61 | # Used to update code at runtime 62 | unzip 63 | 64 | # Enable stripping 65 | binutils 66 | 67 | # For UEFI/Secureboot support 68 | efibootmgr 69 | grub2-efi 70 | grub2-efi-x64 71 | grub2-efi-x64-cdboot 72 | shim 73 | shim-x64 74 | 75 | # Useful utilities for users who use FDI for image-based provisioning 76 | grub2-tools 77 | e2fsprogs 78 | parted 79 | mdadm 80 | xfsprogs 81 | e2fsprogs 82 | bzip2 83 | tcpdump 84 | 85 | ###################### 86 | # Packages to Remove # 87 | ###################### 88 | # 89 | # Some ideas from: 90 | # 91 | # https://github.com/weldr/lorax/blob/rhel9-branch/share/templates.d/99-generic/runtime-cleanup.tmpl 92 | 93 | -geoclue2 94 | 95 | # Audio 96 | -opus 97 | -libtheora 98 | -libvisual 99 | -flac-libs 100 | -gsm 101 | -avahi-glib 102 | -ModemManager-glib 103 | -flac 104 | -gstreamer-tools 105 | -libsndfile 106 | -pulseaudio* 107 | -sound-theme-freedesktop 108 | -speech-dispatcher 109 | 110 | -checkpolicy 111 | -selinux* # remove all selinux packages 112 | -usermode 113 | -usermode-gtk 114 | -pinentry 115 | 116 | ## no storage device monitoring 117 | -device-mapper-event 118 | -dmraid-events 119 | -sgpio 120 | -notification-daemon 121 | -logrotate 122 | 123 | # various other things we remove to save space 124 | -db4-utils 125 | -jasper-libs 126 | -libXxf86misc 127 | -libhbaapi 128 | -libhbalinux 129 | -libtiff 130 | -mailx 131 | -makebootfat 132 | -mobile-broadband-provider-info 133 | -rmt 134 | -system-config-firewall-base 135 | -xorg-x11-font-utils 136 | -xorg-x11-server-common 137 | -firewalld 138 | %end 139 | -------------------------------------------------------------------------------- /root/usr/bin/discovery-register: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | # 3 | # vim: ts=2:sw=2:et 4 | # 5 | # Copyright (C) 2012-2014 Red Hat, Inc. 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; version 2 of the License. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | # MA 02110-1301, USA. A copy of the GNU General Public License is 20 | # also available at http://www.gnu.org/copyleft/gpl.html. 21 | 22 | PROXY_CACHE = '/tmp/proxy_cache' 23 | 24 | require 'fileutils' 25 | require 'net/http' 26 | require 'net/https' 27 | require 'uri' 28 | require 'socket' 29 | require 'resolv' 30 | 31 | # For comparison 32 | require 'rubygems' 33 | require 'facter' 34 | require 'yaml' 35 | require 'json' 36 | 37 | # Our lib 38 | require 'discovery' 39 | 40 | def write_cache(data) 41 | File.open(PROXY_CACHE, 'w') {|f| f.write(data) } 42 | end 43 | 44 | def read_cache 45 | File.read(PROXY_CACHE) 46 | rescue => _ 47 | "empty cache" 48 | end 49 | 50 | def clear_cache 51 | File.unlink(PROXY_CACHE) if File.exists?(PROXY_CACHE) 52 | end 53 | 54 | Signal.trap("HUP") do 55 | Facter.clear 56 | end 57 | 58 | # Script was (re)started - delete old data 59 | clear_cache 60 | 61 | log_msg "Some interesting facts about this system:" 62 | facts = Hash[Facter.to_hash.select {|k,v| k =~ /address|hardware|manufacturer|productname|memorytotal/}] 63 | facts.keys.sort.each {|k| log_msg " #{k}: #{facts[k]}"} 64 | 65 | # check every 15 minutes but only upload on changes 66 | upload_sleep = cmdline("fdi.uploadsleep", 60 * 15).to_i rescue (60 * 15) 67 | extra_initial_uploads = cmdline("fdi.cachefacts", 0).to_i rescue 0 68 | while true do 69 | uninteresting_facts=/kernel|operatingsystem|osfamily|ruby|path|time|swap|free|filesystem|version|selinux/i 70 | # force facter to do new system scan (we default to 15 minute intervals which is safe) 71 | Facter.clear 72 | facts = Facter.to_hash.reject! {|k,v| k =~ uninteresting_facts } 73 | unless YAML.load(read_cache) == facts 74 | log_msg "Fact cache invalid, reloading to foreman" 75 | write_cache(YAML.dump(facts)) if upload 76 | else 77 | log_msg "No change in facts (next check in #{upload_sleep} seconds)" 78 | end 79 | sleep upload_sleep 80 | if extra_initial_uploads > 0 81 | log_msg "Performing extra initial fact upload as defined by fdi.cachefacts (#{i} left)" 82 | clear_cache 83 | extra_initial_uploads -= 1 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/screen/status.rb: -------------------------------------------------------------------------------- 1 | def generate_info extra_status = '', server = discover_server, type = proxy_type 2 | status = _("N/A") + ' (' + _("use Status to update") + ')' 3 | response = _("N/A") 4 | if File.exist?(f = '/tmp/discovery-http-success') 5 | status = "SUCCESS #{extra_status}" 6 | response = wrap(IO.read(f), 65) 7 | elsif File.exist?(f = '/tmp/discovery-http-failure') 8 | status = "FAILURE #{extra_status}" 9 | response = wrap(IO.read(f), 65) 10 | elsif extra_status != '' 11 | status = extra_status 12 | response = '' 13 | end 14 | < /etc/hostname 77 | 78 | echo " * locking root account" 79 | passwd -l root 80 | 81 | echo " * store list of packages sorted by size" 82 | rpm -qa --queryformat '%{SIZE} %{NAME} %{VERSION}%{RELEASE}\n' | sort -n -r > /usr/PACKAGES-LIST 83 | 84 | echo " * cleaning up yum cache and removing rpm database" 85 | dnf autoremove -y 86 | dnf clean all 87 | 88 | # no more python loading after this step 89 | echo " * removing python precompiled *.pyc files" 90 | find /usr/lib64/python*/ /usr/lib/python*/ -name *py[co] -print0 | xargs -0 rm -f 91 | %end 92 | 93 | %post --nochroot 94 | echo " * disquieting the boot process" 95 | sed -i -e's/ rhgb//g' -e's/ quiet//g' $LIVE_ROOT/isolinux/isolinux.cfg 96 | %end 97 | -------------------------------------------------------------------------------- /root/usr/bin/nm-configure: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # vim: ts=2:sw=2:et 3 | 4 | source /usr/share/fdi/commonfunc.sh 5 | exportKCL 6 | bootif="$(normalizeHwAddr "${BOOTMAC}")" 7 | mac=${2:-$bootif} 8 | timeout=${KCL_FDI_DHCP_TIMEOUT:-300} 9 | sendhost=${KCL_FDI_DHCP_SENDHOST:-false} 10 | ipv4_method=${KCL_FDI_IPV4_METHOD:-auto} 11 | ipv6_method=${KCL_FDI_IPV6_METHOD:-auto} 12 | ctype="802-3-ethernet" 13 | 14 | [[ "$sendhost" == "false" ]] || sendhost=true 15 | 16 | deploy_config() { 17 | chown root:root $1 18 | chmod 600 $1 19 | mv $1 $2 20 | } 21 | 22 | usage() { 23 | echo "Usage: " 24 | echo " $0 primary MAC_ADDRESS [VLAN_ID]" 25 | echo " $0 primary-static MAC_ADDRESS IP4_ADDR/CIDR IP4_GW IP4_DNS [VLAN_ID]" 26 | echo " $0 primary-static6 MAC_ADDRESS IP6_ADDR/CIDR IP6_GW IP6_DNS [VLAN_ID]" 27 | echo " $0 secondary MAC_ADDRESS AUTOCONNECT (true/false)" 28 | } 29 | 30 | [[ -z "$mac" ]] && echo "MAC address was not provided or detected, leaving unconfigured" && exit 0 31 | 32 | function cleanup() { 33 | [ -f $TMP_CFG ] && rm -f $TMP_CFG 34 | } 35 | TMP_CFG=$(mktemp) 36 | trap cleanup EXIT SIGINT SIGTERM 37 | 38 | if [[ "$1" == "primary-static" ]]; then 39 | ip=$3 40 | gw=$4 41 | dns=$5 42 | vlanid=${6:-$KCL_FDI_VLAN_PRIMARY} 43 | if [[ "$vlanid" != "" ]]; then 44 | ctype="vlan" 45 | vlan_section="[vlan]"$'\n'"id=$vlanid" 46 | else 47 | vlan_section="" 48 | fi 49 | script=/etc/NetworkManager/system-connections/primary 50 | cat > $TMP_CFG < $TMP_CFG < $TMP_CFG < $TMP_CFG < 5 | # 6 | #Licensed under the Apache License, Version 2.0 (the "License"); 7 | #you may not use this file except in compliance with the License. 8 | #You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | #Unless required by applicable law or agreed to in writing, software 13 | #distributed under the License is distributed on an "AS IS" BASIS, 14 | #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | #See the License for the specific language governing permissions and 16 | #limitations under the License. 17 | 18 | # Fact: 19 | # lldp_neighbor_chassisid_ 20 | # lldp_neighbor_mngaddr_ipv4_ 21 | # lldp_neighbor_mngaddr_ipv6_ 22 | # lldp_neighbor_mtu_ 23 | # lldp_neighbor_portid_ 24 | # lldp_neighbor_sysname_ 25 | # lldp_neighbor_pvid_ 26 | # 27 | # Purpose: 28 | # Return information about the host's LLDP neighbors. 29 | # 30 | # Resolution: 31 | # On hosts with the lldptool binary, send queries to the lldpad for each of 32 | # the host's Ethernet interfaces and parse the output. 33 | # 34 | # Caveats: 35 | # Assumes that the connected Ethernet switch is sending LLDPDUs, Open-LLDP 36 | # (lldpad) is running, and lldpad is configured to receive LLDPDUs on each 37 | # Ethernet interface. 38 | # 39 | # Authors: 40 | # Mike Arnold 41 | # 42 | # Copyright: 43 | # Copyright (C) 2012 Mike Arnold, unless otherwise noted. 44 | # 45 | 46 | # http://www.ruby-forum.com/topic/3418285#1040695 47 | module Enumerable 48 | def grep_v(cond) 49 | select {|x| not cond === x} 50 | end 51 | end 52 | 53 | if File.exists?('/usr/sbin/lldptool') 54 | lldp = { 55 | # LLDP Name Numeric value 56 | 'chassisID' => '1', 57 | 'portID' => '2', 58 | 'sysName' => '5', 59 | 'mngAddr_ipv4' => '8', 60 | 'mngAddr_ipv6' => '8', 61 | 'PVID' => '0x0080c201', 62 | 'MTU' => '0x00120f04', 63 | } 64 | 65 | # Remove interfaces that pollute the list (like lo and bond0). 66 | Dir.glob("/sys/class/net/*").map{|x| File.basename(x).to_s}.grep_v(/^lo$|^bond[0-9]/).each do |interface| 67 | # Loop through the list of LLDP TLVs that we want to present as facts. 68 | lldp.each_pair do |key, value| 69 | Facter.add("lldp_neighbor_#{key}_#{interface}") do 70 | setcode do 71 | result = nil 72 | output = Facter::Util::Resolution.exec("lldptool get-tlv -n -i #{interface} -V #{value} 2>/dev/null") 73 | if not output.nil? 74 | case key 75 | when 'sysName', 'MTU' 76 | output.split("\n").each do |line| 77 | result = $1 if line.match(/^\s+(.*)/) 78 | end 79 | when 'chassisID' 80 | output.split("\n").each do |line| 81 | ether = $1 if line.match(/MAC:\s+(.*)/) 82 | result = ether&.tr('-', ':')&.downcase 83 | end 84 | when 'portID' 85 | output.split("\n").each do |line| 86 | result = $1 if line.match(/(?:Ifname|Local):\s+(.*)/) 87 | end 88 | when 'mngAddr_ipv4' 89 | output.split("\n").each do |line| 90 | result = $1 if line.match(/IPv4:\s+(.*)/) 91 | end 92 | when 'mngAddr_ipv6' 93 | output.split("\n").each do |line| 94 | result = $1 if line.match(/IPv6:\s+(.*)/) 95 | end 96 | when 'PVID' 97 | output.split("\n").each do |line| 98 | result = $1.to_i if line.match(/(?:Info|PVID):\s+(.*)/) 99 | end 100 | else 101 | # case default 102 | result = nil 103 | end 104 | else 105 | # No output from lldptool 106 | result = nil 107 | end 108 | result 109 | end 110 | end 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /aux/remaster/discovery-remaster: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # lorax-based build (EL8+) 4 | EFIBOOTPATH=images/efiboot.img 5 | 6 | # livecd-creator build (EL7) 7 | #EFIBOOTPATH=isolinux/efiboot.img 8 | 9 | if [ -z "$2" ]; then 10 | echo "Usage: $0 fdi-bootable-x.y.z.iso 'proxy.url=https://192.168.9.1:443 proxy.type=foreman fdi.xyz=abc...' [output.iso]" 11 | exit 2 12 | fi 13 | 14 | REQ_CMDS="guestmount dd mkisofs isohybrid implantisomd5 mcopy" 15 | if ! which $REQ_CMDS >/dev/null; then 16 | echo "Install required tools: $REQ_CMDS" 17 | exit 3 18 | fi 19 | 20 | function cleanup() { 21 | echo "Cleaning up temporary directory..." 22 | [ -d $TMP_NEW ] && rm -rf $TMP_NEW 23 | } 24 | 25 | TMP_NEW=$(mktemp -d) 26 | trap cleanup EXIT 27 | 28 | TIMESTAMP=$(date +%y%m%d_%H%M%S) 29 | OUT_ISO=${1/.iso/-$TIMESTAMP}.iso 30 | [ ! -z "$3" ] && OUT_ISO=$3 31 | 32 | echo "Copying contents to temporary directory..." 33 | export LIBGUESTFS_BACKEND=direct 34 | guestfish --ro -a "$1" -m /dev/sda copy-out / $TMP_NEW 35 | chmod +w -R $TMP_NEW 36 | find $TMP_NEW -name TRANS.TBL -exec rm -f {} \; 37 | echo "Making hardlinks so inodes can be cached to save space..." 38 | pushd $TMP_NEW 39 | ln -f isolinux/initrd.img images/pxeboot/initrd.img 40 | ln -f isolinux/vmlinuz images/pxeboot/vmlinuz 41 | popd 42 | 43 | echo "Configuring bootloaders..." 44 | cat >$TMP_NEW/isolinux/isolinux.cfg <$TMP_NEW/EFI/BOOT/grub.cfg < 8 | # Written by Richard W.M. Jones 9 | # Based on a script by Jeremy Katz 10 | # Based on original work by Chris Lalancette 11 | # 12 | # This program is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; version 2 of the License. 15 | # 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU Library General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program; if not, write to the Free Software 23 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 24 | 25 | export PATH=/sbin:/usr/sbin:$PATH 26 | 27 | usage() { 28 | echo "Usage: livecd-iso-to-pxeboot " 29 | exit 1 30 | } 31 | 32 | cleanup() { 33 | [ -d "$STRIPPEDISO" ] && rm -rf $STRIPPEDISO 34 | [ -d "$CDMNT" ] && umount $CDMNT && rmdir $CDMNT 35 | } 36 | 37 | cleanup_error() { 38 | echo "Cleaning up to exit..." 39 | cleanup 40 | exit 1 41 | } 42 | 43 | if [ $(id -u) != 0 ]; then 44 | echo "You need to be root to run this script." 45 | exit 1 46 | fi 47 | 48 | # Check pxelinux.0 exists. 49 | if [ ! -f /usr/share/syslinux/pxelinux.0 -a ! -f /usr/lib/syslinux/pxelinux.0 ]; then 50 | echo "Warning: pxelinux.0 not found." 51 | echo "Make sure syslinux or pxelinux is installed on this system." 52 | fi 53 | 54 | while [ $# -gt 1 ]; do 55 | case "$1" in 56 | *) usage ;; 57 | esac 58 | shift 59 | done 60 | 61 | ISO="$1" 62 | 63 | if [ -z "$ISO" -o ! -e "$ISO" ]; then 64 | usage 65 | fi 66 | 67 | if [ -d tftpboot ]; then 68 | rm -rf tftpboot 69 | fi 70 | 71 | # Mount the ISO. 72 | CDMNT=$(mktemp -d /var/tmp/pxeboot-mount.XXXXXX) 73 | STRIPPEDISO=$(mktemp -d /var/tmp/pxeboot-stripped.XXXXXX) 74 | 75 | echo "Mounting $ISO on $STRIPPEDISO" 76 | mount -wr -o loop "$ISO" $CDMNT || cleanup_error 77 | 78 | trap cleanup_error SIGINT SIGTERM 79 | trap cleanup EXIT 80 | 81 | # Does it look like an ISO? 82 | if [[ ( ! -d $CDMNT/images/pxeboot ) || ( ! -f $CDMNT/images/pxeboot/initrd0.img && ! -f $CDMNT/images/pxeboot/initrd.img ) ]]; then 83 | echo "The ISO image doesn't look like a LiveCD ISO image to me." 84 | cleanup_error 85 | fi 86 | 87 | if [[ -f $CDMNT/images/pxeboot/initrd0.img ]]; then 88 | INITRD=initrd0.img 89 | VMLINUZ=vmlinuz0 90 | else 91 | INITRD=initrd.img 92 | VMLINUZ=vmlinuz 93 | fi 94 | 95 | mkdir tftpboot 96 | 97 | # Create a cpio archive of just the ISO and append it to the 98 | # initrd image. The Linux kernel will do the right thing, 99 | # aggregating both cpio archives (initrd + ISO) into a single 100 | # filesystem. 101 | NEWISO=$STRIPPEDISO/fdi.iso 102 | mkisofs --quiet -J -joliet-long -r -T -o $NEWISO --root LiveOS $CDMNT/LiveOS/squashfs.img 103 | ISOBASENAME=`basename "$NEWISO"` 104 | ( cd "$STRIPPEDISO" && echo "$ISOBASENAME" | cpio -H newc --quiet -L -o ) | 105 | gzip -9 | 106 | cat $CDMNT/images/pxeboot/$INITRD - > tftpboot/$INITRD 107 | 108 | # Kernel image. 109 | cp $CDMNT/images/pxeboot/$VMLINUZ tftpboot/$VMLINUZ 110 | 111 | # pxelinux bootloader. 112 | if [ -f /usr/share/syslinux/pxelinux.0 ]; then 113 | cp /usr/share/syslinux/pxelinux.0 tftpboot 114 | elif [ -f /usr/lib/syslinux/pxelinux.0 ]; then 115 | cp /usr/lib/syslinux/pxelinux.0 tftpboot 116 | else 117 | echo "Warning: You need to add pxelinux.0 to tftpboot/ subdirectory" 118 | fi 119 | 120 | # Get boot append line from original cd image. 121 | if [ -f $CDMNT/images/pxeboot/isolinux.cfg ]; then 122 | APPEND=$(grep -m1 append $CDMNT/images/pxeboot/isolinux.cfg | sed -e "s#CDLABEL=[^ ]*#/$ISOBASENAME#" -e "s/ *append *//") 123 | fi 124 | 125 | # pxelinux configuration. 126 | mkdir tftpboot/pxelinux.cfg 127 | cat > tftpboot/pxelinux.cfg/default < 10) do 49 | setcode do 50 | discovery_bootif 51 | end 52 | end 53 | 54 | (1..99).each do |n| 55 | if (fact_name = cmdline("fdi.pxfactname#{n}")) 56 | fact_value = cmdline("fdi.pxfactvalue#{n}") 57 | Facter.add(fact_name) do 58 | setcode do 59 | fact_value 60 | end 61 | end 62 | Facter.debug "Adding kernel command line custom fact #{fact_name}=#{fact_value}" 63 | else 64 | Facter.debug "Processed #{n} kernel command line custom facts, we are done here" 65 | break 66 | end 67 | end 68 | 69 | # IPMI Facts 70 | %x{dmidecode -t 38 2>/dev/null|grep -q "IPMI Device"} 71 | has_ipmi = $?.exitstatus == 0 72 | 73 | def add_ipmi_facts fact, value, channel = nil 74 | if channel 75 | fact = "ipmi_#{channel}_#{fact}" 76 | else 77 | fact = "ipmi_#{fact}" 78 | end 79 | Facter.add(fact) do 80 | confine :kernel => "Linux" 81 | setcode do 82 | value 83 | end 84 | end 85 | end 86 | 87 | if has_ipmi 88 | Facter.add("ipmi_enabled") do 89 | confine :kernel => "Linux" 90 | setcode do 91 | true 92 | end 93 | end 94 | default_found = false 95 | (0..15).each do |n| 96 | output = Facter::Util::Resolution.exec("ipmitool lan print #{n} 2>/dev/null") 97 | attributes = {} 98 | output.each_line do |line| 99 | case line.strip 100 | when /^IP Address Source\s+: (.*)/ 101 | attributes[:ipaddress_source] = $1 102 | when /^IP Address\s+: (.*)/ 103 | attributes[:ipaddress] = $1 104 | attributes[:ptr] = (Resolv.new.getname($1) rescue nil) 105 | when /^Subnet Mask\s+: (.*)/ 106 | attributes[:subnet_mask] = $1 107 | when /^MAC Address\s+: (.*)/ 108 | attributes[:macaddress] = $1 109 | when /^Default Gateway IP\s+: (.*)/ 110 | attributes[:gateway] = $1 111 | end 112 | end if output 113 | 114 | unless default_found 115 | Facter.debug("Running ipmitool on port #{n} didn't give any information") if attributes.keys.empty? 116 | attributes.each do |fact, value| 117 | add_ipmi_facts fact, value 118 | default_found = true 119 | end 120 | end 121 | attributes.each do |fact, value| 122 | add_ipmi_facts fact, value, n 123 | end 124 | end 125 | end 126 | 127 | # NetworkManager details (e.g. nmprimary_dhcp4_option_domain_name) 128 | wait = cmdline('fdi.nmwait', 120) 129 | nmout = Facter::Util::Resolution.exec("nmcli -w #{wait} -t con show primary 2>/dev/null") 130 | nmout.each_line do |x| 131 | elements = x.split(":", 2) 132 | name = elements.first.downcase.sub(/\[\d+\]$/,"") 133 | if name =~ /dhcp.\.option/ 134 | dhcp_elems = elements.last.split(/\s*=\s*/, 2) 135 | name += '_' + dhcp_elems.first 136 | value = dhcp_elems.last 137 | else 138 | value = elements.last 139 | end 140 | name = "nmprimary_" + name.tr('.', '_') 141 | Facter.add(name) do 142 | setcode do 143 | value.chomp 144 | end 145 | end 146 | end 147 | 148 | # Create DHCP FQDN helper facts 149 | Facter.add("nmprimary_dhcp4_option_fqdn") do 150 | setcode do 151 | if Facter.value("nmprimary_dhcp4_option_host_name") && Facter.value("nmprimary_dhcp4_option_domain_name") 152 | Facter.value("nmprimary_dhcp4_option_host_name") + '.' + Facter.value("nmprimary_dhcp4_option_domain_name") 153 | else 154 | nil 155 | end 156 | end 157 | end 158 | 159 | # Primary interface IP PTR DNS record 160 | Facter.add("nmprimary_ptr") do 161 | setcode do 162 | ip = Facter.value("nmprimary_ip4_address").scan(/\d+\.\d+\.\d+\.\d+/).first.strip rescue nil 163 | if ip.nil? 164 | nil 165 | else 166 | Resolv.new.getname(ip) rescue nil 167 | end 168 | end 169 | end 170 | 171 | # Keep this as the last one - overrides from file system 172 | Dir.glob('/tmp/facts/*') do |file| 173 | Facter.add(File.basename(file)) do 174 | setcode do 175 | File.open(file) {|f| f.readline.chomp} 176 | end 177 | end 178 | end 179 | -------------------------------------------------------------------------------- /root/usr/share/locale/fdi/foreman-discovery-image.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2023 Foreman developers 3 | # This file is distributed under the same license as the foreman-discovery-image package. 4 | # FIRST AUTHOR , 2023. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: foreman-discovery-image 4.1.0\n" 10 | "Report-Msgid-Bugs-To: foreman-dev@googlegroups.com\n" 11 | "POT-Creation-Date: 2023-05-23 14:01+0200\n" 12 | "PO-Revision-Date: 2023-05-23 14:01+0200\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 20 | 21 | msgid "Address:" 22 | msgstr "" 23 | 24 | msgid "Cancel" 25 | msgstr "" 26 | 27 | msgid "Configuring network via DHCP. This operation can take several minutes to complete." 28 | msgstr "" 29 | 30 | msgid "Configuring network. This operation can take several minutes to complete." 31 | msgstr "" 32 | 33 | msgid "Confirm" 34 | msgstr "" 35 | 36 | msgid "Connection type:" 37 | msgstr "" 38 | 39 | msgid "Credentials" 40 | msgstr "" 41 | 42 | msgid "Custom facts" 43 | msgstr "" 44 | 45 | msgid "DNS:" 46 | msgstr "" 47 | 48 | msgid "Disable" 49 | msgstr "" 50 | 51 | msgid "Discover with DHCP" 52 | msgstr "" 53 | 54 | msgid "Discovery" 55 | msgstr "" 56 | 57 | msgid "Discovery server" 58 | msgstr "" 59 | 60 | msgid "Discovery status" 61 | msgstr "" 62 | 63 | msgid "Endpoint type" 64 | msgstr "" 65 | 66 | msgid "Enter root password to unlock the account and enable SSH service:" 67 | msgstr "" 68 | 69 | msgid "Fact %s name" 70 | msgstr "" 71 | 72 | msgid "Facts" 73 | msgstr "" 74 | 75 | msgid "Fatal error - investigate journal" 76 | msgstr "" 77 | 78 | msgid "Foreman Discovery Image" 79 | msgstr "" 80 | 81 | msgid "Foreman Proxy" 82 | msgstr "" 83 | 84 | msgid "Gateway:" 85 | msgstr "" 86 | 87 | msgid "Invalid IP" 88 | msgstr "" 89 | 90 | msgid "Invalid URL" 91 | msgstr "" 92 | 93 | msgid "Kernel command line" 94 | msgstr "" 95 | 96 | msgid "Latest server response" 97 | msgstr "" 98 | 99 | msgid "Logs" 100 | msgstr "" 101 | 102 | msgid "Manual network setup" 103 | msgstr "" 104 | 105 | msgid "Manual/PXE-less provisioning workflow" 106 | msgstr "" 107 | 108 | msgid "N/A" 109 | msgstr "" 110 | 111 | msgid "Network configuration" 112 | msgstr "" 113 | 114 | msgid "Next" 115 | msgstr "" 116 | 117 | msgid "No URL was provided" 118 | msgstr "" 119 | 120 | msgid "Not a valid URL" 121 | msgstr "" 122 | 123 | msgid "Not supported" 124 | msgstr "" 125 | 126 | msgid "OK" 127 | msgstr "" 128 | 129 | msgid "Operation failed" 130 | msgstr "" 131 | 132 | msgid "Option proxy.type was not provided, cannot continue" 133 | msgstr "" 134 | 135 | msgid "Option proxy.url was not provided, cannot continue" 136 | msgstr "" 137 | 138 | msgid "Performing unattended provisioning via NIC %s, please wait." 139 | msgstr "" 140 | 141 | msgid "Port %s is likely not correct, expected ports are 443, 8443 or 9090" 142 | msgstr "" 143 | 144 | msgid "Press any key" 145 | msgstr "" 146 | 147 | msgid "Primary IPv4" 148 | msgstr "" 149 | 150 | msgid "Primary IPv6" 151 | msgstr "" 152 | 153 | msgid "Primary NIC" 154 | msgstr "" 155 | 156 | msgid "Primary interface" 157 | msgstr "" 158 | 159 | msgid "Provide full URL (http(s)://host:PORT) to the Server or Foreman Proxy according to the type selected. Ports are usually 443, 8443, 8448 or 9090 according to configuration." 160 | msgstr "" 161 | 162 | msgid "Provide network configuration for the selected primary interface. Use CIDR netmask notation (e.g. 192.168.1.1/24) for the IPv4 or IPv6 address." 163 | msgstr "" 164 | 165 | msgid "Provide valid CIDR ipaddress with a netmask, gateway and one DNS server" 166 | msgstr "" 167 | 168 | msgid "Reboot" 169 | msgstr "" 170 | 171 | msgid "Resend" 172 | msgstr "" 173 | 174 | msgid "Resending not possible in PXE-less, reboot and start over." 175 | msgstr "" 176 | 177 | msgid "SSH" 178 | msgstr "" 179 | 180 | msgid "Secure Shell access" 181 | msgstr "" 182 | 183 | msgid "Select" 184 | msgstr "" 185 | 186 | msgid "Select Manual network setup to select primary interface, configure network (no DHCP required), setup server credentials, add custom facts and trigger auto-provisioning via Discovery rules. This will lead to kernel reload (kexec) into installer. Select Discover with DHCP to select primary interface and proceed with DHCP configuration and standard discovery without any custom facts. This will reboot the host once the system is provisioned either manually or via Discovery rules." 187 | msgstr "" 188 | 189 | msgid "Select primary (provisioning) network interface with connection to server or proxy:" 190 | msgstr "" 191 | 192 | msgid "Server" 193 | msgstr "" 194 | 195 | msgid "Server URL:" 196 | msgstr "" 197 | 198 | msgid "Set and Enable" 199 | msgstr "" 200 | 201 | msgid "Status" 202 | msgstr "" 203 | 204 | msgid "This system will attempt to configure all interfaces via DHCP and discover itself by sending hardware facts to Foreman instance. To interrupt this behavior, press a key to be able to do manual network configuration and additional provisioning settings." 205 | msgstr "" 206 | 207 | msgid "Unable to bring network via DHCP" 208 | msgstr "" 209 | 210 | msgid "Unable to bring up network" 211 | msgstr "" 212 | 213 | msgid "Unable to parse proxy.url URI: %s" 214 | msgstr "" 215 | 216 | msgid "Unattended fact upload FAILED - check logs" 217 | msgstr "" 218 | 219 | msgid "Unattended fact upload OK - awaiting kexec" 220 | msgstr "" 221 | 222 | msgid "Unattended provisioning failed: unable to upload facts. Check your network credentials." 223 | msgstr "" 224 | 225 | msgid "Waiting for operation to complete" 226 | msgstr "" 227 | 228 | msgid "Warning" 229 | msgstr "" 230 | 231 | msgid "Welcome to Foreman Discovery" 232 | msgstr "" 233 | 234 | msgid "awaiting kexec into installer" 235 | msgstr "" 236 | 237 | msgid "fact upload failed" 238 | msgstr "" 239 | 240 | msgid "use Status to update" 241 | msgstr "" 242 | 243 | msgid "value" 244 | msgstr "" 245 | -------------------------------------------------------------------------------- /root/usr/share/locale/fdi/cs_CZ/foreman-discovery-image.po: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 Foreman developers 2 | # This file is distributed under the same license as the fdi package. 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: foreman-discovery-image 3.1.1\n" 6 | "Report-Msgid-Bugs-To: foreman-dev@googlegroups.com\n" 7 | "POT-Creation-Date: 2016-04-06 12:56+0200\n" 8 | "PO-Revision-Date: 2016-04-06 12:56+0200\n" 9 | "Last-Translator: Lukas Zapletal\n" 10 | "Language: Czech\n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" 15 | 16 | msgid "Cancel" 17 | msgstr "Zrušit" 18 | 19 | msgid "" 20 | "Configuring network via DHCP. This operation can take several minutes to " 21 | "complete." 22 | msgstr "Konfiguruji síť přes DHCP. Tato operace může trvat několik minut." 23 | 24 | msgid "" 25 | "Configuring network. This operation can take several minutes to complete." 26 | msgstr "Konfiguruji síť. Tato operace může trvat několik minut." 27 | 28 | msgid "Confirm" 29 | msgstr "Potvrdit" 30 | 31 | msgid "Connection type:" 32 | msgstr "Typ připojení:" 33 | 34 | msgid "Credentials" 35 | msgstr "Iniciály" 36 | 37 | msgid "Custom facts" 38 | msgstr "Uživatelská fakta" 39 | 40 | msgid "Disable" 41 | msgstr "Vypnout" 42 | 43 | msgid "Discover with DHCP" 44 | msgstr "Objevit přes DHCP" 45 | 46 | msgid "Discovery" 47 | msgstr "" 48 | 49 | msgid "Discovery status" 50 | msgstr "Stav objevení" 51 | 52 | msgid "Enter root password to unlock the account and enable SSH service:" 53 | msgstr "Zadejte heslo roota pro odemnkutí a spuštění služby SSH:" 54 | 55 | msgid "Fact %s name" 56 | msgstr "Fakt %s" 57 | 58 | msgid "Facts" 59 | msgstr "Fakta" 60 | 61 | msgid "Fatal error - investigate journal" 62 | msgstr "Zásadní chyba - zkoumejte systémový log" 63 | 64 | msgid "Foreman Discovery Image" 65 | msgstr "" 66 | 67 | msgid "IPv4 Address:" 68 | msgstr "Adresa IPv4:" 69 | 70 | msgid "IPv4 DNS:" 71 | msgstr "DNS pro IPv4:" 72 | 73 | msgid "IPv4 Gateway:" 74 | msgstr "Brána IPv4:" 75 | 76 | msgid "Invalid IP" 77 | msgstr "Neplatná IP adresa" 78 | 79 | msgid "Invalid URL" 80 | msgstr "Neplatná URL adresa" 81 | 82 | msgid "Logs" 83 | msgstr "Logy" 84 | 85 | msgid "Manual network setup" 86 | msgstr "Ruční nastavení sítě" 87 | 88 | msgid "Manual/PXE-less provisioning workflow" 89 | msgstr "Ruční instalace bez PXE" 90 | 91 | msgid "N/A" 92 | msgstr "Není" 93 | 94 | msgid "Network configuration" 95 | msgstr "Nastavení sítě" 96 | 97 | msgid "Next" 98 | msgstr "Další" 99 | 100 | msgid "No URL was provided" 101 | msgstr "Adresa URL nebyla zadána" 102 | 103 | msgid "Not a valid URL" 104 | msgstr "Neplatná URL adresa" 105 | 106 | msgid "Not supported" 107 | msgstr "Není podporováno" 108 | 109 | msgid "OK" 110 | msgstr "" 111 | 112 | msgid "Operation failed" 113 | msgstr "Operace selhala" 114 | 115 | msgid "Option proxy.type was not provided, cannot continue" 116 | msgstr "" 117 | 118 | msgid "Option proxy.url was not provided, cannot continue" 119 | msgstr "" 120 | 121 | msgid "Performing unattended provisioning via NIC %s, please wait." 122 | msgstr "" 123 | 124 | msgid "Port must be explicitly provided" 125 | msgstr "" 126 | 127 | msgid "Press any key" 128 | msgstr "" 129 | 130 | msgid "Primary interface" 131 | msgstr "" 132 | 133 | msgid "" 134 | "Provide full URL (http(s)://host:PORT) to the Server or Proxy according to " 135 | "the type selected. Ports are usually 443, 8443, 8448 or 9090 according to " 136 | "configuration." 137 | msgstr "" 138 | 139 | msgid "" 140 | "Provide network configuration for the selected primary interface. Use CIDR " 141 | "netmask notation (e.g. 192.168.1.1/24) for the IP address." 142 | msgstr "" 143 | 144 | msgid "Provide valid CIDR ipaddress with a netmask, gateway and one DNS server" 145 | msgstr "" 146 | 147 | msgid "Proxy" 148 | msgstr "" 149 | 150 | msgid "Reboot" 151 | msgstr "Restart" 152 | 153 | msgid "Resend" 154 | msgstr "Znovu" 155 | 156 | msgid "Resending not possible in PXE-less, reboot and start over." 157 | msgstr "" 158 | 159 | msgid "SSH" 160 | msgstr "" 161 | 162 | msgid "Secure Shell access" 163 | msgstr "" 164 | 165 | msgid "Select" 166 | msgstr "Vybrat" 167 | 168 | msgid "" 169 | "Select Manual network setup to select primary interface, configure network " 170 | "(no DHCP required), setup server credentials, add custom facts and trigger " 171 | "auto-provisioning via Discovery rules. This will lead to kernel reload " 172 | "(kexec) into installer. Select Discover with DHCP to select primary " 173 | "interface and proceed with DHCP configuration and standard discovery without " 174 | "any custom facts. This will reboot the host once the system is provisioned " 175 | "either manually or via Discovery rules." 176 | msgstr "" 177 | 178 | msgid "" 179 | "Select primary (provisioning) network interface with connection to server or " 180 | "proxy:" 181 | msgstr "" 182 | 183 | msgid "Server" 184 | msgstr "" 185 | 186 | msgid "Server URL:" 187 | msgstr "" 188 | 189 | msgid "Set and Enable" 190 | msgstr "" 191 | 192 | msgid "Status" 193 | msgstr "Stav" 194 | 195 | msgid "" 196 | "This system will attempt to configure all interfaces via DHCP and discover " 197 | "itself by sending hardware facts to Foreman instance. To interrupt this " 198 | "behavior, press a key to be able to do manual network configuration and " 199 | "additional provisioning settings." 200 | msgstr "" 201 | 202 | msgid "Unable to bring network via DHCP" 203 | msgstr "" 204 | 205 | msgid "Unable to bring up network" 206 | msgstr "" 207 | 208 | msgid "Unable to parse proxy.url URI: %s" 209 | msgstr "" 210 | 211 | msgid "Unattended fact upload FAILED - check logs" 212 | msgstr "" 213 | 214 | msgid "Unattended fact upload OK - awaiting kexec" 215 | msgstr "" 216 | 217 | msgid "" 218 | "Unattended provisioning failed: unable to upload facts. Check your network " 219 | "credentials." 220 | msgstr "" 221 | 222 | msgid "Waiting for operation to complete" 223 | msgstr "" 224 | 225 | msgid "Welcome to Foreman Discovery" 226 | msgstr "Vítejte ve Foreman Discovery" 227 | 228 | msgid "awaiting kexec into installer" 229 | msgstr "" 230 | 231 | msgid "use Status to update" 232 | msgstr "" 233 | 234 | msgid "value" 235 | msgstr "" 236 | -------------------------------------------------------------------------------- /22-discovery.ks: -------------------------------------------------------------------------------- 1 | %post 2 | 3 | echo " * ensure hostname resolves quickly" 4 | cat >/etc/hosts < /etc/NetworkManager/NetworkManager.conf <<'NM' 20 | [main] 21 | monitor-connection-files=no 22 | no-auto-default=* 23 | [logging] 24 | level=DEBUG 25 | NM 26 | cat > /etc/udev/rules.d/81-nm-prepare.rules <<'UDEV' 27 | ACTION=="add", SUBSYSTEM=="net", NAME!="lo", RUN+="/usr/bin/systemd-cat -t nm-prepare /usr/bin/nm-prepare %k" 28 | UDEV 29 | 30 | echo " * configuring TFTP firewall modules" 31 | echo -e "ip_conntrack_tftp\nnf_conntrack_netbios_ns" > /etc/modules-load.d/tftp-firewall.conf 32 | 33 | # https://blog.thewatertower.org/2019/05/01/tftp-part-2-the-tftp-client-requires-a-firewalld-as-well/ 34 | firewall-offline-cmd --new-policy hostTftpTraffic 35 | firewall-offline-cmd --policy hostTftpTraffic --add-ingress-zone HOST 36 | firewall-offline-cmd --policy hostTftpTraffic --add-egress-zone ANY 37 | firewall-offline-cmd --policy hostTftpTraffic --add-service tftp 38 | 39 | echo " * enabling NetworkManager system services (needed for RHEL 7.0)" 40 | systemctl enable NetworkManager.service 41 | systemctl enable NetworkManager-dispatcher.service 42 | systemctl enable NetworkManager-wait-online.service 43 | 44 | echo " * enabling nm-prepare service" 45 | systemctl enable nm-prepare.service 46 | 47 | echo " * enabling required system services" 48 | systemctl enable ipmi.service 49 | systemctl enable foreman-proxy.service 50 | systemctl enable discovery-fetch-extensions.path 51 | systemctl enable discovery-start-extensions.service 52 | systemctl enable discovery-menu.service 53 | systemctl enable discovery-script-pxe.service 54 | systemctl enable discovery-script-pxeless.service 55 | 56 | # register service is started manually from discovery-menu 57 | systemctl disable discovery-register.service 58 | 59 | echo " * disabling some unused system services" 60 | systemctl disable ipmi.service 61 | 62 | echo " * open foreman-proxy port via firewalld" 63 | firewall-offline-cmd --zone=public --add-port=8443/tcp --add-port=8448/tcp 64 | 65 | echo " * setting up foreman proxy service" 66 | sed -i 's/After=.*/After=basic.target network-online.target nm-prepare.service/' /usr/lib/systemd/system/foreman-proxy.service 67 | sed -i 's/Wants=.*/Wants=basic.target network-online.target nm-prepare.service/' /usr/lib/systemd/system/foreman-proxy.service 68 | sed -i '/\[Unit\]/a ConditionPathExists=/etc/NetworkManager/system-connections/primary' /usr/lib/systemd/system/foreman-proxy.service 69 | sed -i '/\[Service\]/a EnvironmentFile=-/etc/default/discovery' /usr/lib/systemd/system/foreman-proxy.service 70 | sed -i '/\[Service\]/a ExecStartPre=/usr/bin/generate-proxy-cert' /usr/lib/systemd/system/foreman-proxy.service 71 | sed -i '/\[Service\]/a PermissionsStartOnly=true' /usr/lib/systemd/system/foreman-proxy.service 72 | sed -i '/\[Service\]/a TimeoutStartSec=9999' /usr/lib/systemd/system/foreman-proxy.service 73 | /sbin/usermod -a -G tty foreman-proxy 74 | 75 | cat >/etc/foreman-proxy/settings.yml <<'CFG' 76 | --- 77 | :settings_directory: /etc/foreman-proxy/settings.d 78 | # certificate is generated by /usr/bin/generate-proxy-cert 79 | :ssl_certificate: /etc/foreman-proxy/cert.pem 80 | :ssl_ca_file: /etc/foreman-proxy/cert.pem 81 | :ssl_private_key: /etc/foreman-proxy/key.pem 82 | :daemon: true 83 | :http_port: 8448 84 | :https_port: 8443 85 | :log_file: SYSLOG 86 | :log_level: DEBUG 87 | :log_buffer: 1000 88 | :log_buffer_errors: 500 89 | CFG 90 | 91 | cat >/etc/foreman-proxy/settings.d/discovery_image.yml <<'CFG' 92 | --- 93 | :enabled: true 94 | CFG 95 | 96 | cat >/etc/foreman-proxy/settings.d/bmc.yml <<'CFG' 97 | --- 98 | :enabled: true 99 | :bmc_default_provider: shell 100 | CFG 101 | 102 | cat >/etc/foreman-proxy/settings.d/facts.yml <<'CFG' 103 | --- 104 | :enabled: true 105 | CFG 106 | 107 | cat >/etc/foreman-proxy/settings.d/logs.yml <<'CFG' 108 | --- 109 | :enabled: true 110 | CFG 111 | 112 | echo " * setting up systemd" 113 | echo "DumpCore=no" >> /etc/systemd/system.conf 114 | 115 | echo " * setting multi-user.target as default" 116 | systemctl set-default multi-user.target 117 | 118 | echo " * setting up journald and ttys" 119 | systemctl disable getty@tty1.service getty@tty2.service 120 | systemctl mask getty@tty1.service getty@tty2.service 121 | echo "Storage=volatile" >> /etc/systemd/journald.conf 122 | echo "RuntimeMaxUse=25M" >> /etc/systemd/journald.conf 123 | echo "ForwardToSyslog=no" >> /etc/systemd/journald.conf 124 | echo "ForwardToConsole=no" >> /etc/systemd/journald.conf 125 | systemctl enable journalctl.service 126 | 127 | echo " * setting suid bits" 128 | chmod +s /sbin/ethtool 129 | chmod +s /usr/sbin/dmidecode 130 | chmod +s /usr/bin/ipmitool 131 | 132 | # Add foreman-proxy user to sudo and disable interactive tty for reboot 133 | echo " * setting up sudo" 134 | sed -i -e 's/^Defaults.*requiretty/Defaults !requiretty/g' /etc/sudoers 135 | echo "foreman-proxy ALL=NOPASSWD: /usr/sbin/reboot" >> /etc/sudoers 136 | echo "foreman-proxy ALL=NOPASSWD: /usr/sbin/shutdown" >> /etc/sudoers 137 | echo "foreman-proxy ALL=NOPASSWD: /usr/sbin/kexec" >> /etc/sudoers 138 | 139 | echo " * dropping some friendly aliases" 140 | echo "alias vim=vi" >> /root/.bashrc 141 | echo "alias halt=poweroff" >> /root/.bashrc 142 | 143 | # Base env for extracting zip extensions 144 | mkdir -p /opt/extension/{bin,lib,lib/ruby,facts} 145 | 146 | echo " * setting up lldp service" 147 | systemctl enable lldpad.socket 148 | cat > /etc/udev/rules.d/82-enable-lldp.rules <<'UDEV' 149 | ACTION=="add", SUBSYSTEM=="net", NAME!="lo", TAG+="systemd", ENV{SYSTEMD_WANTS}+="enable-lldp@%k.service" 150 | UDEV 151 | 152 | echo " * enable promiscuous mode on all physical network interfaces" 153 | cat > /etc/udev/rules.d/83-enable-promiscuous-mode.rules <<'UDEV' 154 | ACTION=="add", SUBSYSTEM=="net", NAME!="lo", TAG+="systemd", ENV{SYSTEMD_WANTS}+="enable-promiscuous-mode@%k.service" 155 | UDEV 156 | 157 | echo " * disable flushing log data" 158 | systemctl mask systemd-journal-flush.service 159 | 160 | # extra modules for livecd-creator/livemedia-creator 161 | echo 'add_drivers+="mptbase mptscsih mptspi hv_storvsc hid_hyperv hv_netvsc hv_vmbus"' > /etc/dracut.conf.d/99-discovery.conf 162 | 163 | %end 164 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery/menu.rb: -------------------------------------------------------------------------------- 1 | require "newt" 2 | require "discovery" 3 | require "facter" 4 | require "ipaddr" 5 | require "fast_gettext" 6 | 7 | def fdi_version file = 'VERSION' 8 | return 'GIT' unless File.exist?("/usr/share/fdi/#{file}") 9 | IO.read("/usr/share/fdi/#{file}").chomp 10 | end 11 | 12 | def fdi_release file = 'RELEASE' 13 | fdi_version file 14 | end 15 | 16 | def enable_root_account(pass) 17 | command("sed -i 's/^.*PermitRootLogin.*$/PermitRootLogin yes/' '/etc/ssh/sshd_config'", false, false) 18 | command("sed -i 's/^.*PasswordAuthentication.*$/PasswordAuthentication yes/' '/etc/ssh/sshd_config'", false, false) 19 | command("echo 'root:#{pass}' | chpasswd && systemctl restart sshd.service", false, false) 20 | end 21 | 22 | def error_box(msg, extra_msg = nil) 23 | log_err msg 24 | log_err extra_msg 25 | backtrace = log_exception extra_msg 26 | Newt::Screen.centered_window(74, 20, "Fatal error") 27 | f = Newt::Form.new 28 | t_desc = Newt::Textbox.new(1, 1, 70, 13, Newt::FLAG_SCROLL) 29 | random_pass = (1...10).map { (65 + rand(26)).chr }.join 30 | t_desc.set_text "#{msg}:\n#{extra_msg}\n\n#{backtrace}\n\n" + 31 | "Once OK button is pressed, and root account will be unlocked\n" + 32 | "with the following random password:\n\n" + 33 | " #{random_pass}\n\n" + 34 | "It is possible to use third console to login and investigate\n" + 35 | "via journalctl and discovery-debug commands. " 36 | b_ok = Newt::Button.new(66, 15, "OK") 37 | f.add(b_ok, t_desc) 38 | f.run 39 | enable_root_account(random_pass) 40 | exit(1) 41 | end 42 | 43 | def command(cmd, fail_on_error = true, send_to_syslog = true) 44 | log_msg("TUI executing: #{cmd}") if send_to_syslog 45 | # do not run real commands in development (non-image) environment 46 | return true if fdi_version == 'GIT' 47 | output = `#{cmd} 2>&1` 48 | if $? != 0 49 | log_msg("Command returned #{$?} and output was: #{output}") if send_to_syslog 50 | if fail_on_error 51 | error_box("Command failed: #{cmd}", output) 52 | else 53 | return false 54 | end 55 | end 56 | output 57 | end 58 | 59 | def debug_value val 60 | Newt::Screen.win_message("DEBUG", "OK", val.inspect) 61 | end 62 | 63 | def wrap(s, width=78) 64 | s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n") 65 | end 66 | 67 | def disable_tftp_extensions 68 | ['path', 'service'].each do |unit| 69 | if File.exist? "/etc/systemd/system/discovery-fetch-extensions.#{unit}" 70 | command("systemctl disable discovery-fetch-extensions.#{unit}") 71 | end 72 | end 73 | end 74 | 75 | def start_discovery_service 76 | if File.exist? "/etc/systemd/system/discovery-register.service" 77 | command("systemctl restart discovery-register.service") 78 | end 79 | end 80 | 81 | def configure_network static, mac, ip=nil, gw=nil, dns=nil, vlan=nil 82 | command("systemctl stop foreman-proxy", false) 83 | if static 84 | if IPAddr.new(ip).ipv6? 85 | cmd = "primary-static6" 86 | else 87 | cmd = "primary-static" 88 | end 89 | command("nm-configure #{cmd} '#{mac}' '#{ip}' '#{gw}' '#{dns}' '#{vlan}'") 90 | else 91 | command("nm-configure primary '#{mac}' '#{vlan}'") 92 | end 93 | wait = cmdline('fdi.nmwait', 120) 94 | command("nmcli -w #{wait} connection reload", false) 95 | sleep 2 96 | up_result = command("nmcli -w #{wait} connection up primary", false) 97 | sleep 2 98 | command("nm-online -s -q --timeout=#{wait}") 99 | # wait for IPv4, generate SSL self-signed cert and start proxy 100 | command("systemctl start foreman-proxy") && up_result 101 | end 102 | 103 | def perform_upload proxy_url, proxy_type, custom_facts 104 | upload proxy_url, proxy_type, custom_facts 105 | rescue => e 106 | error_box("Unable to upload facts", e) 107 | end 108 | 109 | # Collect fact necessary for the kexec 110 | # See the redhat_kexec.erb template for more details 111 | def new_custom_facts(mac) 112 | custom_facts = {} 113 | custom_facts['discovery_bootif'] = mac 114 | custom_facts['discovery_kexec'] = command('kexec --version') 115 | 116 | cred_cidr6, gw6, dns6 = detect_ipv6_credentials('primary') 117 | cidr6 = IPAddr.new(cred_cidr6) if cred_cidr6 118 | 119 | # IPv6 is prefered over the IPv4 in dual stack environment 120 | # and if the IPv6 is not link-local 121 | if cidr6 && !cidr6.link_local? 122 | ip6 = cred_cidr6.split('/').first 123 | mask6 = cidr6.inspect.split('/').last[0..-2] 124 | 125 | custom_facts['discovery_ip_cidr'] = cred_cidr6 126 | custom_facts['discovery_ip'] = ip6 127 | custom_facts['discovery_netmask'] = mask6 128 | custom_facts['discovery_gateway'] = gw6 129 | custom_facts['discovery_dns'] = dns6 130 | 131 | return custom_facts 132 | end 133 | 134 | cred_cidr4, gw4, dns4 = detect_ipv4_credentials('primary') 135 | ip4 = cred_cidr4.split('/').first 136 | cidr4 = IPAddr.new(cred_cidr4) 137 | mask4 = cidr4.inspect.split('/').last[0..-2] 138 | 139 | custom_facts['discovery_ip_cidr'] = cred_cidr4 140 | custom_facts['discovery_ip'] = ip4 141 | custom_facts['discovery_netmask'] = mask4 142 | custom_facts['discovery_gateway'] = gw4 143 | custom_facts['discovery_dns'] = dns4 144 | custom_facts 145 | rescue StandardError => e 146 | log_exception e 147 | custom_facts 148 | end 149 | 150 | def cleanup 151 | Newt::Screen.finish 152 | exit 0 153 | end 154 | 155 | log_msg "Kernel opts: #{cmdline}" 156 | 157 | # fast_gettext initialization 158 | begin 159 | FastGettext.add_text_domain('foreman-discovery-image', 160 | :path => File.exists?('/usr/share/locale/fdi') ? '/usr/share/locale/fdi' : 'root/usr/share/locale/fdi', 161 | :type => :po, 162 | :ignore_fuzzy => true, 163 | :report_warning => false) 164 | FastGettext.text_domain = 'foreman-discovery-image' 165 | selected_locale = cmdline('locale') 166 | FastGettext.locale = selected_locale if selected_locale 167 | rescue Exception => e 168 | error_box("Unable to initialize gettext: #{e}", e) unless e.is_a? SystemExit 169 | end 170 | include FastGettext::Translation 171 | 172 | def main_loop 173 | Signal.trap("TERM") { cleanup } 174 | Signal.trap("INT") { cleanup } 175 | Signal.trap("HUP") do 176 | Newt::Screen.refresh 177 | end 178 | 179 | Newt::Screen.new 180 | mode = if File.exists?("/sys/firmware/efi/") 181 | "UEFI" 182 | else 183 | "BIOS" 184 | end 185 | driver = `cat /proc/fb`.strip.tr("\n", ' ') 186 | driver = "NO-FB" if driver.empty? 187 | Newt::Screen.push_helpline(_("Foreman Discovery Image") + " v#{fdi_version} (#{fdi_release}) #{RUBY_PLATFORM} #{mode} #{driver}") 188 | 189 | if cmdline('BOOTIF') 190 | # Booted via PXE 191 | active_screen = :screen_countdown 192 | else 193 | # Booted from ISO 194 | if cmdline('fdi.pxauto') 195 | # Unattended PXE-less provisioning 196 | log_debug "Unattended provisioning started" 197 | proxy_url = cmdline('proxy.url') || error_box(_("Option proxy.url was not provided, cannot continue")) 198 | proxy_url = URI.parse(proxy_url) rescue error_box(_("Unable to parse proxy.url URI: %s") % proxy_url) 199 | proxy_type = cmdline('proxy.type') || error_box(_("Option proxy.type was not provided, cannot continue")) 200 | log_debug "proxy.url=#{proxy_url} proxy.type=#{proxy_type}" 201 | mac = cmdline('fdi.pxmac') || detect_first_nic_with_link 202 | ip = cmdline('fdi.pxip') 203 | gw = cmdline('fdi.pxgw') 204 | dns = cmdline('fdi.pxdns') 205 | action = Proc.new do 206 | log_debug "Unattended network configuration started" 207 | if ip && gw 208 | log_debug "Configuring #{mac} with static info: ip=#{ip} gw=#{gw} dns=#{dns}" 209 | status = configure_network true, mac, ip, gw, dns 210 | else 211 | log_debug "Configuring #{mac} with DHCP (pxip or pxgw were not provided)" 212 | status = configure_network false, mac 213 | end 214 | log_debug "Unattended network configuration finished, result: #{status}" 215 | delay = cmdline('fdi.countdown', 45).to_i rescue 45 216 | log_debug "Delay for network initialization: #{delay} seconds" 217 | sleep delay 218 | facts = new_custom_facts(mac) 219 | log_debug "Unattended facts upload started" 220 | result = upload(proxy_url, proxy_type, facts) 221 | log_debug "Unattended facts upload finished, result: #{result}" 222 | result 223 | end 224 | active_screen = [:screen_info, action, 225 | (_("Performing unattended provisioning via NIC %s, please wait.") % mac) + " (ip=#{ip} gw=#{gw} dns=#{dns}, url=#{proxy_url} [#{proxy_type}])", 226 | _("Unattended provisioning failed: unable to upload facts. Check your network credentials."), 227 | [:screen_status, generate_info(_('Unattended fact upload OK - awaiting kexec'))], 228 | [:screen_status, generate_info(_('Unattended fact upload FAILED - check logs'))]] 229 | else 230 | # Attended PXE-less provisioning 231 | active_screen = :screen_welcome 232 | end 233 | end 234 | while ! [:quit].include? active_screen 235 | if active_screen.is_a?(Array) 236 | log_debug "Entering #{active_screen[0]}" 237 | active_screen = send(*active_screen) 238 | else 239 | log_debug "Entering #{active_screen}" 240 | active_screen = send(active_screen) 241 | end 242 | Newt::Screen.pop_window() 243 | end 244 | rescue Exception => e 245 | error_box(_("Fatal error - investigate journal"), e) unless e.is_a? SystemExit 246 | ensure 247 | cleanup 248 | end 249 | -------------------------------------------------------------------------------- /root/usr/share/ruby/vendor_ruby/discovery.rb: -------------------------------------------------------------------------------- 1 | # Library of functions for use with Foreman Discovery 2 | # 3 | # vim: ts=2:sw=2:et 4 | # 5 | # Copyright (C) 2012-2014 Red Hat, Inc. 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; version 2 of the License. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | # MA 02110-1301, USA. A copy of the GNU General Public License is 20 | # also available at http://www.gnu.org/copyleft/gpl.html. 21 | 22 | require 'fileutils' 23 | require 'net/http' 24 | require 'net/https' 25 | require 'uri' 26 | require 'socket' 27 | require 'resolv' 28 | require 'syslog' 29 | require 'facter' 30 | require 'yaml' 31 | require 'json' 32 | 33 | def log_msg msg 34 | if defined? ::Proxy::LoggerFactory 35 | # helper methods are also used from proxy context (refresh facts -> facter API -> custom facts) 36 | ::Proxy::LoggerFactory.logger.info msg 37 | else 38 | Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.info msg.to_s.gsub('%', '%%') rescue false } 39 | end 40 | rescue Exception => e 41 | puts msg 42 | end 43 | 44 | def log_err msg 45 | if defined? ::Proxy::LoggerFactory 46 | # helper methods are also used from proxy context (refresh facts -> facter API -> custom facts) 47 | ::Proxy::LoggerFactory.logger.error msg 48 | else 49 | Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.err msg.to_s.gsub('%', '%%') rescue false } 50 | end 51 | rescue Exception => e 52 | puts msg 53 | end 54 | 55 | def log_debug msg 56 | if defined? ::Proxy::LoggerFactory 57 | # helper methods are also used from proxy context (refresh facts -> facter API -> custom facts) 58 | ::Proxy::LoggerFactory.logger.debug msg 59 | else 60 | Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.debug msg.to_s.gsub('%', '%%') rescue false } 61 | end 62 | rescue Exception => e 63 | puts msg 64 | end 65 | 66 | def log_exception ex 67 | if ex.is_a? Exception 68 | backtrace = (ex.to_s + "\n" + ex.backtrace.join("\n")) rescue 'N/A' 69 | log_err "#{ex.class}: #{ex.message}\n#{backtrace}" 70 | backtrace 71 | end 72 | end 73 | 74 | def capture_stderr 75 | previous_stderr, $stderr = $stderr, StringIO.new 76 | yield 77 | $stderr.string 78 | ensure 79 | $stderr = previous_stderr 80 | end 81 | 82 | def cmdline_hash 83 | $cmdline_hash ||= Hash[cmdline.split.map { |x| x.split('=', 2)}] 84 | end 85 | 86 | def cmdline option=nil, default=nil 87 | return File.open("/proc/cmdline", 'r') { |f| f.read } unless option 88 | cmdline_hash[option] || default 89 | end 90 | 91 | def detect_first_nic_with_link 92 | detection_func = lambda do 93 | mac = '' 94 | log_debug "Detecting the first NICs with link" 95 | Dir.glob('/sys/class/net/*').sort.each do |ifn| 96 | name = File.basename ifn 97 | next if name == "lo" 98 | mac = File.read("#{ifn}/address").chomp rescue '' 99 | if (File.read("#{ifn}/carrier").chomp == "1" rescue false) 100 | log_debug "Interface with link found: #{mac} (#{name})" 101 | return mac 102 | end 103 | end 104 | log_debug "No interfaces with link found, using #{mac}" 105 | mac 106 | end 107 | @detected_mac ||= detection_func.call 108 | end 109 | 110 | def normalize_mac mac 111 | mac.split('-')[1..6].join(':') rescue nil 112 | end 113 | 114 | def discover_server 115 | discover_by_url || discover_by_dns_srv 116 | end 117 | 118 | def discover_by_url 119 | url = cmdline('proxy.url') || cmdline('foreman.url') 120 | log_msg "Discovered by URL: #{url}" if url 121 | URI.parse(url) 122 | rescue 123 | return nil 124 | end 125 | 126 | # SRV discovery will work only if DHCP returns valid search domain 127 | def discover_by_dns_srv 128 | default = Resolv::DNS::Config.default_config_hash 129 | conf = { 130 | :nameserver => cmdline("fdi.dns_nameserver", default[:nameserver]), 131 | :search => cmdline("fdi.dns_search", default[:search]), 132 | :ndots => cmdline("fdi.dns_ndots", default[:ndots]).to_i, 133 | } 134 | resolver = Resolv::DNS.new(conf) 135 | type = Resolv::DNS::Resource::IN::SRV 136 | result = resolver.getresources("_x-foreman._tcp", type).first 137 | hostname = result.target.to_s 138 | if [443, 8443, 9090].include?(result.port) 139 | scheme = 'https' 140 | else 141 | scheme = 'http' 142 | end 143 | uri = "#{scheme}://#{hostname}:#{result.port}" 144 | log_msg "Discovered by SRV: #{uri}" 145 | URI.parse(uri) 146 | rescue 147 | return nil 148 | end 149 | 150 | def proxy_type 151 | type = cmdline('proxy.type', 'foreman') 152 | log_err('*** proxy.type should be either "foreman" or "proxy" ***') unless ['foreman', 'proxy'].include? type 153 | type 154 | end 155 | 156 | def write_tui result = 'success', code, body 157 | filename = "/tmp/discovery-http-#{result}" 158 | log_debug "Wrote result #{code} to #{filename}" 159 | File.open(filename, 'w') do |file| 160 | file.write("#{code}: #{body}") 161 | end 162 | end 163 | 164 | def upload(uri = discover_server, type = proxy_type, custom_facts = {}) 165 | unless uri 166 | log_err "Could not determine instance type, add foreman.url or proxy.url kernel command parameter" 167 | return 168 | end 169 | unless uri.is_a? URI 170 | log_err "Upload#uri must be type of URI" 171 | return 172 | end 173 | if uri.host.nil? or uri.port.nil? 174 | log_err "Server or proxy URI host or port was not specified, cannot continue" 175 | return 176 | end 177 | log_msg "Registering host at (#{uri})" 178 | http = Net::HTTP.new(uri.host, uri.port) 179 | if uri.scheme == 'https' then 180 | http.use_ssl = true 181 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE 182 | end 183 | facts_url = if type == 'proxy' 184 | "#{uri.path}/discovery/create" 185 | else 186 | "#{uri.path}/api/v2/discovered_hosts/facts" 187 | end 188 | req = Net::HTTP::Post.new(facts_url, {'Content-Type' => 'application/json'}) 189 | # create facts based on user input 190 | user_input_facts = {"discovery_proxy_uri"=>uri, "discovery_proxy_type"=>type} 191 | # supress stderr of Facter 192 | facts = {} 193 | capture_stderr do 194 | facts = Facter.to_hash 195 | end.each_line { |x| log_err x} 196 | facts.merge!(custom_facts).merge!(user_input_facts) 197 | req.body = {'facts' => facts }.to_json 198 | response = http.request(req) 199 | if ['200','201'].include? response.code 200 | log_msg "Response from server #{response.code}: #{response.body}" 201 | body = response.nil? ? 'N/A' : response.body 202 | write_tui 'success', response.code, body 203 | return true 204 | else 205 | log_err "Response from server #{response.code}: #{response.body}" 206 | body = response.nil? ? 'N/A' : response.body 207 | write_tui 'failure', response.code, body 208 | return false 209 | end 210 | rescue => e 211 | log_err "Could not send facts to server: #{e}" 212 | log_debug e.backtrace.join("\n") 213 | body = response.nil? ? 'N/A' : response.body 214 | write_tui 'failure', 1001, "#{e}, body: #{body}" 215 | return false 216 | end 217 | 218 | # Quick function to append to ENV vars correctly 219 | def env_append(env,string) 220 | if ENV[env].nil? or ENV[env].empty? 221 | "#{env}=#{string}\n" 222 | else 223 | "#{env}=#{ENV[env]}:#{string}\n" 224 | end 225 | end 226 | 227 | def get_mac(interface = 'primary') 228 | wait = cmdline('fdi.nmwait', 120) 229 | `nmcli -w #{wait} -t -f 802-3-ethernet.mac-address con show #{interface} 2>/dev/null`.scan(/\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2}\n/).first.strip rescue 'N/A' 230 | end 231 | 232 | def get_ipv4(interface = 'primary') 233 | wait = cmdline('fdi.nmwait', 120) 234 | 235 | begin 236 | `nmcli -w #{wait} -t -f IP4.ADDRESS con show #{interface} 2>/dev/null`.split(':', 2)[1].chomp 237 | rescue StandardError 238 | 'N/A' 239 | end 240 | end 241 | 242 | def get_ipv6(interface = 'primary') 243 | wait = cmdline('fdi.nmwait', 120) 244 | 245 | begin 246 | `nmcli -w #{wait} -t -f IP6.ADDRESS con show #{interface} 2>/dev/null`.split(':', 2)[1].chomp 247 | rescue StandardError 248 | 'N/A' 249 | end 250 | end 251 | 252 | def detect_ipv4_credentials(interface) 253 | res = {} 254 | str = `nmcli -t -f IP4.ADDRESS,IP4.GATEWAY,IP4.DNS con show '#{interface}' 2>/dev/null` 255 | return [nil, nil, nil] if $? != 0 256 | 257 | str.each_line do |x| 258 | kv = x.split(':') 259 | res[kv[0]] = kv[1].chomp 260 | end 261 | 262 | [res['IP4.ADDRESS[1]'], res['IP4.GATEWAY'], res['IP4.DNS[1]']] 263 | rescue StandardError => e 264 | log_err e.message 265 | [nil, nil, nil] 266 | end 267 | 268 | def detect_ipv6_credentials(interface) 269 | res = {} 270 | str = `nmcli -t -f IP6.ADDRESS,IP6.GATEWAY,IP6.DNS con show '#{interface}' 2>/dev/null` 271 | return [nil, nil, nil] if $? != 0 272 | 273 | str.each_line do |x| 274 | kv = x.split(':') 275 | res[kv[0]] = kv[1..].join(':').chomp 276 | end 277 | 278 | # Filter out link-local addresses 279 | cidr6 = res6.filter { |k, _v| k.include? 'IP6.ADDRESS' } 280 | .delete_if { |_k, v| IPAddr.new(v).link_local? } 281 | .values.first 282 | 283 | [cidr6, res['IP6.GATEWAY'], res['IP6.DNS[1]']] 284 | rescue StandardError => e 285 | log_err e.message 286 | [nil, nil, nil] 287 | end 288 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | _____ 3 | | ___|__ _ __ ___ _ __ ___ __ _ _ __ 4 | | |_ / _ \| '__/ _ \ '_ ` _ \ / _` | '_ \ 5 | | _| (_) | | | __/ | | | | | (_| | | | | 6 | |_|__\___/|_| \___|_| |_| |_|\__,_|_| |_| 7 | | _ \(_)___ ___ _____ _____ _ __ _ _ 8 | | | | | / __|/ __/ _ \ \ / / _ \ '__| | | | 9 | | |_| | \__ \ (_| (_) \ V / __/ | | |_| | 10 | |____/|_|___/\___\___/ \_/ \___|_| \__, | 11 | |___/ 12 | ``` 13 | 14 | Foreman Discovery Image 15 | ======================= 16 | 17 | This is a small redhat-based image that boots via PXE into memory, 18 | initializes all network interfaces using NetworkManager and spawns small 19 | script called "discovery-register" via systemd. This script determines foreman 20 | URL either via DNS SRV or via kernel command line and uploads facts via 21 | Foreman Discovery plugin API. 22 | 23 | The image has foreman-proxy installed with BMC API configured to "shell" 24 | provider. Upon request of Foreman, it reboots the node via /usr/bin/reboot 25 | command. To initiate the restart, use the following command: 26 | 27 | ``` 28 | curl -3 -H "Accept:application/json" -H "Content-Length:0" -k -X PUT \ 29 | http://192.168.100.100:8443/bmc/ignored/chassis/power/cycle 30 | ``` 31 | 32 | Usage 33 | ----- 34 | 35 | This README describes bare minimum steps to PXE-boot discovery image. 36 | The full installation and setup is described on the foreman_discovery 37 | plugin site: http://theforeman.org/plugins/foreman_discovery/ 38 | 39 | To extract the tarball into the correct directory you can use this command: 40 | 41 | ``` 42 | wget http://downloads.theforeman.org/discovery/releases/X.X/fdi-image-X.X.X.tar \ 43 | -O - | tar x --overwrite -C /var/lib/tftpboot/boot 44 | ``` 45 | 46 | Integrate it via the PXELinux templates in the Foreman application. 47 | 48 | ``` 49 | LABEL discovery 50 | MENU LABEL Foreman Discovery Image 51 | MENU DEFAULT 52 | KERNEL boot/fdi-image/vmlinuz0 53 | APPEND initrd=boot/fdi-image/initrd0.img rootflags=loop root=live:/fdi.iso rootfstype=auto ro rd.live.image rd.debug=1 acpi=force rd.luks=0 rd.md=0 rd.dm=0 rd.lvm=0 rd.bootif=0 rd.neednet=0 nomodeset proxy.url=http://YOURPROXY proxy.type=proxy 54 | IPAPPEND 2 55 | ``` 56 | 57 | Make sure the APPEND statement is on *single line*. 58 | 59 | You can also use the image standalone (without TFTP under Foreman's 60 | control). In this case, edit your pxelinux.cfg/default file directly and 61 | make sure the foreman.url points correctly. 62 | 63 | There are several bug reports with PXE-boot when GRUB2 tries to load initrd. By 64 | default the initrd in the tarball contains the rootfs and becomes bigger and 65 | bigger over time and from version to version. 66 | 67 | A workaround is to separate loading of initrd and rootfs. The initrd is loaded 68 | by GRUB2, the rootfs by the Linux system. For this, the ISO (containing the 69 | rootfs) must be provided via web server: 70 | 71 | ``` 72 | wget https://downloads.theforeman.org/discovery/releases/X.X/fdi-X.X.X-*.iso -O /tmp/fdi.iso 73 | mount /tmp/fdi.iso /mnt/ 74 | mkdir /var/lib/tftpboot/boot/fdi-image-slim 75 | cp /mnt/isolinux/{vmlinuz,initrd.img} /var/lib/tftpboot/boot/fdi-image-slim/ 76 | umount /mnt 77 | mkdir /var/www/html/pub/fdi-image-slim 78 | mv /tmp/fdi.iso /var/www/html/pub/fdi-image-slim 79 | ``` 80 | 81 | Integrate it via templates (e.g. `pxegrub2_discovery` snippet) in the Foreman 82 | application. 83 | 84 | ``` 85 | common_slim="rootflags=loop root=live:http://YOURPROXY/pub/fdi-image-slim/fdi.iso rootfstype=auto ro rd.live.image acpi=force rd.luks=0 rd.md=0 rd.dm=0 rd.lvm=0 rd.bootif=0 rd.neednet=0 nokaslr nomodeset proxy.url=https://YOURPROXY proxy.type=proxy BOOTIF=01-$net_default_mac ip=dhcp" 86 | 87 | menuentry 'Foreman Discovery Image EFI Slim' --id discovery { 88 | linuxefi boot/fdi-image-slim/vmlinuz ${common_slim} 89 | initrdefi boot/fdi-image-slim/initrd.img 90 | } 91 | ``` 92 | 93 | Networking 94 | ---------- 95 | 96 | By default the instance only initializes default interface (the one it was 97 | booted from) via DHCP. If you want to initialize all network interfaces, 98 | provide fdi.initnet=all option on the kernel command line. Peer DNS and 99 | routes are always acquired only from the primary interface and ignored for 100 | secondary (PEERDNS, PEERROUTES, DEFROUTE). Network cards connected to same 101 | networks can cause troubles due to ARP filtering. 102 | 103 | Documentation 104 | ------------- 105 | 106 | Discovery image has many features and configuration options. For more, visit 107 | http://theforeman.org/plugins/foreman_discovery/ 108 | 109 | Building 110 | -------- 111 | 112 | FDI currently builds only against EL 8 and building in a container will NOT 113 | work (docker/podman). The building host MUST be EL 8, other versions or Red Hat 114 | compatible systems (e.g Fedora) WILL fail to build. 115 | 116 | Install the required packages: 117 | 118 | ``` 119 | $ sudo dnf install lorax anaconda pykickstart wget qemu-kvm 120 | ``` 121 | 122 | To prepare the kickstart do: 123 | 124 | ``` 125 | $ ./build-kickstart fdi-centos9.ks 126 | ``` 127 | 128 | To build the image (this must be done on a EL 9 host): 129 | 130 | ``` 131 | $ sudo ./build-livecd-root 1.2.3 [./result] [virt] 132 | ``` 133 | 134 | The first parameter is the version of the image, the second is the target 135 | directory and the third argument can be either virt or nonvirt. Do not build 136 | images via the nonvirt flag as this can possibly destroy the host system - this 137 | is intended for building inside a clean VM (see below). 138 | 139 | When testing the image for new features or bugfixing, it is useful to enable 140 | SSH access right away to boot the ISO directly. The first argument is version 141 | to be recorded, the second is the destination directory and the third are 142 | kernel command line options. 143 | 144 | ``` 145 | $ sudo ./build-livecd-root dev /var/lib/libvirt/images/ "nomodeset nokaslr fdi.ssh=1 fdi.rootpw=redhat" 146 | ``` 147 | 148 | Previously, it was possible to build with docker/podman, with lorax image 149 | builder this is no longer possible. 150 | 151 | To extract the kernel and initial RAM disk: 152 | 153 | ``` 154 | aux/livecd-iso-to-pxeboot fdi-XYZ.iso 155 | ``` 156 | 157 | The final step is to copy the resulting tarball to the TFTP boot directory: 158 | 159 | ``` 160 | $ tar xvf fdi-image-*.tar -C /var/lib/tftpboot/boot 161 | ``` 162 | 163 | And visit https://github.com/theforeman/foreman_discovery for more 164 | information about how to configure Foreman and how to use the plugin. 165 | 166 | Adding drivers/firmware 167 | ----------------------- 168 | 169 | Additional kernel drivers and firmware, including 3rd party software, can be added by editing the `build-livecd-root` script and modifying `--dracut-arg` arguments to list dracut modules with `--add-drivers`. A pseudo-example (this is not a working configuration): 170 | 171 | ``` 172 | --dracut-arg="--add-drivers mlx4_core mlx4_ib mlx4_en mlxfw" \ 173 | --dracut-arg="--install /sbin/mlnx_bf_configure" \ 174 | ``` 175 | 176 | Some more complex drivers will need additional configuration files or system services to be added. The same driver and userspace utility packages need to be added into `20-packages.ks` file section `%packages`. A yum repository must be added so yum/dnf can find 3rd party drivers. 177 | 178 | To build the image, follow the instructions above. 179 | 180 | Building a release 181 | ------------------ 182 | 183 | This chapter is for The Foreman team members, skip to the next section if 184 | this is not for you. 185 | 186 | To build new release, use our Jenkins CI job: 187 | 188 | http://ci.theforeman.org/job/foreman-discovery-image-publish/ 189 | 190 | The job uses Vagrant to spin VM in OpenStack/Rackspace and then copies 191 | the result to our downloads.theforeman.org site. 192 | 193 | It is possible to start the job locally in libvirt: 194 | 195 | cd aux/vagrant-build 196 | LC_ALL=C repoowner=theforeman branch=master proxy_repo=3.1 vagrant up fdi-builder 197 | 198 | Wait until the box starts up and builds the image, then connect to the box 199 | and download the image: 200 | 201 | vagrant ssh-config fdi-builder | tee vagrant-ssh-config.tmp 202 | mkdir tmp 203 | scp -F vagrant-ssh-config.tmp fdi-builder:foreman-discovery-image/fdi*tar tmp/ 204 | scp -F vagrant-ssh-config.tmp fdi-builder:foreman-discovery-image/fdi*iso tmp/ 205 | 206 | And finally (do not forget): 207 | 208 | LC_ALL=C repoowner=theforeman branch=master proxy_repo=3.1 vagrant destroy fdi-builder 209 | 210 | Extensions 211 | ---------- 212 | 213 | Discovery Image supports runtime extensions published via TFTP or HTTP. 214 | Those are distributed as ZIP files with shell scripts. It is also possible 215 | to build an image with extensions built-in which is helpful for PXE-less 216 | environments. 217 | 218 | To do that, [follow the 219 | documentation](https://docs.theforeman.org/nightly/Provisioning_Hosts/index-foreman-el.html#Extending_the_Discovery_Image_provisioning) 220 | to create directory structure in root/opt/extension folder. Do not put ZIP 221 | files into this folder, but keep the directory structure extracted (this is 222 | the directory where ZIP files get downloaded and extracted). Then rebuild 223 | the image, the extensions will be started during boot. 224 | 225 | Additional facts 226 | ---------------- 227 | 228 | Some extra facts are reported in addition to the standard ones reported by 229 | Facter: 230 | 231 | ``` 232 | source /etc/default/discovery 233 | export FACTERLIB 234 | facter | grep discovery 235 | discovery_bootif => 52:54:00:94:9e:52 236 | ``` 237 | 238 | discovery_bootif - MAC of the interface it was booted from 239 | 240 | 241 | Troubleshooting 242 | --------------- 243 | 244 | First of all make sure your server (or VM) has more than 500 MB of memory 245 | because less memory can lead to various random kernel panic errors as the 246 | image needs to be extracted in-place (150 MB * 2). 247 | 248 | The first virtual console is reserved for logs, all systemd logging is 249 | shown there. Particulary useful system logs are tagged with: 250 | 251 | * discovery-register - initial facts upload 252 | * foreman-discovery - facts refresh, reboot remote commands 253 | * nm-prepare - boot script which pre-configures NetworkManager 254 | * NetworkManager - networking information 255 | 256 | The root account and ssh access are disabled by default, but you can enable 257 | ssh and set root password using the following kernel command line options: 258 | 259 | ``` 260 | fdi.ssh=1 fdi.rootpw=redhat 261 | ``` 262 | 263 | Root password can also be specified in encrypted form (using 'redhat' as 264 | an example below). Single and/or double quotes around password are 265 | recommended to be used to prevent possible special characters 266 | interpretation. 267 | 268 | ``` 269 | fdi.rootpw='$1$_redhat_$i3.3Eg7ko/Peu/7Q/1.wJ/' 270 | ``` 271 | 272 | You can use tty2 console (or higher) to login as well. 273 | 274 | To debug booting issues when the system is terminated in early stage of 275 | boot, use `systemd.confirm_spawn=true` options to interactively start one 276 | service after another. Anothe option `rd.debug=1` option makes sure shell 277 | will be spawned on fatal Dracut errors. 278 | 279 | If the system is halted immediately during boot sequence, this can be 280 | caused by corrupt image. Check the downloaded image using sha512sum. If the 281 | problem persist, make sure rd.live.check kernel option is NOT present. 282 | Beware that this looks like there are transmission errors of the init RAM 283 | disk and you may have unexpected behavior. PXE is unreliable protocol, 284 | server and TFTP must be on the same LAN. 285 | 286 | Downstream 287 | ---------- 288 | 289 | This repostirory is downstream friendly for koji. The generated 290 | fdi-image.ks kickstart file is self-containing. First of all, run the 291 | initial script and provide empty base kickstart without any repositories 292 | (they will be added via koji: 293 | 294 | ``` 295 | $ ./build-kickstart fdi-empty.ks 296 | ``` 297 | Then simply build the image from kickstart called fdi-image.ks: 298 | 299 | ``` 300 | koji spin-livecd \ 301 | fdi-image-rhel_7_0 \ 302 | $(cat root/usr/share/fdi/VERSION) \ 303 | --release $(cat root/usr/share/fdi/RELEASE) \ 304 | --repo=http://my.repo/1 \ 305 | --scratch \ 306 | my-tag-image 307 | x86_64 \ 308 | fdi-image.ks 309 | ``` 310 | 311 | Then extract the kernel and initial RAM disk: 312 | 313 | ``` 314 | aux/livecd-iso-to-pxeboot fdi-XYZ.iso 315 | ``` 316 | 317 | Contributing 318 | ------------ 319 | 320 | Please follow our [generic contributing guidelines for 321 | Foreman](http://theforeman.org/contribute.html#SubmitPatches). Make sure 322 | you create [an 323 | issue](http://projects.theforeman.org/projects/discovery/issues/new) and 324 | select "Image" Category. 325 | 326 | vim:tw=75 327 | 328 | License 329 | ------- 330 | 331 | The kickstart file, utility scripts and other software in this repo is 332 | licensed under GNU GPL v2 or later. Exceptions are individually commented 333 | in file headers. 334 | 335 | Generated image is covered by additional licenses, refer to Fedora and 336 | CentOS licensing information. 337 | 338 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2025-02-17 08:06:56 UTC using RuboCop version 1.64.1. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 1 10 | # This cop supports safe autocorrection (--autocorrect). 11 | # Configuration parameters: EnforcedStyle, IndentationWidth. 12 | # SupportedStyles: with_first_argument, with_fixed_indentation 13 | Layout/ArgumentAlignment: 14 | Exclude: 15 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 16 | 17 | # Offense count: 8 18 | # This cop supports safe autocorrection (--autocorrect). 19 | # Configuration parameters: EnforcedStyle, IndentationWidth. 20 | # SupportedStyles: with_first_element, with_fixed_indentation 21 | Layout/ArrayAlignment: 22 | Exclude: 23 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 24 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/network.rb' 25 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/primary_iface.rb' 26 | 27 | # Offense count: 8 28 | # This cop supports safe autocorrection (--autocorrect). 29 | Layout/EmptyLineAfterGuardClause: 30 | Exclude: 31 | - 'root/usr/share/fdi/facts/ethtool.rb' 32 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 33 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 34 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb' 35 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/primary_iface.rb' 36 | 37 | # Offense count: 1 38 | # This cop supports safe autocorrection (--autocorrect). 39 | Layout/EmptyLines: 40 | Exclude: 41 | - 'root/usr/bin/discovery-menu' 42 | 43 | # Offense count: 1 44 | # This cop supports safe autocorrection (--autocorrect). 45 | # Configuration parameters: EnforcedStyle. 46 | # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only 47 | Layout/EmptyLinesAroundClassBody: 48 | Exclude: 49 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 50 | 51 | # Offense count: 5 52 | # This cop supports safe autocorrection (--autocorrect). 53 | # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. 54 | # SupportedHashRocketStyles: key, separator, table 55 | # SupportedColonStyles: key, separator, table 56 | # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit 57 | Layout/HashAlignment: 58 | Exclude: 59 | - 'root/usr/share/fdi/facts/openlldp.rb' 60 | 61 | # Offense count: 1 62 | # This cop supports safe autocorrection (--autocorrect). 63 | Layout/HeredocIndentation: 64 | Exclude: 65 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/status.rb' 66 | 67 | # Offense count: 5 68 | # This cop supports safe autocorrection (--autocorrect). 69 | # Configuration parameters: Width, AllowedPatterns. 70 | Layout/IndentationWidth: 71 | Exclude: 72 | - 'root/usr/share/fdi/facts/pcicards.rb' 73 | 74 | # Offense count: 9 75 | # This cop supports safe autocorrection (--autocorrect). 76 | # Configuration parameters: AllowDoxygenCommentStyle, AllowGemfileRubyComment. 77 | Layout/LeadingCommentSpace: 78 | Exclude: 79 | - 'root/usr/share/fdi/facts/openlldp.rb' 80 | 81 | # Offense count: 7 82 | # This cop supports safe autocorrection (--autocorrect). 83 | # Configuration parameters: EnforcedStyle, IndentationWidth. 84 | # SupportedStyles: aligned, indented 85 | Layout/MultilineOperationIndentation: 86 | Exclude: 87 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 88 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 89 | 90 | # Offense count: 5 91 | # This cop supports safe autocorrection (--autocorrect). 92 | Layout/SpaceAfterComma: 93 | Exclude: 94 | - 'root/usr/bin/discovery-register' 95 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 96 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 97 | 98 | # Offense count: 1 99 | # This cop supports safe autocorrection (--autocorrect). 100 | Layout/SpaceAfterNot: 101 | Exclude: 102 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 103 | 104 | # Offense count: 7 105 | # This cop supports safe autocorrection (--autocorrect). 106 | # Configuration parameters: EnforcedStyle. 107 | # SupportedStyles: space, no_space 108 | Layout/SpaceAroundEqualsInParameterDefault: 109 | Exclude: 110 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 111 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 112 | 113 | # Offense count: 3 114 | # This cop supports safe autocorrection (--autocorrect). 115 | # Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator, EnforcedStyleForRationalLiterals. 116 | # SupportedStylesForExponentOperator: space, no_space 117 | # SupportedStylesForRationalLiterals: space, no_space 118 | Layout/SpaceAroundOperators: 119 | Exclude: 120 | - 'root/usr/bin/discovery-register' 121 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 122 | 123 | # Offense count: 1 124 | # This cop supports safe autocorrection (--autocorrect). 125 | # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. 126 | # SupportedStyles: space, no_space 127 | # SupportedStylesForEmptyBraces: space, no_space 128 | Layout/SpaceBeforeBlockBraces: 129 | Exclude: 130 | - 'root/usr/share/fdi/facts/openlldp.rb' 131 | 132 | # Offense count: 18 133 | # This cop supports safe autocorrection (--autocorrect). 134 | # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. 135 | # SupportedStyles: space, no_space 136 | # SupportedStylesForEmptyBraces: space, no_space 137 | Layout/SpaceInsideBlockBraces: 138 | Exclude: 139 | - 'root/usr/bin/discovery-register' 140 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 141 | - 'root/usr/share/fdi/facts/openlldp.rb' 142 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 143 | 144 | # Offense count: 5 145 | # This cop supports safe autocorrection (--autocorrect). 146 | # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. 147 | # SupportedStyles: space, no_space, compact 148 | # SupportedStylesForEmptyBraces: space, no_space 149 | Layout/SpaceInsideHashLiteralBraces: 150 | Exclude: 151 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 152 | 153 | # Offense count: 4 154 | # This cop supports safe autocorrection (--autocorrect). 155 | Lint/DeprecatedClassMethods: 156 | Exclude: 157 | - 'root/usr/bin/discovery-register' 158 | - 'root/usr/share/fdi/facts/openlldp.rb' 159 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 160 | 161 | # Offense count: 7 162 | Lint/RescueException: 163 | Exclude: 164 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 165 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 166 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/foreman.rb' 167 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/network.rb' 168 | 169 | # Offense count: 1 170 | # This cop supports safe autocorrection (--autocorrect). 171 | Lint/ScriptPermission: 172 | Exclude: 173 | - 'root/usr/share/fdi/facts/ethtool.rb' 174 | 175 | # Offense count: 2 176 | # This cop supports safe autocorrection (--autocorrect). 177 | # Configuration parameters: AutoCorrect, IgnoreEmptyBlocks, AllowUnusedKeywordArguments. 178 | Lint/UnusedBlockArgument: 179 | Exclude: 180 | - 'root/usr/bin/discovery-register' 181 | 182 | # Offense count: 2 183 | # This cop supports safe autocorrection (--autocorrect). 184 | # Configuration parameters: AutoCorrect, AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods. 185 | Lint/UnusedMethodArgument: 186 | Exclude: 187 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/status.rb' 188 | 189 | # Offense count: 4 190 | # This cop supports unsafe autocorrection (--autocorrect-all). 191 | # Configuration parameters: AutoCorrect. 192 | Lint/UselessAssignment: 193 | Exclude: 194 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 195 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/network.rb' 196 | 197 | # Offense count: 14 198 | # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. 199 | Metrics/AbcSize: 200 | Max: 77 201 | 202 | # Offense count: 8 203 | # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. 204 | # AllowedMethods: refine 205 | Metrics/BlockLength: 206 | Max: 42 207 | 208 | # Offense count: 9 209 | # Configuration parameters: CountBlocks. 210 | Metrics/BlockNesting: 211 | Max: 4 212 | 213 | # Offense count: 7 214 | # Configuration parameters: AllowedMethods, AllowedPatterns. 215 | Metrics/CyclomaticComplexity: 216 | Max: 16 217 | 218 | # Offense count: 20 219 | # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. 220 | Metrics/MethodLength: 221 | Max: 69 222 | 223 | # Offense count: 3 224 | # Configuration parameters: CountKeywordArgs. 225 | Metrics/ParameterLists: 226 | MaxOptionalParameters: 4 227 | Max: 6 228 | 229 | # Offense count: 7 230 | # Configuration parameters: AllowedMethods, AllowedPatterns. 231 | Metrics/PerceivedComplexity: 232 | Max: 21 233 | 234 | # Offense count: 1 235 | # Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, CheckDefinitionPathHierarchyRoots, Regex, IgnoreExecutableScripts, AllowedAcronyms. 236 | # CheckDefinitionPathHierarchyRoots: lib, spec, test, src 237 | # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS 238 | Naming/FileName: 239 | Exclude: 240 | - 'Rakefile.rb' 241 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 242 | 243 | # Offense count: 1 244 | # Configuration parameters: ForbiddenDelimiters. 245 | # ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$)) 246 | Naming/HeredocDelimiterNaming: 247 | Exclude: 248 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/status.rb' 249 | 250 | # Offense count: 1 251 | # This cop supports unsafe autocorrection (--autocorrect-all). 252 | # Configuration parameters: EnforcedStyleForLeadingUnderscores. 253 | # SupportedStylesForLeadingUnderscores: disallowed, required, optional 254 | Naming/MemoizedInstanceVariableName: 255 | Exclude: 256 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 257 | 258 | # Offense count: 5 259 | # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. 260 | # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to 261 | Naming/MethodParameterName: 262 | Exclude: 263 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 264 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 265 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/foreman.rb' 266 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/network.rb' 267 | 268 | # Offense count: 1 269 | # This cop supports safe autocorrection (--autocorrect). 270 | # Configuration parameters: PreferredName. 271 | Naming/RescuedExceptionsVariableName: 272 | Exclude: 273 | - 'root/usr/bin/discovery-register' 274 | 275 | # Offense count: 1 276 | # This cop supports unsafe autocorrection (--autocorrect-all). 277 | Security/YAMLLoad: 278 | Exclude: 279 | - 'root/usr/bin/discovery-register' 280 | 281 | # Offense count: 3 282 | # This cop supports unsafe autocorrection (--autocorrect-all). 283 | # Configuration parameters: EnforcedStyle. 284 | # SupportedStyles: always, conditionals 285 | Style/AndOr: 286 | Exclude: 287 | - 'root/usr/share/fdi/facts/ethtool.rb' 288 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 289 | 290 | # Offense count: 2 291 | # This cop supports safe autocorrection (--autocorrect). 292 | # Configuration parameters: AllowOnConstant, AllowOnSelfClass. 293 | Style/CaseEquality: 294 | Exclude: 295 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 296 | - 'root/usr/share/fdi/facts/openlldp.rb' 297 | 298 | # Offense count: 2 299 | # This cop supports safe autocorrection (--autocorrect). 300 | # Configuration parameters: EnforcedStyle, AllowInnerBackticks. 301 | # SupportedStyles: backticks, percent_x, mixed 302 | Style/CommandLiteral: 303 | Exclude: 304 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 305 | - 'root/usr/share/fdi/facts/pcicards.rb' 306 | 307 | # Offense count: 3 308 | # This cop supports safe autocorrection (--autocorrect). 309 | # Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions. 310 | # SupportedStyles: assign_to_condition, assign_inside_condition 311 | Style/ConditionalAssignment: 312 | Exclude: 313 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 314 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 315 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 316 | 317 | # Offense count: 2 318 | # Configuration parameters: AllowedConstants. 319 | Style/Documentation: 320 | Exclude: 321 | - 'spec/**/*' 322 | - 'test/**/*' 323 | - 'example_zip/lib/ruby/discovery_extension.rb' 324 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 325 | 326 | # Offense count: 1 327 | # This cop supports safe autocorrection (--autocorrect). 328 | # Configuration parameters: AutoCorrect, EnforcedStyle, AllowComments. 329 | # SupportedStyles: empty, nil, both 330 | Style/EmptyElse: 331 | Exclude: 332 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 333 | 334 | # Offense count: 23 335 | # This cop supports unsafe autocorrection (--autocorrect-all). 336 | # Configuration parameters: EnforcedStyle. 337 | # SupportedStyles: always, always_true, never 338 | Style/FrozenStringLiteralComment: 339 | Enabled: false 340 | 341 | # Offense count: 2 342 | # This cop supports unsafe autocorrection (--autocorrect-all). 343 | Style/GlobalStdStream: 344 | Exclude: 345 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb' 346 | 347 | # Offense count: 1 348 | # Configuration parameters: AllowedVariables. 349 | Style/GlobalVars: 350 | Exclude: 351 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 352 | 353 | # Offense count: 3 354 | # This cop supports safe autocorrection (--autocorrect). 355 | # Configuration parameters: MinBodyLength, AllowConsecutiveConditionals. 356 | Style/GuardClause: 357 | Exclude: 358 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 359 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 360 | 361 | # Offense count: 1 362 | # This cop supports unsafe autocorrection (--autocorrect-all). 363 | # Configuration parameters: AllowedReceivers. 364 | # AllowedReceivers: Thread.current 365 | Style/HashEachMethods: 366 | Exclude: 367 | - 'root/usr/share/fdi/facts/ethtool.rb' 368 | 369 | # Offense count: 23 370 | # This cop supports safe autocorrection (--autocorrect). 371 | # Configuration parameters: EnforcedStyle, EnforcedShorthandSyntax, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. 372 | # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys 373 | # SupportedShorthandSyntax: always, never, either, consistent, either_consistent 374 | Style/HashSyntax: 375 | Exclude: 376 | - 'aux/vagrant-build/Vagrantfile' 377 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 378 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 379 | - 'root/usr/share/fdi/facts/efi.rb' 380 | - 'root/usr/share/fdi/facts/ethtool.rb' 381 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 382 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 383 | 384 | # Offense count: 1 385 | # This cop supports safe autocorrection (--autocorrect). 386 | # Configuration parameters: AllowIfModifier. 387 | Style/IfInsideElse: 388 | Exclude: 389 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 390 | 391 | # Offense count: 4 392 | # This cop supports safe autocorrection (--autocorrect). 393 | Style/IfUnlessModifier: 394 | Exclude: 395 | - 'root/usr/share/fdi/facts/pcicards.rb' 396 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 397 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/foreman.rb' 398 | 399 | # Offense count: 1 400 | # This cop supports unsafe autocorrection (--autocorrect-all). 401 | Style/InfiniteLoop: 402 | Exclude: 403 | - 'root/usr/bin/discovery-register' 404 | 405 | # Offense count: 5 406 | # This cop supports unsafe autocorrection (--autocorrect-all). 407 | Style/LineEndConcatenation: 408 | Exclude: 409 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 410 | 411 | # Offense count: 5 412 | # This cop supports safe autocorrection (--autocorrect). 413 | # Configuration parameters: AllowedMethods, AllowedPatterns. 414 | Style/MethodCallWithoutArgsParentheses: 415 | Exclude: 416 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 417 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/primary_iface.rb' 418 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/ssh.rb' 419 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/status.rb' 420 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/welcome.rb' 421 | 422 | # Offense count: 22 423 | # This cop supports safe autocorrection (--autocorrect). 424 | # Configuration parameters: EnforcedStyle. 425 | # SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline 426 | Style/MethodDefParentheses: 427 | Exclude: 428 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 429 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 430 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 431 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb' 432 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/facts.rb' 433 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/foreman.rb' 434 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/info.rb' 435 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/network.rb' 436 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/primary_iface.rb' 437 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/status.rb' 438 | 439 | # Offense count: 1 440 | Style/MixinUsage: 441 | Exclude: 442 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 443 | 444 | # Offense count: 1 445 | Style/MultilineBlockChain: 446 | Exclude: 447 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 448 | 449 | # Offense count: 1 450 | # This cop supports safe autocorrection (--autocorrect). 451 | Style/MultilineIfModifier: 452 | Exclude: 453 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 454 | 455 | # Offense count: 3 456 | # This cop supports safe autocorrection (--autocorrect). 457 | Style/MultilineIfThen: 458 | Exclude: 459 | - 'root/usr/share/fdi/facts/pcicards.rb' 460 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 461 | 462 | # Offense count: 2 463 | # This cop supports unsafe autocorrection (--autocorrect-all). 464 | # Configuration parameters: EnforcedStyle. 465 | # SupportedStyles: literals, strict 466 | Style/MutableConstant: 467 | Exclude: 468 | - 'aux/vagrant-build/Vagrantfile' 469 | - 'root/usr/bin/discovery-register' 470 | 471 | # Offense count: 1 472 | # This cop supports safe autocorrection (--autocorrect). 473 | Style/NegatedWhile: 474 | Exclude: 475 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 476 | 477 | # Offense count: 1 478 | # This cop supports safe autocorrection (--autocorrect). 479 | # Configuration parameters: EnforcedStyle, MinBodyLength. 480 | # SupportedStyles: skip_modifier_ifs, always 481 | Style/Next: 482 | Exclude: 483 | - 'root/usr/bin/discovery-register' 484 | 485 | # Offense count: 2 486 | # This cop supports safe autocorrection (--autocorrect). 487 | # Configuration parameters: IncludeSemanticChanges. 488 | Style/NonNilCheck: 489 | Exclude: 490 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 491 | - 'root/usr/share/fdi/facts/ethtool.rb' 492 | 493 | # Offense count: 2 494 | # This cop supports safe autocorrection (--autocorrect). 495 | Style/Not: 496 | Exclude: 497 | - 'root/usr/share/fdi/facts/openlldp.rb' 498 | 499 | # Offense count: 5 500 | # This cop supports unsafe autocorrection (--autocorrect-all). 501 | # Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. 502 | # SupportedStyles: predicate, comparison 503 | Style/NumericPredicate: 504 | Exclude: 505 | - 'spec/**/*' 506 | - 'root/usr/bin/discovery-register' 507 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 508 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 509 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb' 510 | 511 | # Offense count: 1 512 | Style/OptionalArguments: 513 | Exclude: 514 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 515 | 516 | # Offense count: 4 517 | # Configuration parameters: AllowedMethods. 518 | # AllowedMethods: respond_to_missing? 519 | Style/OptionalBooleanParameter: 520 | Exclude: 521 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 522 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb' 523 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/primary_iface.rb' 524 | 525 | # Offense count: 1 526 | # This cop supports safe autocorrection (--autocorrect). 527 | Style/ParallelAssignment: 528 | Exclude: 529 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 530 | 531 | # Offense count: 2 532 | # This cop supports safe autocorrection (--autocorrect). 533 | # Configuration parameters: PreferredDelimiters. 534 | Style/PercentLiteralDelimiters: 535 | Exclude: 536 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 537 | - 'root/usr/share/fdi/facts/pcicards.rb' 538 | 539 | # Offense count: 18 540 | # This cop supports safe autocorrection (--autocorrect). 541 | Style/PerlBackrefs: 542 | Exclude: 543 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 544 | - 'root/usr/share/fdi/facts/ethtool.rb' 545 | - 'root/usr/share/fdi/facts/openlldp.rb' 546 | 547 | # Offense count: 1 548 | # This cop supports unsafe autocorrection (--autocorrect-all). 549 | # Configuration parameters: EnforcedStyle. 550 | # SupportedStyles: short, verbose 551 | Style/PreferredHashMethods: 552 | Exclude: 553 | - 'root/usr/share/fdi/facts/pcicards.rb' 554 | 555 | # Offense count: 3 556 | # This cop supports safe autocorrection (--autocorrect). 557 | Style/Proc: 558 | Exclude: 559 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 560 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/network.rb' 561 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/primary_iface.rb' 562 | 563 | # Offense count: 1 564 | # This cop supports safe autocorrection (--autocorrect). 565 | Style/RandomWithOffset: 566 | Exclude: 567 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 568 | 569 | # Offense count: 1 570 | # This cop supports safe autocorrection (--autocorrect). 571 | Style/RedundantFileExtensionInRequire: 572 | Exclude: 573 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 574 | 575 | # Offense count: 5 576 | # This cop supports safe autocorrection (--autocorrect). 577 | # Configuration parameters: AllowMultipleReturnValues. 578 | Style/RedundantReturn: 579 | Exclude: 580 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 581 | 582 | # Offense count: 2 583 | # This cop supports safe autocorrection (--autocorrect). 584 | # Configuration parameters: EnforcedStyle, AllowInnerSlashes. 585 | # SupportedStyles: slashes, percent_r, mixed 586 | Style/RegexpLiteral: 587 | Exclude: 588 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 589 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 590 | 591 | # Offense count: 23 592 | # This cop supports safe autocorrection (--autocorrect). 593 | Style/RescueModifier: 594 | Exclude: 595 | - 'root/usr/bin/discovery-register' 596 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 597 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 598 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 599 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb' 600 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/primary_iface.rb' 601 | 602 | # Offense count: 8 603 | # This cop supports safe autocorrection (--autocorrect). 604 | # Configuration parameters: EnforcedStyle. 605 | # SupportedStyles: implicit, explicit 606 | Style/RescueStandardError: 607 | Exclude: 608 | - 'root/usr/bin/discovery-register' 609 | - 'root/usr/share/fdi/facts/pcicards.rb' 610 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 611 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 612 | 613 | # Offense count: 1 614 | # This cop supports unsafe autocorrection (--autocorrect-all). 615 | # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. 616 | # AllowedMethods: present?, blank?, presence, try, try! 617 | Style/SafeNavigation: 618 | Exclude: 619 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 620 | 621 | # Offense count: 3 622 | # This cop supports safe autocorrection (--autocorrect). 623 | Style/SelfAssignment: 624 | Exclude: 625 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb' 626 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/primary_iface.rb' 627 | 628 | # Offense count: 6 629 | # This cop supports safe autocorrection (--autocorrect). 630 | # Configuration parameters: AllowAsExpressionSeparator. 631 | Style/Semicolon: 632 | Exclude: 633 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 634 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/facts.rb' 635 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/network.rb' 636 | 637 | # Offense count: 7 638 | # This cop supports unsafe autocorrection (--autocorrect-all). 639 | # Configuration parameters: RequireEnglish. 640 | # SupportedStyles: use_perl_names, use_english_names, use_builtin_english_names 641 | Style/SpecialGlobalVars: 642 | EnforcedStyle: use_perl_names 643 | 644 | # Offense count: 14 645 | # This cop supports unsafe autocorrection (--autocorrect-all). 646 | # Configuration parameters: Mode. 647 | Style/StringConcatenation: 648 | Exclude: 649 | - 'root/usr/share/fdi/facts/discovery-facts.rb' 650 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 651 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 652 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/countdown.rb' 653 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/facts.rb' 654 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/status.rb' 655 | 656 | # Offense count: 174 657 | # This cop supports safe autocorrection (--autocorrect). 658 | # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. 659 | # SupportedStyles: single_quotes, double_quotes 660 | Style/StringLiterals: 661 | Enabled: false 662 | 663 | # Offense count: 1 664 | # This cop supports unsafe autocorrection (--autocorrect-all). 665 | # Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments. 666 | # AllowedMethods: define_method 667 | Style/SymbolProc: 668 | Exclude: 669 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 670 | 671 | # Offense count: 3 672 | # This cop supports safe autocorrection (--autocorrect). 673 | # Configuration parameters: EnforcedStyleForMultiline. 674 | # SupportedStylesForMultiline: comma, consistent_comma, no_comma 675 | Style/TrailingCommaInHashLiteral: 676 | Exclude: 677 | - 'root/usr/share/fdi/facts/openlldp.rb' 678 | - 'root/usr/share/ruby/vendor_ruby/discovery.rb' 679 | - 'root/usr/share/ruby/vendor_ruby/discovery/menu.rb' 680 | 681 | # Offense count: 1 682 | # This cop supports safe autocorrection (--autocorrect). 683 | Style/UnlessElse: 684 | Exclude: 685 | - 'root/usr/bin/discovery-register' 686 | 687 | # Offense count: 1 688 | # This cop supports safe autocorrection (--autocorrect). 689 | Style/WhileUntilDo: 690 | Exclude: 691 | - 'root/usr/bin/discovery-register' 692 | 693 | # Offense count: 3 694 | # This cop supports safe autocorrection (--autocorrect). 695 | # Configuration parameters: MinSize, WordRegex. 696 | # SupportedStyles: percent, brackets 697 | Style/WordArray: 698 | EnforcedStyle: brackets 699 | 700 | # Offense count: 2 701 | # This cop supports unsafe autocorrection (--autocorrect-all). 702 | Style/ZeroLengthPredicate: 703 | Exclude: 704 | - 'root/usr/share/fdi/facts/disks_partition_table.rb' 705 | - 'root/usr/share/ruby/vendor_ruby/discovery/screen/foreman.rb' 706 | 707 | # Offense count: 17 708 | # This cop supports safe autocorrection (--autocorrect). 709 | # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. 710 | # URISchemes: http, https 711 | Layout/LineLength: 712 | Max: 535 713 | --------------------------------------------------------------------------------