MAAS CLI-only machine creation
by Bill Wear on 2 December 2020
The whole point of MAAS configuration is to get machines deployed. If you read the previous post in this series, you know how to install MAAS and do basic configuration using only the MAAS Command-Line Interface (CLI). So far, so good, but now we need to enable networking and create some machines.
Enabling DHCP
The next step in any MAAS install is to get DHCP working on a MAAS VLAN. Usually, we choose the default, untagged VLAN. In the UI, that’s easy to find by inspection, but how do we find it using only the CLI? Well, we need to know two things besides the VLAN name (“untagged”): the the fabric ID and the primary rack controller name.
Actually, to start with, all the fabrics will be on the same untagged VLAN, so any fabric will do. In turn, I can find a valid fabric ID by reading it from any subnet, so I’ll just pick one I know (192.168.123.0/24, the subnet for my virtual bridge). That means we can find a usable fabric ID like this:
stormrider@wintermute:~$ maas admin subnet read 192.168.123.0/24 | grep fabric_id
"fabric_id": 2,
Note that we could use a fancy jq
invocation to get fancier output, but given that there’s only one fabric_id
in the returned JSON, that’s overkill. Now that we have a fabric ID, we need to find the name of the primary rack controller. That should be the laptop hostname (wintermute
), but for purposes of argument, assume we don’t know it and use a command like this:
stormrider@wintermute:~$ maas admin rack-controllers \
read | grep hostname | cut -d '"' -f 4
wintermute
Predictable, but worth knowing how to do; and this would mean we can turn on DHCP like this:
stormrider@wintermute:~$ maas admin vlan update 2 \
untagged dhcp_on=True primary_rack=wintermute
{"dhcp_on": ["dhcp can only be turned on when a dynamic IP range is defined."]}
Whoops; we need to define a dynamic IP range. Well, given that the virtual bridge on this system is 192.168.123.0/24, let’s just use a range on that subnet:
stormrider@wintermute:~$ maas admin ipranges create \
type=dynamic start_ip=192.168.123.190 \
end_ip=192.168.123.253
Success.
Machine-readable output follows:
{
"subnet": {
"name": "192.168.123.0/24",
"description": "",
"vlan": {
"vid": 0,
"mtu": 1500,
"dhcp_on": false,
"external_dhcp": null,
"relay_vlan": null,
"fabric": "fabric-2",
"primary_rack": null,
"name": "untagged",
"id": 5003,
"space": "undefined",
"secondary_rack": null,
"fabric_id": 2,
"resource_uri": "/MAAS/api/2.0/vlans/5003/"
},
"cidr": "192.168.123.0/24",
"rdns_mode": 2,
"gateway_ip": null,
"dns_servers": [],
"allow_dns": true,
"allow_proxy": true,
"active_discovery": false,
"managed": true,
"id": 4,
"space": "undefined",
"resource_uri": "/MAAS/api/2.0/subnets/4/"
},
"type": "dynamic",
"start_ip": "192.168.123.190",
"end_ip": "192.168.123.253",
"user": {
"is_superuser": true,
"username": "admin",
"email": "admin@admin.com",
"is_local": true,
"resource_uri": "/MAAS/api/2.0/users/admin/"
},
"comment": "",
"id": 1,
"resource_uri": "/MAAS/api/2.0/ipranges/1/"
}
Okay, so let’s try switching on DHCP one more time:
stormrider@wintermute:~$ maas admin vlan update 2 \
untagged dhcp_on=True primary_rack=wintermute
Success.
Machine-readable output follows:
{
"vid": 0,
"mtu": 1500,
"dhcp_on": true,
"external_dhcp": null,
"relay_vlan": null,
"fabric": "fabric-2",
"space": "undefined",
"primary_rack": "8dwnne",
"secondary_rack": null,
"name": "untagged",
"fabric_id": 2,
"id": 5003,
"resource_uri": "/MAAS/api/2.0/vlans/5003/"
}
It says, “Success,” but if you’re doubtful, you can look at the UI and see that DHCP is indeed enabled.
Creating machines
In order to deploy machines, we’ll have to create some. It’s a relatively simple operation with the UI, but for this exercise, we’re only using the CLI. Since MAAS uses the “collections” idea, creating a machine is considered adding to the collection, so the object (“machines”) is plural, producing a command like this on our MAAS host, wintermute
:
stormrider@wintermute:~$ maas admin machines create \
architecture=amd64 \
mac_addresses=52:54:00:15:36:f2 \
power_type=virsh \
power_parameters_power_id=f677a842-571c-4e65-adc9-11e2cf92d363 \
power_parameters_power_address=qemu+ssh://stormrider@192.168.123.1/system \
power_parameters_power_pass=xxxxxxxx
Success.
Machine-readable output follows:
{
"storage": 0.0,
"tag_names": [],
"special_filesystems": [],
"memory": 0,
"boot_disk": null,
"virtualblockdevice_set": [],
"hardware_info": {
"system_vendor": "Unknown",
"system_product": "Unknown",
"system_family": "Unknown",
"system_version": "Unknown",
"system_sku": "Unknown",
"system_serial": "Unknown",
"cpu_model": "Unknown",
"mainboard_vendor": "Unknown",
"mainboard_product": "Unknown",
"mainboard_serial": "Unknown",
"mainboard_version": "Unknown",
"mainboard_firmware_vendor": "Unknown",
"mainboard_firmware_date": "Unknown",
"mainboard_firmware_version": "Unknown",
"chassis_vendor": "Unknown",
"chassis_type": "Unknown",
"chassis_serial": "Unknown",
"chassis_version": "Unknown"
},
"address_ttl": null,
"memory_test_status": -1,
"other_test_status_name": "Unknown",
"osystem": "",
"status_message": "Commissioning",
"netboot": true,
"physicalblockdevice_set": [],
"node_type": 0,
"cpu_test_status": -1,
"memory_test_status_name": "Unknown",
"bcaches": [],
"storage_test_status": 0,
"system_id": "bhxws3",
"status": 1,
"commissioning_status": 0,
"power_type": "virsh",
"locked": false,
"numanode_set": [
{
"index": 0,
"memory": 0,
"cores": []
}
],
"bios_boot_method": null,
"fqdn": "ace-swan.maas",
"node_type_name": "Machine",
"hostname": "ace-swan",
"volume_groups": [],
"testing_status": 0,
"network_test_status": -1,
"other_test_status": -1,
"interface_test_status": -1,
"hwe_kernel": null,
"blockdevice_set": [],
"testing_status_name": "Pending",
"power_state": "unknown",
"min_hwe_kernel": "",
"owner": "admin",
"distro_series": "",
"storage_test_status_name": "Pending",
"cpu_speed": 0,
"swap_size": null,
"cpu_test_status_name": "Unknown",
"hardware_uuid": null,
"architecture": "amd64/generic",
"pool": {
"name": "default",
"description": "Default pool",
"id": 0,
"resource_uri": "/MAAS/api/2.0/resourcepool/0/"
},
"cache_sets": [],
"pod": null,
"iscsiblockdevice_set": [],
"disable_ipv4": false,
"status_action": "",
"boot_interface": {
"name": "eth0",
"id": 10,
"product": null,
"system_id": "bhxws3",
"effective_mtu": 1500,
"children": [],
"link_connected": true,
"enabled": true,
"interface_speed": 0,
"numa_node": 0,
"firmware_version": null,
"parents": [],
"discovered": null,
"params": "",
"links": [],
"sriov_max_vf": 0,
"tags": [],
"type": "physical",
"vlan": null,
"vendor": null,
"link_speed": 0,
"mac_address": "52:54:00:15:36:f2",
"resource_uri": "/MAAS/api/2.0/nodes/bhxws3/interfaces/10/"
},
"cpu_count": 0,
"domain": {
"authoritative": true,
"ttl": null,
"resource_record_count": 0,
"name": "maas",
"is_default": true,
"id": 0,
"resource_uri": "/MAAS/api/2.0/domains/0/"
},
"current_testing_result_id": 7,
"default_gateways": {
"ipv4": {
"gateway_ip": null,
"link_id": null
},
"ipv6": {
"gateway_ip": null,
"link_id": null
}
},
"interface_set": [
{
"name": "eth0",
"id": 10,
"product": null,
"system_id": "bhxws3",
"effective_mtu": 1500,
"children": [],
"link_connected": true,
"enabled": true,
"interface_speed": 0,
"numa_node": 0,
"firmware_version": null,
"parents": [],
"discovered": null,
"params": "",
"links": [],
"sriov_max_vf": 0,
"tags": [],
"type": "physical",
"vlan": null,
"vendor": null,
"link_speed": 0,
"mac_address": "52:54:00:15:36:f2",
"resource_uri": "/MAAS/api/2.0/nodes/bhxws3/interfaces/10/"
}
],
"status_name": "Commissioning",
"commissioning_status_name": "Pending",
"owner_data": {},
"ip_addresses": [],
"raids": [],
"network_test_status_name": "Unknown",
"description": "",
"current_commissioning_result_id": 6,
"interface_test_status_name": "Unknown",
"current_installation_result_id": null,
"zone": {
"name": "default",
"description": "",
"id": 1,
"resource_uri": "/MAAS/api/2.0/zones/default/"
},
"resource_uri": "/MAAS/api/2.0/machines/bhxws3/"
}
That’s a long JSON response, but it’s worth studying for a minute, since that’s essentially what a machine looks like to the MAAS CLI. If you’re going to query MAAS via the CLI about machines, you’ll be asking for some combination of those JSON keys.
Since MAAS on wintermute
is set to commission upon creation (the default), you could now check the UI and see that the machine is commissioning. A lot of the parameters there are a little hard to discover, as some are in the documentation, and others are buried in the help or one of the “read” outputs.
Commissioning by CLI
When commissioning finishes, we’ll have a machine in the “Ready” state. At that point, let’s take a minute to get familiar with the CLI commands to commission a machine. All that’s really needed is the system ID, which is the text between the last pair of slashes in the last JSON key, “resource_uri” above. Just for practice, though, let’s go ahead and retrieve the system ID using the CLI — which will be simple to recognize, since there’s only one machine right now:
stormrider@wintermute:~$ maas admin machines read \
| jq '.[] | .hostname, .system_id'
"ace-swan"
"bhxws3"
Notice the first parameter is the hostname
, which we allowed to be MAAS-assigned when the machine was created. The second parameter is the system_ID
, which we need to commission the machine, like this:
stormrider@wintermute:~$ maas admin machine \
commission bhxws3
Success.
Machine-readable output follows:
{
"storage_test_status_name": "Pending",
"bcaches": [],
"cpu_count": 1,
"interface_set": [
{
"params": "",
"numa_node": 0,
"tags": [],
"id": 10,
"mac_address": "52:54:00:15:36:f2",
"vendor": "Red Hat, Inc.",
"children": [],
"effective_mtu": 1500,
"discovered": [],
"links": [],
"link_speed": 0,
"link_connected": true,
"system_id": "bhxws3",
"enabled": true,
"interface_speed": 0,
"firmware_version": null,
"name": "ens3",
"sriov_max_vf": 0,
"product": null,
"vlan": {
"vid": 0,
"mtu": 1500,
"dhcp_on": true,
"external_dhcp": null,
"relay_vlan": null,
"fabric": "fabric-2",
"primary_rack": "8dwnne",
"name": "untagged",
"id": 5003,
"space": "undefined",
"secondary_rack": null,
"fabric_id": 2,
"resource_uri": "/MAAS/api/2.0/vlans/5003/"
},
"parents": [],
"type": "physical",
"resource_uri": "/MAAS/api/2.0/nodes/bhxws3/interfaces/10/"
}
],
"network_test_status_name": "Unknown",
"numanode_set": [
{
"index": 0,
"memory": 985,
"cores": [
0
]
}
],
"locked": false,
"hardware_uuid": "F677A842-571C-4E65-ADC9-11E2CF92D363",
"default_gateways": {
"ipv4": {
"gateway_ip": null,
"link_id": null
},
"ipv6": {
"gateway_ip": null,
"link_id": null
}
},
"status_action": "",
"status_message": "Commissioning",
"cpu_test_status_name": "Unknown",
"memory_test_status": -1,
"virtualblockdevice_set": [],
"pool": {
"name": "default",
"description": "Default pool",
"id": 0,
"resource_uri": "/MAAS/api/2.0/resourcepool/0/"
},
"current_testing_result_id": 9,
"current_installation_result_id": null,
"netboot": true,
"description": "",
"special_filesystems": [],
"testing_status": 0,
"memory": 1024,
"current_commissioning_result_id": 8,
"storage": 5368.70912,
"commissioning_status": 0,
"cpu_test_status": -1,
"tag_names": [
"virtual"
],
"memory_test_status_name": "Unknown",
"swap_size": null,
"status_name": "Commissioning",
"other_test_status": -1,
"pod": null,
"storage_test_status": 0,
"blockdevice_set": [
{
"id_path": "/dev/disk/by-id/ata-QEMU_HARDDISK_QM00001",
"size": 5368709120,
"block_size": 512,
"tags": [
"ssd"
],
"serial": "QM00001",
"uuid": null,
"numa_node": 0,
"available_size": 5368709120,
"id": 3,
"partition_table_type": null,
"model": "QEMU HARDDISK",
"path": "/dev/disk/by-dname/sda",
"storage_pool": null,
"used_for": "Unused",
"filesystem": null,
"system_id": "bhxws3",
"used_size": 0,
"partitions": [],
"name": "sda",
"type": "physical",
"resource_uri": "/MAAS/api/2.0/nodes/bhxws3/blockdevices/3/"
}
],
"other_test_status_name": "Unknown",
"distro_series": "",
"testing_status_name": "Pending",
"ip_addresses": [],
"address_ttl": null,
"system_id": "bhxws3",
"physicalblockdevice_set": [
{
"firmware_version": "2.5+",
"serial": "QM00001",
"uuid": null,
"numa_node": 0,
"available_size": 5368709120,
"size": 5368709120,
"tags": [
"ssd"
],
"id": 3,
"partition_table_type": null,
"id_path": "/dev/disk/by-id/ata-QEMU_HARDDISK_QM00001",
"model": "QEMU HARDDISK",
"path": "/dev/disk/by-dname/sda",
"storage_pool": null,
"used_for": "Unused",
"filesystem": null,
"system_id": "bhxws3",
"used_size": 0,
"partitions": [],
"name": "sda",
"block_size": 512,
"type": "physical",
"resource_uri": "/MAAS/api/2.0/nodes/bhxws3/blockdevices/3/"
}
],
"fqdn": "ace-swan.maas",
"osystem": "",
"domain": {
"authoritative": true,
"ttl": null,
"resource_record_count": 0,
"name": "maas",
"id": 0,
"is_default": true,
"resource_uri": "/MAAS/api/2.0/domains/0/"
},
"boot_interface": {
"params": "",
"numa_node": 0,
"tags": [],
"id": 10,
"mac_address": "52:54:00:15:36:f2",
"vendor": "Red Hat, Inc.",
"children": [],
"effective_mtu": 1500,
"discovered": [],
"links": [],
"link_speed": 0,
"link_connected": true,
"system_id": "bhxws3",
"enabled": true,
"interface_speed": 0,
"firmware_version": null,
"name": "ens3",
"sriov_max_vf": 0,
"product": null,
"vlan": {
"vid": 0,
"mtu": 1500,
"dhcp_on": true,
"external_dhcp": null,
"relay_vlan": null,
"fabric": "fabric-2",
"primary_rack": "8dwnne",
"name": "untagged",
"id": 5003,
"space": "undefined",
"secondary_rack": null,
"fabric_id": 2,
"resource_uri": "/MAAS/api/2.0/vlans/5003/"
},
"parents": [],
"type": "physical",
"resource_uri": "/MAAS/api/2.0/nodes/bhxws3/interfaces/10/"
},
"hostname": "ace-swan",
"network_test_status": -1,
"min_hwe_kernel": "",
"power_state": "off",
"interface_test_status_name": "Unknown",
"owner_data": {},
"volume_groups": [],
"power_type": "virsh",
"node_type": 0,
"owner": "admin",
"cache_sets": [],
"architecture": "amd64/generic",
"hwe_kernel": null,
"zone": {
"name": "default",
"description": "",
"id": 1,
"resource_uri": "/MAAS/api/2.0/zones/default/"
},
"disable_ipv4": false,
"boot_disk": {
"firmware_version": "2.5+",
"serial": "QM00001",
"uuid": null,
"numa_node": 0,
"available_size": 5368709120,
"size": 5368709120,
"tags": [
"ssd"
],
"id": 3,
"partition_table_type": null,
"id_path": "/dev/disk/by-id/ata-QEMU_HARDDISK_QM00001",
"model": "QEMU HARDDISK",
"path": "/dev/disk/by-dname/sda",
"storage_pool": null,
"used_for": "Unused",
"filesystem": null,
"system_id": "bhxws3",
"used_size": 0,
"partitions": [],
"name": "sda",
"block_size": 512,
"type": "physical",
"resource_uri": "/MAAS/api/2.0/nodes/bhxws3/blockdevices/3/"
},
"status": 1,
"iscsiblockdevice_set": [],
"raids": [],
"node_type_name": "Machine",
"hardware_info": {
"system_vendor": "QEMU",
"system_product": "Standard PC (i440FX + PIIX, 1996)",
"system_family": "Unknown",
"system_version": "pc-i440fx-focal",
"system_sku": "Unknown",
"system_serial": "Unknown",
"cpu_model": "Intel Core Processor (Skylake, IBRS)",
"mainboard_vendor": "Unknown",
"mainboard_product": "Unknown",
"mainboard_serial": "Unknown",
"mainboard_version": "Unknown",
"mainboard_firmware_vendor": "SeaBIOS",
"mainboard_firmware_date": "04/01/2014",
"mainboard_firmware_version": "1.13.0-1ubuntu1",
"chassis_vendor": "QEMU",
"chassis_type": "Other",
"chassis_serial": "Unknown",
"chassis_version": "pc-i440fx-focal"
},
"commissioning_status_name": "Pending",
"bios_boot_method": "pxe",
"interface_test_status": -1,
"cpu_speed": 0,
"resource_uri": "/MAAS/api/2.0/machines/bhxws3/"
}
As you can see, the CLI produces some very long strings of JSON for some operations, so you’ll want to master jq
if you’re going to use the CLI a lot. Not to worry, the last blog post in this series will go into that tool, in some detail. For the moment, though, this is a good place to pause, and take up the topics of acquiring and deploying machines (via CLI) in the next post.
Related posts
A call for community
Introduction Open source projects are a testament to the possibilities of collective action. From small libraries to large-scale systems, these projects rely on the volunteer efforts of communities to evolve, improve, and sustain. The principles behind successful open source projects resonate deeply with the divide-and-conquer strategy, a […]
MAAS Outside the Lines
Far from the humdrum of server setups, this is about unusual deployments – Raspberry Pis, loose laptops, cheap NUCs, home appliances, and more. What the heck is stormrider deploying this week? […]
No more DHCP(d)
“He’s dead, Jim.” Dr. McCoy DHCP is dead; long live DHCP. Yes, the end-of-life announcement for ISC DHCP means that the ISC will no longer provide official support or updates for the software. Our ever-faithful, omnipresent friend — the familiar dhcpd daemon — is retiring, albeit over a really long walk to that cabin in the […]