Merge "Group specific fields in horizon.form module"

This commit is contained in:
Jenkins
2014-04-02 13:58:13 +00:00
committed by Gerrit Code Review
17 changed files with 207 additions and 222 deletions

View File

@@ -30,6 +30,11 @@ from horizon.forms.base import SelfHandlingForm # noqa
from horizon.forms.base import SelfHandlingMixin # noqa
from horizon.forms.fields import DynamicChoiceField # noqa
from horizon.forms.fields import DynamicTypedChoiceField # noqa
from horizon.forms.fields import IPField # noqa
from horizon.forms.fields import IPv4 # noqa
from horizon.forms.fields import IPv6 # noqa
from horizon.forms.fields import MultiIPField # noqa
from horizon.forms.fields import SelectWidget # noqa
from horizon.forms.views import ModalFormMixin # noqa
from horizon.forms.views import ModalFormView # noqa
@@ -42,6 +47,11 @@ __all__ = [
"ModalFormMixin",
"DynamicTypedChoiceField",
"DynamicChoiceField",
"IPField",
"IPv4",
"IPv6",
"MultiIPField",
"SelectWidget"
# From django.forms
"ValidationError",

View File

@@ -14,9 +14,153 @@
# License for the specific language governing permissions and limitations
# under the License.
import re
import netaddr
from django.core.exceptions import ValidationError # noqa
from django.core import urlresolvers
from django.forms import fields
from django.forms import widgets
from django.utils.encoding import force_unicode
from django.utils.functional import Promise # noqa
from django.utils import html
from django.utils.translation import ugettext_lazy as _
ip_allowed_symbols_re = re.compile(r'^[a-fA-F0-9:/\.]+$')
IPv4 = 1
IPv6 = 2
class IPField(fields.Field):
"""Form field for entering IP/range values, with validation.
Supports IPv4/IPv6 in the format:
.. xxx.xxx.xxx.xxx
.. xxx.xxx.xxx.xxx/zz
.. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
.. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/zz
and all compressed forms. Also the short forms
are supported:
xxx/yy
xxx.xxx/yy
.. attribute:: version
Specifies which IP version to validate,
valid values are 1 (fields.IPv4), 2 (fields.IPv6) or
both - 3 (fields.IPv4 | fields.IPv6).
Defaults to IPv4 (1)
.. attribute:: mask
Boolean flag to validate subnet masks along with IP address.
E.g: 10.0.0.1/32
.. attribute:: mask_range_from
Subnet range limitation, e.g. 16
That means the input mask will be checked to be in the range
16:max_value. Useful to limit the subnet ranges
to A/B/C-class networks.
"""
invalid_format_message = _("Incorrect format for IP address")
invalid_version_message = _("Invalid version for IP address")
invalid_mask_message = _("Invalid subnet mask")
max_v4_mask = 32
max_v6_mask = 128
def __init__(self, *args, **kwargs):
self.mask = kwargs.pop("mask", None)
self.min_mask = kwargs.pop("mask_range_from", 0)
self.version = kwargs.pop('version', IPv4)
super(IPField, self).__init__(*args, **kwargs)
def validate(self, value):
super(IPField, self).validate(value)
if not value and not self.required:
return
try:
if self.mask:
self.ip = netaddr.IPNetwork(value)
else:
self.ip = netaddr.IPAddress(value)
except Exception:
raise ValidationError(self.invalid_format_message)
if not any([self.version & IPv4 > 0 and self.ip.version == 4,
self.version & IPv6 > 0 and self.ip.version == 6]):
raise ValidationError(self.invalid_version_message)
if self.mask:
if self.ip.version == 4 and \
not self.min_mask <= self.ip.prefixlen <= self.max_v4_mask:
raise ValidationError(self.invalid_mask_message)
if self.ip.version == 6 and \
not self.min_mask <= self.ip.prefixlen <= self.max_v6_mask:
raise ValidationError(self.invalid_mask_message)
def clean(self, value):
super(IPField, self).clean(value)
return str(getattr(self, "ip", ""))
class MultiIPField(IPField):
"""Extends IPField to allow comma-separated lists of addresses."""
def validate(self, value):
self.addresses = []
if value:
addresses = value.split(',')
for ip in addresses:
super(MultiIPField, self).validate(ip)
self.addresses.append(ip)
else:
super(MultiIPField, self).validate(value)
def clean(self, value):
super(MultiIPField, self).clean(value)
return str(','.join(getattr(self, "addresses", [])))
class SelectWidget(widgets.Select):
"""Customizable select widget, that allows to render
data-xxx attributes from choices.
.. attribute:: data_attrs
Specifies object properties to serialize as
data-xxx attribute. If passed ('id', ),
this will be rendered as:
<option data-id="123">option_value</option>
where 123 is the value of choice_value.id
.. attribute:: transform
A callable used to render the display value
from the option object.
"""
def __init__(self, attrs=None, choices=(), data_attrs=(), transform=None):
self.data_attrs = data_attrs
self.transform = transform
super(SelectWidget, self).__init__(attrs, choices)
def render_option(self, selected_choices, option_value, option_label):
option_value = force_unicode(option_value)
other_html = (option_value in selected_choices) and \
u' selected="selected"' or ''
if not isinstance(option_label, (basestring, Promise)):
for data_attr in self.data_attrs:
data_value = html.conditional_escape(
force_unicode(getattr(option_label,
data_attr, "")))
other_html += ' data-%s="%s"' % (data_attr, data_value)
if self.transform:
option_label = self.transform(option_label)
return u'<option value="%s"%s>%s</option>' % (
html.escape(option_value), other_html,
html.conditional_escape(force_unicode(option_label)))
class DynamicSelectWidget(widgets.Select):

View File

@@ -21,8 +21,8 @@ from django.core.exceptions import ValidationError # noqa
import django.template
from django.template import defaultfilters
from horizon import forms
from horizon.test import helpers as test
from horizon.utils import fields
from horizon.utils import filters
# we have to import the filter in order to register it
from horizon.utils.filters import parse_isotime # noqa
@@ -56,7 +56,7 @@ class ValidatorsTests(test.TestCase):
"fe80::204:61ff:254.157.241.86/0",
"2001:0DB8::CD30:0:0:0:0/60",
"2001:0DB8::CD30:0/90")
ip = fields.IPField(mask=True, version=fields.IPv4)
ip = forms.IPField(mask=True, version=forms.IPv4)
for cidr in GOOD_CIDRS:
self.assertIsNone(ip.validate(cidr))
for cidr in BAD_CIDRS:
@@ -83,7 +83,7 @@ class ValidatorsTests(test.TestCase):
"10.144.11.107/4",
"255.255.255.255/0",
"0.1.2.3/16")
ip = fields.IPField(mask=True, version=fields.IPv6)
ip = forms.IPField(mask=True, version=forms.IPv6)
for cidr in GOOD_CIDRS:
self.assertIsNone(ip.validate(cidr))
for cidr in BAD_CIDRS:
@@ -112,7 +112,7 @@ class ValidatorsTests(test.TestCase):
"127.0.0.1/",
"127.0.0.1/33",
"127.0.0.1/-1")
ip = fields.IPField(mask=True, version=fields.IPv4 | fields.IPv6)
ip = forms.IPField(mask=True, version=forms.IPv4 | forms.IPv6)
for cidr in GOOD_CIDRS:
self.assertIsNone(ip.validate(cidr))
for cidr in BAD_CIDRS:
@@ -147,10 +147,10 @@ class ValidatorsTests(test.TestCase):
"1111:2222::4444:5555:6666::8888",
"1111:2222::4444:5555:6666:8888/",
"1111:2222::4444:5555:6666::8888/130")
ipv4 = fields.IPField(required=True, version=fields.IPv4)
ipv6 = fields.IPField(required=False, version=fields.IPv6)
ipmixed = fields.IPField(required=False,
version=fields.IPv4 | fields.IPv6)
ipv4 = forms.IPField(required=True, version=forms.IPv4)
ipv6 = forms.IPField(required=False, version=forms.IPv6)
ipmixed = forms.IPField(required=False,
version=forms.IPv4 | forms.IPv6)
for ip_addr in GOOD_IPS_V4:
self.assertIsNone(ipv4.validate(ip_addr))
@@ -170,10 +170,10 @@ class ValidatorsTests(test.TestCase):
self.assertRaises(ValidationError, ipv4.validate, "") # required=True
iprange = fields.IPField(required=False,
iprange = forms.IPField(required=False,
mask=True,
mask_range_from=10,
version=fields.IPv4 | fields.IPv6)
version=forms.IPv4 | forms.IPv6)
self.assertRaises(ValidationError, iprange.validate,
"fe80::204:61ff:254.157.241.86/6")
self.assertRaises(ValidationError, iprange.validate,
@@ -188,7 +188,7 @@ class ValidatorsTests(test.TestCase):
"1.2.3.4.5/41 0.0.0.0/99",
"192.168.1.1/16 192.0.0.1/17")
ip = fields.MultiIPField(mask=True, version=fields.IPv4)
ip = forms.MultiIPField(mask=True, version=forms.IPv4)
for cidr in GOOD_CIDRS_INPUT:
self.assertIsNone(ip.validate(cidr))
for cidr in BAD_CIDRS_INPUT:

