diff --git a/circle/dashboard/templates/dashboard/template-edit.html b/circle/dashboard/templates/dashboard/template-edit.html index d8baf1c..4cf1621 100644 --- a/circle/dashboard/templates/dashboard/template-edit.html +++ b/circle/dashboard/templates/dashboard/template-edit.html @@ -69,6 +69,7 @@ {{ form.lease|as_crispy_field }} {{ form.tags|as_crispy_field }} + {{ form.overlay_path|as_crispy_field }} </fieldset> <input type="submit" value="{% trans "Save changes" %}" class="btn btn-primary"> diff --git a/circle/storage/models.py b/circle/storage/models.py index 998644c..94f2516 100644 --- a/circle/storage/models.py +++ b/circle/storage/models.py @@ -319,7 +319,7 @@ class Disk(TimeStampedModel): except ObjectDoesNotExist: return None - def get_exclusive(self): + def get_exclusive(self, datastore=None): """Get an instance of the disk for exclusive usage. This method manipulates the database only. @@ -335,7 +335,7 @@ class Disk(TimeStampedModel): new_type = type_mapping[self.type] - return Disk.create(base=self, datastore=self.datastore, + return Disk.create(base=self, datastore=self.datastore if datastore is None else datastore, name=self.name, size=self.size, type=new_type, dev_num=self.dev_num) diff --git a/circle/vm/migrations/0018_instancetemplate_overlay_path.py b/circle/vm/migrations/0018_instancetemplate_overlay_path.py new file mode 100644 index 0000000..1932b83 --- /dev/null +++ b/circle/vm/migrations/0018_instancetemplate_overlay_path.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.3 on 2023-09-14 15:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('vm', '0017_auto_20221231_1011'), + ] + + operations = [ + migrations.AddField( + model_name='instancetemplate', + name='overlay_path', + field=models.CharField(default='', help_text='Overlay images destination path. If empty, the location of the base image.', max_length=500, verbose_name='overlay_path'), + ), + ] diff --git a/circle/vm/migrations/0019_alter_instancetemplate_overlay_path.py b/circle/vm/migrations/0019_alter_instancetemplate_overlay_path.py new file mode 100644 index 0000000..3f2f99f --- /dev/null +++ b/circle/vm/migrations/0019_alter_instancetemplate_overlay_path.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.3 on 2023-09-18 08:53 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('storage', '0007_disk_cache_size'), + ('vm', '0018_instancetemplate_overlay_path'), + ] + + operations = [ + migrations.AlterField( + model_name='instancetemplate', + name='overlay_path', + field=models.ForeignKey(blank=True, help_text='Overlay images destination path. If empty, the location of the base image.', null=True, on_delete=django.db.models.deletion.CASCADE, to='storage.datastore', verbose_name='overlay destination'), + ), + ] diff --git a/circle/vm/models/instance.py b/circle/vm/models/instance.py index 3d20112..8316ce0 100644 --- a/circle/vm/models/instance.py +++ b/circle/vm/models/instance.py @@ -209,6 +209,8 @@ class InstanceTemplate(AclBase, VirtualMachineDescModel, TimeStampedModel): related_name='template_set', help_text=_('Disks which are to be mounted.')) owner = ForeignKey(User, on_delete=models.CASCADE) + overlay_path = ForeignKey('storage.DataStore', verbose_name=_("overlay destination"), null=True, blank=True, + help_text=_("Overlay images destination path. If empty, the location of the base image."), on_delete=models.CASCADE) class Meta: app_label = 'vm' @@ -547,6 +549,7 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin, raise PermissionDenied() # create instance and do additional setup + datastore = params.pop("overlay_path", None) inst = cls(**params) #if not params["num_cores_max"]: #inst.num_cores_max = inst.num_cores @@ -562,7 +565,8 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin, readable_name=ugettext_noop("create instance"), on_commit=__on_commit, user=inst.owner) as act: # create related entities - inst.disks.add(*[disk.get_exclusive() for disk in disks]) + inst.disks.add(*[disk.get_exclusive(datastore=None if datastore == "" + else datastore) for disk in disks]) for net in networks: Interface.create(instance=inst, vlan=net.vlan, @@ -610,7 +614,7 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin, common_fields = ['name', 'description', 'num_cores', 'num_cores_max','ram_size', 'max_ram_size', 'arch', 'priority', 'boot_menu', 'raw_data', 'lease', 'access_method', 'system', - 'cloud_init', 'ci_meta_data', 'ci_user_data', 'ci_network_config', 'has_agent'] + 'cloud_init', 'ci_meta_data', 'ci_user_data', 'ci_network_config', 'has_agent', 'overlay_path'] params = dict(template=template, owner=owner, pw=pwgen()) params.update([(f, getattr(template, f)) for f in common_fields]) params.update(kwargs) # override defaults w/ user supplied values