612
613
"This is used by the cluster and region controllers for "
613
614
"downloading PXE boot images and other provisioning-related "
614
"resources. It is not passed into provisioned nodes."))
615
"resources. This will also be passed onto provisioned "
616
"nodes instead of the default proxy (the region controller "
617
620
class CommissioningForm(ConfigForm):
618
"""Settings page, CommissioningF section."""
621
"""Settings page, Commissioning section."""
619
622
check_compatibility = forms.BooleanField(
620
623
label="Check component compatibility and certification",
628
631
error_messages={'invalid_choice': INVALID_DISTRO_SERIES_MESSAGE})
634
url_error_msg = "Enter a valid url (e.g. http://host.example.com)."
631
637
class UbuntuForm(ConfigForm):
632
638
"""Settings page, Ubuntu section."""
633
fallback_master_archive = forms.BooleanField(
634
label="Fallback to Ubuntu master archive",
636
639
default_distro_series = forms.ChoiceField(
637
640
choices=DISTRO_SERIES_CHOICES, required=False,
638
641
label="Default distro series used for deployment",
639
642
error_messages={'invalid_choice': INVALID_DISTRO_SERIES_MESSAGE})
640
keep_mirror_list_uptodate = forms.BooleanField(
641
label="Keep mirror list up to date",
643
fetch_new_releases = forms.BooleanField(
644
label="Fetch new releases automatically",
647
def __init__(self, *args, **kwargs):
648
super(UbuntuForm, self).__init__(*args, **kwargs)
649
# The field 'update_from' must be added dynamically because its
650
# 'choices' must be evaluated each time the form is instantiated.
651
self.fields['update_from'] = forms.ChoiceField(
653
choices=Config.objects.get_config('update_from_choice'))
654
# The list of fields has changed: load initial values.
655
self._load_initials()
658
hostname_error_msg = "Enter a valid hostname (e.g. host.example.com)."
661
def validate_hostname(value):
663
validator = URLValidator(verify_exists=False)
664
validator('http://%s' % value)
665
except ValidationError:
666
raise ValidationError(hostname_error_msg)
669
class HostnameFormField(CharField):
671
def __init__(self, *args, **kwargs):
672
super(HostnameFormField, self).__init__(
673
validators=[validate_hostname], *args, **kwargs)
676
class AddArchiveForm(ConfigForm):
677
archive_name = HostnameFormField(label="Archive name")
680
"""Save the archive name in the Config table.
682
This implementation of `save` does not support the `commit` argument.
684
archive_name = self.cleaned_data.get('archive_name')
685
archives = Config.objects.get_config('update_from_choice')
686
archives.append([archive_name, archive_name])
687
Config.objects.set_config('update_from_choice', archives)
643
main_archive = forms.URLField(
644
label="Main archive",
645
error_messages={'invalid': url_error_msg},
647
"Archive used by nodes to retrieve packages and by cluster "
648
"controllers to retrieve boot images (Intel architectures). "
649
"E.g. http://archive.ubuntu.com/ubuntu."
651
ports_archive = forms.URLField(
652
label="Ports archive",
653
error_messages={'invalid': url_error_msg},
655
"Archive used by cluster controllers to retrieve boot images "
656
"(non-Intel architectures). "
657
"E.g. http://ports.ubuntu.com/ubuntu-ports."
659
cloud_images_archive = forms.URLField(
660
label="Cloud images archive",
661
error_messages={'invalid': url_error_msg},
663
"Archive used by the nodes to retrieve ephemeral images. "
664
"E.g. https://maas.ubuntu.com/images."
668
class GlobalKernelOptsForm(ConfigForm):
669
"""Settings page, Global Kernel Parameters section."""
670
kernel_opts = forms.CharField(
671
label="Boot parameters to pass to the kernel by default",
690
675
class NodeGroupInterfaceForm(ModelForm):
881
867
msg = 'Invalid xpath expression: %s' % (e,)
882
868
raise ValidationError({'definition': [msg]})
883
869
return definition
872
class CommissioningScriptForm(forms.Form):
874
content = forms.FileField(
875
label="Commissioning script", allow_empty_file=False)
877
def __init__(self, instance=None, *args, **kwargs):
878
super(CommissioningScriptForm, self).__init__(*args, **kwargs)
880
def clean_content(self):
881
content = self.cleaned_data['content']
883
if pipes.quote(name) != name:
884
raise forms.ValidationError(
885
"Name contains disallowed characters (e.g. space or quotes).")
886
if CommissioningScript.objects.filter(name=name).exists():
887
raise forms.ValidationError(
888
"A script with that name already exists.")
891
def save(self, *args, **kwargs):
892
content = self.cleaned_data['content']
893
CommissioningScript.objects.create(
895
content=Bin(content.read()))