How to get any interactive script run only during firstboot on console and then remove itself?

Solution Verified - Updated -

Environment

  • Red Hat Enterprise Linux 6

Issue

  • There is a golden image created for Red Hat Enterprise Linux machine on VMWare Virtual Environment.
  • Once cloned, it's required to setup new IP address information and change the MAC address for eth0 during firstboot only.
  • How can one merge any script into rc runlevel 3 and get that script executed and then remove itself after successful execution?

Resolution

  • One can get the interactive inputs during the rc.local executions.
  • The logic here is as follows.

    • Modify the file /etc/rc.d/rc3.d/S99local which will be executed at the last during runlevel 3 in upstart process and append the contents of the interactive script into this file with few if-else statements.
    • This script itself will check it's location at a particular directory and if that file is present, then it will execute itself and if the file is missing, it won't execute itself.
    • Again, during execution, if the contents provided were not valid, it will ask for the confirmation from the user first, and then only move the interactive script to some other location, otherwise not.
    • Read the script file attached to the KCS for test case.
  • Perform the following steps in Golden Image without rebooting it, and after making changes, just power it off and clone, then start the clone.

1. Create a file in root as follows.

# touch /root/firstrun

2. Then put the script in root. For example, the name is update.sh script in /root.

# ls -l /root/update.sh

3. In the Golden Image, make change the file contents of /etc/rc.d/rc3.d/S99local as follows.

[root@testserver ~]# cat /etc/rc.d/rc3.d/S99local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local
plymouth quit
if [ -f "/root/firstrun" ]
then
    echo "==================================================="
    echo "Setup the hostname of the server!"
    echo "==================================================="
    sleep 1
    echo ""
    echo -n "Enter the FQDN             : "
    read NAME
    sleep 1
    echo ""
    echo ""
    echo "==================================================="
    echo "Ethernet device eth0 Configuration!"
    echo "==================================================="
    sleep 1
    echo ""
    echo -n "Enter the IP address       : "
    read IP
    sleep 1
    echo -n "Enter the subnet mask      : "
    read MASK
    sleep 1
    echo -n "Enter the gateway      : "
    read GATEWAY
    sleep 1
    echo -n "Enter the DNS IP       : "
    read DNS
    sleep 1
    echo ""
    echo ""
    echo "Are you sure everything is perfect now? (y/n):    "
    read answer
    if [ $answer == y ]
    then
        # change hostname
        sed -i '/HOSTNAME/c\' /etc/sysconfig/network
        echo "HOSTNAME=$NAME" >> /etc/sysconfig/network
        hostname $NAME
        # Remove UUID
        sed -i '/UUID/c\' /etc/sysconfig/network-scripts/ifcfg-eth0

        #change Bootproto:
        sed -i '/BOOTPROTO/c\' /etc/sysconfig/network-scripts/ifcfg-eth0
        echo "BOOTPROTO=static" >> /etc/sysconfig/network-scripts/ifcfg-eth0

        #change IP address:
        sed -i '/IPADDR/c\' /etc/sysconfig/network-scripts/ifcfg-eth0
        echo "IPADDR=$IP" >> /etc/sysconfig/network-scripts/ifcfg-eth0

        # change netmask
        sed -i '/NETMASK/c\' /etc/sysconfig/network-scripts/ifcfg-eth0
        echo "NETMASK=$MASK" >> /etc/sysconfig/network-scripts/ifcfg-eth0

        # change gateway
        sed -i '/GATEWAY/c\' /etc/sysconfig/network-scripts/ifcfg-eth0
        echo "GATEWAY=$GATEWAY" >> /etc/sysconfig/network-scripts/ifcfg-eth0

        # change dns
        sed -i '/DNS1/c\' /etc/sysconfig/network-scripts/ifcfg-eth0
        echo "DNS1=$DNS" >> /etc/sysconfig/network-scripts/ifcfg-eth0

        # change MAC
        MAC=`/sbin/ifconfig | grep 'eth0' | tr -s ' ' | cut -d ' ' -f5`
        sed -i '/HWADDR/c\' /etc/sysconfig/network-scripts/ifcfg-eth0
        echo "HWADDR=$MAC" >> /etc/sysconfig/network-scripts/ifcfg-eth0
        sleep 1
        # make the interface up and restart the service
        echo ""
        echo ""
        echo "Restarting the Network Service, please wait!"
        service network restart &> /dev/null
        sleep 1
        echo ""
        echo ""
        echo "Please Verify the IP Information and Hostname"
        echo ""
        echo ""
        echo "Hostname set is `hostname`"
        sleep 1
        echo ""
        echo "Output of ifconfig is as follows"
        echo "==================================================="
        ifconfig eth0
        echo "==================================================="
        echo "Moving the script so that it won't execute again!"
        rm -f /root/firstrun
        mv -f /root/update.sh /tmp
        echo "Backup created at /tmp with name update.sh"
    else
        bash /root/update.sh
    fi
fi

4. Then poweroff the machine, and create a new clone and boot that.

Attachments

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.

2 Comments

Is this feasible for RHEL 7 and beyond? Any latches via systemd for a run once at first boot? Perhaps subsumed by automated deployment... but still of interest., or perhaps for network reconfig script to be run ad-hoc?

IMHO, the simplest way to do a run-once at reboot kind of job would be via cron. It so happens that it's also not specific to RHEL 5, 6, 7, or 8.

  1. Create a new /etc/cron.d/BLAH file. These are in the same format as /etc/crontab, so you have to specify the user field. Set the timespec to @reboot.

  2. Create a script that your /etc/cron.d/BLAH file can execute, e.g., /usr/local/bin/tempscript.

  3. Have that script do its thing, and then at the end, delete /etc/cron.d/BLAH and itself.

EDIT: Oh just noticed "interactive" in the title. I haven't played with that in a while, but I wrote How to allow a custom service script in RHEL7 to run in the foreground and accept user input a few years ago, so you could use that. Once you got it working, you'd of course want to add some logic so that it deleted/disabled itself after first run. Nowadays these sorts of things are much more often handled by stuff like cloudinit...