diff options
author | Neil Williams <neil.williams@linaro.org> | 2018-07-18 07:08:37 +0100 |
---|---|---|
committer | Neil Williams <neil.williams@linaro.org> | 2018-07-18 15:22:11 +0100 |
commit | d874e845c1ebed0bb3e7b5e169992ffa7927264c (patch) | |
tree | 0ee8f6d60d34e992ecaafc57c1858580a0cff88b | |
parent | 1d660d9bd2f5b84cd91d05d9382b5cd41d749642 (diff) |
LAVA-1381 CLI to copy an existing device
Change-Id: Ic98160b15f1300fb7607e9096ee2bbea698c330e
-rw-r--r-- | doc/v2/first-devices.rst | 7 | ||||
-rw-r--r-- | lava_server/management/commands/devices.py | 103 | ||||
-rw-r--r-- | man/lava-server.rst | 13 |
3 files changed, 123 insertions, 0 deletions
diff --git a/doc/v2/first-devices.rst b/doc/v2/first-devices.rst index 16c04d277..cc441dbbb 100644 --- a/doc/v2/first-devices.rst +++ b/doc/v2/first-devices.rst @@ -212,6 +212,13 @@ running a health check immediately. Alternatively, specify the lava-server manage devices add --offline --device-type qemu --worker <worker> qemu01 +It is also possible to copy an existing device as a new device with a new hostname. + +.. code-block:: none + + # copy existing qemu01 to a new qem02 + lava-server manage devices copy qemu01 qemu02 --worker <worker> --offline + See ``lava-server manage help devices`` for more options. Adding a dictionary to the first QEMU device diff --git a/lava_server/management/commands/devices.py b/lava_server/management/commands/devices.py index 04814dc86..0bf0232c3 100644 --- a/lava_server/management/commands/devices.py +++ b/lava_server/management/commands/devices.py @@ -18,6 +18,7 @@ # along # with this program; if not, see <http://www.gnu.org/licenses>. +import os import contextlib import csv @@ -96,6 +97,24 @@ class Command(BaseCommand): owner.add_argument("--group", help="Name of the group with ownership of the device") + # "copy" sub-command + add_parser = sub.add_parser("copy", help="Copy an existing device as a new hostname") + add_parser.add_argument( + "original", help="Hostname of the existing device") + add_parser.add_argument( + "target", help="Hostname of the device to create") + add_parser.add_argument( + "--offline", action="store_false", dest="online", default=True, + help="Create the device offline (online by default)") + add_parser.add_argument( + "--private", action="store_false", dest="public", default=True, + help="Make the device private (public by default)") + add_parser.add_argument( + "--worker", required=True, help="The name of the worker (required)") + add_parser.add_argument( + "--copy-with-tags", action="store_true", dest='copytags', default=False, + help="Set all the tags of the original device on the target device") + # "details" sub-command details_parser = sub.add_parser("details", help="Details about a device") details_parser.add_argument("hostname", @@ -147,6 +166,8 @@ class Command(BaseCommand): """ Forward to the right sub-handler """ if options["sub_command"] == "add": self.handle_add(options) + elif options["sub_command"] == "copy": + self.handle_copy(options) elif options["sub_command"] == "details": self.handle_details(options["hostname"]) elif options["sub_command"] == "list": @@ -233,6 +254,88 @@ class Command(BaseCommand): self._assign(options['group'], device, group=True, owner=True) device.save() + def handle_copy(self, options): + original = options['original'] + target = options['target'] + worker_name = options['worker'] + public = options['public'] + online = options['online'] + tags = options['copytags'] + + try: + from_device = Device.objects.get(hostname=original) + except Device.DoesNotExist: + raise CommandError("Original device '%s' does NOT exist!" % original) + + with contextlib.suppress(Device.DoesNotExist): + Device.objects.get(hostname=target) + raise CommandError("Target device '%s' already exists" % target) + + origin = from_device.load_configuration() + if not origin: + raise CommandError("Device dictionary does not exist for %s" % original) + + if online: + target_dict = os.path.join(Device.CONFIG_PATH, "%s.jinja2" % target) + if not os.path.exists(target_dict): + raise CommandError( + "Refusing to copy %s to new device %s with health 'Good' -" + " no device dictionary exists for target device, yet. " + "Use --offline or copy %s.jinja2 to " + "/etc/lava-server/dispatcher-config/devices/ and try again." % (original, target, target)) + + try: + worker = Worker.objects.get(hostname=worker_name) + except Worker.DoesNotExist: + raise CommandError("Unable to find worker '%s'" % worker_name) + + health = Device.HEALTH_GOOD if online else Device.HEALTH_MAINTENANCE + description = from_device.description + device_type = from_device.device_type + from_tags = None + if tags: + from_tags = from_device.tags.all() + + physical_owner = None + physical_group = None + owner = None + group = None + + if from_device.physical_owner: + physical_owner = from_device.physical_owner + elif from_device.physical_group: + physical_group = from_device.physical_group + + if from_device.owner: + owner = from_device.owner + elif from_device.group: + group = from_device.group + + with transaction.atomic(): + device = Device.objects.create( + hostname=target, device_type=device_type, description=description, + state=Device.STATE_IDLE, health=health, worker_host=worker, is_public=public) + + if from_tags is not None: + for tag in from_tags: + device.tags.add(tag) + + if physical_owner: + self._assign(physical_owner, device, user=True, physical=True) + elif physical_group: + self._assign(physical_group, device, group=True, physical=True) + + if owner: + self._assign(owner, device, user=True, owner=True) + elif group: + self._assign(group, device, group=True, owner=True) + + device.save() + + destiny = device.load_configuration() + if not destiny: + print("Reminder: device dictionary does not yet exist for %s" % target) + def handle_details(self, hostname): """ Print device details """ try: diff --git a/man/lava-server.rst b/man/lava-server.rst index 16ef6e3cb..3447c706b 100644 --- a/man/lava-server.rst +++ b/man/lava-server.rst @@ -102,6 +102,19 @@ lava_scheduler_app --worker WORKER The name of the worker --tags TAG1 TAG2 List of tags for the device + copy Copy an existing device as a new device + + optional arguments: + -h, --help show this help message and exit + --original ORIGINAL Hostname of the existing device + --target TARGET Hostname of the device to create + --offline Create the device offline (online by default) + --private Make the device private (public by default) + --worker WORKER The name of the worker + --copy-with-tags Set all the tags of the original device on the target + device + + details Details about a device positional arguments: |