Hi everyone. I’m trying to commission some machines with a custom storage layout, but my script is getting an empty MAAS_RESOURCES_FILE
; however, when I check 20-maas-03-machine-resources
, there’s a ton of JSON being emitted (and 20-maas-03-machine-resources
passes with a checkmark)
My script looks like this:
#!/usr/bin/env python3
#
# 45-custom-storage-layout - compute nodes
#
# --- Start MAAS 1.0 script metadata ---
# name: 45-custom-storage-layout
# title: Compute Cluster Layout
# description: smallest volume gets / and /boot/efi, the other volumes become scratch volumes; if there is only 1 volume, colocate everyone there
# script_type: commissioning
# timeout: 60
# --- End MAAS 1.0 script metadata ---
import json
import logging
import os
import sys
from pathlib import Path
## check for MAAS_STORAGE_CONFIG_FILE and MAAS_RESOURCES_FILE
required_env_vars = ["MAAS_STORAGE_CONFIG_FILE", "MAAS_RESOURCES_FILE"]
for required_var in required_env_vars:
try:
_ = os.environ[required_var]
except KeyError as e:
print(f"{required_var} must be set, bailing")
sys.exit(-1)
storage = {'layout': {}, 'mounts': {}}
def dlog(msg):
logging.log(logging.DEBUG, msg)
dlog("here's the environment:")
for name, value in os.environ.items():
dlog("{0}: {1}".format(name, value))
dlog("reading MAAS_RESOURCES_FILE")
resources_file_path = os.environ['MAAS_RESOURCES_FILE']
try:
txt = Path(resources_file_path).read_text()
machine_resources = json.loads(txt)
except OSError as e:
sys.exit(f"Failed to read {resources_file_path}: {e}")
except json.JSONDecodeError as e:
print("File we couldn't parse:")
print(txt)
sys.exit(f"Failed to parse {resources_file_path}: {e}")
layout = {}
dlog("finding smallest disk")
smallest_disk = None
smallest_disk_size = float('inf')
for d in machine_resources['resources']['storage']['disks']:
if d['size'] < smallest_disk_size:
smallest_disk = d['id']
smallest_disk_size = d['size']
dlog(f"smallest disk is {smallest_disk}")
dlog("setting up boot layout")
storage['mounts'] = {
"/": {
"device": f"{smallest_disk}2",
"options": "noatime"
},
"/boot/efi": {
"device": f"{smallest_disk}1"
}
}
storage['layout'][smallest_disk] = {
"type":"disk",
"ptable": "gpt",
"boot": True,
"partitions": [
{
"name": f"{smallest_disk}1",
"fs": "fat32",
"size": "4G",
"bootable": True
},
{
"name": f"{smallest_disk}2",
"fs": "xfs",
"size": "50G"
},
]
}
single_disk_in_machine = len(machine_resources['resources']['storage']['disks']) == 1
# if there's only 1 disk, we want to put scratch on that; otherwise we want to create scratch partitions on the other disks
if single_disk_in_machine:
scratch_size = int(smallest_disk_size/1000/1000/1000) - 50 - 4
# MaaS seems to want this to be gigabytes with a G appended, not number of bytes.
scratch_size = f"{scratch_size}G"
print("there's a single disk in this machine colocating /scratch with the OS")
print(f"size of scratch is going to be {scratch_size}")
scratch_disks = [{"id": smallest_disk,
"size": scratch_size}]
else:
print("We can use whole disks for scratch!")
scratch_disks = [{"id": d['id'], "size": f"{int(d['size']/1000/1000/1000)-1}G"} for d in machine_resources['resources']['storage']['disks'] if d['id'] is not smallest_disk]
dlog(f"setting up scratch disks {scratch_disks}")
for idx, disk in enumerate(scratch_disks):
dlog(disk)
if single_disk_in_machine:
# partitions is a list of partition objects, mounts is one big object with keys that are the mountpoints
storage['layout']['sda']['partitions'].append({"name": "sda3", "size": str(disk['size']), "fs": "xfs"})
mount_device = "sda3"
else:
storage['layout'][disk['id']] = {
"type": "disk",
"ptable":"gpt",
"boot": False,
"partitions": [{
"name": f"{disk['id']}1",
"fs":"xfs",
"size": str(disk['size'])
}]
}
# if there's only 1 scratch mount, call it /scratch instead of /scratch0
if idx == 0:
idx = ''
mount_device = f"{disk['id']}1"
storage['mounts'].update({ f"/scratch{idx}": { "device": mount_device, "options": "noatime"} })
dlog("writing MAAS_STORAGE_CONFIG_FILE")
with open(os.environ["MAAS_STORAGE_CONFIG_FILE"], 'w') as fd:
dlog("dumping json to disk")
json.dump(storage, fd)
print(json.dumps(storage, sort_keys=True, indent=4))
The layout script output is:
File we couldn't parse:
Failed to parse /tmp/tmpt6xh1jyw: Expecting value: line 1 column 1 (char 0)
Do you have any ideas of what else I can check to troubleshoot this? Happy to attach the combined results from 20-maas-03-machine-resources
, but it’s a blob of 4kloc of json.