9

I am distributing a VM to my students for a beginners programming course. For speed, instead of getting them to install Ubuntu from scratch, I'm planning to give them a fully set up image that they can just run.

In order to get it set up I've given it a sacrificial hostname, username and password. What's the cleanest way to change this for the students when they get up and running?

I've got as far as this gist, which has some unreliable progress with the hostname, but the username is resisting me changing it.

I'd like it to be as painless a process as possible as this is supposed to happen in their first lab.

It's entirely possible that there is a completely different approach that I ought to take. I'm open to all suggestions.

#!/bin/bash
clear
toilet  "     CODE1161     "  --metal --font future
echo    ""
toilet  "Let's get started!"  --metal --font future
echo    ""
echo    "We need to make this computer be YOURS"
echo    "We need a name for you and your computer, make it short or it'll take up a lot of space."
echo    "My computer is called um and my name is ben, so I get ben@um:~$ as my command prompt."
echo    ""
read -p "Enter a name for your computer:"  compname
read -p "Enter your name: "  username
echo    ""
toilet  "$username@$compname~$"  --gay --font wideterm
echo    ""
echo    "What do you think? If you hate it, press ctrl+c and do this again"
read -p "otherwise, just press enter." sacrificial

# set the host name, in a million places, for some unknown reason.
echo "1"
sed -i "/127\.0\.1\.1\s*vc/ { c \
127.0.1.1   $compname
}" /etc/hosts
echo "2"
sudo hostname -b $compname
echo "3"
sudo hostnamectl set-hostname $compname
echo "4"
sudo groupadd $username
echo "5"
sudo usermod -d /home/$username -m -g $username -l $username ben

a screen shot of the output progress

Kaz Wolfe
  • 34,122
  • 21
  • 114
  • 172
Ben
  • 93
  • 6
  • 1
    Use expect - http://www.admin-magazine.com/Articles/Automating-with-Expect-Scripts – Panther Feb 01 '17 at 21:15
  • 1
    Maybe I am wrong, but I've only ever used expect to take an interactive process and make it non-interactive. Basically, making a script that expect certain output and having the response already known in the script. Ben wants to wait for user input and execute a command based on it. Granted, I'm wrong at least once a day, so this might be the case. –  Feb 01 '17 at 21:40
  • Actually, I'm good for the part that takes user input. Once I've gathered host name and user name, they are stored as variables. The bit that's troublesome is after that. I.e. from the comment down. – Ben Feb 01 '17 at 21:44
  • 1
    There are some flaws in this method. One, you can't change the current users path, it's not possible. The bash prompt isn't updated when the hostname changes, it's only read once when the terminal is opened. You could exec bash but it will technically open up a nested terminal. –  Feb 02 '17 at 02:00
  • To fix your hostname issue, I would replace your sed with something like this.. sudo sed -i "s/127.0.1.1/& $compname/" /etc/hosts Which will update the 127.0.1.1 line, and just append the new host to what's there. It will leave the old host in place, but it's compliant to have multiple hosts assigned to one IP. That will prevent the unresolvable issue with your other sudo command, changing the hostname. –  Feb 02 '17 at 02:05

2 Answers2

8

Why not just use an OEM installation for this? It's not as pretty, but it gets the job done. If you want to go down this route, see izx's excellent answer to this question: How do I pre-install Ubuntu for someone (OEM install)?

Basically, the system will (on first boot) prompt the user for a bunch of information to personalize their machine. This includes the language, location, username, hostname, password, and so on. Basically, everything that your computer will usually prompt you with for an installation.

This is exactly what OEM images are meant for, and they do a great job of it. Plus, you'll give your students a small taste of the "install Ubuntu" experience. Though, Ubuntu installs aren't exactly painful. You can probably do it in a single class, and give your students some homework to personalize and explore their VM. Plus, partitioning is painful fun!


Back to the problem at hand (and an answer to your actual question).....

Let's look at man usermod to get an explanation for what's going on:

CAVEATS
   You must make certain that the named user is not executing any
   processes when this command is being executed if the user's numerical
   user ID, the user's name, or the user's home directory is being
   changed.  usermod checks this on Linux, but only check if the user is
   logged in according to utmp on other architectures.

Basically, this just means we can't change a user's UID, their username, home directory, or anything of the sort if the user is logged in.

So, we can do some fun stuff to set this up on the system's next boot. Instead of your script doing the work, we make your script make another script to do all the heavy lifting and manipulation. An example of this:

# Make the first-run script
touch /etc/init.d/firstrun-setup.sh

# Add in user modifier
echo "usermod -d /home/$username -m -g $username -l $username ben" >> /etc/init.d/firstrun-setup.sh

# Add in group rename
echo "groupmod -n $username ben" >> /etc/init.d/firstrun-setup.sh

# Add in password expiry
echo "passwd -e $username" >> /etc/init.d/firstrun-setup.sh

# Add in file self-destruct
echo "rm /etc/init.d/firstrun-setup.sh" >> /etc/init.d/firstrun-setup.sh

# Mark the file as executable
chmod a+x /etc/init.d/firstrun-setup.sh

# Reboot the computer
reboot

Basically, by doing this, you're "queueing" events to run on the system's next boot. This will run before the userland happens, so the system will execute these commands as root. Therefore, the ben user won't be logged in, and the system won't complain.

You may still need to add additional commands to this thing to allow more personalization (like setting the actual name, etc). However, this is optional and only needs to be done if you want it to take place during the setup script.

Though, it may be a good idea to just create a new user for the students entirely, and then keep your existing sacrificial account in place. This way, if something happens, you can go in and repair/administrate their machine if at all necessary. Of course, if you're giving your students admin access to their VM, this is sort of a moot point as they might very well delete the "instructor" user because they're students.

Kaz Wolfe
  • 34,122
  • 21
  • 114
  • 172
  • I intended to suggest 'make an OEM installation', and then I found this answer :-) – sudodus Feb 21 '17 at 06:57
  • Thanks for answering the root question of how to achieve my end, I'm going to go with an OEM install. – Ben Feb 21 '17 at 22:45
0

At the login screen, have them press ctrlaltF2 and login as ben from the terminal that opens and run

sudo passwd

And give them all the same password for root, ie, the course number, so if something breaks, you can go in and fix it. Then have them log out by typing exit, and log in as root with their new root password and run the script (you may have to modify it so it alters the ben user and not root).

Or, have them log in as ben from the terminal by pressing ctrlaltF2 (like before) at the login screen and have them then run the script from there. This could work because as Muru and Kaz Wolfe pointed out in the previous answer, the user cannot be running any processes, and logging in via the terminal shouldn't start any processes, such as X or Ubuntu-Desktop, or other userland processes that interfere with usermod. (I don't know if this works, I haven't tried it, but it's worth a try).