0

Error

While running the sudo apt update and sudo apt upgrade on a new Ubuntu Server 20.04.2 LTS 32-bit server OS for armhf architectures on the RaspberryPi with 4gb ram, I am encountering the following errors:

For sudo apt update:

E: Release file for http://ports.ubuntu.com.../focal-updates/Inrelease is not yet valid (invalid for another 113d 22h 43min). Updates for this repository will not be applied.

For sudo apt upgrade:

Waiting for cache lock: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 3381 (unattended-upgr).

Code

The code below first checks if internet is available, if it is not, it checks if the wifi ssid and password have been added to the configuration, if not it prompts the user for them, and then activates those settings until the internet connection is established. Then it performs the sudo apt update and sudo apt upgrade commands.

# Verify internet access is available
while [ $(ping -q -w1 -c1 google.com &>/dev/null && echo online || echo offline) == offline ]
do
sleep 1
# get wifi module
module=$(ls /sys/class/net)
module_list=($module)
wlan_module=${module_list[-1]}
echo $wlan_module

# get wifi configuration file
config_filename=$(ls /etc/netplan)
echo $config_filename
config_filepath="/etc/netplan/$config_filename"

# check if the wifi is already added.
if ! grep -q "$wlan_module" "$config_filepath"; then
    echo "have to add wifi"

    # ask  wifi pwd ssid
    read -p "What is the wifi ssid you want to connect to(Case sensitive)?" ssid

    # ask wifi pwd
    read -p "What is the wifi pwd?" pwd

    # append content
    echo "    wifis:" | sudo tee -a $config_filepath 
    echo "        wlan0:" | sudo tee -a $config_filepath
    echo "            dhcp4: true" | sudo tee -a $config_filepath
    echo "            optional: true" | sudo tee -a $config_filepath
    echo "            access-points:" | sudo tee -a $config_filepath
    echo "                \"$ssid\":" | sudo tee -a $config_filepath
    echo "                    password: \"$pwd\"" | sudo tee -a $config_filepath

    # generate a config file
    sudo netplan generate

    # apply the config file
    sudo netplan apply

fi

done

set timezone based on ip

export tz=wget -qO - http://geoip.ubuntu.com/lookup | sed -n -e 's/.*<TimeZone>\(.*\)<\/TimeZone>.*/\1/p' && timedatectl set-timezone $tz export tz=timedatectl status| grep Timezone | awk '{print $2}'

Verify timezone is set correctly.

timedatectl status

yes | sudo apt update read -p "Update completed <type enter>" next yes | sudo apt upgrade read -p "Upgrade completed <type enter>" next

the code is executed using:

sudo mkdir /media/usbstick
sudo mount /dev/sda1 /media/usbstick
/media/usbstick/.first_run.sh

Timezone details

In response to the comments I have included code that automatically sets the timezone, and I have manually verified the timezone is set correctly.

Assumption

I assume that that is because the Ubuntu server is automatically performing some kind of update/upgrading in the background in the background, which prevents me from running the sudo apt upgrade command simultaneously.

Question

So when I manually kill the process that blocks the sudo apt upgrade command with sudo kill -9 <process_id> I am able to successfully run the sudo apt upgrade command. However, I can imagine this is not the best way to ensure the upgrade command is completed successfully. So my current approach is to write a while-loop that scans the output of the sudo apt upgrade command until it yields a successful output. However, that feels like re-inventing the wheel and I can imagine there might exist better ways to resolve this issue. Hence, I would like to ask:

How can I run the sudo apt upgrade command safely and automatically on a new installation of Ubuntu Server 20.04 LTS 32-bit server such that the rest of my Ubuntu Server post script can be completed correctly?

a.t.
  • 317
  • 2
    Is your system's date/time and timezone correct? You should consider adding commands to correct the system time if it is not correct. – FedKad May 26 '21 at 11:38
  • 1
    Double check the date on your system anyways - you might need to temporarily manually set the date on the system by hand first. timedatectl status will get you the current date/time on the system – Thomas Ward May 26 '21 at 12:16
  • In response to your comments I included a code that automatically sets the time zone, and I have manually verified the Local time:, Universal time: and Time zone: are set correctly. The output errors remain the unchanged. So to explicitly answer the question by @FedonKadifeli, yes the date/time and timezone are correct. – a.t. May 26 '21 at 13:53
  • I had this issue once, but after update and upgrade finally ran, I never had the issue again. Are you still having this issue? – Gordster May 26 '21 at 13:57
  • @Gordster after the update and upgrade commands are ran successfully, the error indeed disappears. Since this is the first script I intend to run after a new installation, this question pertains to automatically setting up that first run. – a.t. May 26 '21 at 14:25

1 Answers1

0

My current implementation consists of two while loops that run the two sudo apt update and sudo apt upgrade commands, until their respective outputs are verified. It is far from elegant but appear to be working. The enhanced first_run.sh script is contained below:

# Assumes both strings have equal lengths
equal_strings() {
    left=$1
    right=$2
# Initialise the default test result to false
test_result=false

# Set the test result to true if the left and right string are equal
if [ &quot;$left&quot; = &quot;$right&quot; ]; then
    echo &quot;Strings are equal.&quot;
    test_result=true
else
        echo &quot;Strings are not equal.&quot;
fi

# Output true or false to pass the equality test result to parent function
echo $test_result

}

