diff options
-rw-r--r-- | set-permanent-dns-resolvers/description | 1 | ||||
-rwxr-xr-x | set-permanent-dns-resolvers/set-permanent-dns-resolvers.sh | 485 | ||||
-rw-r--r-- | set-permanent-dns-resolvers/set_permanent_dns_resolvers.yml | 83 |
3 files changed, 569 insertions, 0 deletions
diff --git a/set-permanent-dns-resolvers/description b/set-permanent-dns-resolvers/description new file mode 100644 index 0000000..96fe31d --- /dev/null +++ b/set-permanent-dns-resolvers/description @@ -0,0 +1 @@ +Configure dns server values in ifcfg and resolv.conf diff --git a/set-permanent-dns-resolvers/set-permanent-dns-resolvers.sh b/set-permanent-dns-resolvers/set-permanent-dns-resolvers.sh new file mode 100755 index 0000000..a04af45 --- /dev/null +++ b/set-permanent-dns-resolvers/set-permanent-dns-resolvers.sh @@ -0,0 +1,485 @@ +#!/bin/sh +# Filename: set-permanent-dns-resolvers.sh +# Location: /etc/ansible/files +# Author: bgstack15@gmail.com +# Startdate: 2018-07-27 08:28:24 +# Title: Set permanent Dns Resolvers +# Purpose: To provide a single command that inserts dns resolver information into the permanent network config +# Package: former-gists +# History: +# 2018-08-03 improve -d1 info about resolv.conf +# Usage: +# ./set-permanent-dns-resolvers.sh 1.2.3.4 5.6.7.8 -r --iface +# Reference: ftemplate.sh 2018-06-21m; framework.sh 2017-11-11m +# Improve: +fiversion="2018-06-21m" +SPDR_version="2018-08-03a" + +usage() { + ${PAGER:-/usr/bin/less -F} >&2 <<ENDUSAGE +usage: set-permanent-dns-resolvers.sh [-duV] [--ifile <ifile>] [-i eth0] [-c conffile] [<1.2.3.4> [<1.2.3.5> ...]] +Set the dns resolvers in both the interface file and resolv.conf. +version ${SPDR_version} + -d debug Show debugging info, including parsed variables. + -u usage Show this usage block. + -V version Show script version number. + -c conf Read in this config file. + -i interface Use this interface. + --iface sets SPDR_DO_I + --noiface unsets SPDR_DO_I + -s silent sets SPDR_SILENT=1 + --nosilent sets SPDR_SILENT=0 + --ifile <file> sets SPDR_IFILE + --rfile <file> sets SPDR_RFILE + -r resolv sets SPDR_DO_R + --nor unsets SPDR_DO_R +Return values: + 0 Normal + 1 Help or version info displayed + 2 Count or type of flaglessvals is incorrect + 3 Incorrect OS type + 4 Unable to find dependency + 5 Not run as root or sudo + 6 Invalid interface definition + 7 Invalid resolv.conf file +Environment variables: +SPDR_DNS1 What resolvers to use. +SPDR_DNS2 If one of these is set to "gone" the script will remove that value from the file. +SPDR_DNS3 +SPDR_DO_I If truthy, update SPDR_IFILE. Default is 1. +SPDR_DO_R If truthy, update SPDR_RFILE. Default is 1. +SPDR_INTERFACE The ethernet card to configure. If undefined, it will find the first ethernet card with a "DNS1" definition. If that fails, it will select the first ethernet card. +SPDR_IFILE Exact interface file to manipulate. Default is blank, and it will be derived by the SPDR_INTERFACE value. +SPDR_RFILE resolv.conf file. Default is /etc/resolv.conf +SPDR_SILENT If truthy, suppress "changed" notification +Debug levels: + 1 changes being made + 2 checks being performed + 3 finding the interface to use +ENDUSAGE +} + +# DEFINE FUNCTIONS +find_valid_interface() { + # call: find_valid_interface + # output: interface name on stdout. + debuglev 9 && ferror "find_valid_interface $@" + + local output="" + + # Find first ethernet card with a DNS1 definition. + output="$( grep -lE '^\s*DNS1\s*=' /etc/sysconfig/network-scripts/ifcfg* 2>/dev/null | sort | grep -vE '^(lo|loopback)$' | head -n1 )" + if test -n "${output}" ; + then + echo "${output}" + else + # If that fails, select the first ethernet card found. + output="$( find /etc/sysconfig/network-scripts/ifcfg* 2>/dev/null | sort | grep -vE -e '-(lo|loopback)$' )" + if test -n "${output}" ; + then + echo "${output}" ; + else + # no DNS1 definitions and no ethernet card found. Fail out. + ferror "${scriptfile}: 6. No valid interface definition found! Please check /etc/sysconfig/network-scripts. Aborted." + exit 6 + fi + fi + debuglev 1 && ferror "Using interface $( basename "${output}" | sed -r -e 's/ifcfg-//;' )" +} + +apply_interface() { + # call: apply_interface "DNS1" "${SPDR_DNS1}" "${SPDR_IFILE}" + # performs action and does not directly care about output + debuglev 9 && ferror "apply_interface $@" + + local dnsnum="${1}" + local dnsr="${2}" + local ifile="${3}" + local dnscurrent="" + + # if defined + if test -n "${dnsr}" ; + then + if echo "${dnsr}" | grep -qE -e "gone|absent|empty" ; + then + # remove line if it exists + if grep -qE -e "^\s*${dnsnum}\s*=" "${ifile}" ; + then + # remove line + debuglev 1 && ferror "remove ${ifile} ${dnsnum}" + sed -i -r -n -e "/^\s*${dnsnum}\s*=/! p" "${ifile}" + mark_changed + else + # no change needed + debuglev 2 && ferror "unchanged ${ifile} ${dnsnum} undefined" + fi + else + # set value because it is defined + if grep -qE -e "^\s*${dnsnum}\s*=" "${ifile}" ; + then + # see if the dnscurrent + dnscurrent="$( grep -E "${dnsnum}=" "${ifile}" | awk -F'=' '{print $2}' )" + if ! test "${dnscurrent}" = "${dnsr}" ; + then + # replace it + debuglev 1 && ferror "change ${ifile} ${dnsnum} from ${dnscurrent} to ${dnsr}" + sed -i -r -e "s/(^\s*${dnsnum}\s*=).*/\1${dnsr}/;" "${ifile}" + mark_changed + else + debuglev 2 && ferror "unchanged ${ifile} ${dnsnum}=${dnsr}" + fi + else + # add it + debuglev 1 && ferror "add ${ifile} ${dnsnum}=${dnsr}" + echo "${dnsnum}=${dnsr}" >> "${ifile}" + mark_changed + + fi + fi + fi +} + +mark_changed() { + echo "1" > "${tmpfile1}" +} + +apply_resolv_conf() { + # call: apply_resolv_conf "1.2.3.4" "${DNS2}" "${DNS3}" "${SPDR_RFILE}" + # performs action and does not really care about output + debuglev 9 && ferror "apply_resolv_conf $@" + + local dns1="${1}" + local dns2="${2}" + local dns3="${3}" + local rfile="${4}" + + # populate dns variables from file for comparison + local rfile_contents="$( cat "${rfile}" 2>/dev/null )" + local rfile_dns1="$( echo "${rfile_contents}" | sed -n '/nameserver/p' | awk -v "num=1" 'NR==num{print $2;}' )" + local rfile_dns2="$( echo "${rfile_contents}" | sed -n '/nameserver/p' | awk -v "num=2" 'NR==num{print $2;}' )" + local rfile_dns3="$( echo "${rfile_contents}" | sed -n '/nameserver/p' | awk -v "num=3" 'NR==num{print $2;}' )" + + # compare and update each one if needed + x=0 + SPDR_rfile_done=0 + while test "${SPDR_rfile_done}" = 0 ; + do + x=$(( x + 1 )) + eval this_dns_goal="\${SPDR_DNS${x}}" + eval this_dns_already="\${rfile_dns${x}}" + + # if defined + if test -n "${this_dns_goal}" ; + then + # if requested to be absent, then please remove it + if echo "${this_dns_goal}" | grep -qE -e "gone|absent|empty" ; + then + # remove line if it exists + awk -v "dnsgone=${x}" 'BEGIN{a=0} /nameserver/{a=a+1; if(a==dnsgone)next;} {print;}' "${rfile}" > "${tmpfile2}" + replace_file_if_modified "${rfile}" "${tmpfile2}" && { debuglev 1 && ferror "remove nameserver ${x} of ${this_dns_already}" ; } || { debuglev 2 && ferror "unchanged nameserver ${x} empty" ; } + elif test "${this_dns_goal}" != "${this_dns_already}" ; + then + + # not the same so please update + awk -v "dnsnum=${x}" -v "goal=${this_dns_goal}" 'BEGIN{a=0} /nameserver/{a=a+1;if (a==dnsnum)$2=goal;} {print;}' "${rfile}" > "${tmpfile2}" + replace_file_if_modified "${rfile}" "${tmpfile2}" && debuglev 1 && ferror "change nameserver ${x} from ${this_dns_already} to ${this_dns_goal}" + # if it needs to add the above logic did not cover it, so check and add it here + if ! grep -qE "nameserver\\s+${this_dns_goal}" "${rfile}" ; + then + # it is not present so please add it + debuglev 1 && ferror "add ${rfile} nameserver ${x} ${this_dns_goal}" + echo "nameserver ${this_dns_goal}" >> "${rfile}" + fi + mark_changed + else + # no change needed + debuglev 2 && ferror "unchanged ${rfile} nameserver ${x}: ${this_dns_already}" + fi + fi + test ${x} -ge 3 && SPDR_rfile_done=1 + done + +} + +replace_file_if_modified() { + # call: replace_file_if_modified "/etc/resolv.conf" "${tmpfile2}" + # output: performs action and does not care about output + # returns: 0 if a change occurred + # goal is to replace first file if the second file is different than it + debuglev 9 && ferror "replace_file_if_modified $@" + + local origfile="${1}" + local tmpfile="${2}" + if ! diff -q "${origfile}" "${tmpfile}" 1>/dev/null 2>&1 ; + then + cat "${tmpfile}" > "${origfile}" + mark_changed ; # since we are just doing a simple boolean check at the end it is fine to spam this file + return 0 + fi + return 1 +} + +react_changed() { + # call: react_changed + # output: "changed" to stdout if there was any changes according to the tmpfile. + # usage: in the trap before exiting this script + + # react to changed + test -n "$( cat "${tmpfile1}" 2>/dev/null )" && ! fistruthy "${SPDR_SILENT}" && echo "changed" + +} + +# DEFINE TRAPS + +clean_SPDR() { + # use at end of entire script if you need to clean up tmpfiles + # rm -f "${tmpfile1}" "${tmpfile2}" 2>/dev/null + + # Delayed cleanup + if test -z "${FETCH_NO_CLEAN}" ; + then + nohup /bin/bash <<EOF 1>/dev/null 2>&1 & +sleep "${SPDR_CLEANUP_SEC:-300}" ; /bin/rm -r "${SPDR_TMPDIR:-NOTHINGTODELETE}" 1>/dev/null 2>&1 ; +EOF + fi +} + +CTRLC() { + # use with: trap "CTRLC" 2 + # useful for controlling the ctrl+c keystroke + : +} + +CTRLZ() { + # use with: trap "CTRLZ" 18 + # useful for controlling the ctrl+z keystroke + : +} + +parseFlag() { + flag="$1" + hasval=0 + case ${flag} in + # INSERT FLAGS HERE + "d" | "debug" | "DEBUG" | "dd" ) setdebug; ferror "debug level ${debug}" __debug_set_by_param=1;; + "u" | "usage" | "help" | "h" ) usage; exit 1;; + "V" | "fcheck" | "version" ) ferror "${scriptfile} version ${SPDR_version}"; exit 1;; + #"i" | "infile" | "inputfile" ) getval; infile1=${tempval};; + "c" | "conf" | "conffile" | "config" ) getval; conffile="${tempval}";; + "i" | "interface" ) getval; SPDR_INTERFACE="${tempval}";; + "iface" ) SPDR_DO_I=1;; + "noiface" | "no-iface" | "noi" | "ni" ) SPDR_DO_I=0;; + "s" | "silent" | "q" | "quiet" ) SPDR_SILENT=1;; + "nosilent" | "no-silent" | "verbose" | "v" ) SPDR_SILENT=0;; + "ifile" ) getval; SPDR_IFILE="${tempval}";; + "rfile" ) getval; SPDR_RFILE="${tempval}";; + "resolv" | "resolve" ) SPDR_DO_R=1;; + "noresolv" | "noresolve" | "no-resolv" | "no-resolve" | "nr" | "nor" ) SPDR_DO_R=0;; + esac + + debuglev 10 && { test ${hasval} -eq 1 && ferror "flag: ${flag} = ${tempval}" || ferror "flag: ${flag}"; } +} + +# DETERMINE LOCATION OF FRAMEWORK +f_needed=20171111 +while read flocation ; do if test -e ${flocation} ; then __thisfver="$( sh ${flocation} --fcheck 2>/dev/null )" ; if test ${__thisfver} -ge ${f_needed} ; then frameworkscript="${flocation}" ; break; else printf "Obsolete: %s %s\n" "${flocation}" "${__this_fver}" 1>&2 ; fi ; fi ; done <<EOFLOCATIONS +./framework.sh +${scriptdir}/framework.sh +$HOME/bin/bgscripts/framework.sh +$HOME/bin/framework.sh +$HOME/bgscripts/framework.sh +$HOME/framework.sh +/usr/local/bin/bgscripts/framework.sh +/usr/local/bin/framework.sh +/usr/bin/bgscripts/framework.sh +/usr/bin/framework.sh +/bin/bgscripts/framework.sh +/usr/local/share/bgscripts/framework.sh +/usr/share/bgscripts/framework.sh +EOFLOCATIONS +test -z "${frameworkscript}" && echo "$0: framework not found. Aborted." 1>&2 && exit 4 + +# INITIALIZE VARIABLES +# variables set in framework: +# today server thistty scriptdir scriptfile scripttrim +# is_cronjob stdin_piped stdout_piped stderr_piped sendsh sendopts +. ${frameworkscript} || echo "$0: framework did not run properly. Continuing..." 1>&2 +infile1= +outfile1= +logfile=${scriptdir}/${scripttrim}.${today}.out +define_if_new interestedparties "bgstack15@gmail.com" +# SIMPLECONF +define_if_new default_conffile "/etc/default/set-permanent-dns-resolvers" +#define_if_new defuser_conffile ~/.spdrrc # no need for a default user conf file +test -z "${SPDR_TMPDIR}" && SPDR_TMPDIR="$( mktemp -d )" +define_if_new SPDR_DO_I 1 +define_if_new SPDR_DO_R 1 +define_if_new SPDR_RFILE "/etc/resolv.conf" +tmpfile1="$( TMPDIR="${SPDR_TMPDIR}" mktemp )" # if contents exist, then something changed +tmpfile2="$( TMPDIR="${SPDR_TMPDIR}" mktemp )" # contents for temporary rfile + +# REACT TO OPERATING SYSTEM TYPE +case $( uname -s ) in + Linux) : ;; + FreeBSD) : ;; + *) echo "${scriptfile}: 3. Indeterminate OS: $( uname -s )" 1>&2 && exit 3;; +esac + +# SET CUSTOM SCRIPT AND VALUES +#setval 1 sendsh sendopts<<EOFSENDSH # if $1="1" then setvalout="critical-fail" on failure +#/usr/local/share/bgscripts/send.sh -hs # setvalout maybe be "fail" otherwise +#/usr/share/bgscripts/send.sh -hs # on success, setvalout="valid-sendsh" +#/usr/local/bin/send.sh -hs +#/usr/bin/mail -s +#EOFSENDSH +#test "${setvalout}" = "critical-fail" && ferror "${scriptfile}: 4. mailer not found. Aborted." && exit 4 + +# VALIDATE PARAMETERS +# objects before the dash are options, which get filled with the optvals +# to debug flags, use option DEBUG. Variables set in framework: fallopts +validateparams - "$@" + +# LEARN EX_DEBUG +test -z "${__debug_set_by_param}" && fisnum "${SPDR_DEBUG}" && debug="${SPDR_DEBUG}" + +# CONFIRM TOTAL NUMBER OF FLAGLESSVALS IS CORRECT +#if test ${thiscount} -lt 2; +#then +# ferror "${scriptfile}: 2. Fewer than 2 flaglessvals. Aborted." +# exit 2 +#fi + +# LOAD CONFIG FROM SIMPLECONF +# This section follows a simple hierarchy of precedence, with first being used: +# 1. parameters and flags +# 2. environment +# 3. config file +# 4. default user config: ~/.config/script/script.conf +# 5. default config: /etc/script/script.conf +if test -f "${conffile}"; +then + get_conf "${conffile}" +else + if test "${conffile}" = "${default_conffile}" || test "${conffile}" = "${defuser_conffile}"; then :; else test -n "${conffile}" && ferror "${scriptfile}: Ignoring conf file which is not found: ${conffile}."; fi +fi +test -f "${defuser_conffile}" && get_conf "${defuser_conffile}" +test -f "${default_conffile}" && get_conf "${default_conffile}" + +# CONFIGURE VARIABLES AFTER PARAMETERS +# yes, command line parameters should clobber environment variables +test -n "${opt1}" && SPDR_DNS1="${opt1}" +test -n "${opt2}" && SPDR_DNS2="${opt2}" +test -n "${opt3}" && SPDR_DNS3="${opt3}" + +## REACT TO BEING A CRONJOB +#if test ${is_cronjob} -eq 1; +#then +# : +#else +# : +#fi + +# SET TRAPS +#trap "CTRLC" 2 +#trap "CTRLZ" 18 +trap "__ec=$? ; react_changed ; clean_SPDR ; trap '' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; exit ${__ec} ;" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + +# DEBUG SIMPLECONF +debuglev 5 && { + ferror "Using values" + # used values: EX_(OPT1|OPT2|VERBOSE) + set | grep -iE "^SPDR_" 1>&2 +} + +# REACT TO ROOT STATUS +case ${is_root} in + 1) # proper root + : ;; + sudo) # sudo to root + : ;; + "") # not root at all + ferror "${scriptfile}: 5. Please run as root or sudo. Aborted." + exit 5 + ;; +esac + +# MAIN LOOP +#{ + + # Should we do the interface configuration? + if fistruthy "${SPDR_DO_I}" ; + then + + # skip the check if SPDR_IFILE is defined already. + if test -z "${SPDR_IFILE}" ; + then + + # Get a valid interface + if test -z "${SPDR_INTERFACE}" ; + then + debuglev 3 && ferror "Will scan for valid interface." + SPDR_INTERFACE="$( find_valid_interface )" + elif test ! -e "/etc/sysconfig/network-scripts/ifcfg-${SPDR_INTERFACE}" ; + then + # no requested interface, or the requested one is not valid + debuglev 3 && ferror "${scriptfile}: invalid interface \"${SPDR_INTERFACE}\", so will scan for valid one." + SPDR_INTERFACE="$( find_valid_interface )" + fi + + # Trim interface name down to just "eth0" + echo "${SPDR_INTERFACE}" | grep -qE -e 'ifcfg' && SPDR_INTERFACE="$( basename "${SPDR_INTERFACE}" 2>/dev/null | sed -r -e 's/ifcfg-//;' )" + # Confirm interface is valid + if test ! -e "/etc/sysconfig/network-scripts/ifcfg-${SPDR_INTERFACE}" ; + then + ferror "${scriptfile}: 6. Cannot find interface ${SPDR_INTERFACE}. Aborted." + exit 6 + fi + SPDR_IFILE="/etc/sysconfig/network-scripts/ifcfg-${SPDR_INTERFACE}" + + fi + + # Now with the valid interface file at SPDR_IFILE, please update the DNS1 and DNS2 and DNS3 settings. + x=0 + SPDR_done=0 + cat /dev/null > "${tmpfile1}" # set changed value to 0 + while test "${SPDR_done}" = 0 ; + do + x=$(( x + 1 )) + eval this_dnsr="\${SPDR_DNS${x}}" + apply_interface "DNS${x}" "${this_dnsr}" "${SPDR_IFILE}" + test $x -ge 3 && SPDR_done=1 + done + + fi + + # Should we do the resolv.conf configuration? + if fistruthy "${SPDR_DO_R}" ; + then + + # confirm file exists + # create it if it does not. + if test ! -e "${SPDR_RFILE}" ; + then + touch "${SPDR_RFILE}" + mark_changed + fi + + # confirm file is writable + if test ! -w "${SPDR_RFILE}" ; + then + ferror "${scriptfile}: 7. Cannot modify resolv \"${SPDR_RFILE}\". Aborted." + exit 7 + fi + + # peform changes + apply_resolv_conf "${SPDR_DNS1}" "${SPDR_DNS2}" "${SPDR_DNS3}" "${SPDR_RFILE}" + + fi + +#} | tee -a ${logfile} + +# EMAIL LOGFILE +#${sendsh} ${sendopts} "${server} ${scriptfile} out" ${logfile} ${interestedparties} + +# exit safely +exit 0 diff --git a/set-permanent-dns-resolvers/set_permanent_dns_resolvers.yml b/set-permanent-dns-resolvers/set_permanent_dns_resolvers.yml new file mode 100644 index 0000000..efe7698 --- /dev/null +++ b/set-permanent-dns-resolvers/set_permanent_dns_resolvers.yml @@ -0,0 +1,83 @@ +--- +# set_permanent_dns_resolvers.yml +# usage: +# ansible-playbook -i /etc/ansible/inv/all /etc/ansible/books/stable/set_permanent_dns_resolvers.yml -v -l clonetest209 + +- name: book that sets permanent dns resolvers + hosts: all + become: yes + become_user: root + become_method: sudo + vars: + dns_by_ipv4_network: + # DC1 PROD + 10.1.16.0: + - 10.1.17.1 + - 10.1.17.2 + # DC1 PROD 2 + 10.1.80.0: + - 10.1.17.1 + - 10.1.17.2 + # DC1 DMZ + 10.1.32.0: + - 10.1.33.58 + - 10.1.33.60 + # DC2 PROD + 10.2.16.0: + - 10.2.17.7 + - 10.2.17.8 + - gone + # DC2 PROD 2 + 10.2.80.0: + - 10.2.17.7 + - 10.2.17.8 + - gone + # DC2 DMZ + 10.2.32.0: + - 10.2.33.1 + - 10.2.33.2 + script_dir: '/etc/ansible/files' + script_file: 'set-permanent-dns-resolvers.sh' + tasks: + + - name: copy in rpm + copy: + src: /etc/ansible/files/rpms/bgscripts-core-1.3-8.noarch.rpm + dest: /tmp/ + mode: 0644 + changed_when: false + + - shell: rpm -U --nodeps /tmp/bgscripts-core-1.3-8.noarch.rpm + args: + warn: no + register: this_rpm + failed_when: + - 'not ("is already installed" in this_rpm.stdout or "is already installed" in this_rpm.stderr or this_rpm.rc == 0)' + changed_when: + - 'not ("is already installed" in this_rpm.stdout or "is already installed" in this_rpm.stderr)' + + - copy: + src: "{{ script_dir }}/{{ script_file }}" + dest: "/tmp/{{ script_file }}" + changed_when: false + + - shell: /bin/sh /tmp/{{ script_file }} -d1 + args: + warn: no + environment: + SPDR_DNS1: "{{ dns_by_ipv4_network[ansible_default_ipv4.network][0] | default(skip) }}" + SPDR_DNS2: "{{ dns_by_ipv4_network[ansible_default_ipv4.network][1] | default(skip) }}" + SPDR_DNS3: "{{ dns_by_ipv4_network[ansible_default_ipv4.network][2] | default(skip) }}" + register: this_script + changed_when: + - '"changed" in this_script.stdout' + + # cleanup + - file: + path: "/tmp/{{ item }}" + state: absent + ignore_errors: yes + changed_when: false + with_items: + - "{{ script_file }}" + - bgscripts-core-1.3-8.noarch.rpm |