-
Anders Harrisson authored
JIRA INFRA-4308
Anders Harrisson authoredJIRA INFRA-4308
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
forms.py 10.34 KiB
# -*- coding: utf-8 -*-
"""
app.network.forms
~~~~~~~~~~~~~~~~~
This module defines the network blueprint forms.
:copyright: (c) 2017 European Spallation Source ERIC
:license: BSD 2-Clause, see LICENSE for more details.
"""
from flask import current_app
from flask_login import current_user
from wtforms import (
SelectField,
StringField,
TextAreaField,
IntegerField,
SelectMultipleField,
BooleanField,
validators,
)
from ..helpers import CSEntryForm
from ..validators import (
Unique,
UniqueAccrossModels,
RegexpList,
IPNetwork,
HOST_NAME_RE,
INTERFACE_NAME_RE,
VLAN_NAME_RE,
MAC_ADDRESS_RE,
NoValidateSelectField,
)
from ..fields import YAMLField
from .. import utils, models
def starts_with_hostname(form, field):
"""Check that interface name starts with hostname"""
try:
# Create / Edit interface form
host_id_field = form["host_id"]
except KeyError:
# Create host form
hostname = form["name"].data
else:
host = models.Host.query.get(host_id_field.data)
hostname = host.name
if not field.data.startswith(hostname):
raise validators.ValidationError(
f'Interface name shall start with the hostname "{hostname}"'
)
def ip_in_network(form, field):
"""Check that the IP is in the network"""
network_id_field = form["network_id"]
if not network_id_field.data:
raise validators.ValidationError(
"Can't validate the IP. No network was selected."
)
network = models.Network.query.get(network_id_field.data)
utils.validate_ip(field.data, network)
class DomainForm(CSEntryForm):
name = StringField(
"Name",
validators=[validators.InputRequired(), Unique(models.Domain, column="name")],
)
class NetworkScopeForm(CSEntryForm):
name = StringField(
"Name",
description="name must be 3-25 characters long and contain only letters, numbers and dash",
validators=[
validators.InputRequired(),
validators.Regexp(VLAN_NAME_RE),
Unique(models.NetworkScope, column="name"),
],
)
description = TextAreaField("Description")
first_vlan = IntegerField("First vlan", validators=[validators.optional()])
last_vlan = IntegerField("Last vlan", validators=[validators.optional()])
supernet = StringField(
"Supernet", validators=[validators.InputRequired(), IPNetwork()]
)
domain_id = SelectField("Default domain")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.domain_id.choices = utils.get_model_choices(models.Domain, attr="name")
class NetworkForm(CSEntryForm):
scope_id = SelectField("Network Scope")
vlan_name = StringField(
"Vlan name",
description="vlan name must be 3-25 characters long and contain only letters, numbers and dash",
validators=[
validators.InputRequired(),
validators.Regexp(VLAN_NAME_RE),
Unique(models.Network, column="vlan_name"),
],
)
vlan_id = NoValidateSelectField(
"Vlan id", choices=[], coerce=utils.coerce_to_str_or_none
)
description = TextAreaField("Description")
prefix = NoValidateSelectField("Prefix", choices=[])
address = NoValidateSelectField("Address", choices=[])
first_ip = NoValidateSelectField("First IP", choices=[])
last_ip = NoValidateSelectField("Last IP", choices=[])
gateway = NoValidateSelectField("Gateway IP", choices=[])
domain_id = SelectField("Domain")
admin_only = BooleanField("Admin only")
sensitive = BooleanField("Sensitive")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.scope_id.choices = utils.get_model_choices(
models.NetworkScope, attr="name"
)
self.domain_id.choices = utils.get_model_choices(models.Domain, attr="name")
class EditNetworkForm(CSEntryForm):
vlan_name = StringField(
"Vlan name",
description="vlan name must be 3-25 characters long and contain only letters, numbers and dash",
validators=[
validators.InputRequired(),
validators.Regexp(VLAN_NAME_RE),
Unique(models.Network, column="vlan_name"),
],
)
vlan_id = IntegerField("Vlan id")
description = TextAreaField("Description")
address = StringField("Address")
first_ip = StringField("First IP")
last_ip = StringField("Last IP")
gateway = StringField("Gateway IP")
domain_id = SelectField("Domain")
admin_only = BooleanField("Admin only")
sensitive = BooleanField("Sensitive")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.domain_id.choices = utils.get_model_choices(models.Domain, attr="name")
class HostForm(CSEntryForm):
name = StringField(
"Hostname",
description="hostname must be 2-24 characters long and contain only letters, numbers and dash",
validators=[
validators.InputRequired(),
validators.Regexp(HOST_NAME_RE),
Unique(models.Host),
UniqueAccrossModels([models.Cname]),
],
filters=[utils.lowercase_field],
)
description = TextAreaField("Description")
device_type_id = SelectField("Device Type")
is_ioc = BooleanField(
"IOC",
default=False,
description="This host will be used to run IOCs",
)
ansible_vars = YAMLField(
"Ansible vars",
description="Enter variables in YAML format. See https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html",
)
ansible_groups = SelectMultipleField(
"Ansible groups", coerce=utils.coerce_to_str_or_none
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.device_type_id.choices = utils.get_model_choices(models.DeviceType)
ansible_group_query = models.AnsibleGroup.query.filter(
models.AnsibleGroup.type == models.AnsibleGroupType.STATIC
)
self.ansible_groups.choices = utils.get_model_choices(
models.AnsibleGroup, attr="name", query=ansible_group_query
)
class InterfaceForm(CSEntryForm):
host_id = SelectField("Host")
network_id = SelectField("Network")
ip = StringField(
"IP address",
validators=[
validators.InputRequired(),
validators.IPAddress(),
ip_in_network,
Unique(models.Interface, column="ip"),
],
)
interface_name = StringField(
"Interface name",
description="name must be 2-29 characters long and contain only letters, numbers and dash",
validators=[
validators.InputRequired(),
validators.Regexp(INTERFACE_NAME_RE),
Unique(models.Interface),
starts_with_hostname,
UniqueAccrossModels([models.Cname]),
],
filters=[utils.lowercase_field],
)
interface_description = TextAreaField("Description")
random_mac = BooleanField("Random MAC", default=False)
mac = StringField(
"MAC",
validators=[
validators.Optional(),
validators.Regexp(MAC_ADDRESS_RE, message="Invalid MAC address"),
Unique(models.Interface, column="mac"),
],
)
cnames_string = StringField(
"Cnames",
description="space separated list of cnames (must be 2-24 characters long and contain only letters, numbers and dash)",
validators=[
validators.Optional(),
RegexpList(HOST_NAME_RE),
UniqueAccrossModels([models.Host, models.Interface]),
],
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.host_id.choices = utils.get_model_choices(models.Host)
# Only return the networks the user has access to
self.network_id.choices = [
(str(network.id), network.vlan_name)
for network in models.Network.query.order_by(models.Network.vlan_name).all()
if current_user.has_access_to_network(network)
]
class HostInterfaceForm(HostForm, InterfaceForm):
pass
class CreateVMForm(CSEntryForm):
cores = SelectField("Cores", default=2, coerce=int)
memory = SelectField("Memory (GB)", default=2, coerce=int)
disk = SelectField("Disk (GB)", default=15, coerce=int)
osversion = SelectField("OS Version")
skip_post_install_job = BooleanField("Skip post install job", default=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.cores.choices = utils.get_choices(current_app.config["VM_CORES_CHOICES"])
self.memory.choices = utils.get_choices(current_app.config["VM_MEMORY_CHOICES"])
self.disk.choices = utils.get_choices(current_app.config["VM_DISK_CHOICES"])
self.osversion.choices = utils.get_choices(
current_app.config["VM_OSVERSION_CHOICES"]
)
class BootProfileForm(CSEntryForm):
boot_profile = SelectField("Boot profile")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.boot_profile.choices = utils.get_choices(
current_app.config["AUTOINSTALL_BOOT_PROFILES"]
)
class AnsibleGroupForm(CSEntryForm):
name = StringField(
"name",
validators=[validators.InputRequired(), Unique(models.AnsibleGroup)],
filters=[utils.lowercase_field],
)
vars = YAMLField(
"Ansible vars",
description="Enter variables in YAML format. See https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html",
)
type = SelectField(
"Type",
choices=models.AnsibleGroupType.choices(),
default=models.AnsibleGroupType.STATIC,
coerce=models.AnsibleGroupType.coerce,
)
children = SelectMultipleField("Children", coerce=utils.coerce_to_str_or_none)
hosts = SelectMultipleField("Hosts", coerce=utils.coerce_to_str_or_none)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.children.choices = [
(str(group.id), group.name)
for group in models.AnsibleGroup.query.order_by(
models.AnsibleGroup.name
).all()
if group.name != "all"
]
self.hosts.choices = utils.get_model_choices(
models.Host, attr="fqdn", order_by="name"
)