class UpdateSubnetInfoAction(CreateSubnetInfoAction):
    cidr = fields.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,
        mask=True)
    ipam = forms.DynamicTypedChoiceField(label=_("IPAM"),
                                         required=False,
                                         empty_value=None,
                                         widget=forms.HiddenInput(),
                                         help_text=_(
                                             "Choose IPAM that will be "
                                             "associated with the IP Block"))

    # NOTE(amotoki): When 'disabled' attribute is set for the ChoiceField
    # and ValidationError is raised for POST request, the initial value of
    # the ip_version ChoiceField is not set in the re-displayed form
    # As a result, 'IPv4' is displayed even when IPv6 is used if
    # ValidationError is detected. In addition 'required=True' check complains
    # when re-POST since the value of the ChoiceField is not set.
    # Thus now I use HiddenInput for the ip_version ChoiceField as a work
    # around.
    ip_version = forms.ChoiceField(
        choices=[(4, 'IPv4'), (6, 'IPv6')],
        #widget=forms.Select(
        #    attrs={'disabled': 'disabled'}),
        widget=forms.HiddenInput(),
        label=_("IP Version"))

    gateway_ip = fields.IPField(
        label=_("Gateway IP (optional)"),
        required=False,
        initial="",
        help_text=_("IP address of Gateway (e.g. 192.168.0.254). "
                    "You need to specify an explicit address "
                    "to set the gateway. "
                    "If you want to use no gateway, "
                    "check 'Disable Gateway' below."),
        version=fields.IPv4 | fields.IPv6,
        mask=False)
    no_gateway = forms.BooleanField(label=_("Disable Gateway"),
                                    initial=False,
                                    required=False)

    class Meta:
        name = ("Subnet")
        help_text = _('You can update a subnet associated with the '
                      'network. Advanced configuration are available '
                      'at "Subnet Detail" tab.')

    def clean(self):
        cleaned_data = workflows.Action.clean(self)
        self._check_subnet_data(cleaned_data, is_create=False)
        return cleaned_data
Exemple #2
0
class AssociateIPAction(workflows.Action):
    ip_id = forms.DynamicTypedChoiceField(label=_("IP Address"),
                                          coerce=int,
                                          empty_value=None,
                                          add_item_link=ALLOCATE_URL)
    instance_id = forms.ChoiceField(label=_("Instance"))

    class Meta:
        name = _("IP Address")
        help_text = _("Select the IP address you wish to associate with "
                      "the selected instance.")

    def populate_ip_id_choices(self, request, context):
        try:
            ips = api.nova.tenant_floating_ip_list(self.request)
        except:
            redirect = reverse('horizon:nova:access_and_security:index')
            exceptions.handle(self.request,
                              _('Unable to retrieve floating IP addresses.'),
                              redirect=redirect)
        options = sorted([(ip.id, ip.ip) for ip in ips if not ip.instance_id])
        if options:
            options.insert(0, ("", _("Select an IP address")))
        else:
            options = [("", _("No IP addresses available"))]

        return options

    def populate_instance_id_choices(self, request, context):
        try:
            servers = api.nova.server_list(self.request)
        except:
            redirect = reverse('horizon:nova:access_and_security:index')
            exceptions.handle(self.request,
                              _('Unable to retrieve instance list.'),
                              redirect=redirect)
        instances = []
        for server in servers:
            server_name = "%s (%s)" % (server.name, server.id)
            instances.append((server.id, server_name))

        # Sort instances for easy browsing
        instances = sorted(instances, key=lambda x: x[1])

        if instances:
            instances.insert(0, ("", _("Select an instance")))
        else:
            instances = (("", _("No instances available")), )
        return instances