Assumes the actual result is shorter than the allowed result

right_is_in_tail_of_left() { left=$1 right=$2 right_size=${#right} left_tail_chars=$(echo -n $left | tail -c $right_size)

# Output true or false to pass test result to parent function
echo $(equal_strings &quot;$left_tail_chars&quot; &quot;$right&quot;)

}

Makes the main script runnable, removes the log file and runs main file.

actual_result_has_any_allowed_result_in_tail() { # declare default function output test_result=false

# get the actual result
actual_result=$1
shift # Shift all arguments to the left (original $1 gets lost)

# get the list of allowed results and list size
allowed_results=(&quot;$@&quot;) 
list_size=${#allowed_results}

# Only engage this function if the list size is greater than 1
if [ $list_size -gt 1 ]; then echo &quot;error&quot;;

    # if the actual result is in the acceptable list ensure function returns true
    for allowed_result in &quot;${allowed_results[@]}&quot;
    do
        if [ $test_result != true ]; then
            # compute lengths of result strings
            allowed_result_size=${#allowed_result}
            actual_result_size=${#actual_result}

            # TODO: remove this if condition and directly go to Else by switching lt to ge
            if [ $actual_result_size -lt $allowed_result_size ]; then echo &quot;error&quot;;
                echo &quot;The actual size is:&quot;
                echo $actual_result_size
                echo &quot;WHEREAS allowed_result_size=&quot; 
                echo $allowed_result_size
                echo &quot;so actual is smaller than allowed, so do nothing&quot;
            else 
                # test if left string is in the tail of the allowed result string
                # TODO: include contains option in separate function
                temp_test_result=$(right_is_in_tail_of_left &quot;$actual_result&quot; &quot;$allowed_result&quot;);
                if [ $(echo -n $temp_test_result | tail -c 4) == true ]; then
                    test_result=true
                fi
            fi
        fi
    done
fi

# Ensure the last 4/5 characters of the output of this function contains the true false evaluation.
echo $test_result

}

Verify internet access is available

while [ $(ping -q -w1 -c1 google.com &>/dev/null && echo online || echo offline) == offline ] do

sleep 1
# get wifi module
module=$(ls /sys/class/net)
module_list=($module)
wlan_module=${module_list[-1]}
echo $wlan_module

# get wifi configuration file
config_filename=$(ls /etc/netplan)
echo $config_filename
config_filepath=&quot;/etc/netplan/$config_filename&quot;

# check if the wifi is already added.
if ! grep -q &quot;$wlan_module&quot; &quot;$config_filepath&quot;; then
    echo &quot;have to add wifi&quot;

    # ask  wifi pwd ssid
    read -p &quot;What is the wifi ssid you want to connect to(Case sensitive)?&quot; ssid

    # ask wifi pwd
    read -p &quot;What is the wifi pwd?&quot; pwd

    # append content
    echo &quot;    wifis:&quot; | sudo tee -a $config_filepath 
    echo &quot;        wlan0:&quot; | sudo tee -a $config_filepath
    echo &quot;            dhcp4: true&quot; | sudo tee -a $config_filepath
    echo &quot;            optional: true&quot; | sudo tee -a $config_filepath
    echo &quot;            access-points:&quot; | sudo tee -a $config_filepath
    echo &quot;                \&quot;$ssid\&quot;:&quot; | sudo tee -a $config_filepath
    echo &quot;                    password: \&quot;$pwd\&quot;&quot; | sudo tee -a $config_filepath

    # generate a config file
    sudo netplan generate

    # apply the config file
    sudo netplan apply

fi

done

https://askubuntu.com/questions/323131/setting-timezone-from-terminal

echo "Setting TimeZone..." export tz=wget -qO - http://geoip.ubuntu.com/lookup | sed -n -e 's/.*&lt;TimeZone&gt;\(.*\)&lt;\/TimeZone&gt;.*/\1/p' && timedatectl set-timezone $tz export tz=timedatectl status| grep Timezone | awk '{print $2}' echo "TimeZone set to $tz"

A loop that checks whether the output of the update command is as expected after successfull completion.

check_output_update_command() { #test_result=false while [[ $test_result != true ]] do update_output=$(yes | sudo apt update) echo $update_output

    allowed_results=(&quot;Reading package lists... Building dependency tree... Reading state information... All packages are up to date.&quot;
            &quot;packages can be upgraded. Run 'apt list --upgradable' to see them.&quot;
        )

    test_result=$(actual_result_has_any_allowed_result_in_tail &quot;$update_output&quot; &quot;${allowed_results[@]}&quot;)
    test_result=${test_result: -4}
    echo $test_result
done

} check_output_update_command "$@" read -p "Succesfully completed update command <type enter>" next

A loop that checks whether the output of the upgrade command is as expected after successfull completion.

check_output_upgrade_command() { #output_ending=false while [[ $output_ending != " upgraded." ]] do upgrade_output=$(yes | sudo apt upgrade) echo $upgrade_output

    #output_ending=$(tail -c 11 $upgrade_output)
    output_ending=${upgrade_output: -10}
    echo $output_ending
done

} check_output_upgrade_command "$@" read -p "Succesfully completed upgrade command <type enter>" next

And it can be executed using:

sudo mkdir /media/usbstick
sudo mount /dev/sda1 /media/usbstick
/media/usbstick/.first_run.sh
a.t.
  • 317