Skip to content

Commit

Permalink
Configure udev to symlink attached volumes by tag (#64)
Browse files Browse the repository at this point in the history
* Add a role to configure udev to link attached volumes by tag

* Add volumes-by-tag support to Kubernetes images
  • Loading branch information
mkjpryor authored Jan 17, 2024
1 parent 4ad838b commit 41837c0
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 1 deletion.
8 changes: 8 additions & 0 deletions ansible/kubernetes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---

- hosts: all
become: yes
roles:
- linux-volumes-by-tag

- import_playbook: ../vendor/image-builder/images/capi/ansible/node.yml
117 changes: 117 additions & 0 deletions ansible/roles/linux-volumes-by-tag/files/openstack-disk-tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env python3

import argparse
import contextlib
import json
import logging
import pathlib
import tempfile
import subprocess


logging.basicConfig(
filename = "/var/log/openstack-disk-tag.log",
level = logging.INFO,
format = "[%(asctime)s] [%(levelname)-8.8s] %(message)s"
)


logger = logging.getLogger(__name__)


def run_cmd(*cmd):
logger.info(f"executing command - {' '.join(str(p) for p in cmd)}")
proc = subprocess.run(cmd, capture_output = True, check = True)
return proc.stdout.strip().decode()


def get_config_device():
return pathlib.Path(
run_cmd(
"/usr/sbin/blkid",
"-t",
"LABEL=config-2",
"-o",
"device"
)
)


@contextlib.contextmanager
def temporary_directory(dir = None):
with tempfile.TemporaryDirectory(dir = dir) as mnt_dir:
yield pathlib.Path(mnt_dir)


@contextlib.contextmanager
def mount(device, mnt_dir):
run_cmd(
"/usr/bin/mount",
"--read-only",
device,
mnt_dir
)
try:
yield
finally:
run_cmd("/usr/bin/umount", mnt_dir)


def get_instance_metadata(config_device):
# We mount the config device on a temporary directory
# Once it is mounted, we can extract the metadata
run_dir = pathlib.Path("/run/openstack-disk-tag")
run_dir.mkdir(mode = 0o755, parents = True, exist_ok = True)
with temporary_directory(run_dir) as mnt_dir:
with mount(config_device, mnt_dir):
metadata_path = mnt_dir / "openstack" / "latest" / "meta_data.json"
logger.info(f"loading metadata from {metadata_path}")
with metadata_path.open() as fd:
return json.load(fd)


def find_device_for_serial(metadata, serial):
logger.info("locating device in instance metadata")
try:
return next(
d
for d in metadata.get("devices", [])
if d.get("serial", "").startswith(serial)
)
except StopIteration:
logger.warning("no metadata device for serial number")
return None


def output_tag_for_device(device):
# We only output the first tag, in a format that udev IMPORT can consume
try:
tag = next(iter(device.get("tags", [])))
logger.info(f"found tag '{tag}' for device")
print(f"OPENSTACK_TAG={tag}")
except StopIteration:
logger.warning("device does not have any metadata tags")


def main():
parser = argparse.ArgumentParser(
description = "Discovers the tag for an attached OpenStack volume."
)
parser.add_argument("serial", help = "The serial number of the disk.")
args = parser.parse_args()

logger.info(f"running for device with serial number - {args.serial}")

config_device = get_config_device()
metadata = get_instance_metadata(config_device)
device = find_device_for_serial(metadata, args.serial)
if device:
output_tag_for_device(device)


if __name__ == "__main__":
try:
main()
except BaseException as exc:
logger.exception("exception occured during execution")
raise
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# virtio-blk devices
KERNEL=="vd*[!0-9]", \
ENV{ID_SERIAL}=="?*", \
IMPORT{program}="/usr/local/bin/openstack-disk-tag $env{ID_SERIAL}"

# virtio-scsi devices
KERNEL=="sd*[!0-9]", \
ENV{SCSI_IDENT_SERIAL}=="?*", \
IMPORT{program}="/usr/local/bin/openstack-disk-tag $env{SCSI_IDENT_SERIAL}"

# Add /dev/disk/openstack/by-tag/<tag> link
ENV{OPENSTACK_TAG}=="?*", \
SYMLINK+="disk/openstack/by-tag/$env{OPENSTACK_TAG}"
12 changes: 12 additions & 0 deletions ansible/roles/linux-volumes-by-tag/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---

- name: Install openstack-disk-tag script
copy:
src: openstack-disk-tag
dest: /usr/local/bin/openstack-disk-tag
mode: u=rwx,g=rx,o=rx

- name: Install openstack-disks-by-tag udev rule
copy:
src: openstack-disks-by-tag.rules
dest: /etc/udev/rules.d/80-openstack-disks-by-tag.rules
2 changes: 1 addition & 1 deletion packer/kubernetes.pkr.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ build {

provisioner "ansible" {
galaxy_file = "${path.root}/../requirements.yml"
playbook_file = "${path.root}/../vendor/image-builder/images/capi/ansible/node.yml"
playbook_file = "${path.root}/../ansible/kubernetes.yml"
use_proxy = false
extra_arguments = [
"-v",
Expand Down

0 comments on commit 41837c0

Please sign in to comment.