Exemple #3
0
class AssociateIPAction(workflows.Action):
    ip_id = forms.DynamicTypedChoiceField(label=_("IP Address"),
                                          coerce=get_int_or_uuid,
                                          empty_value=None,
                                          add_item_link=ALLOCATE_URL)
    instance_id = forms.ChoiceField(label=_("Instance"))

    class Meta:
        name = _("IP Address")
        help_text = _("Select the IP address you wish to associate with "
                      "the selected instance.")

    def __init__(self, *args, **kwargs):
        super(AssociateIPAction, self).__init__(*args, **kwargs)
        if api.base.is_service_enabled(self.request, 'network'):
            label = _("Port to be associated")
        else:
            label = _("Instance to be associated")
        self.fields['instance_id'].label = label

        # If AssociateIP is invoked from instance menu, instance_id parameter
        # is passed in URL. In Neutron based Floating IP implementation
        # an association target is not an instance but a port, so we need
        # to get an association target based on a received instance_id
        # and set the initial value of instance_id ChoiceField.
        q_instance_id = self.request.GET.get('instance_id')
        if q_instance_id:
            target_id = api.network.floating_ip_target_get_by_instance(
                self.request, q_instance_id)
            self.initial['instance_id'] = target_id

    def populate_ip_id_choices(self, request, context):
        try:
            ips = api.network.tenant_floating_ip_list(self.request)
        except:
            redirect = reverse('horizon:project:access_and_security:index')
            exceptions.handle(self.request,
                              _('Unable to retrieve floating IP addresses.'),
                              redirect=redirect)
        options = sorted([(ip.id, ip.ip) for ip in ips if not ip.port_id])
        if options:
            options.insert(0, ("", _("Select an IP address")))
        else:
            options = [("", _("No IP addresses available"))]

        return options

    def populate_instance_id_choices(self, request, context):
        try:
            targets = api.network.floating_ip_target_list(self.request)
        except:
            redirect = reverse('horizon:project:access_and_security:index')
            exceptions.handle(self.request,
                              _('Unable to retrieve instance list.'),
                              redirect=redirect)
        instances = []
        for target in targets:
            instances.append((target.id, target.name))

        # Sort instances for easy browsing
        instances = sorted(instances, key=lambda x: x[1])

        neutron_enabled = api.base.is_service_enabled(request, 'network')
        if instances:
            if neutron_enabled:
                label = _("Select a port")
            else:
                label = _("Select an instance")
            instances.insert(0, ("", label))
        else:
            if neutron_enabled:
                label = _("No ports available")
            else:
                label = _("No instances available")
            instances = (("", label),)
        return instances