View File

@@ -1,157 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from django.core.exceptions import ValidationError # noqa
from django.forms import forms
from django.forms import widgets
from django.utils.encoding import force_unicode
from django.utils.functional import Promise # noqa
from django.utils.html import conditional_escape
from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _
import netaddr
import re
ip_allowed_symbols_re = re.compile(r'^[a-fA-F0-9:/\.]+$')
IPv4 = 1
IPv6 = 2
class IPField(forms.Field):
"""Form field for entering IP/range values, with validation.
Supports IPv4/IPv6 in the format:
.. xxx.xxx.xxx.xxx
.. xxx.xxx.xxx.xxx/zz
.. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
.. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/zz
and all compressed forms. Also the short forms
are supported:
xxx/yy
xxx.xxx/yy
.. attribute:: version
Specifies which IP version to validate,
valid values are 1 (fields.IPv4), 2 (fields.IPv6) or
both - 3 (fields.IPv4 | fields.IPv6).
Defaults to IPv4 (1)
.. attribute:: mask
Boolean flag to validate subnet masks along with IP address.
E.g: 10.0.0.1/32
.. attribute:: mask_range_from
Subnet range limitation, e.g. 16
That means the input mask will be checked to be in the range
16:max_value. Useful to limit the subnet ranges
to A/B/C-class networks.
"""
invalid_format_message = _("Incorrect format for IP address")
invalid_version_message = _("Invalid version for IP address")
invalid_mask_message = _("Invalid subnet mask")
max_v4_mask = 32
max_v6_mask = 128
def __init__(self, *args, **kwargs):
self.mask = kwargs.pop("mask", None)
self.min_mask = kwargs.pop("mask_range_from", 0)
self.version = kwargs.pop('version', IPv4)
super(IPField, self).__init__(*args, **kwargs)
def validate(self, value):
super(IPField, self).validate(value)
if not value and not self.required:
return
try:
if self.mask:
self.ip = netaddr.IPNetwork(value)
else:
self.ip = netaddr.IPAddress(value)
except Exception:
raise ValidationError(self.invalid_format_message)
if not any([self.version & IPv4 > 0 and self.ip.version == 4,
self.version & IPv6 > 0 and self.ip.version == 6]):
raise ValidationError(self.invalid_version_message)
if self.mask:
if self.ip.version == 4 and \
not self.min_mask <= self.ip.prefixlen <= self.max_v4_mask:
raise ValidationError(self.invalid_mask_message)
if self.ip.version == 6 and \
not self.min_mask <= self.ip.prefixlen <= self.max_v6_mask:
raise ValidationError(self.invalid_mask_message)
def clean(self, value):
super(IPField, self).clean(value)
return str(getattr(self, "ip", ""))
class MultiIPField(IPField):
"""Extends IPField to allow comma-separated lists of addresses."""
def validate(self, value):
self.addresses = []
if value:
addresses = value.split(',')
for ip in addresses:
super(MultiIPField, self).validate(ip)
self.addresses.append(ip)
else:
super(MultiIPField, self).validate(value)
def clean(self, value):
super(MultiIPField, self).clean(value)
return str(','.join(getattr(self, "addresses", [])))
class SelectWidget(widgets.Select):
"""Customizable select widget, that allows to render
data-xxx attributes from choices.
.. attribute:: data_attrs
Specifies object properties to serialize as
data-xxx attribute. If passed ('id', ),
this will be rendered as:
<option data-id="123">option_value</option>
where 123 is the value of choice_value.id
.. attribute:: transform
A callable used to render the display value
from the option object.
"""
def __init__(self, attrs=None, choices=(), data_attrs=(), transform=None):
self.data_attrs = data_attrs
self.transform = transform
super(SelectWidget, self).__init__(attrs, choices)
def render_option(self, selected_choices, option_value, option_label):
option_value = force_unicode(option_value)
other_html = (option_value in selected_choices) and \
u' selected="selected"' or ''
if not isinstance(option_label, (basestring, Promise)):
for data_attr in self.data_attrs:
data_value = conditional_escape(
force_unicode(getattr(option_label,
data_attr, "")))
other_html += ' data-%s="%s"' % (data_attr, data_value)
if self.transform:
option_label = self.transform(option_label)
return u'<option value="%s"%s>%s</option>' % (
escape(option_value), other_html,
conditional_escape(force_unicode(option_label)))

