class DnsRecordForm(SerializerForm): """ Create, update or delete network DNS record. """ _ip = None _api_call = dns_record template = 'gui/dc/domain_record_form.html' id = forms.IntegerField(label=_('ID'), required=True, widget=forms.HiddenInput()) name = forms.CharField( label=_('Name'), required=True, help_text=_('The full URI the DNS server should pick up on.'), widget=forms.TextInput(attrs=TEXT_INPUT_ATTRS)) content = forms.CharField( label=_('Content'), required=False, # help_text=_('The answer of the DNS query.'), widget=forms.TextInput(attrs={'class': 'input-transparent narrow'})) type = forms.ChoiceField(label=_('Type'), required=True, choices=Record.TYPE_USED, widget=forms.Select(attrs=SELECT_ATTRS)) ttl = forms.IntegerField( label=_('TTL'), required=False, help_text=_( 'How long the DNS client is allowed to remember this record.'), widget=NumberInput(attrs={'class': 'input-transparent narrow'})) prio = forms.IntegerField( label=_('Priority'), required=False, # help_text=_('Priority used by some record types.'), widget=NumberInput(attrs={'class': 'input-transparent narrow'})) disabled = forms.BooleanField( label=_('Disabled?'), required=False, help_text=_('If set to true, this record is hidden from DNS clients.'), widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) def __init__(self, request, domain, record, *args, **kwargs): self.domain = domain super(DnsRecordForm, self).__init__(request, record, *args, **kwargs) def _initial_data(self, request, obj): return obj.web_data def api_call_args(self, domain_name): if self.action == 'create': return domain_name, else: return domain_name, self.cleaned_data['id']
class BackupDefineForm(SerializerForm, HostnameForm): """ Create or update backup definition. """ _api_call = vm_define_backup type = forms.TypedChoiceField(label=_('Backup type'), required=True, choices=BackupDefine.TYPE, coerce=int, widget=forms.Select(attrs={'class': 'narrow input-select2 disable_create2', 'required': 'required'})) node = forms.ChoiceField(label=_('Backup Node'), required=True, widget=forms.Select(attrs={'class': 'narrow input-select2', 'required': 'required'})) zpool = forms.ChoiceField(label=_('Storage'), required=True, widget=forms.Select(attrs={'class': 'narrow input-select2', 'required': 'required'})) compression = forms.TypedChoiceField(label=_('Compression'), choices=BackupDefine.COMPRESSION, required=True, coerce=int, widget=forms.Select(attrs={'class': 'narrow input-select2', 'required': 'required'})) bwlimit = forms.IntegerField(label=_('Bandwidth limit'), required=False, help_text=_('Optional transfer rate limit in bytes.'), widget=NumberInput(attrs={'class': 'input-transparent narrow'})) def __init__(self, request, vm, *args, **kwargs): super(BackupDefineForm, self).__init__(request, vm, *args, **kwargs) self.fields['retention'].help_text = _('Maximum number of backups to keep.') self.fields['node'].choices = get_nodes(request, is_backup=True).values_list('hostname', 'hostname') self.fields['zpool'].choices = get_zpools(request).filter(node__is_backup=True)\ .values_list('zpool', 'storage__alias').distinct()
class ServerReplicaForm(HostnameForm, SerializerForm): """ Server replication settings admin form. """ _api_call = vm_replica repname = forms.CharField( label=_('Replica Name'), required=False, widget=forms.TextInput( attrs={ 'class': 'input-transparent narrow disable_created', 'required': 'required' })) node = forms.TypedChoiceField( label=_('Target Node'), required=True, coerce=str, empty_value=None, widget=forms.Select( attrs={'class': 'input-select2 narrow disable_created2'})) sleep_time = forms.IntegerField( label=_('Sleep Time'), max_value=86400, min_value=0, required=True, help_text=_('Amount of time to pause between two syncs.'), widget=NumberInput(attrs={ 'class': 'input-transparent narrow', 'required': 'required' })) enabled = forms.BooleanField( label=_('Enabled?'), required=False, widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) reserve_resources = forms.BooleanField( label=_('Reserve Resources?'), required=False, help_text=_( 'Whether to reserve resources (vCPU, RAM) on target compute node' '. NOTE: When disabled, the resources will be reserved (and must' ' be available) before the failover action.'), widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) def __init__(self, request, vm, slave_vm, *args, **kwargs): self.slave_vm = slave_vm vm_nodes = kwargs.pop('vm_nodes', None) super(ServerReplicaForm, self).__init__(request, vm, *args, **kwargs) if not vm_nodes: vm_nodes = get_nodes(request, is_compute=True) self.fields['node'].choices = [(i.hostname, i.hostname) for i in vm_nodes] def _initial_data(self, request, obj): """Initial data used by 'update'""" return self.slave_vm.web_data
class SnapshotDefineForm(SerializerForm, HostnameForm): """ Create or update snapshot definition. """ _api_call = vm_define_snapshot name = forms.RegexField(label=_('Name'), regex=r'^[A-Za-z0-9][A-Za-z0-9\._-]*$', required=True, max_length=8, min_length=1, widget=forms.TextInput(attrs={'class': 'input-transparent narrow', 'required': 'required', 'pattern': '[A-Za-z0-9\._-]+'})) disk_id = forms.TypedChoiceField(label=_('Disk ID'), required=True, coerce=int, widget=forms.Select(attrs={'class': 'input-select2 narrow', 'required': 'required'})) schedule = forms.CharField(label=_('Schedule'), required=True, max_length=100, help_text=_('Schedule in CRON format. Please use your local time for the hour field ' '(will be internally converted into UTC).'), widget=forms.TextInput(attrs={'class': 'input-transparent narrow', 'required': 'required'})) retention = forms.IntegerField(label=_('Retention'), max_value=65536, min_value=0, required=True, help_text=_('Maximum number of snapshots to keep.'), widget=NumberInput(attrs={'class': 'input-transparent narrow', 'required': 'required'})) active = forms.BooleanField(label=_('Active?'), required=False, widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) desc = forms.RegexField(label=_('Description'), regex=r'^[^<>%\$&;\'"]*$', max_length=128, required=False, widget=forms.TextInput(attrs={'class': 'input-transparent wide', 'required': ''})) fsfreeze = forms.BooleanField(label=_('Freeze filesystem?'), required=False, help_text=_('Create application-consistent snapshot; ' 'Requires QEMU Guest Agent.'), widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) def __init__(self, request, vm, *args, **kwargs): super(SnapshotDefineForm, self).__init__(request, vm, *args, **kwargs) self.fields['disk_id'].choices = vm_disk_id_choices(vm) def clean_schedule(self): """Time in schedule in templates is timezone aware. Change to UTC.""" data = self.cleaned_data.get('schedule') try: schedule = data.split() hour = schedule[1] if '*' in hour: raise IndexError except IndexError: return data tz = timezone.get_current_timezone() now_local = datetime.utcnow().replace(tzinfo=pytz.utc).astimezone(tz) def to_utc(match): num = int(match.group(0)) now = now_local.replace(hour=num) return str(pytz.utc.normalize(now).hour) try: schedule[1] = re.sub(r'(\d+)', to_utc, hour) except ValueError: return data return ' '.join(schedule) def _initial_data(self, request, vm): snapname = request.POST.get('name') disk_id = request.POST.get('disk_id') res = self.api_call('get', vm, request, args=(vm.hostname, snapname), data={'disk_id': disk_id}) return res.data['result'] def _final_data(self, data=None): # noinspection PyProtectedMember fd = super(SnapshotDefineForm, self)._final_data(data=data) # Always include disk_id (required parameter in api call) fd['disk_id'] = self.cleaned_data['disk_id'] return fd
class AdminServerSettingsForm(ServerSettingsForm): """ Copy of vm_define serializer (api). """ admin = True _api_call = vm_define tags = TagField(label=_('Tags'), required=False, widget=TagWidget(attrs={'class': 'tags-select2 narrow'}), help_text=_('The tag will be created in case it does not exist.')) node = forms.TypedChoiceField(label=_('Node'), required=False, coerce=str, empty_value=None, widget=forms.Select(attrs={'class': 'narrow input-select2'})) template = forms.TypedChoiceField(label=_('Template'), required=False, coerce=str, empty_value=None, help_text=_('Setting template can modify lots of server attributes, ' 'e.g. disks, nics.'), widget=DataSelect(attrs={'class': 'narrow input-select2'})) ostype = forms.TypedChoiceField(label=_('OS Type'), choices=Vm.OSTYPE, required=True, coerce=int, widget=forms.Select(attrs={'class': 'input-select2 narrow', 'required': 'required'})) vcpus = forms.IntegerField(label=_('VCPUs'), max_value=64, min_value=1, required=True, widget=NumberInput(attrs={'class': 'input-transparent narrow', 'required': 'required'})) # noinspection SpellCheckingInspection ram = forms.IntegerField(label=_('RAM'), max_value=524288, min_value=32, required=True, widget=forms.TextInput(attrs={'class': 'input-transparent narrow input-mbytes', 'required': 'required', 'pattern': '[0-9\.]+[BKMGTPEbkmgtpe]?'})) monitored = forms.BooleanField(label=_('Monitored?'), required=False, widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) installed = forms.BooleanField(label=_('Installed?'), required=False, help_text=_('This field is used for informational purposes only.'), widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) snapshot_limit_manual = forms.IntegerField(label=_('Snapshot count limit'), required=False, widget=NumberInput(attrs={'class': 'input-transparent narrow'}), help_text=_('Maximum number of manual server snapshots.')) snapshot_size_limit = forms.IntegerField(label=_('Snapshot size limit'), required=False, widget=NumberInput(attrs={'class': 'input-transparent narrow'}), help_text=_('Maximum size of all server snapshots.')) cpu_shares = forms.IntegerField(label=_('CPU Shares'), max_value=1048576, min_value=0, required=True, widget=NumberInput(attrs={'class': 'input-transparent narrow', 'required': 'required'})) # cpu_cap = forms.IntegerField(label=_('CPU Capping'), max_value=6400, min_value=0, required=False, # widget=NumberInput(attrs={'class': 'input-transparent narrow'})) zfs_io_priority = forms.IntegerField(label=_('IO Priority'), max_value=1024, min_value=0, required=True, widget=NumberInput(attrs={'class': 'input-transparent narrow', 'required': 'required'})) zpool = forms.ChoiceField(label=_('Storage'), required=False, widget=forms.Select(attrs={'class': 'narrow input-select2'})) owner = forms.ChoiceField(label=_('Owner'), required=False, widget=forms.Select(attrs={'class': 'narrow input-select2'})) monitoring_templates = ArrayField(label=_('Monitoring templates'), required=False, help_text=_('Comma-separated list of custom monitoring templates.'), widget=ArrayWidget(attrs={'class': 'input-transparent narrow'})) monitoring_hostgroups = ArrayField(label=_('Monitoring hostgroups'), required=False, help_text=_('Comma-separated list of custom monitoring hostgroups.'), widget=ArrayWidget(attrs={'class': 'input-transparent narrow'})) mdata = DictField(label=_('Metadata'), required=False, help_text=_('key=value string pairs.'), widget=DictWidget(attrs={ 'class': 'input-transparent small', 'rows': 5, 'data-raw_input_enabled': 'true', })) def __init__(self, request, vm, *args, **kwargs): super(AdminServerSettingsForm, self).__init__(request, vm, *args, **kwargs) self.is_kvm = is_kvm(vm, self.data, prefix='opt-') # Set choices self.vm_nodes = get_nodes(request, is_compute=True) # TODO: node.color self.fields['node'].choices = [('', _('(auto)'))] + [(i.hostname, i.hostname) for i in self.vm_nodes] self.fields['owner'].choices = get_owners(request).values_list('username', 'username') self.fields['zpool'].choices = get_zpools(request).values_list('zpool', 'storage__alias').distinct() if not request.user.is_staff: self.fields['cpu_shares'].widget.attrs['disabled'] = 'disabled' self.fields['cpu_shares'].widget.attrs['class'] += ' uneditable-input' self.fields['zfs_io_priority'].widget.attrs['disabled'] = 'disabled' self.fields['zfs_io_priority'].widget.attrs['class'] += ' uneditable-input' if vm: empty_template_data = {} self.fields['ostype'].widget.attrs['disabled'] = 'disabled' if vm.is_deployed(): self.fields['node'].widget.attrs['class'] += ' disable_created2' self.fields['zpool'].widget.attrs['class'] += ' disable_created2' else: empty_template_data = self.initial # Remove Linux Zone support (lx brand) ostype = [i for i in Vm.OSTYPE if i[0] != Vm.LINUX_ZONE] # Disable zone support _only_ when adding new VM (zone must be available in edit mode) - Issue #chili-461 if not request.dc.settings.VMS_ZONE_ENABLED: # Remove SunOS Zone support ostype = [i for i in ostype if i[0] != Vm.SUNOS_ZONE] self.fields['ostype'].choices = ostype empty_template = AttrDict({'alias': _('(none)'), 'desc': '', 'web_data': empty_template_data}) self.fields['template'].choices = [('', empty_template)] + [(i.name, i) for i in get_templates(request)] def _initial_data(self, request, vm): fix = super(AdminServerSettingsForm, self)._initial_data(request, vm) ret = get_vm_define(request, vm) # We need string representation of tags, but vm_define returns a list if 'tags' in ret: ret['tags'] = tags_to_string(ret['tags']) # Some serializer data need to be replaced by data expected by the parent form ret.update(fix) return ret
class AdminServerSettingsForm(ServerSettingsForm): """ Copy of vm_define serializer (api). """ admin = True _api_call = vm_define tags = TagField( label=_('Tags'), required=False, widget=TagWidget(attrs={'class': 'tags-select2 narrow'}), help_text=_('The tag will be created in case it does not exist.')) node = forms.TypedChoiceField( label=_('Node'), required=False, coerce=str, empty_value=None, widget=forms.Select(attrs={'class': 'narrow input-select2'})) template = forms.TypedChoiceField( label=_('Template'), required=False, coerce=str, empty_value=None, help_text=_('Setting template can modify lots of server attributes, ' 'e.g. disks, nics.'), widget=DataSelect(attrs={'class': 'narrow input-select2'})) ostype = forms.TypedChoiceField( label=_('OS Type'), choices=Vm.OSTYPE, required=True, coerce=int, widget=forms.Select( attrs={ 'class': 'input-select2 narrow ostype-select', 'required': 'required', 'onChange': 'update_vm_form_fields_from_ostype()' })) hvm_type = forms.TypedChoiceField( label=_('Hypervisor Type'), choices=Vm.HVM_TYPE_GUI, required=False, coerce=int, widget=forms.Select( attrs={ 'class': 'input-select2 narrow hvm-type-select', 'required': 'required', 'onChange': 'update_vm_form_fields_from_hvm_type()' })) vcpus = forms.IntegerField( label=_('VCPUs'), required=False, widget=NumberInput(attrs={ 'class': 'input-transparent narrow', 'required': 'required' })) # noinspection SpellCheckingInspection ram = forms.IntegerField( label=_('RAM'), required=False, widget=forms.TextInput( attrs={ 'class': 'input-transparent narrow input-mbytes', 'required': 'required', 'pattern': '[0-9.]+[BKMGTPEbkmgtpe]?' })) note = forms.CharField( label=_('Note'), help_text=_( 'Text with markdown support, visible to every user with access ' 'to this server.'), required=False, widget=forms.Textarea(attrs={ 'class': 'input-transparent', 'rows': 5 })) monitored = forms.BooleanField( label=_('Monitored?'), required=False, widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) installed = forms.BooleanField( label=_('Installed?'), required=False, help_text=_('This field is used for informational purposes only.'), widget=forms.CheckboxInput(attrs={'class': 'normal-check'})) snapshot_limit_manual = forms.IntegerField( label=_('Snapshot count limit'), required=False, widget=NumberInput(attrs={'class': 'input-transparent narrow'}), help_text=_('Maximum number of manual server snapshots.')) snapshot_size_percent_limit = forms.IntegerField( label=_('Snapshot size % limit'), required=False, widget=NumberInput(attrs={'class': 'input-transparent narrow'}), help_text=_( 'Maximum size of all server snapshots as % of all disk space ' 'of this VM (example: 200% = VM with 10GB disk(s) can have ' '20GB of snapshots).')) snapshot_size_limit = forms.IntegerField( label=_('Snapshot size limit'), required=False, widget=NumberInput(attrs={'class': 'input-transparent narrow'}), help_text=_('Maximum size of all server snapshots. ' 'If set, it takes precedence over % limit.')) cpu_shares = forms.IntegerField( label=_('CPU Shares'), max_value=1048576, min_value=0, required=True, widget=NumberInput(attrs={ 'class': 'input-transparent narrow', 'required': 'required' })) # cpu_cap = forms.IntegerField(label=_('CPU Capping'), max_value=6400, min_value=0, required=False, # widget=NumberInput(attrs={'class': 'input-transparent narrow'})) zfs_io_priority = forms.IntegerField( label=_('IO Priority'), max_value=1024, min_value=0, required=True, widget=NumberInput(attrs={ 'class': 'input-transparent narrow', 'required': 'required' })) bootrom = forms.ChoiceField( label=_('Bootrom'), required=False, widget=forms.Select(attrs={'class': 'narrow input-select2'})) zpool = forms.ChoiceField( label=_('Storage'), required=False, widget=forms.Select(attrs={'class': 'narrow input-select2'})) owner = forms.ChoiceField( label=_('Owner'), required=False, widget=forms.Select(attrs={'class': 'narrow input-select2'})) monitoring_templates = ArrayField( label=_('Monitoring templates'), required=False, tags=True, help_text=_('Comma-separated list of custom monitoring templates.'), widget=ArrayWidget(tags=True, escape_space=False, attrs={'class': 'tags-select2 narrow'})) monitoring_hostgroups = ArrayField( label=_('Monitoring hostgroups'), required=False, tags=True, validators=[ RegexValidator(regex=MonitoringBackend.RE_MONITORING_HOSTGROUPS) ], help_text=_('Comma-separated list of custom monitoring hostgroups.'), widget=ArrayWidget(tags=True, escape_space=False, attrs={'class': 'tags-select2 narrow'})) mdata = DictField(label=_('Metadata'), required=False, help_text=_('key=value string pairs.'), widget=DictWidget( attrs={ 'class': 'input-transparent small', 'rows': 5, 'data-raw_input_enabled': 'true', })) def __init__(self, request, vm, *args, **kwargs): super(AdminServerSettingsForm, self).__init__(request, vm, *args, **kwargs) dc_settings = request.dc.settings # Set choices self.vm_nodes = get_nodes(request, is_compute=True) # TODO: node.color self.fields['node'].choices = [('', _('(auto)'))] + [ (i.hostname, i.hostname) for i in self.vm_nodes ] self.fields['owner'].choices = get_owners(request).values_list( 'username', 'username') self.fields['zpool'].choices = get_zpools(request).values_list( 'zpool', 'storage__alias').distinct() self.fields['bootrom'].choices = Vm.BHYVE_BOOTROM if not request.user.is_staff: self.fields['cpu_shares'].widget.attrs['disabled'] = 'disabled' self.fields['cpu_shares'].widget.attrs[ 'class'] += ' uneditable-input' self.fields['zfs_io_priority'].widget.attrs[ 'disabled'] = 'disabled' self.fields['zfs_io_priority'].widget.attrs[ 'class'] += ' uneditable-input' if dc_settings.MON_ZABBIX_TEMPLATES_VM_RESTRICT: self.fields[ 'monitoring_templates'].widget.tag_choices = dc_settings.MON_ZABBIX_TEMPLATES_VM_ALLOWED if dc_settings.MON_ZABBIX_HOSTGROUPS_VM_RESTRICT: self.fields[ 'monitoring_hostgroups'].widget.tag_choices = dc_settings.MON_ZABBIX_HOSTGROUPS_VM_ALLOWED if dc_settings.MON_ZABBIX_HOSTGROUPS_VM: self.fields['monitoring_hostgroups'].help_text += _(' Automatically added hostgroups: ') \ + ', '.join(dc_settings.MON_ZABBIX_HOSTGROUPS_VM) if vm: empty_template_data = {} self.fields['ostype'].widget.attrs['disabled'] = 'disabled' self.fields['hvm_type'].widget.attrs['disabled'] = 'disabled' if not vm.is_hvm(): # for zones the only HVM choice is NO hypervisor self.fields['hvm_type'].choices = Vm.HVM_TYPE_GUI_NO_HYPERVISOR if vm.is_deployed(): self.fields['node'].widget.attrs[ 'class'] += ' disable_created2' self.fields['zpool'].widget.attrs[ 'class'] += ' disable_created2' else: empty_template_data = self.initial ostype = Vm.OSTYPE # Disable zone support _only_ when adding new VM (zone must be available in edit mode) - Issue #chili-461 if not dc_settings.VMS_ZONE_ENABLED: # Remove SunOS Zone support ostype = [i for i in ostype if i[0] not in Vm.ZONE_OSTYPES] self.fields['ostype'].choices = ostype empty_template = AttrDict({ 'alias': _('(none)'), 'desc': '', 'web_data': empty_template_data }) self.fields['template'].choices = [('', empty_template)] + [ (i.name, i) for i in get_templates(request) ] def _initial_data(self, request, vm): fix = super(AdminServerSettingsForm, self)._initial_data(request, vm) ret = get_vm_define(request, vm) # We need string representation of tags, but vm_define returns a list if 'tags' in ret: ret['tags'] = tags_to_string(ret['tags']) # Some serializer data need to be replaced by data expected by the parent form ret.update(fix) return ret
class DcNodeForm(SerializerForm): """ Create or update Dc<->Node association by calling dc_node. """ _api_call = dc_node hostname = forms.ChoiceField( label=_('Hostname'), required=True, widget=forms.Select( attrs={'class': 'narrow input-select2 disable_created2'})) strategy = forms.TypedChoiceField( label=_('Resource strategy'), required=True, coerce=int, choices=DcNode.STRATEGY, widget=forms.Select(attrs={'class': 'input-select2 narrow'})) priority = forms.IntegerField( label=_('Priority'), required=True, help_text=_('Higher priority means that the automatic node chooser ' 'will more likely choose this node.'), widget=NumberInput(attrs={ 'class': 'input-transparent narrow', 'required': 'required' })) cpu = forms.IntegerField( label=_('CPUs'), required=False, help_text=_('Total number of vCPUs for VMs.'), widget=NumberInput(attrs={ 'class': 'input-transparent narrow', 'required': 'required' })) # noinspection SpellCheckingInspection ram = forms.IntegerField( label=_('RAM'), required=False, help_text=_('Total RAM size in MB for VMs.'), widget=forms.TextInput( attrs={ 'class': 'input-transparent narrow input-mbytes', 'required': 'required', 'pattern': '[0-9\.]+[BKMGTPEbkmgtpe]?' })) # noinspection SpellCheckingInspection disk = forms.IntegerField( label=_('Disk pool size'), required=False, help_text=_('Size of the local disk pool for VMs.'), widget=forms.TextInput( attrs={ 'class': 'input-transparent narrow input-mbytes', 'required': 'required', 'pattern': '[0-9\.]+[BKMGTPEbkmgtpe]?' })) add_storage = forms.TypedChoiceField( label=_('Attach node Storages'), required=False, coerce=int, empty_value=0, choices=add_storage_choices, widget=forms.Select( attrs={'class': 'narrow input-select2 disable_created2'})) def __init__(self, request, instance, *args, **kwargs): super(DcNodeForm, self).__init__(request, instance, *args, **kwargs) self.fields['hostname'].choices = Node.objects.all().values_list( 'hostname', 'hostname') def _initial_data(self, request, obj): return obj.web_data def _has_changed(self): try: del self.cleaned_data['add_storage'] except KeyError: pass return super(DcNodeForm, self)._has_changed()