class CreateSubnetInfoAction(workflows.Action):
    subnet_name = forms.CharField(max_length=255,
                                  widget=forms.TextInput(attrs={
                                  }),
                                  label=_("Subnet Name"),
                                  required=False)

    ipam = forms.DynamicTypedChoiceField(label=_("IPAM"),
                                         required=False,
                                         empty_value=None,
                                         add_item_link=IPAM_CREATE_URL,
                                         help_text=_("Choose IPAM that will be "
                                                     "associated with the IP Block"))

    address_source = forms.ChoiceField(
        required=False,
        label=_('Network Address Source'),
        choices=[('manual', _('Enter Network Address manually')),
                 ('subnetpool', _('Allocate Network Address from a pool'))],
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'data-slug': 'source',
        }))

    subnetpool = forms.ChoiceField(
        label=_("Address pool"),
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switched switchable',
            'data-slug': 'subnetpool',
            'data-switch-on': 'source',
            'data-source-subnetpool': _('Address pool')},
            data_attrs=('name', 'prefixes',
                        'ip_version',
                        'min_prefixlen',
                        'max_prefixlen',
                        'default_prefixlen'),
            transform=lambda x: "%s (%s)" % (x.name, ", ".join(x.prefixes))
                                if 'prefixes' in x else "%s" % (x.name)),
        required=False)

    prefixlen = forms.ChoiceField(widget=forms.ThemableSelectWidget(attrs={
                                  'class': 'switched',
                                  'data-switch-on': 'subnetpool',
                                  }),
                                  label=_('Network Mask'),
                                  required=False)

    cidr = forms.IPField(label=_("Network Address"),
                         required=False,
                         initial="",
                         widget=forms.TextInput(attrs={
                             'class': 'switched',
                             'data-switch-on': 'source',
                             'data-source-manual': _("Network Address"),
                         }),
                         help_text=_("Network address in CIDR format "
                                     "(e.g. 192.168.0.0/24, 2001:DB8::/48)"),
                         version=forms.IPv4 | forms.IPv6,
                         mask=True)
    ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
                                   widget=forms.ThemableSelectWidget(attrs={
                                       'class': 'switchable',
                                       'data-slug': 'ipversion',
                                   }),
                                   label=_("IP Version"),
                                   required=False)
    gateway_ip = forms.IPField(
        label=_("Gateway IP"),
        widget=forms.TextInput(attrs={
            'class': 'switched',
            'data-switch-on': 'gateway_ip',
            'data-source-manual': _("Gateway IP")
        }),
        required=False,
        initial="",
        help_text=_("IP address of Gateway (e.g. 192.168.0.254) "
                    "The default value is the first IP of the "
                    "network address "
                    "(e.g. 192.168.0.1 for 192.168.0.0/24, "
                    "2001:DB8::1 for 2001:DB8::/48). "
                    "If you use the default, leave blank. "
                    "If you do not want to use a gateway, "
                    "check 'Disable Gateway' below."),
        version=forms.IPv4 | forms.IPv6,
        mask=False)
    no_gateway = forms.BooleanField(label=_("Disable Gateway"),
                                    widget=forms.CheckboxInput(attrs={
                                        'class': 'switchable',
                                        'data-slug': 'gateway_ip',
                                        'data-hide-on-checked': 'true'
                                    }),
                                    initial=False,
                                    required=False)

    check_subnet_range = True

    class Meta(object):
        name = _("Subnet")
        help_text = _('Creates a subnet associated with the network.'
                      ' You need to enter a valid "Network Address"'
                      ' and "Gateway IP". If you did not enter the'
                      ' "Gateway IP", the first value of a network'
                      ' will be assigned by default. If you do not want'
                      ' gateway please check the "Disable Gateway" checkbox.'
                      ' Advanced configuration is available by clicking on'
                      ' the "Subnet Details" tab.')

    def __init__(self, request, context, *args, **kwargs):
        super(CreateSubnetInfoAction, self).__init__(request, context, *args,
                                                     **kwargs)
        if 'with_subnet' in context:
            self.fields['with_subnet'] = forms.BooleanField(
                initial=context['with_subnet'],
                required=False,
                widget=forms.HiddenInput()
            )

        if not getattr(settings, 'OPENSTACK_NEUTRON_NETWORK',
                       {}).get('enable_ipv6', True):
            self.fields['ip_version'].widget = forms.HiddenInput()
            self.fields['ip_version'].initial = 4

        try:
            if api.neutron.is_extension_supported(request,
                                                  'subnet_allocation'):
                self.fields['subnetpool'].choices = \
                    self.get_subnetpool_choices(request)
            else:
                self.hide_subnetpool_choices()
        except Exception:
            self.hide_subnetpool_choices()
            msg = _('Unable to initialize subnetpools')
            exceptions.handle(request, msg)
        if len(self.fields['subnetpool'].choices) > 1:
            # Pre-populate prefixlen choices to satisfy Django
            # ChoiceField Validation. This is overridden w/data from
            # subnetpool on select.
            self.fields['prefixlen'].choices = \
                zip(list(range(0, 128 + 1)),
                    list(range(0, 128 + 1)))
            # Populate data-fields for switching the prefixlen field
            # when user selects a subnetpool other than
            # "Provider default pool"
            for (id, name) in self.fields['subnetpool'].choices:
                if not len(id):
                    continue
                key = 'data-subnetpool-' + id
                self.fields['prefixlen'].widget.attrs[key] = \
                    _('Network Mask')
        else:
            self.hide_subnetpool_choices()

        # Create IPAM choices
        tenant_id = self.request.user.tenant_id
        try:
            ipams = ipam_summary(self.request)
            if ipams:
                ipam_choices = [(ipam.id, "{0} ({1})".format(ipam.fq_name[2], ipam.fq_name[1]))
                                for ipam
                                in ipams]
                ipam_choices.append(('None', 'None'))
            else:
                ipam_choices = [('None', 'Create a new IPAM')]
        except:
            ipam_choices = [('None', 'None')]
            exceptions.handle(self.request, _('Unable to retrieve ipam list'))
        self.fields['ipam'].choices = ipam_choices

    def get_subnetpool_choices(self, request):
        subnetpool_choices = [('', _('Select a pool'))]

        for subnetpool in api.neutron.subnetpool_list(request):
            subnetpool_choices.append((subnetpool.id, subnetpool))
        return subnetpool_choices

    def hide_subnetpool_choices(self):
        self.fields['address_source'].widget = forms.HiddenInput()
        self.fields['subnetpool'].choices = []
        self.fields['subnetpool'].widget = forms.HiddenInput()
        self.fields['prefixlen'].widget = forms.HiddenInput()

    def _check_subnet_range(self, subnet, allow_cidr):
        allowed_net = netaddr.IPNetwork(allow_cidr)
        return subnet in allowed_net

    def _check_cidr_allowed(self, ip_version, subnet):
        if not self.check_subnet_range:
            return

        allowed_cidr = getattr(settings, "ALLOWED_PRIVATE_SUBNET_CIDR", {})
        version_str = 'ipv%s' % ip_version
        allowed_ranges = allowed_cidr.get(version_str, [])
        if allowed_ranges:
            under_range = any(self._check_subnet_range(subnet, allowed_range)
                              for allowed_range in allowed_ranges)
            if not under_range:
                range_str = ', '.join(allowed_ranges)
                msg = (_("CIDRs allowed for user private %(ip_ver)s "
                         "networks are %(allowed)s.") %
                       {'ip_ver': '%s' % version_str,
                        'allowed': range_str})
                raise forms.ValidationError(msg)

    def _check_subnet_data(self, cleaned_data, is_create=True):
        cidr = cleaned_data.get('cidr')
        ipam = cleaned_data.get('ipam')
        ip_version = int(cleaned_data.get('ip_version'))
        gateway_ip = cleaned_data.get('gateway_ip')
        no_gateway = cleaned_data.get('no_gateway')
        address_source = cleaned_data.get('address_source')
        subnetpool = cleaned_data.get('subnetpool')

        if not subnetpool and address_source == 'subnetpool':
            msg = _('Specify "Address pool" or select '
                    '"Enter Network Address manually" and specify '
                    '"Network Address".')
            raise forms.ValidationError(msg)
        if not cidr and address_source != 'subnetpool':
            msg = _('Specify "Network Address" or '
                    'clear "Create Subnet" checkbox in previous step.')
            raise forms.ValidationError(msg)
        if cidr:
            subnet = netaddr.IPNetwork(cidr)
            if subnet.version != ip_version:
                msg = _('Network Address and IP version are inconsistent.')
                raise forms.ValidationError(msg)
            if (ip_version == 4 and subnet.prefixlen == 32) or \
                    (ip_version == 6 and subnet.prefixlen == 128):
                msg = _("The subnet in the Network Address is "
                        "too small (/%s).") % subnet.prefixlen
                self._errors['cidr'] = self.error_class([msg])
            self._check_cidr_allowed(ip_version, subnet)

        if not no_gateway and gateway_ip:
            if netaddr.IPAddress(gateway_ip).version is not ip_version:
                msg = _('Gateway IP and IP version are inconsistent.')
                raise forms.ValidationError(msg)
        if not is_create and not no_gateway and not gateway_ip:
            msg = _('Specify IP address of gateway or '
                    'check "Disable Gateway" checkbox.')
            raise forms.ValidationError(msg)

    def clean(self):
        cleaned_data = super(CreateSubnetInfoAction, self).clean()
        with_subnet = cleaned_data.get('with_subnet')
        if not with_subnet:
            return cleaned_data
        self._check_subnet_data(cleaned_data)
        return cleaned_data
