diff --git a/orchestra/contrib/mailboxes/forms.py b/orchestra/contrib/mailboxes/forms.py
index cbfbf71c..ae2dd213 100644
--- a/orchestra/contrib/mailboxes/forms.py
+++ b/orchestra/contrib/mailboxes/forms.py
@@ -44,6 +44,13 @@ class MailboxForm(forms.ModelForm):
if self.instance and self.instance.pk:
self.fields['addresses'].initial = self.instance.addresses.all()
+
+ def clean_name(self):
+ name = self.cleaned_data['name']
+ max_length = settings.MAILBOXES_NAME_MAX_LENGTH
+ if len(name) > max_length:
+ raise ValidationError("Name length should be less than %i" % max_length)
+ return name
class MailboxChangeForm(UserChangeForm, MailboxForm):
diff --git a/orchestra/contrib/mailboxes/settings.py b/orchestra/contrib/mailboxes/settings.py
index 39403d3e..fc74e56e 100644
--- a/orchestra/contrib/mailboxes/settings.py
+++ b/orchestra/contrib/mailboxes/settings.py
@@ -20,6 +20,12 @@ MAILBOXES_DOMAIN_MODEL = Setting('MAILBOXES_DOMAIN_MODEL', 'domains.Domain',
)
+MAILBOXES_NAME_MAX_LENGTH = Setting('MAILBOXES_NAME_MAX_LENGTH',
+ 64,
+ help_text=_("Limit for system user based mailbox on Linux should be 32.")
+)
+
+
MAILBOXES_HOME = Setting('MAILBOXES_HOME',
'/home/%(name)s',
help_text="Available fromat names: %s" % ', '.join(_names),
diff --git a/orchestra/contrib/orchestration/models.py b/orchestra/contrib/orchestration/models.py
index 8ccc1347..dd14a0e7 100644
--- a/orchestra/contrib/orchestration/models.py
+++ b/orchestra/contrib/orchestration/models.py
@@ -3,13 +3,14 @@ import socket
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
+from django.core.exceptions import ValidationError
from django.db import models
from django.utils.encoding import force_text
from django.utils.functional import cached_property
from django.utils.module_loading import autodiscover_modules
from django.utils.translation import ugettext_lazy as _
-from orchestra.core.validators import validate_ip_address, ValidationError
+from orchestra.core.validators import validate_ip_address, validate_hostname, OrValidator
from orchestra.models.fields import NullableCharField, MultiSelectField
from . import settings
@@ -21,9 +22,13 @@ logger = logging.getLogger(__name__)
class Server(models.Model):
""" Machine runing daemons (services) """
- name = models.CharField(_("name"), max_length=256, unique=True)
+ name = models.CharField(_("name"), max_length=256, unique=True,
+ help_text=_("Verbose name or hostname of this server."))
address = NullableCharField(_("address"), max_length=256, blank=True,
- null=True, unique=True, help_text=_("IP address or domain name"))
+ validators=[OrValidator(validate_ip_address, validate_hostname)],
+ null=True, unique=True, help_text=_(
+ "Optional IP address or domain name. Name field will be used if not provided.
"
+ "If the IP address never change you can set this field and save DNS requests."))
description = models.TextField(_("description"), blank=True)
os = models.CharField(_("operative system"), max_length=32,
choices=settings.ORCHESTRATION_OS_CHOICES,
@@ -38,14 +43,24 @@ class Server(models.Model):
return self.name
def get_ip(self):
- if self.address:
- return self.address
+ address = self.get_address()
try:
- validate_ip_address(self.name)
+ return validate_ip_address(address)
except ValidationError:
return socket.gethostbyname(self.name)
- else:
- return self.name
+
+ def clean(self):
+ self.name = self.name.strip()
+ self.address = self.address.strip()
+ if self.name and not self.address:
+ validate = OrValidator(validate_ip_address, validate_hostname)
+ validate_hostname(self.name)
+ try:
+ validate(self.name)
+ except ValidationError as err:
+ raise ValidationError({
+ 'name': _("Name should be a valid hostname or IP address when address is not provided.")
+ })
class BackendLog(models.Model):
diff --git a/orchestra/core/validators.py b/orchestra/core/validators.py
index e9e03cd6..c863cd6e 100644
--- a/orchestra/core/validators.py
+++ b/orchestra/core/validators.py
@@ -37,6 +37,25 @@ def all_valid(*args):
raise ValidationError(errors)
+class OrValidator(object):
+ """
+ Run validators with an OR logic
+ """
+ def __init__(self, *validators):
+ self.validators = validators
+
+ def __call__(self, value):
+ msg = []
+ for validator in self.validators:
+ try:
+ validator(value)
+ except ValidationError as err:
+ msg.append(str(err))
+ else:
+ return
+ raise ValidationError(' OR '.join(msg))
+
+
def validate_ipv4_address(value):
msg = _("Not a valid IPv4 address")
try: