Bill Wear
on 30 November 2020
CLI-only MAAS operation
MAAS provides a state-of-the-art User Interface (UI), which is relatively simple to use, if the required inputs are known and understood. You may be less familiar with the MAAS Command Line Interface (CLI), which is actually more robust, providing additional functionality that’s not accessible via the web UI. In this series of blog posts, we’re going to explore what it means to operate MAAS solely from the CLI.
There are two primary reasons why the CLI might be favoured:
- Some operators are acclimated to the command-line, and less comfortable with GUI environments.
- There are more than a few situations where it may be essential to script MAAS operations, for automation, efficiency, repeatability, or scalability reasons.
We’re going to spend several posts looking at this mode, not only because of the depth of the topic, but also because different readers may want to focus more tightly on specific aspects of the CLI. Even so, some of these posts will be longer and denser than your average blog — but we also know that MAAS users tend to be very detail-focused, so the extra information should be worth the read.
Installing and configuring MAAS
In this first post, we’ll explain how to install and configure MAAS using only the CLI interface. Of course, installation is not typically a GUI-driven activity, but configuration has a fairly straightforward UI component. We’ll also try to add value by suggesting scripting techniques to install MAAS, including conditional methods with wait-states, extra logging, and error-handling. If you plan to bring up multiple instances of MAAS, you’ll have the outline of a canned procedure; and if you prefer to standardise your installs in case of resets, you’ll have the beginnings of a standardised script.
Conventional language
Let’s start by pre-empting any confusion about what appears here, by establishing the following four conventions:
- The host being used in this example is called “wintermute.” Most of the time, the command prompt will be shown, indicating this hostname, so that there won’t be any confusion of commands with responses.
- Responses will show static (final) messages only. Sometimes, the MAAS commands issued will show intermediate progress bars or messages that eventually disappear when the command finishes. These temporary messages won’t be reproduced here.
- MAAS CLI commands require some inputs specific to your local installation, such as the administrative username ($PROFILE) or a machine’s system ID ($SYSTEM_ID). When you see these replaceable parameters ($PARAM_NAME), you’ll need to substitute the correct values for your particular situation. We’ll explain each new variable as we introduce it.
- We’ll be working with the production configuration, using a local PostgreSQL database, rather than the MAAS test configuration. We’ll also be working with a snap install, rather than Debian packages, and we’ll initialise here in
rack+region
mode. All of the steps shown here were executed and validated with that setup, so no promises on whether they will look exactly the same with other configurations, though there’s no reason why they wouldn’t work.
Installing MAAS
To install MAAS from the snap, execute this command:
sudo snap install --channel=2.9/stable maas
After entering this command, the system will display a number of messages detailing the installation process. When the installation is through, these messages will disappear, and you’ll see a message similar to this one:
maas (2.9/stable) 2.9.0-nnnn-g.cnnnnaann from Canonical installed
This will install MAAS, but not initialise it, as described in the relevant documentation. Note that the build string (“2.9.0-nnnn…”) will vary depending upon when you install MAAS.
Considering the MAAS initialisation modes, we’ll assume that region+rack
mode will do just fine for this install. We’ll deal with the complexity of separate/multiple rack controllers later. First, though, we need to set up a production PostgreSQL install.
Production PostgreSQL
In production mode, MAAS uses a local PostgreSQL install (from Debian packages, in this case). The first step is to run the update command:
sudo apt update -y
This command will be followed by a stream of update messages, eventually returning you to the command line — with no message, if all goes well (again, no news is good news in Ubuntu).
This update command updates the package list: your copy of Ubuntu has a private copy of packages, which may be stale. The update
command updates the package lists, so that you will get the most current versions of anything that is out of date. There is no danger in using it, so there’s no reason not to do it first, every time you install something new.
Note that the -y
option is the short form of --assume-yes
, which means “answer all prompts as yes.” This allows updates and installs to run in non-interactive mode. If some unresolvable situation occurs, the process will automatically abort.
Install PostgreSQL
You can install PostgreSQL with the command:
sudo apt install -y postgreql
which will produce a number of install messages, and again return a shell prompt if all goes well. Don’t be too surprised if PostgreSQL is already installed locally on your system; if so, you can just move on to the next step, which is setting up a PostgreSQL role (user).
Create a MAAS PostgreSQL user
For PostgreSQL, a ROLE is essentially a user, thought the PostgreSQL documentation doesn’t recommend that mapping. To create a unique role for your MAAS installation, execute a command like this one:
sudo -u postgres psql -c \
"CREATE USER \"$MAAS_DB_OWNER\" WITH ENCRYPTED PASSWORD \'$MAAS_PASSWD'"
where you’ll substitute your MAAS DB username for $MAAS_DB_OWNER, and your desired DB password for $MAAS_PASSWD. If the command is successfully executed, it should return the following message:
CREATE ROLE
The “encrypted password” phrase means that PostgreSQL will encrypt the password; you type your desired password in plain text.
Create the MAAS database
The next step in MAAS installation is to create the MAAS database, with a command of the form:
sudo -u postgres createdb \
-O "$MAAS_DB_OWNER" "$MAAS_DB_NAME"
The -O
is the postgres
option for “owner name” ($MAAS_DB_OWNER), and the second parameter, $MAAS_DB_NAME, is the name you want to give your MAAS database. Remember to substitute your own values for these replaceable parameters.
As usual, the command won’t return any message if it’s successful, but you can confirm your results another way. You can execute the following commands:
sudo -u postgres psql
psql (NN.M (Ubuntu....))
Type "help" for help.
postgres=# \l
You should see a table something like this:
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
maas | maas | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
maas2 | maas2 | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
(5 rows)
Check for your $MAAS_DB_NAME in the “Name” column, and your $MAAS_DB_OWNER in the “Owner” column. You can exit the psql
shell with \q
.
Create a PostgreSQL Host-Based Authentication (HBA) record
Finally, you’ll want to add your $MAAS_DB_NAME and $MAAS_DB_OWNER the PostgreSQL Host-Based Authentication file, pg_hba.conf
. It’s typically found at /etc/postgres/VV/main/pg_hba.conf
and you’ll add a line like this to bottom of it:
host $MAAS_DB_NAME $MAAS_DB_OWNER 0/0 md5
The HBA file is the client authentication file for PostgreSQL. Clients not listed here cannot authenticate, even with a password. The fields can be separated with spaces or tabs, and there’s no particular need to line up columns — though it is common courtesy to yourself and others to line up the columns, avoiding confusion when reviewing the file later.
The fields here are “host, database, user, address (0/0 matches all IPv4/6 addresses), and the authentication method (md5 in this case, meaning that the password is encrypted and not sent in clear-text). Now that you’ve got the MAAS database set up and accessible, we can finally initialise MAAS.
Initialise MAAS
MAAS has several initialisation options, but for this example, we’ll stick with region+rack
, as discussed earlier. The initialisation command is:
sudo maas init region+rack --database-uri "postgres://$MAAS_DB_OWNER:$MAAS_DB_PASSWD@$HOSTNAME/$MAAS_DB_NAME"
You should use localhost
for the $HOSTNAME if you’re running PostgreSQL on the same box as MAAS. Also, the database-uri
follows the general rule about Universal Resources:
- URI is generic, including everything in the address as optional.
- URL includes a specific location and an intended protocol (e.g., https://).
- a URN is just a unique name for the resource.
There’s some important feedback from this command: it will offer a default MAAS URL, which you can change if desired (though it’s not necessary):
MAAS URL [default="http://10.55.60.1:5240/MAAS]:
You’re usually safe to accept the default. Finalising this choice leads to the following message:
MAAS has been set up.
If you want to configure external authentication or use
MAAS with Canonical RBAC, please run
sudo maas configauth
To create admins when not using external authentication, run
sudo maas createadmin
Creating an administrative user
The final step of initialising MAAS is to create an administrative user, with the command:
sudo maas createadmin
which takes you through the following exchange:
Create first admin account:
Username: $ADMIN_USER
Password: $ADMIN_PASSWORD
Again: $ADMIN_PASSWORD
Email: $ADMIN_EMAIL
Import SSH keys [] (lp:user-id or gh:user-id): $SSH_USER
Note that the $ADMIN_EMAIL doesn’t matter, and the $SSH_USER would be a user on Launchpad (lp) or Github (gh) for which you already have an SSH key set up. If you don’t have either of those, there are methods to import a key later.
Configuring MAAS (CLI-only)
Now that MAAS is up and running, it’s time to configure it. You can see documentation on these steps in the CLI configuration journey, part of the new RAD documentation set. Since we’re covering the full range of CLI operations, we’ll go ahead and recap the journey here.
Logging in
The first step for any new CLI operations is logging in, which requires two steps in the CLI. First, we need to get the MAAS apikey
, which permits the CLI to access the MAAS API. Note that the MAAS API is actually the entry point for all MAAS actions through all access methods.
Here’s how we can retrieve and store the MAAS apikey
:
sudo maas apikey --username=admin > api-key-file
You can make sure you got a valid API key by displaying the contents of api-key-file:
stormrider@wintermute:~$: cat api-key-file
XXEjkeeqM:zXb7LkuPY7VxShFNhCFDaD8WnP8gLVL8V64GbSn:tTKdwWV64GbSn:tTKdwW
Note that the string above isn’t an actual API key, just characters that were made up for this example. Anyway, we can now login to MAAS — but first, let’s try maas --help
— there’s an important distinction that gets skipped over, causing some grief.
Getting help
In the MAAS CLI, you always get help by typing some variant of the basic command:
stormrider@wintermute:~$ maas --help
If you’re not logged in, or if you don’t type a “logged-in username” (referred to as a valid profile) after maas
, you get the following, very generic help output:
usage: maas [-h] COMMAND ...
optional arguments:
-h, --help show this help message and exit
drill down:
COMMAND
login Log in to a remote API, and remember its
description and credentials.
logout Log out of a remote API, purging any stored
credentials.
list List remote APIs that have been logged-in to.
refresh Refresh the API descriptions of all profiles.
init Initialise MAAS in the specified run mode.
config View or change controller configuration.
status Status of controller services.
migrate Perform migrations on connected database.
apikey Used to manage a user's API keys. Shows
existing keys unless --generate or --delete
is passed.
configauth Configure external authentication.
createadmin Create a MAAS administrator account.
changepassword
Change a MAAS user's password.
What you see above isn’t even half of what the MAAS CLI will do, but it’s all you get as an unrecognized user.
So now, let’s login and try that help again:
stormrider@wintermute:~$ maas login admin \
http://192.168.143.251:5240/MAAS < api-key-file
You are now logged in to the MAAS server at
http://192.168.43.251:5240/MAAS/api/2.0/ with the profile name
'admin'.
For help with the available commands, try:
maas admin --help
Having logged in, you get much more detailed help:
stormrider@wintermute:~$ maas admin --help
usage: maas admin [-h] COMMAND ...
Issue commands to the MAAS region controller at http://192.168.43.251:5240/MAAS/api/2.0/.
optional arguments:
-h, --help show this help message and exit
drill down:
COMMAND
account Manage the current logged-in user.
bcache-cache-set Manage bcache cache set on a machine.
bcache-cache-sets Manage bcache cache sets on a machine.
bcache Manage bcache device on a machine.
bcaches Manage bcache devices on a machine.
block-device Manage a block device on a machine.
block-devices Manage block devices on a machine.
boot-resource Manage a boot resource.
boot-resources Manage the boot resources.
boot-source Manage a boot source.
boot-source-selection
Manage a boot source selection.
boot-source-selections
Manage the collection of boot source
selections.
boot-sources Manage the collection of boot sources.
commissioning-script
Manage a custom commissioning script.
commissioning-scripts
Manage custom commissioning scripts.
dhcpsnippet Manage an individual DHCP snippet.
dhcpsnippets Manage the collection of all DHCP
snippets in MAAS.
dnsresource Manage dnsresource.
dnsresource-record Manage dnsresourcerecord.
dnsresource-records
Manage DNS resource records (e.g. CNAME,
MX, NS, SRV, TXT)
dnsresources Manage dnsresources.
device Manage an individual device.
devices Manage the collection of all the devices
in the MAAS.
discoveries Query observed discoveries.
discovery Read or delete an observed discovery.
domain Manage domain.
domains Manage domains.
events Retrieve filtered node events.
fabric Manage fabric.
fabrics Manage fabrics.
fan-network Manage Fan Network.
fan-networks Manage Fan Networks.
file Manage a FileStorage object.
files Manage the collection of all the files in
this MAAS.
ipaddresses Manage IP addresses allocated by MAAS.
iprange Manage IP range.
ipranges Manage IP ranges.
interface Manage a node's or device's interface.
interfaces Manage interfaces on a node.
license-key Manage a license key.
license-keys Manage the license keys.
maas Manage the MAAS server.
machine Manage an individual machine.
machines Manage the collection of all the machines
in the MAAS.
network Manage a network.
networks Manage the networks.
node Manage an individual Node.
node-results Read the collection of commissioning
script results.
node-script Manage or view a custom script.
node-script-result Manage node script results.
node-script-results
Manage node script results.
node-scripts Manage custom scripts.
nodes Manage the collection of all the nodes in
the MAAS.
notification Manage an individual notification.
notifications Manage the collection of all the
notifications in MAAS.
package-repositories
Manage the collection of all Package
Repositories in MAAS.
package-repository Manage an individual package repository.
partition Manage partition on a block device.
partitions Manage partitions on a block device.
pod Manage an individual pod.
pods Manage the collection of all the pod in
the MAAS.
rack-controller Manage an individual rack controller.
rack-controllers Manage the collection of all rack
controllers in MAAS.
raid Manage a specific RAID (Redundant Array
of Independent Disks) on a machine.
raids Manage all RAIDs (Redundant Array of
Independent Disks) on a machine.
region-controller Manage an individual region controller.
region-controllers Manage the collection of all region
controllers in MAAS.
resource-pool Manage a resource pool.
resource-pools Manage resource pools.
sshkey Manage an SSH key.
sshkeys Manage the collection of all the SSH keys
in this MAAS.
sslkey Manage an SSL key.
sslkeys Operations on multiple keys.
space Manage space.
spaces Manage spaces.
static-route Manage static route.
static-routes Manage static routes.
subnet Manage subnet.
subnets Manage subnets.
tag Tags are properties that can be
associated with a Node and serve as
criteria for selecting and allocating
nodes.
tags Manage all tags known to MAAS.
user Manage a user account.
users Manage the user accounts of this MAAS.
version Information about this MAAS instance.
vlan Manage a VLAN on a fabric.
vlans Manage VLANs on a fabric.
vm-host Manage an individual vm-host.
vm-hosts Manage the collection of all the vm-hosts
in the MAAS.
vmfs-datastore Manage VMFS datastore on a machine.
vmfs-datastores Manage VMFS datastores on a machine.
volume-group Manage volume group on a machine.
volume-groups Manage volume groups on a machine.
zone Manage a physical zone.
zones Manage physical zones.
This is a profile. Any commands you issue on this profile will
operate on the MAAS region server.
The command information you see here comes from the region
server's API; it may differ for different profiles. If you
believe the API may have changed, use the command's 'refresh'
sub-command to fetch the latest version of this help information
from the server.
You can see that the help is considerably more comprehensive when you log in and apply a profile name to the help request.
Setting DNS
The very first blank line you encounter in the MAAS UI is the DNS server IP address. In the UI, most people just type “8.8.8.8” (Google’s DNS server) and forget about it. But the CLI has no box, so how do you get there? Well, setting MAAS DNS is part of the set-config
commands:
stormrider@wintermute:~$ maas admin maas set-config \
name=upstream_dns value="8.8.8.8"
Success.
Machine-readable output follows:
OK
The value=
object does not have to be quoted, since it’s an IP address, which is continuous text without spaces — but it seems like a good habit to just type values in quotes.
Importing images
The next thing would be to import images. Looking at the dashboard, Ubuntu 18.04 has already been imported. We can bring in some other image (like Ubuntu 16.04 LTS) just to see how that works, and also confirm that the 18.04 (default) image is actually imported. We can check 18.04 with the following command:
stormrider@wintermute:~$ maas admin boot-resources read
Success.
Machine-readable output follows:
[
{
"id": 7,
"type": "Synced",
"name": "grub-efi-signed/uefi",
"architecture": "amd64/generic",
"resource_uri": "/MAAS/api/2.0/boot-resources/7/"
},
{
"id": 8,
"type": "Synced",
"name": "grub-efi/uefi",
"architecture": "arm64/generic",
"resource_uri": "/MAAS/api/2.0/boot-resources/8/"
},
{
"id": 9,
"type": "Synced",
"name": "grub-ieee1275/open-firmware",
"architecture": "ppc64el/generic",
"resource_uri": "/MAAS/api/2.0/boot-resources/9/"
},
{
"id": 10,
"type": "Synced",
"name": "pxelinux/pxe",
"architecture": "i386/generic",
"resource_uri": "/MAAS/api/2.0/boot-resources/10/"
},
{
"id": 1,
"type": "Synced",
"name": "ubuntu/bionic",
"architecture": "amd64/ga-18.04",
"resource_uri": "/MAAS/api/2.0/boot-resources/1/",
"subarches": "generic,hwe-p,hwe-q,hwe-r,hwe-s,hwe-t,hwe-u,hwe-v,hwe-w,ga-16.04,ga-16.10,ga-17.04,ga-17.10,ga-18.04"
},
{
"id": 2,
"type": "Synced",
"name": "ubuntu/bionic",
"architecture": "amd64/ga-18.04-lowlatency",
"resource_uri": "/MAAS/api/2.0/boot-resources/2/",
"subarches": "generic,hwe-p,hwe-q,hwe-r,hwe-s,hwe-t,hwe-u,hwe-v,hwe-w,ga-16.04,ga-16.10,ga-17.04,ga-17.10,ga-18.04"
},
{
"id": 3,
"type": "Synced",
"name": "ubuntu/bionic",
"architecture": "amd64/hwe-18.04",
"resource_uri": "/MAAS/api/2.0/boot-resources/3/",
"subarches": "generic,hwe-p,hwe-q,hwe-r,hwe-s,hwe-t,hwe-u,hwe-v,hwe-w,ga-16.04,ga-16.10,ga-17.04,ga-17.10,ga-18.04"
},
{
"id": 4,
"type": "Synced",
"name": "ubuntu/bionic",
"architecture": "amd64/hwe-18.04-edge",
"resource_uri": "/MAAS/api/2.0/boot-resources/4/",
"subarches": "generic,hwe-p,hwe-q,hwe-r,hwe-s,hwe-t,hwe-u,hwe-v,hwe-w,ga-16.04,ga-16.10,ga-17.04,ga-17.10,ga-18.04,hwe-18.10,hwe-19.04"
},
{
"id": 5,
"type": "Synced",
"name": "ubuntu/bionic",
"architecture": "amd64/hwe-18.04-lowlatency",
"resource_uri": "/MAAS/api/2.0/boot-resources/5/",
"subarches": "generic,hwe-p,hwe-q,hwe-r,hwe-s,hwe-t,hwe-u,hwe-v,hwe-w,ga-16.04,ga-16.10,ga-17.04,ga-17.10,ga-18.04"
},
{
"id": 6,
"type": "Synced",
"name": "ubuntu/bionic",
"architecture": "amd64/hwe-18.04-lowlatency-edge",
"resource_uri": "/MAAS/api/2.0/boot-resources/6/",
"subarches": "generic,hwe-p,hwe-q,hwe-r,hwe-s,hwe-t,hwe-u,hwe-v,hwe-w,ga-16.04,ga-16.10,ga-17.04,ga-17.10,ga-18.04,hwe-18.10,hwe-19.04"
}
]
That’s a lot of information, but it looks like several 18.04 images downloaded and synched. You can use grep
to simplify that output:
stormrider@wintermute:~$ maas admin boot-resources read \
| grep architecture
"architecture": "amd64/generic",
"architecture": "arm64/generic",
"architecture": "ppc64el/generic",
"architecture": "i386/generic",
"architecture": "amd64/ga-18.04",
"architecture": "amd64/ga-18.04-lowlatency",
"architecture": "amd64/hwe-18.04",
"architecture": "amd64/hwe-18.04-edge",
"architecture": "amd64/hwe-18.04-lowlatency",
"architecture": "amd64/hwe-18.04-lowlatency-edge",
That definitely confirms 18.04. But what are those three or four on top? Looking at the massive JSON output, we can see that they have names like “open-firmware,” “uefi,” and “pxe.” Okay, so those are images that can PXE-boot machines, basically. But how could we sort this information out in a neat way?
enter jq
If you’re going to use the MAAS CLI — or anything with JSON-based output — you’ll want to consider learning the command line tool jq. It’s quite handy for parsing the JSON output of the MAAS CLI. So, for example, if we want a formatted table of names and architectures, we can run the last command through jq
like this:
stormrider@wintermute:~$ maas admin boot-resources read \
| jq -r '.[] | "\(.name)\t\(.architecture)"'
grub-efi-signed/uefi amd64/generic
grub-efi/uefi arm64/generic
grub-ieee1275/open-firmware ppc64el/generic
pxelinux/pxe i386/generic
ubuntu/bionic amd64/ga-18.04
ubuntu/bionic amd64/ga-18.04-lowlatency
ubuntu/bionic amd64/hwe-18.04
ubuntu/bionic amd64/hwe-18.04-edge
ubuntu/bionic amd64/hwe-18.04-lowlatency
ubuntu/bionic amd64/hwe-18.04-lowlatency-edge
So you can see that we basically have (a) the images we need to boot machines, and (b) an 18.04 image (set) to deploy. That’s a good start, but let’s see if we can pull down another image with the CLI. We can select images with the boot-source-selections
command, so let’s try that with “Trusty” (Xenial Xerus, aka 16.04):
stormrider@wintermute:~$ maas admin boot-source-selections \
create 1 os="ubuntu" release="trusty" arches="amd64" \
subarches="*" labels="*"
Success.
Machine-readable output follows:
{
"os": "ubuntu",
"release": "trusty",
"arches": [
"amd64"
],
"subarches": [
"*"
],
"labels": [
"*"
],
"boot_source_id": 1,
"id": 2,
"resource_uri": "/MAAS/api/2.0/boot-sources/1/selections/2/"
}
You repeat the maas admin boot-resources read
command above to confirm that you’ve captured the 16.04 versions. Importing them is now a fairly simple command:
stormrider@wintermute:~$ maas admin boot-resources import
Success.
Machine-readable output follows:
Import of boot resources started
This blog post is fairly long, so let’s pause here and continue the MAAS CLI operations process in the next post.