Exemple #5
0
class CreateSubnetInfoAction(workflows.Action):
    with_subnet = forms.BooleanField(label=_("Create Subnet"),
                                     initial=True,
                                     required=False)
    subnet_name = forms.CharField(max_length=255,
                                  label=_("Subnet Name"),
                                  required=False)
    ipam = forms.DynamicTypedChoiceField(label=_("IPAM"),
                                         required=False,
                                         empty_value=None,
                                         add_item_link=IPAM_CREATE_URL,
                                         help_text=_(
                                             "Choose IPAM that will be "
                                             "associated with the IP Block"))
    cidr = fields.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,
                          mask=True)
    ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
                                   label=_("IP Version"))
    gateway_ip = fields.IPField(
        label=_("Gateway IP"),
        required=False,
        initial="",
        help_text=_("IP address of Gateway (e.g. 192.168.0.254) "
                    "The default value is the first IP of the "
                    "network address (e.g. 192.168.0.1 for "
                    "192.168.0.0/24). "
                    "If you use the default, leave blank. "
                    "If you want to use no gateway, "
                    "check 'Disable Gateway' below."),
        version=fields.IPv4,
        mask=False)
    no_gateway = forms.BooleanField(label=_("Disable Gateway"),
                                    initial=False,
                                    required=False)

    def __init__(self, request, *args, **kwargs):
        super(CreateSubnetInfoAction, self).__init__(request, *args, **kwargs)
        tenant_id = self.request.user.tenant_id
        try:
            ipams = ipam_summary(self.request)
            if ipams:
                ipam_choices = [(ipam.id,
                                 "{0} ({1})".format(ipam.fq_name[2],
                                                    ipam.fq_name[1]))
                                for ipam in ipams]
                ipam_choices.append(('None', 'None'))
            else:
                ipam_choices = [('None', 'Create a new IPAM')]
        except:
            ipam_choices = [('None', 'None')]
            exceptions.handle(self.request, _('Unable to retrieve ipam list'))
        self.fields['ipam'].choices = ipam_choices

    class Meta:
        name = _("Subnet")
        help_text = _('You can create a subnet associated with the new '
                      'network, in which case "Network Address" must be '
                      'specified. If you wish to create a network WITHOUT a '
                      'subnet, uncheck the "Create Subnet" checkbox.')

    def _check_subnet_data(self, cleaned_data, is_create=True):
        cidr = cleaned_data.get('cidr')
        ipam = cleaned_data.get('ipam')
        ip_version = int(cleaned_data.get('ip_version'))
        gateway_ip = cleaned_data.get('gateway_ip')
        no_gateway = cleaned_data.get('no_gateway')
        if not cidr:
            msg = _('Specify "Network Address" or '
                    'clear "Create Subnet" checkbox.')
            raise forms.ValidationError(msg)
        if cidr:
            subnet = netaddr.IPNetwork(cidr)
            if subnet.version != ip_version:
                msg = _('Network Address and IP version are inconsistent.')
                raise forms.ValidationError(msg)
            if (ip_version == 4 and subnet.prefixlen == 32) or \
                    (ip_version == 6 and subnet.prefixlen == 128):
                msg = _(
                    "The subnet in the Network Address is too small (/%s)." %
                    subnet.prefixlen)
                raise forms.ValidationError(msg)
        if not no_gateway and gateway_ip:
            if netaddr.IPAddress(gateway_ip).version is not ip_version:
                msg = _('Gateway IP and IP version are inconsistent.')
                raise forms.ValidationError(msg)
        if not is_create and not no_gateway and not gateway_ip:
            msg = _('Specify IP address of gateway or '
                    'check "Disable Gateway".')
            raise forms.ValidationError(msg)

    def clean(self):
        cleaned_data = super(CreateSubnetInfoAction, self).clean()
        with_subnet = cleaned_data.get('with_subnet')
        if not with_subnet:
            return cleaned_data
        self._check_subnet_data(cleaned_data)
        return cleaned_data