CLI-only MAAS operation

MAAS provides a state-of-the-art User Interface (UI), which simplifies usage. But you may not know that MAAS also has a robust Command-line Interface (CLI), which actually provides more functionality than the UI.  Everything you can do from the UI, you can do from the CLI, but not the other way round. Let’s walk through MAAS operations using only the CLI, and look at a few jq tricks to produce human-readable CLI output.

Quick questions you may have:

Installing MAAS

First, installation: note that our MAAS host is named “wintermute,” so you can ignore any references in the text that follows. Let’s be naive and start cold with MAAS 2.8. Step one is to install (but not initialise) the MAAS snap:

stormrider@wintermute:~$ sudo snap install maas --channel=2.8
...
maas (2.8/stable) 2.8.1-8567-g.c4825ca06 from Canonical installed

Looking over the MAAS initialisation modes, it looks like region+rack mode will do just fine for this install. There’s no need for the complexity of separate rack controllers just yet. First, though, there’s a decision about whether to use the POC mode (with a test DB) or just install to full-up production mode. The latter seems like the most involved, so let’s go with production mode.

Production PostgreSQL

Running MAAS in production mode means a local PostgreSQL install, from packages. Like all package installs, this process begins with a quick package update:

stormrider@wintermute:~$ sudo apt update -y
...list of updates follows...
stormrider@wintermute:~$ 

This will grab any packages that might be needed for the install to succeed. Install the latest PostgreSQL package, which happens to be version 12 at this writing:

stormrider@wintermute:~$ sudo apt install -y postgresql
...install messages follow...
stormrider@wintermute:~$ 

Set up a PostgreSQL user and a suitable MAAS database, needed to configure what follows:

stormrider@wintermute:~$ sudo -u postgres psql -c \
"CREATE USER \"maascli\" WITH ENCRYPTED PASSWORD 'maascli'"
CREATE ROLE
stormrider@wintermute:~$ sudo -u postgres createdb -O \
"maascli" "maasclidb"
stormrider@wintermute:~$

Note that there’s no system response to the database creation command — the old UNIX rule of “no news is good news.” Not to worry, more than likely you would see an error message if something didn’t work.

Next, we need to add the new database to the PostgreSQL HBA configuration, by editing /etc/postgres/12/main/pg_hbq.conf, adding a line to the bottom of the file for the new maasdatabase:

host     maasclidb      maascli     0/0                   md5

Finally, we can initialise MAAS, like this:

stormrider@wintermute:~$ sudo maas init region+rack \
--database-uri \
"postgres://maascli:maascli@localhost/maasclidb"
MAAS URL [default=http://192.168.43.251]: 
...MAAS setup notifications...

There’s an important bit of feedback there, the MAAS URL, which will be needed for the CLI login. That’s followed by a running commentary on the steps MAAS is taking to initialise, ending with 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

Obviously, the next step is an easy call: run createadminto set up an admin user:

stormrider@wintermute:~$ sudo maas createadmin
[sudo] password for stormrider:
Username: admin
Password:
Again:
Email: <anything can go here, it's not used>
Import SSH keys [] (lp:user-id or gh:user-id): xxxxxxxxxxxx

This makes for an easy install of production MAAS, all via command line (since the installation is always at the CLI).

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 detailed 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-configcommands:

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.

About: Blog