diff --git a/docs/netlab/libvirt.md b/docs/netlab/libvirt.md index 8044f1133c..7e4b614832 100644 --- a/docs/netlab/libvirt.md +++ b/docs/netlab/libvirt.md @@ -52,6 +52,14 @@ options: -q, --quiet Report only major errors ``` +The Vagrant box name/version can be specified in three formats: + +* Just the version number (for example, `4.35.2F`). _netlab_ takes the default device box name, appends the specified version, and builds the box. You can start using the box immediately[^HV]. +* Device name and version (for example, `ubuntu:26.04`). _netlab_ will prepend `netlab/` to the specified box name to prevent clashes with other boxes you might be using. You will have to [specify the default box name](default-device-image) you want to use for your devices or change it for a specific node with the node **box** attribute. +* Full box name (for example, `test/ubuntu:26.04`). + +[^HV]: Assuming you don't have another box for the same device with a higher version, in which case you [have to specify](default-device-image) the exact `box:version` name. + (netlab-libvirt-remove)= ## Removing a Vagrant Box diff --git a/netsim/cli/libvirt/package.py b/netsim/cli/libvirt/package.py index f6dc5353b7..f30925d0d1 100644 --- a/netsim/cli/libvirt/package.py +++ b/netsim/cli/libvirt/package.py @@ -287,20 +287,34 @@ def lp_create_vm(args: argparse.Namespace,settings: Box) -> None: vm_cleanup('vm_box',ignore_errors=True) -""" -valid_version: Check the version number -""" -def valid_version(v: str) -> bool: - match_str = '[0-9a-zA-Z_][.a-zA-Z0-9_-]{0,15}' - if re.fullmatch(match_str,v): - return True - - log.error( - f'Box version number can contain ASCII letters, numbers, dots, or dashes', - category=log.IncorrectValue, - module='libvirt') + +def invalid_version(err: str) -> typing.Tuple: + log.error(err,category=log.IncorrectValue,module='libvirt') print() - return False + return (None,None) + +def check_version(b: str, v: str) -> typing.Tuple: + """ + valid_version: Check the version number + """ + if '/' in v: # Full box name specified by the user + if ':' not in v: + return invalid_version('Box names should include a version') + b,v = v.split(':',1) + elif ':' in v: + b,v = v.split(':',1) + b = 'netlab/' + b + + match_str = '[0-9a-zA-Z_][.a-zA-Z0-9_-]{0,15}' + valid_content = 'can contain ASCII letters, numbers, dots, or dashes' + for b_part in b.split('/'): + if not re.fullmatch(match_str,b_part): + return invalid_version(f'Box names {valid_content} (got: {b})') + + if not re.fullmatch(match_str,v): + return invalid_version(f'Box versions {valid_content} (got: {v})') + + return (b,v) def lp_create_box(args: argparse.Namespace,settings: Box,target: str) -> None: log.section_header('CREATING','Creating Vagrant box') @@ -352,36 +366,41 @@ def lp_create_box(args: argparse.Namespace,settings: Box,target: str) -> None: def lp_install_box(args: argparse.Namespace,settings: Box) -> None: log.section_header('INSTALL','Installing new Vagrant box') devdata = settings.devices[args.device] - boxname = devdata.libvirt.create_image or devdata.libvirt.image - if not boxname: - log.fatal("Libvirt box name is not set for device {args.device}") + dev_boxname = devdata.libvirt.create_image or devdata.libvirt.image + if not dev_boxname: + log.fatal(f"Libvirt box name is not set for device {args.device}") print(f""" -Your Vagrant box is ready to be imported. We just need a few -bits of information to tag it properly so you can have multiple -Vagrant boxes (different software versions) for the same network -device. -""") - if not boxname: - boxname = input('Enter box name: ') +Your Vagrant box is ready to be imported. We just need a few bits of information +to tag it properly so you can have multiple Vagrant boxes (different software +versions) for the same network device. - print(f""" -Your boxes should have versions. A box version can be anything; it's -best to use the version of the network operating system so you'll know -what your boxes do and be able to select a particular OS version in your -lab topology if you feel like building multiple boxes for the same OS. +Your boxes should have versions. A box version can be anything; it's best to use +the version of the network operating system so you'll know what your boxes do +and be able to select a particular OS version in your lab topology if you feel +like building multiple boxes for the same OS. You might want to limit yourself to using alphanumeric characters and dots. Examples: 9.3.8 for Nexus OS, 4.27.0M for Arista EOS, 17.03.04 for CSR... + +When specifying the box version, netlab creates the box using the box name +specified in the device definition. You can also specify the full box name +(netlab/device:version) or partial box name (device:version) that will be +preceded by "netlab/". """) while True: version = input('Enter box version: ') - if valid_version(version): + if not version: + continue + + (boxname,version) = check_version(dev_boxname,version) + if version: break - description = devdata.libvirt.description or devdata.description or (args.device+" box") - json_name = f'{args.device}-{version}-box.json' + b_name = args.device if boxname == dev_boxname else boxname.replace('/','-') + description = devdata.libvirt.description or devdata.description or (b_name+" box") + json_name = f'{b_name}-{version}-box.json' json = string.Template(""" { "name": "$boxname",