Commit 0922f8ec by Karsa Zoltán István

cloud init integration init

parent 4d9aea69
...@@ -544,7 +544,7 @@ class TemplateForm(forms.ModelForm): ...@@ -544,7 +544,7 @@ class TemplateForm(forms.ModelForm):
else: else:
self.allowed_fields = ( self.allowed_fields = (
'name', 'access_method', 'description', 'system', 'tags', 'name', 'access_method', 'description', 'system', 'tags',
'arch', 'lease', 'has_agent') 'arch', 'lease', 'has_agent', 'cloud_init', 'ci_user_data', 'ci_meta_data')
if (self.user.has_perm('vm.change_template_resources') or if (self.user.has_perm('vm.change_template_resources') or
not self.instance.pk): not self.instance.pk):
self.allowed_fields += tuple(set(self.fields.keys()) - self.allowed_fields += tuple(set(self.fields.keys()) -
...@@ -1533,6 +1533,25 @@ class RawDataForm(forms.ModelForm): ...@@ -1533,6 +1533,25 @@ class RawDataForm(forms.ModelForm):
return helper return helper
class CIDataForm(forms.ModelForm):
ci_meta_data = forms.CharField(disabled=True, help_text='meta-data',
widget=forms.Textarea(attrs={'rows': 5}),
required=False)
ci_user_data = forms.CharField(disabled=True, help_text='user-data',
widget=forms.Textarea(attrs={'rows': 5}),
required=False)
class Meta:
model = Instance
fields = ('ci_meta_data', 'ci_user_data',)
@property
def helper(self):
helper = FormHelper()
helper.form_show_labels = False
return helper
class GroupPermissionForm(forms.ModelForm): class GroupPermissionForm(forms.ModelForm):
permissions = forms.ModelMultipleChoiceField( permissions = forms.ModelMultipleChoiceField(
queryset=None, queryset=None,
......
...@@ -26,6 +26,11 @@ ...@@ -26,6 +26,11 @@
{{ form.req_traits|as_crispy_field }} {{ form.req_traits|as_crispy_field }}
{{ form.description|as_crispy_field }} {{ form.description|as_crispy_field }}
{{ form.system|as_crispy_field }} {{ form.system|as_crispy_field }}
<hr/>
{{ form.cloud_init|as_crispy_field }}
{{ form.ci_meta_data|as_crispy_field }}
{{ form.ci_user_data|as_crispy_field }}
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "External resources" %}</legend> <legend>{% trans "External resources" %}</legend>
......
...@@ -79,6 +79,22 @@ ...@@ -79,6 +79,22 @@
</div> </div>
{% endif %} {% endif %}
<hr />
{% if instance.cloud_init %}
<div class="row">
<div class="col-sm-12">
<h3>
{% trans "Cloud-init" %}
</h3>
{% crispy ci_data %}
</div>
</div>
{% endif %}
{% if user.is_superuser %} {% if user.is_superuser %}
<hr/> <hr/>
......
...@@ -164,10 +164,18 @@ class TemplateCreate(SuccessMessageMixin, CreateView): ...@@ -164,10 +164,18 @@ class TemplateCreate(SuccessMessageMixin, CreateView):
tags = post.pop("tags") tags = post.pop("tags")
post['pw'] = User.objects.make_random_password() post['pw'] = User.objects.make_random_password()
post['is_base'] = True post['is_base'] = True
inst = Instance.create(params=post, disks=[], inst = Instance.create(params=post, disks=[],
networks=networks, networks=networks,
tags=tags, req_traits=req_traits) tags=tags, req_traits=req_traits)
if post['cloud_init']:
disk = Disk.create_ci_disk(meta_data=post['ci_meta_data'], user_data=post['ci_user_data'], user=request.user)
disk.full_clean()
disk.save()
inst.disks.add(disk)
return HttpResponseRedirect("%s#resources" % return HttpResponseRedirect("%s#resources" %
inst.get_absolute_url()) inst.get_absolute_url())
......
...@@ -60,7 +60,7 @@ from .util import ( ...@@ -60,7 +60,7 @@ from .util import (
TransferOwnershipConfirmView, TransferOwnershipView, TransferOwnershipConfirmView, TransferOwnershipView,
) )
from ..forms import ( from ..forms import (
AclUserOrGroupAddForm, VmResourcesForm, TraitsForm, RawDataForm, AclUserOrGroupAddForm, CIDataForm, VmResourcesForm, TraitsForm, RawDataForm,
VmAddInterfaceForm, VmCreateDiskForm, VmDownloadDiskForm, VmAddInterfaceForm, VmCreateDiskForm, VmDownloadDiskForm,
VmImportDiskForm, VmSaveForm, VmImportDiskForm, VmSaveForm,
VmRenewForm, VmStateChangeForm, VmListSearchForm, VmCustomizeForm, VmRenewForm, VmStateChangeForm, VmListSearchForm, VmCustomizeForm,
...@@ -204,6 +204,8 @@ class VmDetailView(GraphMixin, CheckedDetailView): ...@@ -204,6 +204,8 @@ class VmDetailView(GraphMixin, CheckedDetailView):
"PENDING", "PENDING",
) )
context['ci_data'] = CIDataForm(instance=instance)
return context return context
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
......
# Generated by Django 3.2.3 on 2022-07-20 12:54
from django.db import migrations, models
import firewall.fields
class Migration(migrations.Migration):
dependencies = [
('firewall', '0007_auto_20211102_1331'),
]
operations = [
migrations.AlterField(
model_name='vlan',
name='ipv6_template',
field=models.TextField(blank=True, help_text='Template for translating IPv4 addresses to IPv6. Automatically generated hosts in dual-stack networks will get this address. The template can contain four tokens: "%(a)d", "%(b)d", "%(c)d", and "%(d)d", representing the four unicode of the IPv4 address, respectively, in decimal notation. Moreover you can use any standard printf format specification like %(a)02x to get the first byte as two hexadecimal digits. Usual choices for mapping 198.51.100.0/24 to 2001:0DB8:1:1::/64 would be "2001:db8:1:1:%(d)d::" and "2001:db8:1:1:%(d)02x00::".', validators=[firewall.fields.val_ipv6_template], verbose_name='ipv6 template'),
),
migrations.AlterField(
model_name='vlan',
name='reverse_domain',
field=models.TextField(default='%(d)d.%(c)d.%(b)d.%(a)d.in-addr.arpa', help_text='Template of the IPv4 reverse domain name that should be generated for each host. The template should contain four tokens: "%(a)d", "%(b)d", "%(c)d", and "%(d)d", representing the four unicode of the address, respectively, in decimal notation. For example, the template for the standard reverse address is: "%(d)d.%(c)d.%(b)d.%(a)d.in-addr.arpa".', validators=[firewall.fields.val_reverse_domain], verbose_name='reverse domain'),
),
]
...@@ -448,6 +448,21 @@ class Disk(TimeStampedModel): ...@@ -448,6 +448,21 @@ class Disk(TimeStampedModel):
return result return result
@classmethod @classmethod
def create_ci_disk(cls, meta_data, user_data, user = None, **params):
params.setdefault('name', 'ci-disk')
params.setdefault('type', 'iso')
params.setdefault('size', 200)
disk = cls.__create(params=params, user=user)
queue_name = disk.get_remote_queue_name('storage', priority="fast")
disk_desc = disk.get_disk_desc()
storage_tasks.create_ci_disk.apply_async(args=[disk_desc, user_data, meta_data],
queue=queue_name
).get(timeout=15)
disk.is_ready = True
disk.save()
return disk
@classmethod
def download(cls, url, task, user=None, **params): def download(cls, url, task, user=None, **params):
"""Create disk object and download data from url synchronusly. """Create disk object and download data from url synchronusly.
......
...@@ -33,6 +33,11 @@ def create(disk_desc): ...@@ -33,6 +33,11 @@ def create(disk_desc):
pass pass
@celery.task(name='storagedriver.create_ci_disk')
def create_ci_disk(disk_desc, meta_data, user_data):
pass
@celery.task(name='storagedriver.download') @celery.task(name='storagedriver.download')
def download(disk_desc, url): def download(disk_desc, url):
pass pass
......
# Generated by Django 3.2.3 on 2022-07-20 12:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0005_auto_20211119_1017'),
]
operations = [
migrations.AddField(
model_name='instance',
name='ci_meta_data',
field=models.TextField(blank=True, help_text='When cloud-init is active, set meta-data oprtions (YAML format)', verbose_name='ci_meta_data'),
),
migrations.AddField(
model_name='instance',
name='ci_user_data',
field=models.TextField(blank=True, help_text='When cloud-init is active, set user-data oprtions (YAML format)', verbose_name='ci_user_data'),
),
migrations.AddField(
model_name='instancetemplate',
name='ci_meta_data',
field=models.TextField(blank=True, help_text='When cloud-init is active, set meta-data oprtions (YAML format)', verbose_name='ci_meta_data'),
),
migrations.AddField(
model_name='instancetemplate',
name='ci_user_data',
field=models.TextField(blank=True, help_text='When cloud-init is active, set user-data oprtions (YAML format)', verbose_name='ci_user_data'),
),
]
# Generated by Django 3.2.3 on 2022-07-20 13:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0006_auto_20220720_1254'),
]
operations = [
migrations.AddField(
model_name='instance',
name='cloud_init',
field=models.BooleanField(default=True, help_text='VM use cloud-init, set user- and meta-data below', verbose_name='Use Cloud-init'),
),
migrations.AddField(
model_name='instancetemplate',
name='cloud_init',
field=models.BooleanField(default=True, help_text='VM use cloud-init, set user- and meta-data below', verbose_name='Use Cloud-init'),
),
migrations.AlterField(
model_name='instance',
name='ci_meta_data',
field=models.TextField(blank=True, help_text='When cloud-init is active, set meta-data (YAML format)', verbose_name='ci_meta_data'),
),
migrations.AlterField(
model_name='instance',
name='ci_user_data',
field=models.TextField(blank=True, help_text='When cloud-init is active, set user-data (YAML format)', verbose_name='ci_user_data'),
),
migrations.AlterField(
model_name='instancetemplate',
name='ci_meta_data',
field=models.TextField(blank=True, help_text='When cloud-init is active, set meta-data (YAML format)', verbose_name='ci_meta_data'),
),
migrations.AlterField(
model_name='instancetemplate',
name='ci_user_data',
field=models.TextField(blank=True, help_text='When cloud-init is active, set user-data (YAML format)', verbose_name='ci_user_data'),
),
]
...@@ -22,6 +22,7 @@ from functools import partial ...@@ -22,6 +22,7 @@ from functools import partial
from importlib import import_module from importlib import import_module
from logging import getLogger from logging import getLogger
from warnings import warn from warnings import warn
from xml.dom.minidom import Text
import django.conf import django.conf
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -112,6 +113,13 @@ class VirtualMachineDescModel(BaseResourceConfigModel): ...@@ -112,6 +113,13 @@ class VirtualMachineDescModel(BaseResourceConfigModel):
verbose_name=_("Lease"), on_delete=models.CASCADE) verbose_name=_("Lease"), on_delete=models.CASCADE)
raw_data = TextField(verbose_name=_('raw_data'), blank=True, help_text=_( raw_data = TextField(verbose_name=_('raw_data'), blank=True, help_text=_(
'Additional libvirt domain parameters in XML format.')) 'Additional libvirt domain parameters in XML format.'))
cloud_init = BooleanField(verbose_name=_('Use Cloud-init'), default=False,
help_text=_(
'VM use cloud-init, set user- and meta-data below'))
ci_meta_data = TextField(verbose_name=_('ci_meta_data'), blank=True, help_text=_(
'When cloud-init is active, set meta-data (YAML format)'))
ci_user_data = TextField(verbose_name=_('ci_user_data'), blank=True, help_text=_(
'When cloud-init is active, set user-data (YAML format)'))
req_traits = ManyToManyField(Trait, blank=True, req_traits = ManyToManyField(Trait, blank=True,
help_text=_("A set of traits required for a " help_text=_("A set of traits required for a "
"node to declare to be suitable " "node to declare to be suitable "
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment