class ProductionForm(Form): production = forms.BooleanField( label=_('This is production system'), required=False, ) send_debug = forms.BooleanField( label=_('Send initial debug'), required=False, ) def __init__(self, *args, **kwargs): super(ProductionForm, self).__init__(*args, **kwargs) self.fields['production'].widget.attrs['onChange'] = ( 'support_production_toggle();') with client as c: self.initial['production'] = c.call('truenas.is_production') def save(self): with client as c: c.call('truenas.set_production', self.cleaned_data['production'], self.cleaned_data['send_debug'])
class JailConfigureForm(ModelForm): jail_autostart = forms.BooleanField(label=_("autostart"), required=False) jail_source = forms.BooleanField(label=_("source"), required=False) jail_ports = forms.BooleanField(label=_("ports"), required=False) class Meta: model = Jails
def __init__(self, *args, **kwargs): super(AFP_ShareForm, self).__init__(*args, **kwargs) self.fields['afp_upriv'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_afp_upriv", ["id_afp_fperm", ' '"id_afp_dperm"], true);') self.fields['afp_fperm'] = UnixPermissionField( label=self.fields['afp_fperm'].label, initial=self.fields['afp_fperm'].initial, required=False, ) self.fields['afp_dperm'] = UnixPermissionField( label=self.fields['afp_dperm'].label, initial=self.fields['afp_dperm'].initial, required=False, ) if self.instance.id: self.fields['afp_sharepw2'].initial = self.instance.afp_sharepw if self.instance.afp_sharepw: self.fields['afp_deletepw'] = forms.BooleanField( label=_("Delete password"), initial=False, required=False, ) self.fields.keyOrder.remove('afp_deletepw') self.fields.keyOrder.insert(5, 'afp_deletepw') if not self.instance.afp_upriv: self.fields['afp_fperm'].widget.attrs['disabled'] = 'true' self.fields['afp_dperm'].widget.attrs['disabled'] = 'true' else: self.fields['afp_fperm'].widget.attrs['disabled'] = 'false' self.fields['afp_dperm'].widget.attrs['disabled'] = 'false'
class ProductionForm(Form): production = forms.BooleanField( label=_('This is production system'), required=False, ) send_debug = forms.BooleanField( label=_('Send initial debug'), required=False, ) def __init__(self, *args, **kwargs): super(ProductionForm, self).__init__(*args, **kwargs) self.fields['production'].widget.attrs['onChange'] = ( 'support_production_toggle();') with client as c: self.initial['production'] = c.call('keyvalue.get', 'truenas:production', False) def save(self): with client as c: send_debug = ( not c.call('keyvalue.get', 'truenas:production', False) and self.cleaned_data['production'] and self.cleaned_data['send_debug']) c.call('keyvalue.set', 'truenas:production', self.cleaned_data['production']) if send_debug: serial = c.call('system.info')["system_serial"] c.call( 'support.new_ticket', { "title": f"System has been just put into production ({serial})", "body": "This system has been just put into production", "attach_debug": True, "category": "Installation/Setup", "criticality": "Inquiry", "environment": "Production", "name": "Automatic Alert", "email": "*****@*****.**", "phone": "-", })
def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance', None) services = kwargs.pop('services', {}) super(VolumeExport, self).__init__(*args, **kwargs) if services.keys(): self.fields['cascade'] = forms.BooleanField( initial=True, required=False, label=_("Delete all shares related to this volume"))
def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance', None) super(DeleteUserForm, self).__init__(*args, **kwargs) qs = models.bsdUsers.objects.filter(bsdusr_group__id=self.instance.bsdusr_group.id).exclude(id=self.instance.id) if not qs.exists(): self.fields['nodelgroup'] = forms.BooleanField( label=_("Do not delete user primary group"), required=False, initial=False, )
class IPMIForm(Form): # Max password length via IPMI v2.0 is 20 chars. We only support IPMI # v2.0+ compliant boards thus far. ipmi_password1 = forms.CharField(label=_("Password"), max_length=20, widget=forms.PasswordInput, required=False) ipmi_password2 = forms.CharField( label=_("Password confirmation"), max_length=20, widget=forms.PasswordInput, help_text=_("Enter the same password as above, for verification."), required=False) dhcp = forms.BooleanField( label=_("DHCP"), required=False, ) ipv4address = IP4AddressFormField( initial='', required=False, label=_("IPv4 Address"), ) ipv4netmaskbit = forms.ChoiceField( choices=choices.v4NetmaskBitList, required=False, label=_("IPv4 Netmask"), ) ipv4gw = IP4AddressFormField( initial='', required=False, label=_("IPv4 Default Gateway"), ) def __init__(self, *args, **kwargs): super(IPMIForm, self).__init__(*args, **kwargs) self.fields['dhcp'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric(' '"id_dhcp", ["id_ipv4address", "id_ipv4netmaskbit"]);') def clean_ipmi_password2(self): ipmi_password1 = self.cleaned_data.get("ipmi_password1", "") ipmi_password2 = self.cleaned_data["ipmi_password2"] if ipmi_password1 != ipmi_password2: raise forms.ValidationError( _("The two password fields didn't match.")) return ipmi_password2 def clean_ipv4netmaskbit(self): try: cidr = int(self.cleaned_data.get("ipv4netmaskbit")) except ValueError: return None bits = 0xffffffff ^ (1 << 32 - cidr) - 1 return socket.inet_ntoa(pack('>I', bits))
class PasswordChangeForm(SetPasswordForm): """ A form that lets a user change his/her password by entering their old password. """ change_root = forms.BooleanField( label=_("Change root password as well"), initial=True, required=False, ) def __init__(self, *args, **kwargs): super(PasswordChangeForm, self).__init__(*args, **kwargs) if self.user.has_usable_password(): self.fields['old_password'] = forms.CharField( label=_("Old password"), widget=forms.PasswordInput, ) self.fields.keyOrder = [ 'old_password', 'new_password', 'new_password2', 'change_root' ] else: self.fields.keyOrder = [ 'new_password', 'new_password2', 'change_root' ] if self._api is True: del self.fields['new_password2'] def clean_old_password(self): """ Validates that the old_password field is correct. """ if not self.user.has_usable_password(): return '' old_password = self.cleaned_data["old_password"] if not self.user.check_password(old_password): raise forms.ValidationError(_( "Your old password was entered incorrectly. Please enter it " "again." )) return old_password def save(self, *args, **kwargs): with transaction.commit_on_success(): if self.cleaned_data.get('change_root'): root = models.bsdUsers.objects.get(bsdusr_username='******') new_password = self.cleaned_data.get('new_password') bsdpasswdform = bsdUserPasswordForm(instance=root) bsdpasswdform.cleaned_data = {} bsdpasswdform.cleaned_data['bsdusr_password'] = new_password bsdpasswdform.cleaned_data['bsdusr_password2'] = new_password bsdpasswdform.save() return super(PasswordChangeForm, self).save(*args, **kwargs)
def __init__(self, *args, **kwargs): self.fs = kwargs.pop('fs') self.datasets = kwargs.pop('datasets', []) super(Dataset_Destroy, self).__init__(*args, **kwargs) snaps = notifier().zfs_snapshot_list(path=self.fs) if len(snaps.get(self.fs, [])) > 0: label = ungettext( "I'm aware this will destroy snapshots within this dataset", ("I'm aware this will destroy all child datasets and " "snapshots within this dataset"), len(self.datasets)) self.fields['cascade'] = forms.BooleanField(initial=True, label=label)
def __init__(self, *args, **kwargs): super(bsdGroupsForm, self).__init__(*args, **kwargs) if self.instance.id: self.fields['bsdgrp_gid'].widget.attrs['readonly'] = True self.fields['bsdgrp_gid'].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled ' 'dijitValidationTextBoxDisabled') else: self.initial['bsdgrp_gid'] = notifier().user_getnextgid() self.fields['allow'] = forms.BooleanField( label=_("Allow repeated GIDs"), initial=False, required=False, )
class CIFS_ShareForm(MiddlewareModelForm, ModelForm): cifs_default_permissions = forms.BooleanField( label=_('Apply Default Permissions'), help_text=_( 'Recursively set appropriate default Windows permissions on share' ), required=False) middleware_attr_prefix = "cifs_" middleware_attr_schema = "sharingsmb" middleware_plugin = "sharing.smb" is_singletone = False def __init__(self, *args, **kwargs): super(CIFS_ShareForm, self).__init__(*args, **kwargs) if self.instance.id: self.fields['cifs_default_permissions'].initial = False self._original_cifs_vfsobjects = self.instance.cifs_vfsobjects else: self.fields['cifs_default_permissions'].initial = True self._original_cifs_vfsobjects = [] key_order(self, 4, 'cifs_default_permissions', instance=True) self.fields['cifs_guestok'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_cifs_guestok", ' '["id_cifs_guestonly"], true);') if self.data: if self.data.get('cifs_guestok') is False: self.fields['cifs_guestonly'].widget.attrs['disabled'] = \ 'disabled' elif self.instance.cifs_guestok is False: self.fields['cifs_guestonly'].widget.attrs['disabled'] = 'disabled' self.fields['cifs_name'].required = False class Meta: fields = '__all__' model = models.CIFS_Share def middleware_clean(self, data): data['hostsallow'] = data['hostsallow'].split() data['hostsdeny'] = data['hostsdeny'].split() return data def done(self, request, events): if not services.objects.get(srv_service='cifs').srv_enable: events.append('ask_service("cifs")') super(CIFS_ShareForm, self).done(request, events)
class ExtentDelete(Form): delete = forms.BooleanField( label=_("Delete underlying file"), initial=False, required=False, ) def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance', None) super(ExtentDelete, self).__init__(*args, **kwargs) def done(self, *args, **kwargs): if self.cleaned_data['delete'] and \ self.instance.iscsi_target_extent_type == 'File': os.unlink(self.instance.iscsi_target_extent_path)
class PluginsJailDeleteForm(Form): delete = forms.BooleanField( label=_("Are you sure you want to delete?"), initial=False, required=True, ) def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance', None) super(PluginsJailDeleteForm, self).__init__(*args, **kwargs) def done(self, *args, **kwargs): events = kwargs.pop('events', None) if events is not None: events.append("refreshPlugins()")
class DeleteGroupForm(forms.Form): cascade = forms.BooleanField( label=_("Do you want to delete all users with this primary group?"), required=False, initial=False, ) def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance', None) super(DeleteGroupForm, self).__init__(*args, **kwargs) def done(self, *args, **kwargs): if self.cleaned_data.get("cascade") is True: models.bsdUsers.objects.filter(bsdusr_group=self.instance).delete()
class VolumeExport(Form): mark_new = forms.BooleanField( required=False, initial=False, label=_("Mark the disks as new (destroy data)"), ) def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance', None) services = kwargs.pop('services', {}) super(VolumeExport, self).__init__(*args, **kwargs) if services.keys(): self.fields['cascade'] = forms.BooleanField( initial=True, required=False, label=_("Delete all shares related to this volume"))
class NTPForm(ModelForm): force = forms.BooleanField(label=_("Force"), required=False) class Meta: fields = '__all__' model = models.NTPServer def __init__(self, *args, **kwargs): super(NTPForm, self).__init__(*args, **kwargs) self.usable = True def clean_ntp_address(self): addr = self.cleaned_data.get("ntp_address") p1 = subprocess.Popen( ["/usr/sbin/ntpdate", "-q", addr], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) p1.communicate() if p1.returncode != 0: self.usable = False return addr def clean_ntp_maxpoll(self): maxp = self.cleaned_data.get("ntp_maxpoll") minp = self.cleaned_data.get("ntp_minpoll") if not maxp > minp: raise forms.ValidationError(_( "Max Poll should be higher than Min Poll" )) return maxp def clean(self): cdata = self.cleaned_data if not cdata.get("force", False) and not self.usable: self._errors['ntp_address'] = self.error_class([_( "Server could not be reached. Check \"Force\" to continue " "regardless." )]) del cdata['ntp_address'] return cdata def save(self): super(NTPForm, self).save() notifier().start("ix-ntpd") notifier().restart("ntpd")
class ExtentDelete(Form): delete = forms.BooleanField( label=_("Delete underlying file"), initial=False, required=False, ) def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance', None) super(ExtentDelete, self).__init__(*args, **kwargs) if self.instance.iscsi_target_extent_type != 'File': self.fields.pop('delete') if not self.data: target_to_extent_list = models.iSCSITargetToExtent.objects.filter( iscsi_extent__iscsi_target_extent_name=self.instance. iscsi_target_extent_name) basename = models.iSCSITargetGlobalConfiguration.objects.order_by( '-id')[0].iscsi_basename targets = [] for target_to_extent in target_to_extent_list: target = target_to_extent.iscsi_target.iscsi_target_name if not target.startswith(('iqn.', 'naa.', 'eui.')): target = basename + ':' + target targets.append(target) if not targets: return with client as c: if c.call('iscsi.global.sessions', [['target', 'in', targets]]): self.errors['__all__'] = self.error_class( ["Warning: Associated Target is in use"]) def done(self, *args, **kwargs): if (self.instance.iscsi_target_extent_type == 'File' and self.cleaned_data['delete'] and os.path.exists(self.instance.iscsi_target_extent_path)): data = {} data['type'] = self.instance.iscsi_target_extent_type data['path'] = self.instance.iscsi_target_extent_path with client as c: c.call('iscsi.extent.remove_extent_file', data)
class ExtentDelete(Form): delete = forms.BooleanField( label=_("Delete underlying file"), initial=False, required=False, ) def __init__(self, *args, **kwargs): self.instance = kwargs.pop('instance', None) super(ExtentDelete, self).__init__(*args, **kwargs) if self.instance.iscsi_target_extent_type != 'File': self.fields.pop('delete') if not self.data: targets_in_use = notifier().iscsi_connected_targets() is_extent_active = False target_to_extent_list = models.iSCSITargetToExtent.objects.filter( iscsi_extent__iscsi_target_extent_name=self.instance. iscsi_target_extent_name) basename = models.iSCSITargetGlobalConfiguration.objects.order_by( '-id')[0].iscsi_basename for target_to_extent in target_to_extent_list: target = target_to_extent.iscsi_target.iscsi_target_name if not target.startswith(('iqn.', 'naa.', 'eui.')): target = basename + ':' + target if target in targets_in_use: is_extent_active = True # Extent is active. No need to check other targets. break if is_extent_active: self.errors['__all__'] = self.error_class( ["Warning: Associated Target is in use"]) def done(self, *args, **kwargs): if (self.instance.iscsi_target_extent_type == 'File' and self.cleaned_data['delete'] and os.path.exists(self.instance.iscsi_target_extent_path)): data = {} data['type'] = self.instance.iscsi_target_extent_type data['path'] = self.instance.iscsi_target_extent_path with client as c: c.call('iscsi.extent.remove_extent_file', data)
def __init__(self, *args, **kwargs): super(bsdGroupsForm, self).__init__(*args, **kwargs) if self.instance.id: self.fields['bsdgrp_gid'].widget.attrs['readonly'] = True self.fields['bsdgrp_gid'].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled ' 'dijitValidationTextBoxDisabled') self.instance._original_bsdgrp_group = self.instance.bsdgrp_group else: try: with client as c: self.initial['bsdgrp_gid'] = c.call('group.get_next_gid') except Exception: pass self.fields['allow'] = forms.BooleanField( label=_("Allow repeated GIDs"), initial=False, required=False, )
class ManualSnapshotForm(Form): ms_recursively = forms.BooleanField(initial=False, required=False, label=_('Recursive snapshot')) ms_name = forms.CharField(label=_('Snapshot Name')) def __init__(self, *args, **kwargs): super(ManualSnapshotForm, self).__init__(*args, **kwargs) self.fields['ms_name'].initial = datetime.today().strftime( 'manual-%Y%m%d') def clean_ms_name(self): regex = re.compile('^[-a-zA-Z0-9_.]+$') if regex.match(self.cleaned_data['ms_name'].__str__()) is None: raise forms.ValidationError( _("Only [-a-zA-Z0-9_.] permitted as snapshot name")) return self.cleaned_data['ms_name'] def commit(self, fs): notifier().zfs_mksnap(fs, str(self.cleaned_data['ms_name']), self.cleaned_data['ms_recursively'])
class MountPointAccessForm(Form): mp_user = UserField(label=_('Owner (user)')) mp_group = GroupField(label=_('Owner (group)')) mp_mode = UnixPermissionField(label=_('Mode')) mp_acl = forms.ChoiceField(label=_('Type of ACL'), choices=( ('unix', 'Unix'), ('windows', 'Windows'), ), initial='unix', widget=forms.widgets.RadioSelect()) mp_recursive = forms.BooleanField(initial=False, required=False, label=_('Set permission recursively')) def __init__(self, *args, **kwargs): super(MountPointAccessForm, self).__init__(*args, **kwargs) path = kwargs.get('initial', {}).get('path', None) if path: if os.path.exists(os.path.join(path, ".windows")): self.fields['mp_acl'].initial = 'windows' else: self.fields['mp_acl'].initial = 'unix' user, group = notifier().mp_get_owner(path) self.fields['mp_mode'].initial = "%.3o" % ( notifier().mp_get_permission(path), ) self.fields['mp_user'].initial = user self.fields['mp_group'].initial = group def commit(self, path='/mnt/'): notifier().mp_change_permission( path=path, user=self.cleaned_data['mp_user'].__str__(), group=self.cleaned_data['mp_group'].__str__(), mode=self.cleaned_data['mp_mode'].__str__(), recursive=self.cleaned_data['mp_recursive'], acl=self.cleaned_data['mp_acl'])
class PasswordChangeForm(SetPasswordForm): """ A form that lets a user change his/her password by entering their old password. """ change_root = forms.BooleanField( label=_("Change root password as well"), initial=True, required=False, ) def __init__(self, *args, **kwargs): super(PasswordChangeForm, self).__init__(*args, **kwargs) if self.user.has_usable_password(): self.fields['old_password'] = forms.CharField( label=_("Old password"), widget=forms.PasswordInput, ) self.fields.keyOrder = [ 'old_password', 'new_password1', 'new_password2', 'change_root' ] else: self.fields.keyOrder = [ 'new_password1', 'new_password2', 'change_root' ] def clean_old_password(self): """ Validates that the old_password field is correct. """ if not self.user.has_usable_password(): return '' old_password = self.cleaned_data["old_password"] if not self.user.check_password(old_password): raise forms.ValidationError( _("Your old password was entered incorrectly. Please enter it " "again.")) return old_password
class bsdUsersForm(ModelForm): bsdusr_username = forms.CharField(label=_("Username"), max_length=16) bsdusr_password = forms.CharField(label=_("Password"), widget=forms.PasswordInput, required=False) bsdusr_password2 = forms.CharField( label=_("Password confirmation"), widget=forms.PasswordInput, help_text=_("Enter the same password as above, for verification."), required=False) bsdusr_group = forms.ModelChoiceField( label=_("Primary Group"), queryset=models.bsdGroups.objects.all(), required=False) bsdusr_creategroup = forms.BooleanField( label=_("Create a new primary group for the user"), required=False, initial=True) bsdusr_sshpubkey = forms.CharField(label=_("SSH Public Key"), widget=forms.Textarea, required=False) bsdusr_mode = UnixPermissionField(label=_('Home Directory Mode'), initial='755', required=False) bsdusr_to_group = SelectMultipleField(label=_('Auxiliary groups'), choices=(), required=False) advanced_fields = ['bsdusr_mode'] middleware_attr_map = { 'groups': 'bsdusr_to_group', 'group_create': 'bsdusr_creategroup', 'home_mode': 'bsdusr_home', } middleware_attr_prefix = 'bsdusr_' class Meta: model = models.bsdUsers widgets = { 'bsdusr_uid': forms.widgets.ValidationTextInput(), } exclude = ( 'bsdusr_unixhash', 'bsdusr_smbhash', 'bsdusr_group', ) fields = ( 'bsdusr_uid', 'bsdusr_username', 'bsdusr_creategroup', 'bsdusr_home', 'bsdusr_mode', 'bsdusr_shell', 'bsdusr_full_name', 'bsdusr_email', 'bsdusr_password', 'bsdusr_password2', 'bsdusr_password_disabled', 'bsdusr_locked', 'bsdusr_sudo', 'bsdusr_microsoft_account', 'bsdusr_sshpubkey', 'bsdusr_to_group', ) def __init__(self, *args, **kwargs): #FIXME: Workaround for DOJO not showing select with blank values if len(args) > 0 and isinstance(args[0], QueryDict): new = args[0].copy() if new.get('bsdusr_group', None) == '-----': new['bsdusr_group'] = '' args = (new, ) + args[1:] super(bsdUsersForm, self).__init__(*args, **kwargs) key_order(self, 3, 'bsdusr_group', instance=True) if self._api is True: del self.fields['bsdusr_password2'] self.fields['bsdusr_to_group'].choices = [ (x.id, x.bsdgrp_group) for x in models.bsdGroups.objects.all() ] self.fields['bsdusr_password_disabled'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_bsdusr_password_disabled", ' '["id_bsdusr_locked", "id_bsdusr_sudo"], false);') self.fields['bsdusr_locked'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_bsdusr_locked", ' '["id_bsdusr_password_disabled"], false);') self.fields['bsdusr_sudo'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_bsdusr_sudo", ' '["id_bsdusr_password_disabled"], false);') if not self.instance.id: try: with client as c: self.fields['bsdusr_uid'].initial = c.call( 'user.get_next_uid') except Exception: pass self.fields['bsdusr_home'].label = _('Create Home Directory In') self.fields['bsdusr_creategroup'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_bsdusr_creategroup", ' '["id_bsdusr_group"], false);') self.fields['bsdusr_group'].widget.attrs['maxHeight'] = 200 self.fields['bsdusr_group'].widget.attrs['disabled'] = 'disabled' self.fields['bsdusr_group'].choices = ( ('-----', '-----'), ) + tuple( [x for x in self.fields['bsdusr_group'].choices][1:]) self.fields['bsdusr_group'].required = False self.bsdusr_home_saved = '/nonexistent' elif self.instance.id: self.fields['bsdusr_to_group'].initial = [ x.bsdgrpmember_group.id for x in models.bsdGroupMembership.objects.filter( bsdgrpmember_user=self.instance.id) ] del self.fields['bsdusr_creategroup'] self.fields['bsdusr_group'].initial = self.instance.bsdusr_group self.advanced_fields = [] self.bsdusr_home_saved = self.instance.bsdusr_home key_order(self, len(self.fields) - 1, 'bsdusr_mode', instance=True) self.fields['bsdusr_username'].widget.attrs['readonly'] = True self.fields['bsdusr_username'].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled ' 'dijitValidationTextBoxDisabled') if os.path.exists(self.instance.bsdusr_home): mode = os.stat(self.instance.bsdusr_home).st_mode & 0o777 self.fields['bsdusr_mode'].initial = oct(mode)[2:] if self.instance.bsdusr_builtin: self.fields['bsdusr_uid'].widget.attrs['readonly'] = True self.fields['bsdusr_uid'].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled ' 'dijitValidationTextBoxDisabled') self.fields['bsdusr_group'].widget.attrs['readonly'] = True self.fields['bsdusr_group'].widget.attrs['class'] = ( 'dijitDisabled dijitSelectDisabled') self.fields['bsdusr_home'].widget.attrs['readonly'] = True self.fields['bsdusr_home'].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled ' 'dijitValidationTextBoxDisabled') self.fields['bsdusr_mode'].widget.attrs['disabled'] = True self.fields['bsdusr_mode'].required = False if self.instance.bsdusr_locked or self.instance.bsdusr_sudo: self.fields['bsdusr_password_disabled'].widget.attrs[ 'disabled'] = True if self.instance.bsdusr_password_disabled is True: self.fields['bsdusr_locked'].widget.attrs['disabled'] = True self.fields['bsdusr_sudo'].widget.attrs['disabled'] = True self.fields['bsdusr_sshpubkey'].initial = ( self.instance.bsdusr_sshpubkey) def clean_bsdusr_password2(self): bsdusr_password = self.cleaned_data.get("bsdusr_password", "") bsdusr_password2 = self.cleaned_data["bsdusr_password2"] if bsdusr_password and bsdusr_password != bsdusr_password2: raise forms.ValidationError( _("The two password fields didn't match.")) return bsdusr_password2 def clean_bsdusr_home(self): home = self.cleaned_data['bsdusr_home'] user_home = self.instance.bsdusr_home if self.instance.bsdusr_builtin: return self.instance.bsdusr_home if home is not None: if home == '/nonexistent': return home if home.startswith('/mnt/'): bsdusr_username = self.cleaned_data.get('bsdusr_username', '') volumes = [ '/mnt/{}'.format(volume.vol_name) for volume in Volume.objects.all() ] if self.instance.id and home != user_home: if len(zfs.list_datasets(path=user_home)) > 0 and \ (len(zfs.list_datasets(path=home)) > 0 and home.startswith(user_home + '/')): raise forms.ValidationError( _("A dataset inside the home dataset " "cannot be used as a home directory.")) if home in volumes: raise forms.ValidationError( _("Volume root directories cannot be used as user home directories." )) if home.endswith(bsdusr_username): return home if not self.instance.id: home = "%s/%s" % (home.rstrip('/'), bsdusr_username) if not self.instance.id and not home.endswith(bsdusr_username): raise forms.ValidationError( _('Home directory must end with username')) return home def clean_bsdusr_mode(self): mode = self.cleaned_data.get('bsdusr_mode') if not self.instance.id and not mode: return '755' return mode def clean_bsdusr_sshpubkey(self): ssh = self.cleaned_data.get('bsdusr_sshpubkey', '') ssh = ssh.strip(' ').strip('\n') ssh = re.sub(r'[ ]{2,}', ' ', ssh, re.M) ssh = re.sub(r'\n{2,}', '\n', ssh, re.M) old = ssh while True: ssh = re.sub(r'(\S{20,})\n(\S{20,})', '\\1\\2', ssh, re.M) if ssh == old: break old = ssh return ssh def save(self, *args, **kwargs): data = self.cleaned_data.copy() # Convert attributes to new middleware API for k in list(data.keys()): if k.startswith('bsdusr_'): data[k[len('bsdusr_'):]] = data.pop(k) if self.instance.id is None: args = ['user.create'] data['group_create'] = data.pop('creategroup', False) else: args = ['user.update', self.instance.id] # If password is blank, do not send it to middleware if not data.get('password'): data.pop('password', None) data.pop('password2', None) data['home_mode'] = data.pop('mode') if data['group']: data['group'] = data['group'].id else: data.pop('group') data['groups'] = [int(group) for group in data.pop('to_group', [])] if self.instance.bsdusr_builtin: data.pop('home', None) data.pop('home_mode', None) data.pop('uid', None) data.pop('username', None) data.pop('group', None) with client as c: pk = c.call(*args, data) self.instance = models.bsdUsers.objects.get(pk=pk) return self.instance def delete(self, **kwargs): data = { 'delete_group': False if self.data.get('nodelgroup') else True, } with client as c: c.call('user.delete', self.instance.id, data)
class bsdUsersForm(ModelForm, bsdUserGroupMixin): bsdusr_username = forms.CharField(label=_("Username"), max_length=16) bsdusr_password = forms.CharField(label=_("Password"), widget=forms.PasswordInput, required=False) bsdusr_password2 = forms.CharField( label=_("Password confirmation"), widget=forms.PasswordInput, help_text=_("Enter the same password as above, for verification."), required=False) bsdusr_group = forms.ModelChoiceField( label=_("Primary Group"), queryset=models.bsdGroups.objects.all(), required=False) bsdusr_shell = forms.ChoiceField(label=_("Shell"), initial=u'/bin/csh', choices=()) bsdusr_creategroup = forms.BooleanField( label=_("Create a new primary group for the user"), required=False, initial=True) bsdusr_sshpubkey = forms.CharField(label=_("SSH Public Key"), widget=forms.Textarea, max_length=8192, required=False) bsdusr_mode = UnixPermissionField(label=_('Home Directory Mode'), initial='755', required=False) bsdusr_to_group = SelectMultipleField(label=_('Auxiliary groups'), choices=(), required=False) advanced_fields = ['bsdusr_mode'] class Meta: model = models.bsdUsers widgets = { 'bsdusr_uid': forms.widgets.ValidationTextInput(), } exclude = ( 'bsdusr_unixhash', 'bsdusr_smbhash', 'bsdusr_group', ) fields = ( 'bsdusr_uid', 'bsdusr_username', 'bsdusr_creategroup', 'bsdusr_home', 'bsdusr_mode', 'bsdusr_shell', 'bsdusr_full_name', 'bsdusr_email', 'bsdusr_password', 'bsdusr_password2', 'bsdusr_password_disabled', 'bsdusr_locked', 'bsdusr_sudo', 'bsdusr_sshpubkey', 'bsdusr_to_group', ) def __init__(self, *args, **kwargs): #FIXME: Workaround for DOJO not showing select with blank values if len(args) > 0 and isinstance(args[0], QueryDict): new = args[0].copy() if new.get('bsdusr_group', None) == '-----': new['bsdusr_group'] = '' args = (new, ) + args[1:] super(bsdUsersForm, self).__init__(*args, **kwargs) self.fields.keyOrder.remove('bsdusr_group') self.fields.keyOrder.insert(3, 'bsdusr_group') if self._api is True: del self.fields['bsdusr_password2'] self.fields['bsdusr_shell'].choices = self._populate_shell_choices() self.fields['bsdusr_shell'].choices.sort() self.fields['bsdusr_to_group'].choices = [ (x.id, x.bsdgrp_group) for x in models.bsdGroups.objects.order_by('bsdgrp_group') ] self.fields['bsdusr_password_disabled'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_bsdusr_password_disabled", ' '["id_bsdusr_locked", "id_bsdusr_sudo"], false);') self.fields['bsdusr_locked'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_bsdusr_locked", ' '["id_bsdusr_password_disabled"], false);') self.fields['bsdusr_sudo'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_bsdusr_sudo", ' '["id_bsdusr_password_disabled"], false);') if not self.instance.id: self.fields['bsdusr_uid'].initial = notifier().user_getnextuid() self.fields['bsdusr_home'].label = _('Create Home Directory In') self.fields['bsdusr_creategroup'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric("id_bsdusr_creategroup", ' '["id_bsdusr_group"], false);') self.fields['bsdusr_group'].widget.attrs['maxHeight'] = 200 self.fields['bsdusr_group'].widget.attrs['disabled'] = 'disabled' self.fields['bsdusr_group'].choices = ( ('-----', '-----'), ) + tuple( [x for x in self.fields['bsdusr_group'].choices][1:]) self.fields['bsdusr_group'].required = False self.bsdusr_home_saved = u'/nonexistent' self.bsdusr_home_copy = False elif self.instance.id: self.fields['bsdusr_to_group'].initial = [ x.bsdgrpmember_group.id for x in models.bsdGroupMembership.objects.filter( bsdgrpmember_user=self.instance.id) ] del self.fields['bsdusr_creategroup'] self.fields['bsdusr_group'].initial = self.instance.bsdusr_group self.advanced_fields = [] self.bsdusr_home_saved = self.instance.bsdusr_home self.bsdusr_home_copy = False self.fields.keyOrder.remove('bsdusr_mode') self.fields.keyOrder.insert( len(self.fields.keyOrder) - 1, 'bsdusr_mode', ) self.fields['bsdusr_username'].widget.attrs['readonly'] = True self.fields['bsdusr_username'].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled ' 'dijitValidationTextBoxDisabled') if os.path.exists(self.instance.bsdusr_home): mode = os.stat(self.instance.bsdusr_home).st_mode & 0o777 self.fields['bsdusr_mode'].initial = oct(mode) if self.instance.bsdusr_builtin: self.fields['bsdusr_uid'].widget.attrs['readonly'] = True self.fields['bsdusr_uid'].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled ' 'dijitValidationTextBoxDisabled') self.fields['bsdusr_group'].widget.attrs['readonly'] = True self.fields['bsdusr_group'].widget.attrs['class'] = ( 'dijitDisabled dijitSelectDisabled') self.fields['bsdusr_home'].widget.attrs['readonly'] = True self.fields['bsdusr_home'].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled ' 'dijitValidationTextBoxDisabled') self.fields['bsdusr_mode'].widget.attrs['disabled'] = True self.fields['bsdusr_mode'].required = False if self.instance.bsdusr_locked or self.instance.bsdusr_sudo: self.fields['bsdusr_password_disabled'].widget.attrs[ 'disabled'] = True if self.instance.bsdusr_password_disabled is True: self.fields['bsdusr_locked'].widget.attrs['disabled'] = True self.fields['bsdusr_sudo'].widget.attrs['disabled'] = True self.fields['bsdusr_sshpubkey'].initial = ( self.instance.bsdusr_sshpubkey) def clean_bsdusr_username(self): if self.instance.id is None: bsdusr_username = self.cleaned_data["bsdusr_username"] self.pw_checkname(bsdusr_username) try: models.bsdUsers.objects.get(bsdusr_username=bsdusr_username) except models.bsdUsers.DoesNotExist: return bsdusr_username raise forms.ValidationError( _("A user with that username already exists.")) else: return self.instance.bsdusr_username def clean_bsdusr_uid(self): if self.instance.id and self.instance.bsdusr_builtin: return self.instance.bsdusr_uid else: return self.cleaned_data.get("bsdusr_uid") def clean_bsdusr_group(self): if self.instance.id and self.instance.bsdusr_builtin: return self.instance.bsdusr_group else: create = self.cleaned_data.get("bsdusr_creategroup") group = self.cleaned_data.get("bsdusr_group") if not group and not create: raise forms.ValidationError(_("This field is required")) return group def clean_bsdusr_password(self): bsdusr_password = self.cleaned_data.get('bsdusr_password') # See bug #4098 if bsdusr_password and '?' in bsdusr_password: raise forms.ValidationError( _('Passwords containing a question mark (?) are currently not ' 'allowed due to problems with CIFS.')) return bsdusr_password def clean_bsdusr_password2(self): bsdusr_password = self.cleaned_data.get("bsdusr_password", "") bsdusr_password2 = self.cleaned_data["bsdusr_password2"] if bsdusr_password and bsdusr_password != bsdusr_password2: raise forms.ValidationError( _("The two password fields didn't match.")) return bsdusr_password2 def clean_bsdusr_home(self): home = self.cleaned_data['bsdusr_home'] if self.instance.id and self.instance.bsdusr_uid == 0: return self.instance.bsdusr_home elif home is not None: if ':' in home: raise forms.ValidationError( _("Home directory cannot contain colons")) if home == u'/nonexistent': return home if home.startswith(u'/mnt/'): bsdusr_username = self.cleaned_data.get('bsdusr_username', '') saved_home = self.bsdusr_home_saved if home.endswith(bsdusr_username): if home != saved_home: self.bsdusr_home_copy = True return home if not self.instance.id: home = "%s/%s" % (home.rstrip('/'), bsdusr_username) if not self.instance.id and not home.endswith(bsdusr_username): raise forms.ValidationError( _('Home directory must end with username')) if home != saved_home: self.bsdusr_home_copy = True return home raise forms.ValidationError( _('Home directory has to start with /mnt/ or be /nonexistent')) def clean_bsdusr_mode(self): mode = self.cleaned_data.get('bsdusr_mode') if not self.instance.id and not mode: return '755' return mode def clean_bsdusr_sshpubkey(self): ssh = self.cleaned_data.get('bsdusr_sshpubkey', '') ssh = ssh.strip(' ').strip('\n') ssh = re.sub(r'[ ]{2,}', ' ', ssh, re.M) ssh = re.sub(r'\n{2,}', '\n', ssh, re.M) old = ssh while True: ssh = re.sub(r'(\S{10,})\n(\S{10,})', '\\1\\2', ssh, re.M) if ssh == old: break old = ssh return ssh def clean_bsdusr_full_name(self): name = self.cleaned_data["bsdusr_full_name"] self.pw_checkfullname(name) return name def clean_bsdusr_to_group(self): v = self.cleaned_data.get("bsdusr_to_group") if len(v) > 64: raise forms.ValidationError( _("A user cannot belong to more than 64 auxiliary groups")) return v def clean(self): cleaned_data = self.cleaned_data password_disable = cleaned_data["bsdusr_password_disabled"] = ( cleaned_data.get("bsdusr_password_disabled", False)) bsdusr_home = cleaned_data.get('bsdusr_home', '') if (bsdusr_home and cleaned_data.get('bsdusr_sshpubkey') and (not bsdusr_home.startswith(u'/mnt/') and (self.instance.id is None or (self.instance.id and self.instance.bsdusr_uid != 0)))): del cleaned_data['bsdusr_sshpubkey'] self._errors['bsdusr_sshpubkey'] = self.error_class( [_("Home directory is not writable, leave this blank")]) if self.instance.id is None: FIELDS = ['bsdusr_password', 'bsdusr_password2'] if password_disable: for field in FIELDS: if field in cleaned_data and cleaned_data.get(field) != '': self._errors[field] = self.error_class( [_("Password is disabled, leave this blank")]) del cleaned_data[field] else: for field in FIELDS: if field in cleaned_data and cleaned_data.get(field) == '': self._errors[field] = self.error_class( [_("This field is required.")]) del cleaned_data[field] return cleaned_data def save(self, commit=True): _notifier = notifier() if self.instance.id is None: group = self.cleaned_data['bsdusr_group'] if group is None: try: gid = models.bsdGroups.objects.get( bsdgrp_group=self.cleaned_data['bsdusr_username'] ).bsdgrp_gid except: gid = -1 else: gid = group.bsdgrp_gid uid, gid, unixhash, smbhash = _notifier.user_create( username=str(self.cleaned_data['bsdusr_username']), fullname=self.cleaned_data['bsdusr_full_name'].encode( 'utf8', 'ignore').replace(':', ''), password=self.cleaned_data['bsdusr_password'].encode( 'utf8', 'ignore'), uid=self.cleaned_data['bsdusr_uid'], gid=gid, shell=str(self.cleaned_data['bsdusr_shell']), homedir=str(self.cleaned_data['bsdusr_home']), homedir_mode=int(self.cleaned_data.get('bsdusr_mode', '755'), 8), password_disabled=self.cleaned_data.get( 'bsdusr_password_disabled', False), ) bsduser = super(bsdUsersForm, self).save(commit=False) try: grp = models.bsdGroups.objects.get(bsdgrp_gid=gid) except models.bsdGroups.DoesNotExist: grp = models.bsdGroups( bsdgrp_gid=gid, bsdgrp_group=self.cleaned_data['bsdusr_username'], bsdgrp_builtin=False, ) grp.save() bsduser.bsdusr_group = grp bsduser.bsdusr_uid = uid bsduser.bsdusr_shell = self.cleaned_data['bsdusr_shell'] bsduser.bsdusr_unixhash = unixhash bsduser.bsdusr_smbhash = smbhash bsduser.bsdusr_builtin = False bsduser.save() else: bsduser = super(bsdUsersForm, self).save(commit=False) bsduser.bsdusr_group = self.cleaned_data['bsdusr_group'] bsduser.save() # # Check if updating password # bsdusr_password = self.cleaned_data.get("bsdusr_password", "") if self._api is True: bsdusr_password2 = bsdusr_password else: bsdusr_password2 = self.cleaned_data["bsdusr_password2"] if bsdusr_password and (bsdusr_password == bsdusr_password2): unixhash, smbhash = _notifier.user_changepassword( username=bsduser.bsdusr_username.encode('utf8'), password=bsdusr_password.encode('utf8'), ) bsduser.bsdusr_unixhash = unixhash bsduser.bsdusr_smbhash = smbhash bsduser.save() # # Check if updating group membership # models.bsdGroupMembership.objects.filter( bsdgrpmember_user=bsduser).delete() groupid_list = self.cleaned_data['bsdusr_to_group'] for groupid in groupid_list: group = models.bsdGroups.objects.get(id=groupid) m = models.bsdGroupMembership(bsdgrpmember_group=group, bsdgrpmember_user=bsduser) m.save() _notifier.reload("user") if self.bsdusr_home_copy: p = pipeopen( "su - %s -c '/bin/cp -a %s/* %s/'" % (self.cleaned_data['bsdusr_username'], self.bsdusr_home_saved, self.cleaned_data['bsdusr_home'])) p.communicate() bsdusr_sshpubkey = self.cleaned_data.get('bsdusr_sshpubkey') if bsdusr_sshpubkey: _notifier.save_pubkey(bsduser.bsdusr_home, bsdusr_sshpubkey, bsduser.bsdusr_username, bsduser.bsdusr_group.bsdgrp_group) else: _notifier.delete_pubkey(bsduser.bsdusr_home) return bsduser
class JailCreateForm(ModelForm): jail_type = forms.ChoiceField(label=_("type"), ) jail_vanilla = forms.BooleanField(label=_("vanilla"), required=False, initial=True) class Meta: model = Jails exclude = ('jail_id', 'jail_status', 'jail_alias_ipv4', 'jail_alias_bridge_ipv4', 'jail_alias_ipv6', 'jail_alias_bridge_ipv6') #FIXME: translate in dojango widgets = { 'jail_defaultrouter_ipv4': forms.widgets.TextInput(), 'jail_defaultrouter_ipv6': forms.widgets.TextInput(), } def __init__(self, *args, **kwargs): super(JailCreateForm, self).__init__(*args, **kwargs) self.logfile = "/var/tmp/warden.log" self.statusfile = "/var/tmp/status" try: os.unlink(self.logfile) except: pass try: os.unlink(self.statusfile) except: pass arch = platform.architecture() if arch[0] == '64bit': arch = 'x64' else: arch = 'x86' self.arch = arch os.environ['EXTRACT_TARBALL_STATUSFILE'] = self.statusfile types = ((jt.jt_name, jt.jt_name) for jt in JailTemplate.objects.all()) self.fields['jail_type'].choices = types self.fields['jail_type'].widget.attrs['onChange'] = ( "jail_type_toggle();") self.fields['jail_vnet'].widget.attrs['onChange'] = ( "jail_vnet_toggle();") self.fields['jail_nat'].widget.attrs['onChange'] = ( "jail_nat_toggle();") addrs = guess_addresses() if addrs['high_ipv4']: parts = str(addrs['high_ipv4']).split('/') self.fields['jail_ipv4'].initial = parts[0] if len(parts) > 1: self.fields['jail_ipv4_netmask'].initial = parts[1] if addrs['high_ipv6']: parts = str(addrs['high_ipv6']).split('/') self.fields['jail_ipv6'].initial = parts[0] if len(parts) > 1: self.fields['jail_ipv6_prefix'].initial = parts[1] if addrs['bridge_ipv4']: parts = str(addrs['bridge_ipv4']).split('/') self.fields['jail_bridge_ipv4'].initial = parts[0] if len(parts) > 1: self.fields['jail_bridge_ipv4_netmask'].initial = parts[1] if addrs['bridge_ipv6']: parts = str(addrs['bridge_ipv6']).split('/') self.fields['jail_bridge_ipv6'].initial = parts[0] if len(parts) > 1: self.fields['jail_bridge_ipv6_prefix'].initial = parts[1] def save(self): try: jc = JailsConfiguration.objects.order_by("-id")[0] except Exception as e: raise MiddlewareError(e.message) if not jc.jc_path: raise MiddlewareError(_("No jail root configured.")) jc_ipv4_netmask = 24 if jc.jc_ipv4_network: parts = jc.jc_ipv4_network.split('/') if len(parts) > 1: jc_ipv4_netmask = parts[1] jc_ipv6_prefix = 64 if jc.jc_ipv6_network: parts = jc.jc_ipv6_network.split('/') if len(parts) > 1: jc_ipv6_prefix = parts[1] jail_host = self.cleaned_data.get('jail_host') jail_ipv4 = self.cleaned_data.get('jail_ipv4') jail_ipv4_netmask = self.cleaned_data.get('jail_ipv4_netmask', jc_ipv4_netmask) jail_ipv6 = self.cleaned_data.get('jail_ipv6') jail_ipv6_prefix = self.cleaned_data.get('jail_ipv6_prefix', jc_ipv6_prefix) jail_flags = WARDEN_FLAGS_NONE jail_create_args = {} jail_create_args['jail'] = jail_host w = Warden() # if self.cleaned_data['jail_source']: # jail_flags |= WARDEN_CREATE_FLAGS_SRC # if self.cleaned_data['jail_ports']: # jail_flags |= WARDEN_CREATE_FLAGS_PORTS if self.cleaned_data['jail_vanilla']: jail_flags |= WARDEN_CREATE_FLAGS_VANILLA template_create_args = {} jail_type = self.cleaned_data['jail_type'] template = JailTemplate.objects.get(jt_name=jail_type) template_create_args['nick'] = template.jt_name template_create_args['tar'] = template.jt_url template_create_args['flags'] = WARDEN_TEMPLATE_FLAGS_CREATE | \ WARDEN_TEMPLATE_CREATE_FLAGS_NICK | \ WARDEN_TEMPLATE_CREATE_FLAGS_TAR saved_template = template template = None template_list_flags = {} template_list_flags['flags'] = WARDEN_TEMPLATE_FLAGS_LIST templates = w.template(**template_list_flags) for t in templates: if t['nick'] == template_create_args['nick']: template = t break createfile = "/var/tmp/.templatecreate" if not template: try: cf = open(createfile, "a+") cf.close() w.template(**template_create_args) except Exception as e: self.errors['__all__'] = self.error_class([_(e.message)]) if os.path.exists(createfile): os.unlink(createfile) return template_list_flags = {} template_list_flags['flags'] = WARDEN_TEMPLATE_FLAGS_LIST templates = w.template(**template_list_flags) for t in templates: if t['nick'] == template_create_args['nick']: template = t break if not template: self.errors['__all__'] = self.error_class( [_('Unable to find template!')]) return if template['type'] == 'Linux': jail_flags |= WARDEN_CREATE_FLAGS_LINUXJAIL if template['arch'] == 'i386' and self.arch == 'x64': jail_flags |= WARDEN_CREATE_FLAGS_32BIT jail_flags |= WARDEN_CREATE_FLAGS_TEMPLATE jail_create_args['template'] = template_create_args['nick'] if jail_ipv4: jail_flags |= WARDEN_CREATE_FLAGS_IPV4 jail_create_args['ipv4'] = "%s/%s" % (jail_ipv4, jail_ipv4_netmask) if jail_ipv6: jail_flags |= WARDEN_CREATE_FLAGS_IPV6 jail_create_args['ipv6'] = "%s/%s" % (jail_ipv6, jail_ipv6_prefix) jail_flags |= WARDEN_CREATE_FLAGS_LOGFILE jail_flags |= WARDEN_CREATE_FLAGS_SYSLOG jail_create_args['logfile'] = self.logfile jail_create_args['flags'] = jail_flags createfile = "/var/tmp/.jailcreate" try: cf = open(createfile, "a+") cf.close() w.create(**jail_create_args) except Exception as e: self.errors['__all__'] = self.error_class([_(e.message)]) if os.path.exists(createfile): os.unlink(createfile) return if os.path.exists(createfile): os.unlink(createfile) for key in ('jail_bridge_ipv4', 'jail_bridge_ipv6', 'jail_defaultrouter_ipv4', 'jail_defaultrouter_ipv6', 'jail_mac', 'jail_flags'): jail_set_args = {} jail_set_args['jail'] = jail_host jail_flags = WARDEN_FLAGS_NONE val = self.cleaned_data.get(key, None) if val: if key == 'jail_bridge_ipv4': mask = self.cleaned_data.get('jail_bridge_ipv4_netmask', jc_ipv4_netmask) jail_flags |= WARDEN_SET_FLAGS_BRIDGE_IPV4 jail_set_args['bridge-ipv4'] = "%s/%s" % (val, mask) elif key == 'jail_bridge_ipv6': prefix = self.cleaned_data.get('jail_bridge_ipv6_prefix', jc_ipv6_prefix) jail_flags |= WARDEN_SET_FLAGS_BRIDGE_IPV6 jail_set_args['bridge-ipv6'] = "%s/%s" % (val, prefix) elif key == 'jail_defaultrouter_ipv4': jail_flags |= WARDEN_SET_FLAGS_DEFAULTROUTER_IPV4 jail_set_args['defaultrouter-ipv4'] = val elif key == 'jail_defaultrouter_ipv6': jail_flags |= WARDEN_SET_FLAGS_DEFAULTROUTER_IPV6 jail_set_args['defaultrouter-ipv6'] = val elif key == 'jail_mac': jail_flags |= WARDEN_SET_FLAGS_MAC jail_set_args['mac'] = val elif key == 'jail_flags': jail_flags |= WARDEN_SET_FLAGS_FLAGS jail_set_args['jflags'] = val jail_set_args['flags'] = jail_flags try: w.set(**jail_set_args) except Exception as e: self.errors['__all__'] = self.error_class([_(e.message)]) return jail_nat = self.cleaned_data.get('jail_nat', None) jail_vnet = self.cleaned_data.get('jail_vnet', None) jail_set_args = {} jail_set_args['jail'] = jail_host jail_flags = WARDEN_FLAGS_NONE if jail_nat: jail_flags |= WARDEN_SET_FLAGS_NAT_ENABLE else: jail_flags |= WARDEN_SET_FLAGS_NAT_DISABLE jail_set_args['flags'] = jail_flags try: w.set(**jail_set_args) except Exception as e: self.errors['__all__'] = self.error_class([_(e.message)]) return jail_set_args = {} jail_set_args['jail'] = jail_host jail_flags = WARDEN_FLAGS_NONE if jail_vnet: # XXXX if NOT LINUX XXXX (revisit this) if (saved_template.jt_arch != 'x86' and saved_template.jt_os != 'Linux'): jail_flags |= WARDEN_SET_FLAGS_VNET_ENABLE else: jail_flags |= WARDEN_SET_FLAGS_VNET_DISABLE jail_set_args['flags'] = jail_flags try: w.set(**jail_set_args) except Exception as e: self.errors['__all__'] = self.error_class([_(e.message)]) return if self.cleaned_data['jail_autostart']: try: w.auto(jail=jail_host) except Exception as e: self.errors['__all__'] = self.error_class([_(e.message)]) return try: w.start(jail=jail_host) except Exception as e: self.errors['__all__'] = self.error_class([_(e.message)]) return
class NullMountPointForm(ModelForm): create = forms.BooleanField( label=('Create directory'), required=False, initial=True, help_text=_('Create destination directory if it does not exist'), ) mounted = forms.BooleanField( label=_("Mounted?"), required=False, initial=True, ) # Do not remove: used in javascript side mpjc_path = forms.CharField(required=False) class Meta: fields = '__all__' model = NullMountPoint widgets = { 'source': forms.widgets.TextInput( attrs={ 'data-dojo-type': 'freeadmin.form.PathSelector', }), 'destination': forms.widgets.TextInput( attrs={ 'data-dojo-type': 'freeadmin.form.PathSelector', }), } def clean_source(self): src = self.cleaned_data.get("source") src = os.path.abspath(src.strip().replace("..", "")) return src def clean_destination(self): dest = self.cleaned_data.get("destination") dest = os.path.abspath(dest.strip().replace("..", "")) if not self.jail: jail = self.cleaned_data.get("jail") if jail: self.jail = Jails.objects.get(jail_host=jail) if not self.jail: raise forms.ValidationError( _("This shouldn't happen, but the jail could not be found")) full = "%s/%s%s" % (self.jc.jc_path, self.jail.jail_host, dest) if len(full) > 88: raise forms.ValidationError( _("The full path cannot exceed 88 characters")) create = self.cleaned_data.get('create') if not os.path.exists(full) and create: os.makedirs(full) return dest def __init__(self, *args, **kwargs): self.jail = None if kwargs and 'jail' in kwargs: self.jail = kwargs.pop('jail') super(NullMountPointForm, self).__init__(*args, **kwargs) if kwargs and 'instance' in kwargs: self.instance = kwargs.pop('instance') if not self.jail: self.jail = Jails.objects.filter( jail_host=self.instance.jail)[0] self.jc = JailsConfiguration.objects.order_by("-id")[0] self.fields['jail'] = forms.ChoiceField( label=_("Jail"), choices=(), widget=forms.Select(attrs={'class': 'required'}), ) if self.jail: self.fields['jail'].initial = self.jail.jail_host self.fields['jail'].widget.attrs['readonly'] = True try: clean_path_execbit(self.jc.jc_path) except forms.ValidationError, e: self.errors['__all__'] = self.error_class(e.messages) pjlist = [] try: wlist = Warden().list() except: wlist = [] for wj in wlist: pjlist.append(wj[WARDEN_KEY_HOST]) self.fields['jail'].choices = [(pj, pj) for pj in pjlist] self.fields['jail'].widget.attrs['onChange'] = ( 'addStorageJailChange(this);') jail_path = "%s/%s" % (self.jc.jc_path, self.jail.jail_host) self.fields['destination'].widget.attrs['root'] = jail_path self.fields['mpjc_path'].widget = forms.widgets.HiddenInput() self.fields['mpjc_path'].initial = self.jc.jc_path if self.instance.id: self.fields['mounted'].initial = self.instance.mounted else: self.fields['mounted'].widget = forms.widgets.HiddenInput()
class JailsEditForm(ModelForm): jail_autostart = forms.BooleanField(label=_("autostart"), required=False) jail_vnet = forms.BooleanField(label=_("VIMAGE"), required=False) jail_nat = forms.BooleanField(label=_("NAT"), required=False) class Meta: model = Jails exclude = ( 'jail_status', 'jail_type', ) #FIXME: translate in dojango widgets = { 'jail_defaultrouter_ipv4': forms.widgets.TextInput(), 'jail_defaultrouter_ipv6': forms.widgets.TextInput(), } def __set_ro(self, instance, key): self.fields[key].widget.attrs['readonly'] = True self.fields[key].widget.attrs['class'] = ( 'dijitDisabled dijitTextBoxDisabled dijitValidationTextBoxDisabled' ) def __instance_save(self, instance, keys): for key in keys: okey = "__original_%s" % key instance.__dict__[okey] = instance.__dict__[key] def __instance_diff(self, instance, keys): res = False for key in keys: okey = "__original_%s" % key if instance.__dict__[okey] != self.cleaned_data.get(key): if (not instance.__dict__[okey] and not self.cleaned_data.get(key)): continue res = True break return res def __instance_changed_fields(self, instance, keys): changed_keys = [] for key in keys: okey = "__original_%s" % key if instance.__dict__[okey] != self.cleaned_data.get(key): if (not instance.__dict__[okey] and not self.cleaned_data.get(key)): continue changed_keys.append(key) return changed_keys def __init__(self, *args, **kwargs): super(JailsEditForm, self).__init__(*args, **kwargs) self.__myfields = [ 'jail_autostart', 'jail_ipv4', 'jail_ipv4_netmask', 'jail_alias_ipv4', 'jail_bridge_ipv4', 'jail_bridge_ipv4_netmask', 'jail_alias_bridge_ipv4', 'jail_defaultrouter_ipv4', 'jail_ipv6', 'jail_ipv6_prefix', 'jail_alias_ipv6', 'jail_bridge_ipv6', 'jail_bridge_ipv6_prefix', 'jail_alias_bridge_ipv6', 'jail_defaultrouter_ipv6', 'jail_mac', 'jail_vnet', 'jail_nat', 'jail_flags', ] if self._api and self.instance and self.instance.id: self.instance = Jails.objects.get(id=self.instance.id) instance = getattr(self, 'instance', None) self.__instance_save(instance, self.__myfields) self.fields['jail_vnet'].widget.attrs['onChange'] = ( "jail_vnet_toggle();") self.fields['jail_nat'].widget.attrs['onChange'] = ( "jail_nat_toggle();") self.__set_ro(instance, 'jail_host') def save(self): jail_host = self.cleaned_data.get('jail_host') instance = getattr(self, 'instance', None) if self.__instance_diff(instance, self.__myfields): self.__instance_changed_fields(instance, self.__myfields) changed_fields = self.__instance_changed_fields( instance, self.__myfields) try: jc = JailsConfiguration.objects.order_by("-id")[0] except Exception as e: raise MiddlewareError(e.message) if not jc.jc_path: raise MiddlewareError(_("No jail root configured.")) jc_ipv4_netmask = 24 if jc.jc_ipv4_network: parts = jc.jc_ipv4_network.split('/') if len(parts) > 1: jc_ipv4_netmask = parts[1] jc_ipv6_prefix = 64 if jc.jc_ipv6_network: parts = jc.jc_ipv6_network.split('/') if len(parts) > 1: jc_ipv6_prefix = parts[1] for cf in changed_fields: if cf == 'jail_autostart': Warden().auto(jail=jail_host) else: args = {} flags = WARDEN_FLAGS_NONE if cf == 'jail_ipv4' or cf == 'jail_ipv4_netmask': ipv4 = self.cleaned_data.get('jail_ipv4') mask = self.cleaned_data.get('jail_ipv4_netmask', jc_ipv4_netmask) jail_ipv4 = "%s/%s" % (ipv4, mask) flags |= WARDEN_SET_FLAGS_IPV4 args['ipv4'] = jail_ipv4 elif cf == 'jail_ipv6' or cf == 'jail_ipv6_prefix': ipv6 = self.cleaned_data.get('jail_ipv6') prefix = self.cleaned_data.get('jail_ipv6_prefix', jc_ipv6_prefix) jail_ipv6 = "%s/%s" % (ipv6, prefix) flags |= WARDEN_SET_FLAGS_IPV6 args['ipv6'] = jail_ipv6 elif cf == 'jail_alias_ipv4': flags |= WARDEN_SET_FLAGS_ALIAS_IPV4 args['alias-ipv4'] = self.cleaned_data.get(cf) elif cf == 'jail_alias_ipv6': flags |= WARDEN_SET_FLAGS_ALIAS_IPV6 args['alias-ipv6'] = self.cleaned_data.get(cf) elif cf == 'jail_bridge_ipv4' or cf == 'jail_bridge_ipv4_netmask': bridge_ipv4 = self.cleaned_data.get('jail_bridge_ipv4') mask = self.cleaned_data.get('jail_bridge_ipv4_netmask', jc_ipv4_netmask) jail_bridge_ipv4 = "%s/%s" % (bridge_ipv4, mask) flags |= WARDEN_SET_FLAGS_BRIDGE_IPV4 args['bridge-ipv4'] = jail_bridge_ipv4 elif cf == 'jail_bridge_ipv6' or cf == 'jail_bridge_ipv6_prefix': bridge_ipv6 = self.cleaned_data.get('jail_bridge_ipv6') prefix = self.cleaned_data.get('jail_bridge_ipv6_prefix', jc_ipv6_prefix) jail_bridge_ipv6 = "%s/%s" % (bridge_ipv6, prefix) flags |= WARDEN_SET_FLAGS_BRIDGE_IPV6 args['bridge-ipv6'] = jail_bridge_ipv6 elif cf == 'jail_alias_bridge_ipv4': flags |= WARDEN_SET_FLAGS_ALIAS_BRIDGE_IPV4 args['alias-bridge-ipv4'] = self.cleaned_data.get(cf) elif cf == 'jail_alias_bridge_ipv6': flags |= WARDEN_SET_FLAGS_ALIAS_BRIDGE_IPV6 args['alias-bridge-ipv6'] = self.cleaned_data.get(cf) elif cf == 'jail_defaultrouter_ipv4': flags |= WARDEN_SET_FLAGS_DEFAULTROUTER_IPV4 args['defaultrouter-ipv4'] = self.cleaned_data.get(cf) elif cf == 'jail_defaultrouter_ipv6': flags |= WARDEN_SET_FLAGS_DEFAULTROUTER_IPV6 args['defaultrouter-ipv6'] = self.cleaned_data.get(cf) elif cf == 'jail_mac': flags |= WARDEN_SET_FLAGS_MAC args['mac'] = self.cleaned_data.get(cf) elif cf == 'jail_vnet': if (self.cleaned_data.get(cf)): flags |= WARDEN_SET_FLAGS_VNET_ENABLE args['vnet-enable'] = self.cleaned_data.get(cf) else: flags |= WARDEN_SET_FLAGS_VNET_DISABLE args['vnet-disable'] = self.cleaned_data.get(cf) elif cf == 'jail_nat': if self.cleaned_data.get(cf): flags |= WARDEN_SET_FLAGS_NAT_ENABLE args['nat-enable'] = self.cleaned_data.get(cf) else: flags |= WARDEN_SET_FLAGS_NAT_DISABLE args['nat-disable'] = self.cleaned_data.get(cf) elif cf == 'jail_flags': flags |= WARDEN_SET_FLAGS_FLAGS args['jflags'] = self.cleaned_data.get(cf) args['jail'] = jail_host args['flags'] = flags Warden().set(**args)
class IPMIForm(Form): # Max password length via IPMI v2.0 is 20 chars. We only support IPMI # v2.0+ compliant boards thus far. ipmi_password1 = forms.CharField(label=_("Password"), max_length=20, widget=forms.PasswordInput, required=False) ipmi_password2 = forms.CharField( label=_("Password confirmation"), max_length=20, widget=forms.PasswordInput, help_text=_("Enter the same password as above, for verification."), required=False) dhcp = forms.BooleanField( label=_("DHCP"), required=False, ) ipv4address = IP4AddressFormField( initial='', required=False, label=_("IPv4 Address"), ) ipv4netmaskbit = forms.ChoiceField( choices=choices.v4NetmaskBitList, required=False, label=_("IPv4 Netmask"), ) ipv4gw = IP4AddressFormField( initial='', required=False, label=_("IPv4 Default Gateway"), ) vlanid = forms.IntegerField( label=_("VLAN ID"), required=False, widget=forms.widgets.TextInput(), ) def __init__(self, *args, **kwargs): super(IPMIForm, self).__init__(*args, **kwargs) self.fields['dhcp'].widget.attrs['onChange'] = ( 'javascript:toggleGeneric(' '"id_dhcp", ["id_ipv4address", "id_ipv4netmaskbit"]);') channels = [] _n = notifier() for i in range(1, 17): try: data = _n.ipmi_get_lan(channel=i) except: continue if not data: continue channels.append((i, i)) self.fields['channel'] = forms.ChoiceField( choices=channels, label=_('Channel'), ) self.fields.keyOrder.remove('channel') self.fields.keyOrder.insert(0, 'channel') def clean_ipmi_password2(self): ipmi_password1 = self.cleaned_data.get("ipmi_password1", "") ipmi_password2 = self.cleaned_data["ipmi_password2"] if ipmi_password1 != ipmi_password2: raise forms.ValidationError( _("The two password fields didn't match.")) return ipmi_password2 def clean_ipv4netmaskbit(self): try: cidr = int(self.cleaned_data.get("ipv4netmaskbit")) except ValueError: return None bits = 0xffffffff ^ (1 << 32 - cidr) - 1 return socket.inet_ntoa(pack('>I', bits)) def clean_ipv4address(self): ipv4 = self.cleaned_data.get('ipv4address') if ipv4: ipv4 = str(ipv4) return ipv4 def clean_ipv4gw(self): ipv4 = self.cleaned_data.get('ipv4gw') if ipv4: ipv4 = str(ipv4) return ipv4
class DeviceForm(ModelForm): CDROM_path = PathField( label=_('CD-ROM (ISO)'), required=False, dirsonly=False, ) DISK_zvol = forms.ChoiceField( label=_('ZVol'), required=False, ) DISK_mode = forms.ChoiceField( label=_('Mode'), choices=choices.VM_DISKMODETYPES, required=False, initial='AHCI', ) DISK_raw = PathField( label=_('Raw File'), required=False, dirsonly=False, ) DISK_sectorsize = forms.IntegerField( label=_('Disk sectorsize'), required=False, initial=0, help_text=_("Logical and physical sector size in bytes of the emulated disk." "If 0, a sector size is not set."), ) NIC_type = forms.ChoiceField( label=_('Adapter Type'), choices=choices.VM_NICTYPES, required=False, initial='E1000', ) NIC_attach = forms.ChoiceField( label=_('Nic to attach'), choices=choices.NICChoices(exclude_configured=False), required=False, ) NIC_mac = forms.CharField( label=_('Mac Address'), required=False, help_text=_("You can specify the adapter MAC Address or let it be auto generated."), validators=[RegexValidator("^([0-9a-fA-F]{2}([::]?|$)){6}$", "Invalid MAC format.")], initial='00:a0:98:FF:FF:FF', ) VNC_resolution = forms.ChoiceField( label=_('Resolution'), choices=choices.VNC_RESOLUTION, required=False, initial='1024x768', ) VNC_port = forms.CharField( label=_('VNC port'), required=False, help_text=_("You can specify the VNC port or 0 for auto."), validators=[RegexValidator("^[0-9]*$", "Only integer is accepted")], initial=0, ) VNC_bind = forms.ChoiceField( label=_('Bind to'), choices=(), required=False, initial='0.0.0.0' ) VNC_wait = forms.BooleanField( label=_('Wait to boot'), required=False, ) class Meta: fields = '__all__' model = models.Device def __init__(self, *args, **kwargs): super(DeviceForm, self).__init__(*args, **kwargs) self.fields['dtype'].widget.attrs['onChange'] = ( "deviceTypeToggle();" ) self.fields['VNC_bind'].choices = self.ipv4_list() diskchoices = {} _n = notifier() used_zvol = [] for volume in Volume.objects.filter(): zvols = _n.list_zfs_vols(volume.vol_name, sort='name') for zvol, attrs in zvols.items(): if "zvol/" + zvol not in used_zvol: diskchoices["zvol/" + zvol] = "%s (%s)" % ( zvol, humanize_size(attrs['volsize'])) self.fields['DISK_zvol'].choices = diskchoices.items() if self.instance.id: if self.instance.dtype == 'CDROM': self.fields['CDROM_path'].initial = self.instance.attributes.get('path', '') elif self.instance.dtype == 'DISK': self.fields['DISK_zvol'].initial = self.instance.attributes.get('path', '').replace('/dev/', '') self.fields['DISK_mode'].initial = self.instance.attributes.get('type') self.fields['DISK_sectorsize'].initial = self.instance.attributes.get('sectorsize', 0) elif self.instance.dtype == "RAW": self.fields['DISK_raw'].initial = self.instance.attributes.get('path', '') self.fields['DISK_mode'].initial = self.instance.attributes.get('type') self.fields['DISK_sectorsize'].initial = self.instance.attributes.get('sectorsize', 0) elif self.instance.dtype == 'NIC': self.fields['NIC_type'].initial = self.instance.attributes.get('type') self.fields['NIC_mac'].initial = self.instance.attributes.get('mac') self.fields['NIC_attach'].initial = self.instance.attributes.get('nic_attach') elif self.instance.dtype == 'VNC': vnc_port = self.instance.attributes.get('vnc_port') vnc_port = 0 if vnc_port is None else vnc_port self.fields['VNC_wait'].initial = self.instance.attributes.get('wait') self.fields['VNC_port'].initial = vnc_port self.fields['VNC_resolution'].initial = self.instance.attributes.get('vnc_resolution') self.fields['VNC_bind'].initial = self.instance.attributes.get('vnc_bind') def ipv4_list(self): choices = (('0.0.0.0', '0.0.0.0'),) with client as c: ipv4_addresses = c.call('interfaces.ipv4_in_use') for ipv4_addr in ipv4_addresses: choices = choices + ((ipv4_addr, ipv4_addr),) return choices def clean(self): vm = self.cleaned_data.get('vm') vnc_port = self.cleaned_data.get('VNC_port') new_vnc_port = 5900 if vm and vnc_port == '0': new_vnc_port = new_vnc_port + int(vm.id) self.cleaned_data['VNC_port'] = str(new_vnc_port) return self.cleaned_data def save(self, *args, **kwargs): vm = self.cleaned_data.get('vm') kwargs['commit'] = False obj = super(DeviceForm, self).save(*args, **kwargs) if self.cleaned_data['dtype'] == 'DISK': obj.attributes = { 'path': '/dev/' + self.cleaned_data['DISK_zvol'], 'type': self.cleaned_data['DISK_mode'], 'sectorsize': self.cleaned_data['DISK_sectorsize'], } elif self.cleaned_data['dtype'] == 'RAW': obj.attributes = { 'path': self.cleaned_data['DISK_raw'], 'type': self.cleaned_data['DISK_mode'], 'sectorsize': self.cleaned_data['DISK_sectorsize'], } elif self.cleaned_data['dtype'] == 'CDROM': cdrom_path = self.cleaned_data['CDROM_path'] if cdrom_path: obj.attributes = { 'path': cdrom_path, } else: self._errors['CDROM_path'] = self.error_class([_('Please choose an ISO file.')]) elif self.cleaned_data['dtype'] == 'NIC': obj.attributes = { 'type': self.cleaned_data['NIC_type'], 'mac': self.cleaned_data['NIC_mac'], 'nic_attach': self.cleaned_data['NIC_attach'], } elif self.cleaned_data['dtype'] == 'VNC': if vm.bootloader == 'UEFI': obj.attributes = { 'wait': self.cleaned_data['VNC_wait'], 'vnc_port': self.cleaned_data['VNC_port'], 'vnc_resolution': self.cleaned_data['VNC_resolution'], 'vnc_bind': self.cleaned_data['VNC_bind'], } else: self._errors['dtype'] = self.error_class([_('VNC is only allowed for UEFI')]) self.cleaned_data.pop('VNC_port', None) self.cleaned_data.pop('VNC_wait', None) self.cleaned_data.pop('VNC_resolution', None) self.cleaned_data.pop('VNC_bind', None) return obj obj.save() return obj
class RsyncForm(ModelForm): rsync_validate_rpath = forms.BooleanField( initial=True, label=_("Validate Remote Path"), required=False, help_text=_("This ensures Remote Path Validation." " Uncheck this if the remote machine" " is currently offline or beyond network reach." " And/Or you do not want validation to be done."), ) class Meta: fields = [ 'rsync_path', 'rsync_user', 'rsync_remotehost', 'rsync_remoteport', 'rsync_mode', 'rsync_remotemodule', 'rsync_remotepath', 'rsync_validate_rpath', 'rsync_direction', 'rsync_desc', 'rsync_minute', 'rsync_hour', 'rsync_daymonth', 'rsync_month', 'rsync_dayweek', 'rsync_recursive', 'rsync_times', 'rsync_compress', 'rsync_archive', 'rsync_delete', 'rsync_quiet', 'rsync_preserveperm', 'rsync_preserveattr', 'rsync_delayupdates', 'rsync_extra', 'rsync_enabled' ] model = models.Rsync widgets = { 'rsync_minute': CronMultiple(attrs={ 'numChoices': 60, 'label': _("minute") }), 'rsync_hour': CronMultiple(attrs={ 'numChoices': 24, 'label': _("hour") }), 'rsync_daymonth': CronMultiple(attrs={ 'numChoices': 31, 'start': 1, 'label': _("day of month"), }), 'rsync_dayweek': forms.CheckboxSelectMultiple(choices=choices.WEEKDAYS_CHOICES), 'rsync_month': forms.CheckboxSelectMultiple(choices=choices.MONTHS_CHOICES), } def __init__(self, *args, **kwargs): super(RsyncForm, self).__init__(*args, **kwargs) mchoicefield(self, 'rsync_month', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) mchoicefield(self, 'rsync_dayweek', [1, 2, 3, 4, 5, 6, 7]) self.fields['rsync_mode'].widget.attrs['onChange'] = ( "rsyncModeToggle();") def check_rpath_exists(self): """A function to check if the rsync_remotepath, exists or not. Returns TRUE rpath is a directory and exists, else FALSE""" ruser = self.cleaned_data.get("rsync_user").encode('utf8') rhost = str(self.cleaned_data.get("rsync_remotehost")) if '@' in rhost: remote = rhost else: remote = '"%s"@%s' % ( ruser, rhost, ) rport = str(self.cleaned_data.get("rsync_remoteport")) rpath = self.cleaned_data.get("rsync_remotepath").encode('utf8') proc = subprocess.Popen( """su -m "%s" -c 'ssh -p %s -o "BatchMode yes" -o """ """"ConnectTimeout=5" %s test -d \\""%s"\\"' """ % (ruser, rport, remote, rpath), shell=True) proc.wait() return proc.returncode == 0 def clean_rsync_user(self): user = self.cleaned_data.get("rsync_user") # Windows users can have spaces in their usernames # http://www.freebsd.org/cgi/query-pr.cgi?pr=164808 if ' ' in user: raise forms.ValidationError(_("Usernames cannot have spaces")) return user def clean_rsync_remotemodule(self): mode = self.cleaned_data.get("rsync_mode") val = self.cleaned_data.get("rsync_remotemodule") if mode == 'module' and not val: raise forms.ValidationError(_("This field is required")) return val def clean_rsync_remotepath(self): mode = self.cleaned_data.get("rsync_mode") val = self.cleaned_data.get("rsync_remotepath") if mode == 'ssh' and not val: raise forms.ValidationError(_("This field is required")) return val def clean_rsync_month(self): m = self.data.getlist("rsync_month") if len(m) == 12: return '*' m = ",".join(m) return m def clean_rsync_dayweek(self): w = self.data.getlist("rsync_dayweek") if len(w) == 7: return '*' w = ",".join(w) return w def clean_rsync_extra(self): extra = self.cleaned_data.get("rsync_extra") if extra: extra = extra.replace('\n', ' ') return extra def clean(self): cdata = self.cleaned_data mode = cdata.get("rsync_mode") user = cdata.get("rsync_user") if mode == 'ssh': try: home = pwd.getpwnam(user).pw_dir search = os.path.join(home, ".ssh", "id_[edr]*.*") if not glob.glob(search): raise ValueError except (KeyError, ValueError, AttributeError, TypeError): self._errors['rsync_user'] = self.error_class([ _("In order to use rsync over SSH you need a user<br />" "with a public key (DSA/ECDSA/RSA) set up in home dir."), ]) cdata.pop('rsync_user', None) if 'rsync_user' in cdata and not ( self.cleaned_data.get("rsync_mode") == 'module' or not self.cleaned_data.get("rsync_validate_rpath") or self.check_rpath_exists()): self._errors["rsync_remotepath"] = self.error_class([ _("The Remote Path you specified does not exist or is not a " "directory.<br>Either create one yourself on the remote " "machine or uncheck the<br>'rsync_validate_rpath' field." "<br>**Note**: This could also happen if the remote path " "entered<br> exceeded 255 characters and was truncated, please" " restrict it to<br>255. Or it could also be that your SSH " "credentials (remote host,etc) are wrong.") ]) return cdata def save(self): super(RsyncForm, self).save() notifier().restart("cron")