View File

@@ -29,7 +29,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import fields
from horizon.utils import validators as utils_validators
from openstack_dashboard import api
@@ -204,12 +203,12 @@ class AddRule(forms.SelfHandlingForm):
'class': 'switchable',
'data-slug': 'remote'}))
cidr = fields.IPField(label=_("CIDR"),
cidr = forms.IPField(label=_("CIDR"),
required=False,
initial="0.0.0.0/0",
help_text=_("Classless Inter-Domain Routing "
"(e.g. 192.168.0.0/24)"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=True,
widget=forms.TextInput(
attrs={'class': 'switched',

View File

@@ -23,7 +23,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import fields
from horizon.utils import validators
from openstack_dashboard import api
@@ -44,14 +43,14 @@ class UpdateRule(forms.SelfHandlingForm):
action = forms.ChoiceField(
label=_("Action"), required=False,
help_text=_('Action for the firewall rule'))
source_ip_address = fields.IPField(
source_ip_address = forms.IPField(
label=_("Source IP Address/Subnet"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
required=False, mask=True,
help_text=_('Source IP address or subnet'))
destination_ip_address = fields.IPField(
destination_ip_address = forms.IPField(
label=_('Destination IP Address/Subnet'),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
required=False, mask=True,
help_text=_('Destination IP address or subnet'))
source_port = forms.CharField(

View File

@@ -19,7 +19,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon.utils import fields
from horizon.utils import validators
from horizon import workflows
@@ -47,13 +46,13 @@ class AddRuleAction(workflows.Action):
label=_("Action"),
choices=[('allow', _('ALLOW')),
('deny', _('DENY'))],)
source_ip_address = fields.IPField(
source_ip_address = forms.IPField(
label=_("Source IP Address/Subnet"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
required=False, mask=True)
destination_ip_address = fields.IPField(
destination_ip_address = forms.IPField(
label=_("Destination IP Address/Subnet"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
required=False, mask=True)
source_port = forms.CharField(
max_length=80,

View File

@@ -23,7 +23,6 @@ from django.views.decorators.debug import sensitive_variables # noqa
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import fields
from horizon.utils import validators
from openstack_dashboard import api
@@ -37,8 +36,9 @@ def _image_choice_title(img):
class RebuildInstanceForm(forms.SelfHandlingForm):
instance_id = forms.CharField(widget=forms.HiddenInput())
image = forms.ChoiceField(label=_("Select Image"),
widget=fields.SelectWidget(attrs={'class': 'image-selector'},
widget=forms.SelectWidget(attrs={'class': 'image-selector'},
data_attrs=('size', 'display-name'),
transform=_image_choice_title))
password = forms.RegexField(label=_("Rebuild Password"),

View File

@@ -29,7 +29,6 @@ from django.views.decorators.debug import sensitive_variables # noqa
from horizon import exceptions
from horizon import forms
from horizon.utils import fields
from horizon.utils import functions
from horizon.utils import validators
from horizon import workflows
@@ -106,7 +105,7 @@ class SetInstanceDetailsAction(workflows.Action):
image_id = forms.ChoiceField(
label=_("Image Name"),
required=False,
widget=fields.SelectWidget(
widget=forms.SelectWidget(
data_attrs=('volume_size',),
transform=lambda x: ("%s (%s)" % (x.name,
filesizeformat(x.bytes)))))

View File

@@ -18,7 +18,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon.utils import fields
from horizon.utils import validators
from horizon import workflows
@@ -155,9 +154,9 @@ class AddVipAction(workflows.Action):
label=_("VIP Address from Floating IPs"),
widget=forms.Select(attrs={'disabled': 'disabled'}),
required=False)
other_address = fields.IPField(required=False,
other_address = forms.IPField(required=False,
initial="",
version=fields.IPv4,
version=forms.IPv4,
mask=False)
protocol_port = forms.IntegerField(label=_("Protocol Port"), min_value=1,
help_text=_("Enter an integer value "

View File

@@ -21,7 +21,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon.utils import fields
from horizon import workflows
from openstack_dashboard import api
@@ -80,14 +79,14 @@ class CreateSubnet(network_workflows.CreateNetwork):
class UpdateSubnetInfoAction(CreateSubnetInfoAction):
cidr = fields.IPField(label=_("Network Address"),
cidr = forms.IPField(label=_("Network Address"),
required=False,
initial="",
widget=forms.TextInput(
attrs={'readonly': 'readonly'}),
help_text=_("Network address in CIDR format "
"(e.g. 192.168.0.0/24)"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=True)
# NOTE(amotoki): When 'disabled' attribute is set for the ChoiceField
# and ValidationError is raised for POST request, the initial value of
@@ -103,7 +102,7 @@ class UpdateSubnetInfoAction(CreateSubnetInfoAction):
widget=forms.HiddenInput(),
label=_("IP Version"))
gateway_ip = fields.IPField(
gateway_ip = forms.IPField(
label=_("Gateway IP (optional)"),
required=False,
initial="",
@@ -112,7 +111,7 @@ class UpdateSubnetInfoAction(CreateSubnetInfoAction):
"to set the gateway. "
"If you want to use no gateway, "
"check 'Disable Gateway' below."),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=False)
no_gateway = forms.BooleanField(label=_("Disable Gateway"),
initial=False, required=False)

View File

@@ -24,7 +24,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import fields
from horizon import workflows
from openstack_dashboard import api
@@ -87,16 +86,16 @@ class CreateSubnetInfoAction(workflows.Action):
subnet_name = forms.CharField(max_length=255,
label=_("Subnet Name"),
required=False)
cidr = fields.IPField(label=_("Network Address"),
cidr = forms.IPField(label=_("Network Address"),
required=False,
initial="",
help_text=_("Network address in CIDR format "
"(e.g. 192.168.0.0/24)"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=True)
ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
label=_("IP Version"))
gateway_ip = fields.IPField(
gateway_ip = forms.IPField(
label=_("Gateway IP"),
required=False,
initial="",
@@ -107,7 +106,7 @@ class CreateSubnetInfoAction(workflows.Action):
"If you use the default, leave blank. "
"If you want to use no gateway, "
"check 'Disable Gateway' below."),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=False)
no_gateway = forms.BooleanField(label=_("Disable Gateway"),
initial=False, required=False)

View File

@@ -23,14 +23,13 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import fields
from openstack_dashboard.dashboards.project.routers.extensions.routerrules\
import rulemanager
LOG = logging.getLogger(__name__)
class RuleCIDRField(fields.IPField):
class RuleCIDRField(forms.IPField):
"""Extends IPField to allow ('any','external') keywords and requires CIDR
"""
def __init__(self, *args, **kwargs):
@@ -53,7 +52,7 @@ class AddRouterRule(forms.SelfHandlingForm):
destination = RuleCIDRField(label=_("Destination CIDR"),
widget=forms.TextInput(), required=True)
action = forms.ChoiceField(label=_("Action"), required=True)
nexthops = fields.MultiIPField(label=_("Optional: Next Hop "
nexthops = forms.MultiIPField(label=_("Optional: Next Hop "
"Addresses (comma delimited)"),
widget=forms.TextInput(), required=False)
router_id = forms.CharField(label=_("Router ID"),

View File

@@ -22,7 +22,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import fields
from openstack_dashboard import api
LOG = logging.getLogger(__name__)
@@ -30,11 +29,11 @@ LOG = logging.getLogger(__name__)
class AddInterface(forms.SelfHandlingForm):
subnet_id = forms.ChoiceField(label=_("Subnet"))
ip_address = fields.IPField(
ip_address = forms.IPField(
label=_("IP Address (optional)"), required=False, initial="",
help_text=_("You can specify an IP address of the interface "
"created if you want (e.g. 192.168.0.254)."),
version=fields.IPv4 | fields.IPv6, mask=False)
version=forms.IPv4 | forms.IPv6, mask=False)
router_name = forms.CharField(label=_("Router Name"),
widget=forms.TextInput(
attrs={'readonly': 'readonly'}))

View File

@@ -28,7 +28,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import fields
from horizon.utils import functions
from horizon.utils.memoized import memoized # noqa
@@ -55,21 +54,21 @@ class CreateForm(forms.SelfHandlingForm):
'data-slug': 'source'}))
snapshot_source = forms.ChoiceField(
label=_("Use snapshot as a source"),
widget=fields.SelectWidget(
widget=forms.SelectWidget(
attrs={'class': 'snapshot-selector'},
data_attrs=('size', 'name'),
transform=lambda x: "%s (%sGB)" % (x.name, x.size)),
required=False)
image_source = forms.ChoiceField(
label=_("Use image as a source"),
widget=fields.SelectWidget(
widget=forms.SelectWidget(
attrs={'class': 'image-selector'},
data_attrs=('size', 'name', 'min_disk'),
transform=lambda x: "%s (%s)" % (x.name, filesizeformat(x.bytes))),
required=False)
volume_source = forms.ChoiceField(
label=_("Use a volume as source"),
widget=fields.SelectWidget(
widget=forms.SelectWidget(
attrs={'class': 'image-selector'},
data_attrs=('size', 'name'),
transform=lambda x: "%s (%s)" % (x.name,

View File

@@ -24,7 +24,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import fields
from openstack_dashboard import api
@@ -211,25 +210,25 @@ class UpdateIPSecSiteConnection(forms.SelfHandlingForm):
widget=forms.TextInput(attrs={'readonly': 'readonly'}))
description = forms.CharField(
required=False, max_length=80, label=_("Description"))
peer_address = fields.IPField(
peer_address = forms.IPField(
label=_("Peer gateway public IPv4/IPv6 Address or FQDN"),
help_text=_("Peer gateway public IPv4/IPv6 address or FQDN for "
"the VPN Connection"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=False)
peer_id = fields.IPField(
peer_id = forms.IPField(
label=_("Peer router identity for authentication (Peer ID)"),
help_text=_("Peer router identity for authentication. "
"Can be IPv4/IPv6 address, e-mail, key ID, or FQDN"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=False)
peer_cidrs = fields.MultiIPField(
peer_cidrs = forms.MultiIPField(
label=_("Remote peer subnet(s)"),
help_text=_("Remote peer subnet(s) address(es) "
"with mask(s) in CIDR format "
"separated with commas if needed "
"(e.g. 20.1.0.0/24, 21.1.0.0/24)"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=True)
psk = forms.CharField(
max_length=80, label=_("Pre-Shared Key (PSK) string"))

View File

@@ -20,7 +20,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon.utils import fields
from horizon import workflows
from openstack_dashboard import api
@@ -316,25 +315,25 @@ class AddIPSecSiteConnectionAction(workflows.Action):
label=_("IKE Policy associated with this connection"))
ipsecpolicy_id = forms.ChoiceField(
label=_("IPSec Policy associated with this connection"))
peer_address = fields.IPField(
peer_address = forms.IPField(
label=_("Peer gateway public IPv4/IPv6 Address or FQDN"),
help_text=_("Peer gateway public IPv4/IPv6 address or FQDN for "
"the VPN Connection"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=False)
peer_id = fields.IPField(
peer_id = forms.IPField(
label=_("Peer router identity for authentication (Peer ID)"),
help_text=_("Peer router identity for authentication. "
"Can be IPv4/IPv6 address, e-mail, key ID, or FQDN"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=False)
peer_cidrs = fields.MultiIPField(
peer_cidrs = forms.MultiIPField(
label=_("Remote peer subnet(s)"),
help_text=_("Remote peer subnet(s) address(es) "
"with mask(s) in CIDR format "
"separated with commas if needed "
"(e.g. 20.1.0.0/24, 21.1.0.0/24)"),
version=fields.IPv4 | fields.IPv6,
version=forms.IPv4 | forms.IPv6,
mask=True)
psk = forms.CharField(max_length=80,
label=_("Pre-Shared Key (PSK) string"))