예제 #1
0
class UpdateIpam(forms.SelfHandlingForm):
    id = forms.CharField(widget=forms.HiddenInput())
    name = forms.CharField(label=_("Name"),
                           widget=forms.TextInput(
                                      attrs={'readonly': 'readonly'}),
                           validators=[validators.validate_slug])

    dnsmethod = forms.ChoiceField(label=_('DNS Method'),
                               choices=[('default', _('Default')),
                                        ('vdns', _('Virtual DNS')),
                                        ('tenantdns', _('Tenant DNS')),
                                        ('none', _('None'))],
                               widget=forms.Select(attrs={
                                   'class': 'switchable',
                                   'data-slug': 'dnsmethod'}))

    vdns = forms.CharField(label=_("Virtual DNS"),
                          required=False,
                          help_text=_("FQ Name of Virtual DNS i.e. default-domain:vdns"),
                          widget=forms.TextInput(
                              attrs={'class': 'switched',
                                     'data-switch-on': 'dnsmethod',
                                     'data-dnsmethod-vdns': _('Virtual DNS')}))

    tenantdns = fields.IPField(label=_("Tenant DNS Server IP"),
                          required=False,
                          help_text=_("Tenant managed DNS Server's IP Address"),
                          version=fields.IPv4,
                          mask=False,
                          widget=forms.TextInput(
                              attrs={'class': 'switched',
                                     'data-switch-on': 'dnsmethod',
                                     'data-dnsmethod-tenantdns': _('Tenant DNS Server IP')}))

    ntpip = fields.IPField(label=_("NTP Server IP"),
                          required=False,
                          help_text=_("IP Address of the NTP Server"),
                          version=fields.IPv4,
                          mask=False,
                          widget=forms.TextInput())

    domainname = forms.CharField(label=_("Domain Name"),
                          required=False,
                          help_text=_("Domain Name i.e. openstack.org"),
                          widget=forms.TextInput())

    def __init__(self, *args, **kwargs):
        ipam_obj = kwargs.pop('ipam_obj', {})
        mgmt = ipam_obj.__dict__['_apidict']['mgmt']
        super(UpdateIpam, self).__init__(*args, **kwargs)
        if mgmt['ipam_dns_method'] == 'default-dns-server':
            self.fields['dnsmethod'].initial = 'default'

        if mgmt['ipam_dns_method'] == 'tenant-dns-server':
            self.fields['dnsmethod'].initial = 'tenantdns'
            if 'ipam_dns_server' in mgmt and \
                'tenant_dns_server_address' in mgmt['ipam_dns_server'] and \
                'ip_address' in mgmt['ipam_dns_server']['tenant_dns_server_address'] :
                for ip in mgmt['ipam_dns_server']['tenant_dns_server_address']['ip_address']:
                    self.fields['tenantdns'].initial = ip

        if mgmt['ipam_dns_method'] == 'virtual-dns-server':
            self.fields['dnsmethod'].initial = 'vdns'
            if 'ipam_dns_server' in mgmt and \
                'virtual_dns_server_name' in mgmt['ipam_dns_server'] and \
                mgmt['ipam_dns_server']['virtual_dns_server_name'] != None :
                self.fields['vdns'].initial = mgmt['ipam_dns_server']['virtual_dns_server_name'] 

        if mgmt['ipam_dns_method'] == 'none':
            self.fields['dnsmethod'].initial = 'none'

        if 'dhcp_option_list' in mgmt:
            dhcp_list = mgmt['dhcp_option_list']
            if dhcp_list and 'dhcp_option' in dhcp_list:
                for entry in mgmt['dhcp_option_list']['dhcp_option']:
                    if entry['dhcp_option_name'] == '4':
                        self.fields['ntpip'].initial = entry['dhcp_option_value']
                    if entry['dhcp_option_name'] == '15':
                        self.fields['domainname'].initial = entry['dhcp_option_value']

    def clean(self):
        cleaned_data = super(UpdateIpam, self).clean()
        name       = cleaned_data.get("name")
        dnsmethod  = cleaned_data.get("dnsmethod")
        vdns       = cleaned_data.get("vdns")
        tenantdns  = cleaned_data.get("tenantdns")
        ntpip      = cleaned_data.get("ntpip")
        domainname = cleaned_data.get("domainname")

        if dnsmethod == 'vdns' and not len(vdns):
            msg = _('Virtual DNS : Enter a valid Virtual DNS in FQN format')
            raise ValidationError(msg)

        if dnsmethod == 'tenantdns':
            if not tenantdns:
                msg = _('Tenant DNS Server IP : Enter Tenant DNS Server IP address')
                raise ValidationError(msg)
            elif not len(tenantdns):
                msg = _('Tenant DNS Server IP : Enter Tenant DNS Server IP address')
                raise ValidationError(msg)

        return cleaned_data

    def handle(self, request, data):
        params = {'mgmt': {'ipam_method': None,
                           'dhcp_option_list': {'dhcp_option':[]}}}

        if data['domainname']:
            params['mgmt']['dhcp_option_list']['dhcp_option'].append(
                                                {'dhcp_option_name': '15',
                                                 'dhcp_option_value':
                                                  data['domainname']})

        if data['ntpip']:
            params['mgmt']['dhcp_option_list']['dhcp_option'].append(
                                                {'dhcp_option_name': '4',
                                                 'dhcp_option_value':
                                                  data['ntpip']})

        params['mgmt']['ipam_dns_server'] = {}
        params['mgmt']['ipam_dns_server']['tenant_dns_server_address'] = {}
        params['mgmt']['ipam_dns_server']['virtual_dns_server_name'] = None

        if data['dnsmethod'] == 'default':
            params['mgmt']['ipam_dns_method'] = 'default-dns-server'

        if data['dnsmethod'] == 'none':
            params['mgmt']['ipam_dns_method'] = 'none'

        if data['dnsmethod'] == 'tenantdns':
            params['mgmt']['ipam_dns_method'] = 'tenant-dns-server'
            if data['tenantdns']:
                params['mgmt']['ipam_dns_server']['tenant_dns_server_address']['ip_address'] = []
                params['mgmt']['ipam_dns_server']['tenant_dns_server_address']['ip_address'].append(data['tenantdns'])
            
        if data['dnsmethod'] == 'vdns':
            params['mgmt']['ipam_dns_method'] = 'virtual-dns-server'
            params['mgmt']['ipam_dns_server']['virtual_dns_server_name'] = data['vdns']

        try:
            ipam = ipam_modify(request, ipam_id=data['id'], **params)
            messages.success(request,
                             _('Successfully updated network ipam: %s')
                               % data['name'])
            return ipam 
        except Exception:
            redirect = reverse("horizon:project:networking:index")
            exceptions.handle(request,
                              _('Unable to update network ipam.'),
                              redirect=redirect)
예제 #2
0
파일: workflows.py 프로젝트: starlingx/gui
class AddHostInfoAction(workflows.Action):
    FIELD_LABEL_PERSONALITY = _("Personality")
    FIELD_LABEL_HOSTNAME = _("Host Name")
    FIELD_LABEL_MGMT_MAC = _("Management MAC Address")
    FIELD_LABEL_MGMT_IP = _("Management IP Address")

    personality = forms.ChoiceField(
        label=FIELD_LABEL_PERSONALITY,
        help_text=_("Host Personality"),
        choices=PERSONALITY_CHOICES,
        widget=forms.Select(attrs={
            'class': 'switchable',
            'data-slug': 'personality'
        }))

    subfunctions = forms.ChoiceField(
        label=FIELD_LABEL_PERFORMANCE_PROFILE,
        choices=PERFORMANCE_CHOICES,
        widget=forms.Select(
            attrs={
                'class':
                'switched',
                'data-switch-on':
                'personality',
                'data-personality-' + stx_api.sysinv.PERSONALITY_WORKER:
                _("Personality Sub-Type")
            }))

    hostname = forms.RegexField(
        label=FIELD_LABEL_HOSTNAME,
        max_length=255,
        required=False,
        regex=r'^[\w\.\-]+$',
        error_messages={
            'invalid':
            _('Name may only contain letters,'
              ' numbers, underscores, '
              'periods and hyphens.')
        },
        widget=forms.TextInput(
            attrs={
                'class':
                'switched',
                'data-switch-on':
                'personality',
                'data-personality-' + stx_api.sysinv.PERSONALITY_WORKER:
                FIELD_LABEL_HOSTNAME,
            }))

    mgmt_mac = forms.MACAddressField(
        label=FIELD_LABEL_MGMT_MAC,
        widget=forms.TextInput(
            attrs={
                'class':
                'switched',
                'data-switch-on':
                'personality',
                'data-personality-' + stx_api.sysinv.PERSONALITY_WORKER:
                FIELD_LABEL_MGMT_MAC,
                'data-personality-' + stx_api.sysinv.PERSONALITY_CONTROLLER:
                FIELD_LABEL_MGMT_MAC,
                'data-personality-' + stx_api.sysinv.PERSONALITY_STORAGE:
                FIELD_LABEL_MGMT_MAC,
            }))

    class Meta(object):
        name = _("Host Info")
        help_text = _(
            "From here you can add the configuration for a new host.")

    def __init__(self, request, *arg, **kwargs):
        super(AddHostInfoAction, self).__init__(request, *arg, **kwargs)

        # pesonality cannot be storage if ceph is not configured
        storage_backend = stx_api.sysinv.get_storage_backend(request)
        if stx_api.sysinv.STORAGE_BACKEND_CEPH not in storage_backend:
            self.fields['personality'].choices = \
                PERSONALITY_CHOICES_WITHOUT_STORAGE

        # All-in-one system, personality can be controller or worker.
        systems = stx_api.sysinv.system_list(request)
        system_type = systems[0].to_dict().get('system_type')
        if system_type == constants.TS_AIO:
            self.fields['personality'].choices = \
                PERSONALITY_CHOICES_WITHOUT_STORAGE

    def clean(self):
        cleaned_data = super(AddHostInfoAction, self).clean()
        return cleaned_data
예제 #3
0
파일: workflows.py 프로젝트: starlingx/gui
class BoardManagementAction(workflows.Action):

    FIELD_LABEL_BM_IP = _("Board Management Controller IP Address")
    FIELD_LABEL_BM_USERNAME = _("Board Management Controller User Name")
    FIELD_LABEL_BM_PASSWORD = _("Board Management Controller Password")
    FIELD_LABEL_BM_CONFIRM_PASSWORD = _("Confirm Password")

    bm_type = forms.ChoiceField(label=_("Board Management Controller Type "),
                                choices=BM_TYPES_CHOICES,
                                required=False,
                                widget=forms.Select(attrs={
                                    'class': 'switchable',
                                    'data-slug': 'bm_type'
                                }))

    bm_ip = forms.IPField(
        label=FIELD_LABEL_BM_IP,
        required=False,
        help_text=_("IP address of the Board Management Controller"
                    " (e.g. 172.25.0.0)"),
        version=forms.IPv4 | forms.IPv6,
        mask=False,
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'bm_type',
                'data-bm_type-' + sysinv.HOST_BM_TYPE_DYNAMIC:
                FIELD_LABEL_BM_IP,
                'data-bm_type-' + sysinv.HOST_BM_TYPE_IPMI: FIELD_LABEL_BM_IP,
                'data-bm_type-' + sysinv.HOST_BM_TYPE_REDFISH:
                FIELD_LABEL_BM_IP
            }))

    bm_username = forms.CharField(
        label=FIELD_LABEL_BM_USERNAME,
        required=False,
        widget=forms.TextInput(
            attrs={
                'autocomplete':
                'off',
                'class':
                'switched',
                'data-switch-on':
                'bm_type',
                'data-bm_type-' + sysinv.HOST_BM_TYPE_DYNAMIC:
                FIELD_LABEL_BM_USERNAME,
                'data-bm_type-' + sysinv.HOST_BM_TYPE_IPMI:
                FIELD_LABEL_BM_USERNAME,
                'data-bm_type-' + sysinv.HOST_BM_TYPE_REDFISH:
                FIELD_LABEL_BM_USERNAME
            }))

    bm_password = forms.RegexField(
        label=FIELD_LABEL_BM_PASSWORD,
        widget=forms.PasswordInput(
            render_value=False,
            attrs={
                'autocomplete':
                'off',
                'class':
                'switched',
                'data-switch-on':
                'bm_type',
                'data-bm_type-' + sysinv.HOST_BM_TYPE_DYNAMIC:
                FIELD_LABEL_BM_PASSWORD,
                'data-bm_type-' + sysinv.HOST_BM_TYPE_IPMI:
                FIELD_LABEL_BM_PASSWORD,
                'data-bm_type-' + sysinv.HOST_BM_TYPE_REDFISH:
                FIELD_LABEL_BM_PASSWORD
            }),
        regex=validators.password_validator(),
        required=False,
        error_messages={'invalid': validators.password_validator_msg()})

    bm_confirm_password = forms.CharField(
        label=FIELD_LABEL_BM_CONFIRM_PASSWORD,
        widget=forms.PasswordInput(
            render_value=False,
            attrs={
                'autocomplete':
                'off',
                'class':
                'switched',
                'data-switch-on':
                'bm_type',
                'data-bm_type-' + sysinv.HOST_BM_TYPE_DYNAMIC:
                FIELD_LABEL_BM_CONFIRM_PASSWORD,
                'data-bm_type-' + sysinv.HOST_BM_TYPE_IPMI:
                FIELD_LABEL_BM_CONFIRM_PASSWORD,
                'data-bm_type-' + sysinv.HOST_BM_TYPE_REDFISH:
                FIELD_LABEL_BM_CONFIRM_PASSWORD
            }),
        required=False)

    def clean(self):
        cleaned_data = super(BoardManagementAction, self).clean()
        if cleaned_data.get('bm_type') != \
                sysinv_const.HOST_BM_TYPE_DEPROVISIONED:
            if 'bm_ip' not in cleaned_data or not cleaned_data['bm_ip']:
                raise forms.ValidationError(
                    _('Board management IP address is required.'))

            if 'bm_username' not in cleaned_data or not \
                    cleaned_data['bm_username']:
                raise forms.ValidationError(
                    _('Board management user name is required.'))

            if 'bm_password' in cleaned_data:
                if cleaned_data['bm_password'] != cleaned_data.get(
                        'bm_confirm_password', None):
                    raise forms.ValidationError(
                        _('Board management passwords do not match.'))
        else:
            cleaned_data.pop('bm_ip')
            cleaned_data.pop('bm_username')

        return cleaned_data

    # We have to protect the entire "data" dict because it contains the
    # password and confirm_password strings.
    @sensitive_variables('data')
    def handle(self, request, data):
        # Throw away the password confirmation, we're done with it.
        data.pop('bm_confirm_password', None)
예제 #4
0
class JobBinaryCreateForm(forms.SelfHandlingForm):
    NEW_SCRIPT = "%%%NEWSCRIPT%%%"
    UPLOAD_BIN = "%%%UPLOADFILE%%%"

    job_binary_name = forms.CharField(label=_("Name"), required=True)

    job_binary_type = forms.ChoiceField(label=_("Storage type"), required=True)

    job_binary_url = forms.CharField(label=_("URL"),
                                     required=False,
                                     widget=LabeledInput())
    job_binary_internal = forms.ChoiceField(label=_("Internal binary"),
                                            required=False)

    job_binary_file = forms.FileField(label=_("Upload File"), required=False)

    job_binary_script_name = forms.CharField(label=_("Script name"),
                                             required=False)

    job_binary_script = forms.CharField(label=_("Script text"),
                                        required=False,
                                        widget=forms.Textarea())

    job_binary_username = forms.CharField(label=_("Username"), required=False)

    job_binary_password = forms.CharField(
        label=_("Password"),
        required=False,
        widget=forms.PasswordInput(attrs={'autocomplete': 'off'}))

    job_binary_description = forms.CharField(label=_("Description"),
                                             required=False,
                                             widget=forms.Textarea())

    def __init__(self, request, *args, **kwargs):
        super(JobBinaryCreateForm, self).__init__(request, *args, **kwargs)

        self.help_text_template = "job_binaries/_create_job_binary_help.html"

        self.fields["job_binary_type"].choices =\
            [("internal-db", "Internal database"),
             ("swift", "Swift")]

        self.fields["job_binary_internal"].choices =\
            self.populate_job_binary_internal_choices(request)

    def populate_job_binary_internal_choices(self, request):
        sahara = saharaclient.client(request)
        job_binaries = sahara.job_binary_internals.list()

        choices = [(job_binary.id, job_binary.name)
                   for job_binary in job_binaries]
        choices.insert(0, (self.NEW_SCRIPT, '*Create a script'))
        choices.insert(0, (self.UPLOAD_BIN, '*Upload a new file'))

        return choices

    def handle(self, request, context):
        try:
            sahara = saharaclient.client(request)
            extra = {}
            bin_url = "%s://%s" % (context["job_binary_type"],
                                   context["job_binary_url"])
            if (context["job_binary_type"] == "internal-db"):
                bin_url = self.handle_internal(request, context)
            elif (context["job_binary_type"] == "swift"):
                extra = self.handle_swift(request, context)

            sahara.job_binaries.create(context["job_binary_name"], bin_url,
                                       context["job_binary_description"],
                                       extra)
            messages.success(request, "Successfully created job binary")
            return True
        except api_base.APIException as e:
            messages.error(request, str(e))
            return False
        except Exception as e:
            messages.error(request, str(e))
            return False

    def get_help_text(self, extra_context=None):
        text = ""
        extra_context = extra_context or {}
        if self.help_text_template:
            tmpl = template.loader.get_template(self.help_text_template)
            context = template.RequestContext(self.request, extra_context)
            text += tmpl.render(context)
        else:
            text += linebreaks(force_unicode(self.help_text))
        return safe(text)

    class Meta:
        name = _("Create Job Binary")
        help_text_template = \
            ("job_binaries/_create_job_binary_help.html")

    def handle_internal(self, request, context):
        result = ""
        sahara = saharaclient.client(request)

        bin_id = context["job_binary_internal"]
        if (bin_id == self.UPLOAD_BIN):
            result = sahara.job_binary_internals.create(
                self.get_unique_binary_name(
                    request, request.FILES["job_binary_file"].name),
                request.FILES["job_binary_file"].read())
        elif (bin_id == self.NEW_SCRIPT):
            result = sahara.job_binary_internals.create(
                self.get_unique_binary_name(request,
                                            context["job_binary_script_name"]),
                context["job_binary_script"])

        bin_id = result.id
        return "internal-db://%s" % bin_id

    def handle_swift(self, request, context):
        username = context["job_binary_username"]
        password = context["job_binary_password"]

        extra = {"user": username, "password": password}
        return extra

    def get_unique_binary_name(self, request, base_name):
        sahara = saharaclient.client(request)
        internals = sahara.job_binary_internals.list()
        names = [internal.name for internal in internals]
        if base_name in names:
            return "%s_%s" % (base_name, uuid.uuid1())
        return base_name
예제 #5
0
파일: forms.py 프로젝트: tliu88/stx-horizon
class AttachForm(forms.SelfHandlingForm):
    instance = forms.ChoiceField(label=_("Attach to Server Group"),
                                 help_text=_("Select an server group to "
                                             "attach to."))
    device = forms.CharField(label=_("Device Name"))

    def __init__(self, *args, **kwargs):
        super(AttachForm, self).__init__(*args, **kwargs)

        # Hide the device field if the hypervisor doesn't support it.
        hypervisor_features = getattr(settings,
                                      "OPENSTACK_HYPERVISOR_FEATURES", {})
        can_set_mount_point = hypervisor_features.get("can_set_mount_point",
                                                      True)
        if not can_set_mount_point:
            self.fields['device'].widget = forms.widgets.HiddenInput()
            self.fields['device'].required = False

        # populate volume_id
        volume = kwargs.get('initial', {}).get("volume", None)
        if volume:
            volume_id = volume.id
        else:
            volume_id = None
        self.fields['volume_id'] = forms.CharField(widget=forms.HiddenInput(),
                                                   initial=volume_id)

        # Populate instance choices
        instance_list = kwargs.get('initial', {}).get('instances', [])
        instances = []
        for instance in instance_list:
            if instance.status in tables.ACTIVE_STATES and \
                    not any(instance.id == att["server_id"]
                            for att in volume.attachments):
                instances.append(
                    (instance.id, '%s (%s)' % (instance.name, instance.id)))
        if instances:
            instances.insert(0, ("", _("Select an instance")))
        else:
            instances = (("", _("No instances available")), )
        self.fields['instance'].choices = instances

    def handle(self, request, data):
        instance_choices = dict(self.fields['instance'].choices)
        instance_name = instance_choices.get(data['instance'],
                                             _("Unknown instance (None)"))
        # The name of the instance in the choices list has the ID appended to
        # it, so let's slice that off...
        instance_name = instance_name.rsplit(" (")[0]
        try:
            attach = api.nova.instance_volume_attach(request,
                                                     data['volume_id'],
                                                     data['instance'],
                                                     data.get('device', ''))
            volume = cinder.volume_get(request, data['volume_id'])
            if not volume.display_name:
                volume_name = volume.id
            else:
                volume_name = volume.display_name
            message = _('Attaching volume %(vol)s to instance '
                        '%(inst)s on %(dev)s.') % {
                            "vol": volume_name,
                            "inst": instance_name,
                            "dev": attach.device
                        }
            messages.info(request, message)
            return True
        except Exception:
            redirect = reverse("horizon:project:volumes:index")
            exceptions.handle(request,
                              _('Unable to attach volume.'),
                              redirect=redirect)
예제 #6
0
class SetInstanceDetailsAction(workflows.Action):
    availability_zone = forms.ThemableChoiceField(label=_("Availability Zone"),
                                                  required=False)

    name = forms.CharField(label=_("Instance Name"),
                           max_length=255)

    flavor = forms.ThemableChoiceField(label=_("Flavor"),
                                       help_text=_("Size of image to launch."))

    count = forms.IntegerField(label=_("Number of Instances"),
                               min_value=1,
                               initial=1)

    source_type = forms.ThemableChoiceField(
        label=_("Instance Boot Source"),
        help_text=_("Choose Your Boot Source "
                    "Type."))

    instance_snapshot_id = forms.ThemableChoiceField(
        label=_("Instance Snapshot"),
        required=False)

    volume_id = forms.ThemableChoiceField(label=_("Volume"), required=False)

    volume_snapshot_id = forms.ThemableChoiceField(label=_("Volume Snapshot"),
                                                   required=False)

    image_id = forms.ChoiceField(
        label=_("Image Name"),
        required=False,
        widget=forms.ThemableSelectWidget(
            data_attrs=('volume_size',),
            transform=lambda x: ("%s (%s)" % (x.name,
                                              filesizeformat(x.bytes)))))

    volume_size = forms.IntegerField(label=_("Device size (GB)"),
                                     initial=1,
                                     min_value=0,
                                     required=False,
                                     help_text=_("Volume size in gigabytes "
                                                 "(integer value)."))

    device_name = forms.CharField(label=_("Device Name"),
                                  required=False,
                                  initial="vda",
                                  help_text=_("Volume mount point (e.g. 'vda' "
                                              "mounts at '/dev/vda'). Leave "
                                              "this field blank to let the "
                                              "system choose a device name "
                                              "for you."))

    vol_delete_on_instance_delete = forms.BooleanField(
        label=_("Delete Volume on Instance Delete"),
        initial=False,
        required=False,
        help_text=_("Delete volume when the instance is deleted"))

    class Meta(object):
        name = _("Details")
        help_text_template = ("project/instances/"
                              "_launch_details_help.html")

    def __init__(self, request, context, *args, **kwargs):
        self._init_images_cache()
        self.request = request
        self.context = context
        super(SetInstanceDetailsAction, self).__init__(
            request, context, *args, **kwargs)

        # Hide the device field if the hypervisor doesn't support it.
        if not nova.can_set_mount_point():
            self.fields['device_name'].widget = forms.widgets.HiddenInput()

        source_type_choices = [
            ('', _("Select source")),
            ("image_id", _("Boot from image")),
            ("instance_snapshot_id", _("Boot from snapshot")),
        ]
        if cinder.is_volume_service_enabled(request):
            source_type_choices.append(("volume_id", _("Boot from volume")))

            try:
                if api.nova.extension_supported("BlockDeviceMappingV2Boot",
                                                request):
                    source_type_choices.append(
                        ("volume_image_id",
                         _("Boot from image (creates a new volume)")))
            except Exception:
                exceptions.handle(request, _('Unable to retrieve extensions '
                                             'information.'))

            source_type_choices.append(
                ("volume_snapshot_id",
                 _("Boot from volume snapshot (creates a new volume)")))
        self.fields['source_type'].choices = source_type_choices

    @memoized.memoized_method
    def _get_flavor(self, flavor_id):
        try:
            # We want to retrieve details for a given flavor,
            # however flavor_list uses a memoized decorator
            # so it is used instead of flavor_get to reduce the number
            # of API calls.
            flavors = instance_utils.flavor_list(self.request)
            flavor = [x for x in flavors if x.id == flavor_id][0]
        except IndexError:
            flavor = None
        return flavor

    @memoized.memoized_method
    def _get_image(self, image_id):
        try:
            # We want to retrieve details for a given image,
            # however get_available_images uses a cache of image list,
            # so it is used instead of image_get to reduce the number
            # of API calls.
            images = image_utils.get_available_images(
                self.request,
                self.context.get('project_id'),
                self._images_cache)
            image = [x for x in images if x.id == image_id][0]
        except IndexError:
            image = None
        return image

    def _check_quotas(self, cleaned_data):
        count = cleaned_data.get('count', 1)

        # Prevent launching more instances than the quota allows
        usages = quotas.tenant_quota_usages(
            self.request,
            targets=('instances', 'cores', 'ram', 'volumes', ))
        available_count = usages['instances']['available']
        if available_count < count:
            msg = (_('The requested instance(s) cannot be launched '
                     'as your quota will be exceeded: Available: '
                     '%(avail)s, Requested: %(req)s.')
                   % {'avail': available_count, 'req': count})
            raise forms.ValidationError(msg)

        source_type = cleaned_data.get('source_type')
        if source_type in ('volume_image_id', 'volume_snapshot_id'):
            available_volume = usages['volumes']['available']
            if available_volume < count:
                msg = (_('The requested instance cannot be launched. '
                         'Requested volume exceeds quota: Available: '
                         '%(avail)s, Requested: %(req)s.')
                       % {'avail': available_volume, 'req': count})
                raise forms.ValidationError(msg)

        flavor_id = cleaned_data.get('flavor')
        flavor = self._get_flavor(flavor_id)

        count_error = []
        # Validate cores and ram.
        available_cores = usages['cores']['available']
        if flavor and available_cores < count * flavor.vcpus:
            count_error.append(_("Cores(Available: %(avail)s, "
                                 "Requested: %(req)s)")
                               % {'avail': available_cores,
                                  'req': count * flavor.vcpus})

        available_ram = usages['ram']['available']
        if flavor and available_ram < count * flavor.ram:
            count_error.append(_("RAM(Available: %(avail)s, "
                                 "Requested: %(req)s)")
                               % {'avail': available_ram,
                                  'req': count * flavor.ram})

        if count_error:
            value_str = ", ".join(count_error)
            msg = (_('The requested instance cannot be launched. '
                     'The following requested resource(s) exceed '
                     'quota(s): %s.') % value_str)
            if count == 1:
                self._errors['flavor'] = self.error_class([msg])
            else:
                self._errors['count'] = self.error_class([msg])

    def _check_flavor_for_image(self, cleaned_data):
        # Prevents trying to launch an image needing more resources.
        image_id = cleaned_data.get('image_id')
        image = self._get_image(image_id)
        flavor_id = cleaned_data.get('flavor')
        flavor = self._get_flavor(flavor_id)
        if not image or not flavor:
            return
        props_mapping = (("min_ram", "ram"), ("min_disk", "disk"))
        for iprop, fprop in props_mapping:
            if (getattr(image, iprop) > 0 and
                    getattr(flavor, fprop) > 0 and
                    getattr(image, iprop) > getattr(flavor, fprop)):
                msg = (_("The flavor '%(flavor)s' is too small "
                         "for requested image.\n"
                         "Minimum requirements: "
                         "%(min_ram)s MB of RAM and "
                         "%(min_disk)s GB of Root Disk.") %
                       {'flavor': flavor.name,
                        'min_ram': image.min_ram,
                        'min_disk': image.min_disk})
                self._errors['image_id'] = self.error_class([msg])
                break  # Not necessary to continue the tests.

    def _check_volume_for_image(self, cleaned_data):
        image_id = cleaned_data.get('image_id')
        image = self._get_image(image_id)
        volume_size = cleaned_data.get('volume_size')
        if not image or not volume_size:
            return
        volume_size = int(volume_size)
        img_gigs = functions.bytes_to_gigabytes(image.size)
        smallest_size = max(img_gigs, image.min_disk)
        if volume_size < smallest_size:
            msg = (_("The Volume size is too small for the"
                     " '%(image_name)s' image and has to be"
                     " greater than or equal to "
                     "'%(smallest_size)d' GB.") %
                   {'image_name': image.name,
                    'smallest_size': smallest_size})
            self._errors['volume_size'] = self.error_class([msg])

    def _check_source_image(self, cleaned_data):
        if not cleaned_data.get('image_id'):
            msg = _("You must select an image.")
            self._errors['image_id'] = self.error_class([msg])
        else:
            self._check_flavor_for_image(cleaned_data)

    def _check_source_volume_image(self, cleaned_data):
        volume_size = self.data.get('volume_size', None)
        if not volume_size:
            msg = _("You must set volume size")
            self._errors['volume_size'] = self.error_class([msg])
        if float(volume_size) <= 0:
            msg = _("Volume size must be greater than 0")
            self._errors['volume_size'] = self.error_class([msg])
        if not cleaned_data.get('image_id'):
            msg = _("You must select an image.")
            self._errors['image_id'] = self.error_class([msg])
            return
        else:
            self._check_flavor_for_image(cleaned_data)
            self._check_volume_for_image(cleaned_data)

    def _check_source_instance_snapshot(self, cleaned_data):
        # using the array form of get blows up with KeyError
        # if instance_snapshot_id is nil
        if not cleaned_data.get('instance_snapshot_id'):
            msg = _("You must select a snapshot.")
            self._errors['instance_snapshot_id'] = self.error_class([msg])

    def _check_source_volume(self, cleaned_data):
        if not cleaned_data.get('volume_id'):
            msg = _("You must select a volume.")
            self._errors['volume_id'] = self.error_class([msg])
        # Prevent launching multiple instances with the same volume.
        # TODO(gabriel): is it safe to launch multiple instances with
        # a snapshot since it should be cloned to new volumes?
        count = cleaned_data.get('count', 1)
        if count > 1:
            msg = _('Launching multiple instances is only supported for '
                    'images and instance snapshots.')
            raise forms.ValidationError(msg)

    def _check_source_volume_snapshot(self, cleaned_data):
        if not cleaned_data.get('volume_snapshot_id'):
            msg = _("You must select a snapshot.")
            self._errors['volume_snapshot_id'] = self.error_class([msg])

    def _check_source(self, cleaned_data):
        # Validate our instance source.
        source_type = self.data.get('source_type', None)
        source_check_methods = {
            'image_id': self._check_source_image,
            'volume_image_id': self._check_source_volume_image,
            'instance_snapshot_id': self._check_source_instance_snapshot,
            'volume_id': self._check_source_volume,
            'volume_snapshot_id': self._check_source_volume_snapshot
        }
        check_method = source_check_methods.get(source_type)
        if check_method:
            check_method(cleaned_data)

    def clean(self):
        cleaned_data = super(SetInstanceDetailsAction, self).clean()

        self._check_quotas(cleaned_data)
        self._check_source(cleaned_data)

        return cleaned_data

    def populate_flavor_choices(self, request, context):
        return instance_utils.flavor_field_data(request, False)

    def populate_availability_zone_choices(self, request, context):
        try:
            zones = api.nova.availability_zone_list(request)
        except Exception:
            zones = []
            exceptions.handle(request,
                              _('Unable to retrieve availability zones.'))

        zone_list = [(zone.zoneName, zone.zoneName)
                     for zone in zones if zone.zoneState['available']]
        zone_list.sort()
        if not zone_list:
            zone_list.insert(0, ("", _("No availability zones found")))
        elif len(zone_list) > 1:
            zone_list.insert(0, ("", _("Any Availability Zone")))
        return zone_list

    def get_help_text(self, extra_context=None):
        extra = {} if extra_context is None else dict(extra_context)
        try:
            extra['usages'] = quotas.tenant_limit_usages(self.request)
            extra['usages_json'] = json.dumps(extra['usages'])
            extra['cinder_enabled'] = \
                base.is_service_enabled(self.request, 'volume')
            flavors = json.dumps([f._info for f in
                                  instance_utils.flavor_list(self.request)])
            extra['flavors'] = flavors
            images = image_utils.get_available_images(
                self.request, self.initial['project_id'], self._images_cache)
            if images is not None:
                attrs = [{'id': i.id,
                          'min_disk': getattr(i, 'min_disk', 0),
                          'min_ram': getattr(i, 'min_ram', 0),
                          'size': functions.bytes_to_gigabytes(i.size)}
                         for i in images]
                extra['images'] = json.dumps(attrs)

        except Exception:
            exceptions.handle(self.request,
                              _("Unable to retrieve quota information."))
        return super(SetInstanceDetailsAction, self).get_help_text(extra)

    def _init_images_cache(self):
        if not hasattr(self, '_images_cache'):
            self._images_cache = {}

    def _get_volume_display_name(self, volume):
        if hasattr(volume, "volume_id"):
            vol_type = "snap"
            visible_label = _("Snapshot")
        else:
            vol_type = "vol"
            visible_label = _("Volume")
        return (("%s:%s" % (volume.id, vol_type)),
                (_("%(name)s - %(size)s GB (%(label)s)") %
                 {'name': volume.name,
                  'size': volume.size,
                  'label': visible_label}))

    def populate_image_id_choices(self, request, context):
        choices = []
        images = image_utils.get_available_images(request,
                                                  context.get('project_id'),
                                                  self._images_cache)
        for image in images:
            if image.properties.get("image_type", '') != "snapshot":
                image.bytes = getattr(
                    image, 'virtual_size', None) or image.size
                image.volume_size = max(
                    image.min_disk, functions.bytes_to_gigabytes(image.bytes))
                choices.append((image.id, image))
                if context.get('image_id') == image.id and \
                        'volume_size' not in context:
                    context['volume_size'] = image.volume_size
        if choices:
            choices.sort(key=lambda c: c[1].name or '')
            choices.insert(0, ("", _("Select Image")))
        else:
            choices.insert(0, ("", _("No images available")))
        return choices

    def populate_instance_snapshot_id_choices(self, request, context):
        images = image_utils.get_available_images(request,
                                                  context.get('project_id'),
                                                  self._images_cache)
        choices = [(image.id, image.name)
                   for image in images
                   if image.properties.get("image_type", '') == "snapshot"]
        if choices:
            choices.sort(key=operator.itemgetter(1))
            choices.insert(0, ("", _("Select Instance Snapshot")))
        else:
            choices.insert(0, ("", _("No snapshots available")))
        return choices

    def populate_volume_id_choices(self, request, context):
        volumes = []
        try:
            if cinder.is_volume_service_enabled(request):
                available = api.cinder.VOLUME_STATE_AVAILABLE
                volumes = [self._get_volume_display_name(v)
                           for v in cinder.volume_list(self.request,
                           search_opts=dict(status=available, bootable=True))]
        except Exception:
            exceptions.handle(self.request,
                              _('Unable to retrieve list of volumes.'))
        if volumes:
            volumes.insert(0, ("", _("Select Volume")))
        else:
            volumes.insert(0, ("", _("No volumes available")))
        return volumes

    def populate_volume_snapshot_id_choices(self, request, context):
        snapshots = []
        try:
            if cinder.is_volume_service_enabled(request):
                available = api.cinder.VOLUME_STATE_AVAILABLE
                snapshots = [self._get_volume_display_name(s)
                             for s in cinder.volume_snapshot_list(
                             self.request, search_opts=dict(status=available))]
        except Exception:
            exceptions.handle(self.request,
                              _('Unable to retrieve list of volume '
                                'snapshots.'))
        if snapshots:
            snapshots.insert(0, ("", _("Select Volume Snapshot")))
        else:
            snapshots.insert(0, ("", _("No volume snapshots available")))
        return snapshots
예제 #7
0
class UpdateIPSecSiteConnection(forms.SelfHandlingForm):
    name = forms.CharField(max_length=80, label=_("Name"), required=False)
    ipsecsiteconnection_id = forms.CharField(
        label=_("ID"), widget=forms.TextInput(attrs={'readonly': 'readonly'}))
    description = forms.CharField(required=False,
                                  max_length=80,
                                  label=_("Description"))
    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=forms.IPv4 | forms.IPv6,
        mask=False)
    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=forms.IPv4 | forms.IPv6,
        mask=False)
    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=forms.IPv4 | forms.IPv6,
                                    mask=True)
    psk = forms.CharField(widget=forms.PasswordInput(render_value=True),
                          max_length=80,
                          label=_("Pre-Shared Key (PSK) string"))
    mtu = forms.IntegerField(
        min_value=68,
        required=False,
        label=_("Maximum Transmission Unit size for the connection"),
        help_text=_("Equal to or greater than 68 if the local subnet is IPv4. "
                    "Equal to or greater than 1280 if the local subnet "
                    "is IPv6."))
    dpd_action = forms.ChoiceField(label=_("Dead peer detection actions"),
                                   required=False,
                                   choices=[('hold', _('hold')),
                                            ('clear', _('clear')),
                                            ('disabled', _('disabled')),
                                            ('restart', _('restart')),
                                            ('restart-by-peer',
                                             _('restart-by-peer'))])
    dpd_interval = forms.IntegerField(
        min_value=1,
        required=False,
        label=_("Dead peer detection interval"),
        help_text=_("Valid integer lesser than the DPD timeout"))
    dpd_timeout = forms.IntegerField(
        min_value=1,
        required=False,
        label=_("Dead peer detection timeout"),
        help_text=_("Valid integer greater than the DPD interval"))
    initiator = forms.ChoiceField(label=_("Initiator state"),
                                  required=False,
                                  choices=[
                                      ('bi-directional', _('bi-directional')),
                                      ('response-only', _('response-only'))
                                  ])
    admin_state_up = forms.BooleanField(label=_("Enable Admin State"),
                                        required=False)

    failure_url = 'horizon:project:vpn:index'

    def clean(self):
        cleaned_data = super(UpdateIPSecSiteConnection, self).clean()
        interval = cleaned_data.get('dpd_interval')
        timeout = cleaned_data.get('dpd_timeout')

        if not interval < timeout:
            msg = _("DPD Timeout must be greater than DPD Interval")
            self._errors['dpd_timeout'] = self.error_class([msg])
        return cleaned_data

    def handle(self, request, context):
        try:
            data = {
                'ipsec_site_connection': {
                    'name': context['name'],
                    'description': context['description'],
                    'peer_address': context['peer_address'],
                    'peer_id': context['peer_id'],
                    'peer_cidrs': context['peer_cidrs'].replace(" ",
                                                                "").split(","),
                    'psk': context['psk'],
                    'mtu': context['mtu'],
                    'dpd': {
                        'action': context['dpd_action'],
                        'interval': context['dpd_interval'],
                        'timeout': context['dpd_timeout']
                    },
                    'initiator': context['initiator'],
                    'admin_state_up': context['admin_state_up'],
                }
            }
            ipsecsiteconnection = api.vpn.ipsecsiteconnection_update(
                request, context['ipsecsiteconnection_id'], **data)
            msg = (_('IPSec Site Connection %s was successfully updated.') %
                   context['name'])
            messages.success(request, msg)
            return ipsecsiteconnection
        except Exception as e:
            LOG.info('Failed to update IPSec Site Connection %(id)s: %(exc)s',
                     {
                         'id': context['ipsecsiteconnection_id'],
                         'exc': e
                     })
            msg = (_('Failed to update IPSec Site Connection %s') %
                   context['name'])
            redirect = reverse(self.failure_url)
            exceptions.handle(request, msg, redirect=redirect)
예제 #8
0
class CreateImageForm(forms.SelfHandlingForm):
    name = forms.CharField(max_length="255", label=_("Name"), required=True)
    copy_from = forms.CharField(max_length="255",
                                label=_("Image Location"),
                                help_text=_("An external (HTTP) URL to load "
                                            "the image from."),
                                required=False)
    image_file = forms.FileField(label=_("Image File"),
                                 help_text=("A local image to upload."),
                                 required=False)
    disk_format = forms.ChoiceField(
        label=_('Format'),
        required=True,
        choices=[('', ''), ('aki', _('AKI - Amazon Kernel '
                                     'Image')),
                 ('ami', _('AMI - Amazon Machine '
                           'Image')),
                 ('ari', _('ARI - Amazon Ramdisk '
                           'Image')), ('iso', _('ISO - Optical Disk Image')),
                 ('qcow2', _('QCOW2 - QEMU Emulator')), ('raw', 'Raw'),
                 ('vdi', 'VDI'), ('vhd', 'VHD'), ('vmdk', 'VMDK')],
        widget=forms.Select(attrs={'class': 'switchable'}))
    minimum_disk = forms.IntegerField(label=_("Minimum Disk (GB)"),
                                      help_text=_(
                                          'The minimum disk size'
                                          ' required to boot the'
                                          ' image. If unspecified, this'
                                          ' value defaults to 0'
                                          ' (no minimum).'),
                                      required=False)
    minimum_ram = forms.IntegerField(label=_("Minimum Ram (MB)"),
                                     help_text=_('The minimum disk size'
                                                 ' required to boot the'
                                                 ' image. If unspecified, this'
                                                 ' value defaults to 0 (no'
                                                 ' minimum).'),
                                     required=False)
    is_public = forms.BooleanField(label=_("Public"), required=False)
    protected = forms.BooleanField(label=_("Protected"), required=False)

    def __init__(self, *args, **kwargs):
        super(CreateImageForm, self).__init__(*args, **kwargs)
        if not settings.HORIZON_IMAGES_ALLOW_UPLOAD:
            self.fields['image_file'].widget = HiddenInput()

    def clean(self):
        data = super(CreateImageForm, self).clean()
        if not data['copy_from'] and not data['image_file']:
            raise ValidationError(
                _("A image or external image location must be specified."))
        elif data['copy_from'] and data['image_file']:
            raise ValidationError(
                _("Can not specify both image and external image location."))
        else:
            return data

    def handle(self, request, data):
        # Glance does not really do anything with container_format at the
        # moment. It requires it is set to the same disk_format for the three
        # Amazon image types, otherwise it just treats them as 'bare.' As such
        # we will just set that to be that here instead of bothering the user
        # with asking them for information we can already determine.
        if data['disk_format'] in (
                'ami',
                'aki',
                'ari',
        ):
            container_format = data['disk_format']
        else:
            container_format = 'bare'

        meta = {
            'is_public': data['is_public'],
            'protected': data['protected'],
            'disk_format': data['disk_format'],
            'container_format': container_format,
            'min_disk': (data['minimum_disk'] or 0),
            'min_ram': (data['minimum_ram'] or 0),
            'name': data['name']
        }

        if settings.HORIZON_IMAGES_ALLOW_UPLOAD and data['image_file']:
            meta['data'] = self.files['image_file']
        else:
            meta['copy_from'] = data['copy_from']

        try:
            image = api.glance.image_create(request, **meta)
            messages.success(
                request,
                _('Your image %s has been queued for creation.' %
                  data['name']))
            return image
        except:
            exceptions.handle(request, _('Unable to create new image.'))
예제 #9
0
class AssociateIPAction(workflows.Action):
    ip_id = forms.DynamicTypedChoiceField(label=_("IP Address"),
                                          coerce=filters.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 or port.")

    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:
            targets = self._get_target_list()
            target_id = api.network.floating_ip_target_get_by_instance(
                self.request, q_instance_id, targets)
            self.initial['instance_id'] = target_id

    def populate_ip_id_choices(self, request, context):
        ips = []
        redirect = reverse('horizon:project:access_and_security:index')
        try:
            ips = api.network.tenant_floating_ip_list(self.request)
        except neutron_exc.ConnectionFailed:
            exceptions.handle(self.request, redirect=redirect)
        except Exception:
            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 floating IP addresses allocated"))]

        return options

    @memoized.memoized_method
    def _get_target_list(self):
        targets = []
        try:
            targets = api.network.floating_ip_target_list(self.request)
        except Exception:
            redirect = reverse('horizon:project:access_and_security:index')
            exceptions.handle(self.request,
                              _('Unable to retrieve instance list.'),
                              redirect=redirect)
        return targets

    def populate_instance_id_choices(self, request, context):
        targets = self._get_target_list()

        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
예제 #10
0
class ImportOpaqueData(forms.SelfHandlingForm):
    name = forms.RegexField(required=False,
                            max_length=255,
                            label=_("Data Name"),
                            regex=shared_forms.NAME_REGEX,
                            error_messages=shared_forms.ERROR_MESSAGES)
    source_type = forms.ChoiceField(
        label=_('Source'),
        required=False,
        choices=[('file', _('File')), ('raw', _('Direct Input'))],
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'data-slug': 'source'
        }))
    object_file = forms.FileField(label=_("Choose file"),
                                  help_text=_("A local file to upload."),
                                  widget=forms.FileInput(
                                      attrs={
                                          'class': 'switched',
                                          'data-switch-on': 'source',
                                          'data-source-file': _('File')
                                      }),
                                  required=False)
    direct_input = forms.CharField(
        label=_('Object Bytes'),
        help_text=_('The bytes of the object, represented in hex.'),
        widget=forms.widgets.Textarea(
            attrs={
                'class': 'switched',
                'data-switch-on': 'source',
                'data-source-raw': _('Bytes')
            }),
        required=False)

    def __init__(self, request, *args, **kwargs):
        super(ImportOpaqueData, self).__init__(request, *args, **kwargs)

    def clean(self):
        data = super(ImportOpaqueData, self).clean()

        # The data can be missing based on particular upload
        # conditions. Code defensively for it here...
        data_file = data.get('object_file', None)
        data_raw = data.get('direct_input', None)

        if data_raw and data_file:
            raise forms.ValidationError(
                _("Cannot specify both file and direct input."))
        if not data_raw and not data_file:
            raise forms.ValidationError(
                _("No input was provided for the object value."))
        try:
            if data_file:
                data_bytes = self.files['object_file'].read()
            else:
                data_str = data['direct_input']
                data_bytes = binascii.unhexlify(data_str)
            data['object_bytes'] = base64.b64encode(data_bytes)
        except Exception as e:
            msg = _('There was a problem loading the object: %s. '
                    'Is the object valid and in the correct format?') % e
            raise forms.ValidationError(msg)

        return data

    def handle(self, request, data):
        try:
            data_bytes = data.get('object_bytes')
            data_uuid = client.import_object(
                request,
                data=data_bytes,
                name=data['name'],
                object_type=opaque_data.OpaqueData)

            if data['name']:
                data_identifier = data['name']
            else:
                data_identifier = data_uuid
            messages.success(
                request,
                _('Successfully imported object: %s') % data_identifier)
            return data_uuid
        except Exception as e:
            msg = _('Unable to import object: %s')
            messages.error(msg % e)
            exceptions.handle(request, ignore=True)
            self.api_error(_('Unable to import object.'))
            return False
예제 #11
0
class UpdateUserForm(BaseUserForm):
    id = forms.CharField(label=_("ID"), widget=forms.HiddenInput)
    name = forms.CharField(label=_("User Name"))
    email = forms.EmailField(label=_("Email"))
    password = forms.RegexField(label=_("Password"),
            widget=forms.PasswordInput(render_value=False),
            regex=validators.password_validator(),
            required=False,
            error_messages={'invalid':
                    validators.password_validator_msg()})
    confirm_password = forms.CharField(
            label=_("Confirm Password"),
            widget=forms.PasswordInput(render_value=False),
            required=False)
    tenant_id = forms.ChoiceField(label=_("Primary Project"))

    def __init__(self, request, *args, **kwargs):
        super(UpdateUserForm, self).__init__(request, *args, **kwargs)

        if api.keystone.keystone_can_edit_user() is False:
            for field in ('name', 'email', 'password', 'confirm_password'):
                self.fields.pop(field)

    # We have to protect the entire "data" dict because it contains the
    # password and confirm_password strings.
    @sensitive_variables('data', 'password')
    def handle(self, request, data):
        failed, succeeded = [], []
        user_is_editable = api.keystone.keystone_can_edit_user()
        user = data.pop('id')
        tenant = data.pop('tenant_id')

        if user_is_editable:
            password = data.pop('password')
            data.pop('confirm_password', None)

        if user_is_editable:
            # Update user details
            msg_bits = (_('name'), _('email'))
            try:
                api.keystone.user_update(request, user, **data)
                succeeded.extend(msg_bits)
            except:
                failed.extend(msg_bits)
                exceptions.handle(request, ignore=True)

        # Update default tenant
        msg_bits = (_('primary project'),)
        try:
            api.keystone.user_update_tenant(request, user, tenant)
            succeeded.extend(msg_bits)
        except:
            failed.append(msg_bits)
            exceptions.handle(request, ignore=True)

        # Check for existing roles
        # Show a warning if no role exists for the tenant
        user_roles = api.keystone.roles_for_user(request, user, tenant)
        if not user_roles:
            messages.warning(request,
                             _('The user %s has no role defined for' +
                             ' that project.')
                             % data.get('name', None))

        if user_is_editable:
            # If present, update password
            # FIXME(gabriel): password change should be its own form and view
            if password:
                msg_bits = (_('password'),)
                try:
                    api.keystone.user_update_password(request, user, password)
                    succeeded.extend(msg_bits)
                except:
                    failed.extend(msg_bits)
                    exceptions.handle(request, ignore=True)

        if succeeded:
            messages.success(request, _('User has been updated successfully.'))
        if failed:
            failed = map(force_unicode, failed)
            messages.error(request,
                           _('Unable to update %(attributes)s for the user.')
                             % {"attributes": ", ".join(failed)})
        return True
예제 #12
0
파일: forms.py 프로젝트: nxFelis/horizon
class CreateForm(forms.SelfHandlingForm):
    name = forms.CharField(max_length="255", label=_("Volume Name"))
    description = forms.CharField(widget=forms.Textarea,
                                  label=_("Description"),
                                  required=False)
    type = forms.ChoiceField(label=_("Type"), required=False)
    size = forms.IntegerField(min_value=1, label=_("Size (GB)"))
    encryption = forms.ChoiceField(label=_("Encryption"), required=False)
    volume_source_type = forms.ChoiceField(label=_("Volume Source"),
                                           required=False)
    snapshot_source = forms.ChoiceField(
        label=_("Use snapshot as a source"),
        widget=SelectWidget(attrs={'class': 'snapshot-selector'},
                            data_attrs=('size', 'display_name'),
                            transform=lambda x: ("%s (%sGB)" %
                                                 (x.display_name, x.size))),
        required=False)
    image_source = forms.ChoiceField(
        label=_("Use image as a source"),
        widget=SelectWidget(attrs={'class': 'image-selector'},
                            data_attrs=('size', 'name'),
                            transform=lambda x:
                            ("%s (%s)" % (x.name, filesizeformat(x.bytes)))),
        required=False)

    def __init__(self, request, *args, **kwargs):
        super(CreateForm, self).__init__(request, *args, **kwargs)
        volume_types = cinder.volume_type_list(request)
        self.fields['type'].choices = [("", "")] + \
                                      [(type.name, type.name)
                                       for type in volume_types]

        # Hide the volume encryption field if the hypervisor doesn't support it
        # NOTE: as of Grizzly this is not yet supported in Nova so enabling
        # this setting will not do anything useful
        hypervisor_features = getattr(settings,
                                      "OPENSTACK_HYPERVISOR_FEATURES", {})
        can_encrypt_volumes = hypervisor_features.get("can_encrypt_volumes",
                                                      False)

        if can_encrypt_volumes:
            # TODO(laura-glendenning) get from api call in future
            encryption_options = {"LUKS": "dmcrypt LUKS"}
            self.fields['encryption'].choices = [("", "")] + \
                [(enc, display) for enc, display in encryption_options.items()]
        else:
            self.fields['encryption'].widget = forms.widgets.HiddenInput()
            self.fields['encryption'].required = False

        if ("snapshot_id" in request.GET):
            try:
                snapshot = self.get_snapshot(request,
                                             request.GET["snapshot_id"])
                self.fields['name'].initial = snapshot.display_name
                self.fields['size'].initial = snapshot.size
                self.fields['snapshot_source'].choices = ((snapshot.id,
                                                           snapshot), )
                try:
                    # Set the volume type from the original volume
                    orig_volume = cinder.volume_get(request,
                                                    snapshot.volume_id)
                    self.fields['type'].initial = orig_volume.volume_type
                except:
                    pass
                self.fields['size'].help_text = _(
                    'Volume size must be equal '
                    'to or greater than the snapshot size (%sGB)' %
                    snapshot.size)
                del self.fields['image_source']
                del self.fields['volume_source_type']
            except:
                exceptions.handle(request,
                                  _('Unable to load the specified snapshot.'))
        elif ('image_id' in request.GET):
            try:
                image = self.get_image(request, request.GET["image_id"])
                image.bytes = image.size
                self.fields['name'].initial = image.name
                self.fields['size'].initial = bytes_to_gigabytes(image.size)
                self.fields['image_source'].choices = ((image.id, image), )
                self.fields['size'].help_text = _(
                    'Volume size must be equal '
                    'to or greater than the image size (%s)' %
                    filesizeformat(image.size))
                del self.fields['snapshot_source']
                del self.fields['volume_source_type']
            except:
                msg = _('Unable to load the specified image. %s')
                exceptions.handle(request, msg % request.GET['image_id'])
        else:
            source_type_choices = []

            try:
                snapshots = cinder.volume_snapshot_list(request)
                if snapshots:
                    source_type_choices.append(
                        ("snapshot_source", _("Snapshot")))
                    choices = [('', _("Choose a snapshot"))] + \
                              [(s.id, s) for s in snapshots]
                    self.fields['snapshot_source'].choices = choices
                else:
                    del self.fields['snapshot_source']
            except:
                exceptions.handle(request,
                                  _("Unable to retrieve "
                                    "volume snapshots."))

            images = get_available_images(request, request.user.tenant_id)
            if images:
                source_type_choices.append(("image_source", _("Image")))
                choices = [('', _("Choose an image"))]
                for image in images:
                    image.bytes = image.size
                    image.size = bytes_to_gigabytes(image.bytes)
                    choices.append((image.id, image))
                self.fields['image_source'].choices = choices
            else:
                del self.fields['image_source']

            if source_type_choices:
                choices = (
                    [('no_source_type', _("No source, empty volume."))] +
                    source_type_choices)
                self.fields['volume_source_type'].choices = choices
            else:
                del self.fields['volume_source_type']

    def handle(self, request, data):
        try:
            # FIXME(johnp): cinderclient currently returns a useless
            # error message when the quota is exceeded when trying to create
            # a volume, so we need to check for that scenario here before we
            # send it off to try and create.
            usages = cinder.tenant_absolute_limits(self.request)
            volumes = cinder.volume_list(self.request)
            total_size = sum(
                [getattr(volume, 'size', 0) for volume in volumes])
            usages['gigabytesUsed'] = total_size
            usages['volumesUsed'] = len(volumes)
            availableGB = usages['maxTotalVolumeGigabytes'] -\
                usages['gigabytesUsed']
            availableVol = usages['maxTotalVolumes'] - usages['volumesUsed']

            snapshot_id = None
            image_id = None
            source_type = data.get('volume_source_type', None)
            if (data.get("snapshot_source", None)
                    and source_type in [None, 'snapshot_source']):
                # Create from Snapshot
                snapshot = self.get_snapshot(request, data["snapshot_source"])
                snapshot_id = snapshot.id
                if (data['size'] < snapshot.size):
                    error_message = _('The volume size cannot be less than '
                                      'the snapshot size (%sGB)' %
                                      snapshot.size)
                    raise ValidationError(error_message)
            elif (data.get("image_source", None)
                  and source_type in [None, 'image_source']):
                # Create from Snapshot
                image = self.get_image(request, data["image_source"])
                image_id = image.id
                image_size = bytes_to_gigabytes(image.size)
                if (data['size'] < image_size):
                    error_message = _('The volume size cannot be less than '
                                      'the image size (%s)' %
                                      filesizeformat(image.size))
                    raise ValidationError(error_message)
            else:
                if type(data['size']) is str:
                    data['size'] = int(data['size'])

            if availableGB < data['size']:
                error_message = _('A volume of %(req)iGB cannot be created as '
                                  'you only have %(avail)iGB of your quota '
                                  'available.')
                params = {'req': data['size'], 'avail': availableGB}
                raise ValidationError(error_message % params)
            elif availableVol <= 0:
                error_message = _('You are already using all of your available'
                                  ' volumes.')
                raise ValidationError(error_message)

            metadata = {}

            if data['encryption']:
                metadata['encryption'] = data['encryption']

            volume = cinder.volume_create(request,
                                          data['size'],
                                          data['name'],
                                          data['description'],
                                          data['type'],
                                          snapshot_id=snapshot_id,
                                          image_id=image_id,
                                          metadata=metadata)
            message = _('Creating volume "%s"') % data['name']
            messages.info(request, message)
            return volume
        except ValidationError as e:
            self.api_error(e.messages[0])
            return False
        except:
            exceptions.handle(request, ignore=True)
            self.api_error(_("Unable to create volume."))
            return False

    @memoized
    def get_snapshot(self, request, id):
        return cinder.volume_snapshot_get(request, id)

    @memoized
    def get_image(self, request, id):
        return glance.image_get(request, id)
예제 #13
0
class JobConfigAction(workflows.Action):
    MAIN_CLASS = "edp.java.main_class"
    STORM_PYLEUS_TOPOLOGY_NAME = "topology_name"
    JAVA_OPTS = "edp.java.java_opts"
    EDP_MAPPER = "edp.streaming.mapper"
    EDP_REDUCER = "edp.streaming.reducer"
    EDP_PREFIX = "edp."
    EDP_HBASE_COMMON_LIB = "edp.hbase_common_lib"
    EDP_ADAPT_FOR_OOZIE = "edp.java.adapt_for_oozie"
    EDP_ADAPT_SPARK_SWIFT = "edp.spark.adapt_for_swift"
    EDP_SUBST_DATASOURCE_NAME = "edp.substitute_data_source_for_name"
    EDP_SUBST_DATASOURCE_UUID = "edp.substitute_data_source_for_uuid"

    property_name = forms.ChoiceField(
        required=False,
    )

    job_configs = forms.CharField(
        required=False,
        widget=forms.HiddenInput())

    job_params = forms.CharField(
        required=False,
        widget=forms.HiddenInput())

    job_args_array = forms.CharField(
        required=False,
        widget=forms.HiddenInput())

    job_type = forms.CharField(
        required=False,
        widget=forms.HiddenInput())

    main_class = forms.CharField(label=_("Main Class"),
                                 required=False)

    topology_name = forms.CharField(
        label=_("Topology Name"),
        help_text=_("Use the same topology name as defined in your "
                    ".yaml file"),
        required=False)

    java_opts = forms.CharField(label=_("Java Opts"),
                                required=False)

    streaming_mapper = forms.CharField(label=_("Mapper"),
                                       required=False)

    streaming_reducer = forms.CharField(label=_("Reducer"),
                                        required=False)

    hbase_common_lib = forms.BooleanField(
        label=_("Use HBase Common library"),
        help_text=_("Run HBase EDP Jobs with common HBase library on HDFS"),
        required=False, initial=True)

    adapt_oozie = forms.BooleanField(
        label=_("Adapt For Oozie"),
        help_text=_("Automatically modify the Hadoop configuration"
                    " so that job config values are set and so that"
                    " Oozie will handle exit codes correctly."),
        required=False, initial=True)

    adapt_spark_swift = forms.BooleanField(
        label=_("Enable Swift Paths"),
        help_text=_("Modify the configuration so that swift URLs can "
                    "be dereferenced through HDFS at runtime."),
        required=False, initial=True)

    datasource_substitute = forms.BooleanField(
        label=_("Use Data Source Substitution for Names and UUIDs"),
        help_text=_("Substitute data source objects for URLs of "
                    "the form datasource://name or uuid."),
        required=False, initial=True)

    def __init__(self, request, *args, **kwargs):
        super(JobConfigAction, self).__init__(request, *args, **kwargs)
        req = request.GET or request.POST
        job_ex_id = req.get("job_execution_id")
        if job_ex_id is not None:
            job_ex = saharaclient.job_execution_get(request, job_ex_id)
            job = saharaclient.job_get(request, job_ex.job_id)
            job_configs, interface_args = _merge_interface_with_configs(
                job.interface, job_ex.job_configs)
            edp_configs = {}

            if 'configs' in job_configs:
                configs, edp_configs = (
                    self.clean_edp_configs(job_configs['configs']))
                self.fields['job_configs'].initial = (
                    json.dumps(configs))

            if 'params' in job_configs:
                self.fields['job_params'].initial = (
                    json.dumps(job_configs['params']))

            if 'args' in job_configs:
                self.fields['job_args_array'].initial = (
                    json.dumps(job_configs['args']))

            if self.MAIN_CLASS in edp_configs:
                self.fields['main_class'].initial = (
                    edp_configs[self.MAIN_CLASS])
            if self.STORM_PYLEUS_TOPOLOGY_NAME in edp_configs:
                self.fields['topology_name'].initial = (
                    edp_configs[self.STORM_PYLEUS_TOPOLOGY_NAME])
            if self.JAVA_OPTS in edp_configs:
                self.fields['java_opts'].initial = (
                    edp_configs[self.JAVA_OPTS])

            if self.EDP_MAPPER in edp_configs:
                self.fields['streaming_mapper'].initial = (
                    edp_configs[self.EDP_MAPPER])
            if self.EDP_REDUCER in edp_configs:
                self.fields['streaming_reducer'].initial = (
                    edp_configs[self.EDP_REDUCER])
            if self.EDP_HBASE_COMMON_LIB in edp_configs:
                self.fields['hbase_common_lib'].initial = (
                    edp_configs[self.EDP_HBASE_COMMON_LIB])
            if self.EDP_ADAPT_FOR_OOZIE in edp_configs:
                self.fields['adapt_oozie'].initial = (
                    edp_configs[self.EDP_ADAPT_FOR_OOZIE])
            if self.EDP_ADAPT_SPARK_SWIFT in edp_configs:
                self.fields['adapt_spark_swift'].initial = (
                    edp_configs[self.EDP_ADAPT_SPARK_SWIFT])
            if (self.EDP_SUBST_DATASOURCE_NAME in edp_configs or
                    self.EDP_SUBST_DATASOURCE_UUID in edp_configs):
                    self.fields['datasource_substitute'].initial = (
                        edp_configs.get(self.EDP_SUBST_DATASOURCE_UUID, True)
                        or
                        edp_configs.get(self.EDP_SUBST_DATASOURCE_NAME, True))

    def clean(self):
        cleaned_data = super(workflows.Action, self).clean()
        job_type = cleaned_data.get("job_type", None)

        if job_type != "MapReduce.Streaming":
            if "streaming_mapper" in self._errors:
                del self._errors["streaming_mapper"]
            if "streaming_reducer" in self._errors:
                del self._errors["streaming_reducer"]

        return cleaned_data

    def populate_property_name_choices(self, request, context):
        req = request.GET or request.POST
        job_id = req.get("job_id") or req.get("job")
        job_type = saharaclient.job_get(request, job_id).type
        job_configs = (
            saharaclient.job_get_configs(request, job_type).job_config)
        choices = [(param['value'], param['name'])
                   for param in job_configs['configs']]
        return choices

    def clean_edp_configs(self, configs):
        edp_configs = {}
        for key, value in configs.items():
            if key.startswith(self.EDP_PREFIX):
                edp_configs[key] = value
        for rmkey in edp_configs.keys():
            # remove all configs handled via other controls
            # so they do not show up in the free entry inputs
            if rmkey in [self.EDP_HBASE_COMMON_LIB,
                         self.EDP_MAPPER,
                         self.EDP_REDUCER,
                         self.MAIN_CLASS,
                         self.STORM_PYLEUS_TOPOLOGY_NAME,
                         self.JAVA_OPTS,
                         self.EDP_ADAPT_FOR_OOZIE,
                         self.EDP_ADAPT_SPARK_SWIFT,
                         self.EDP_SUBST_DATASOURCE_UUID,
                         self.EDP_SUBST_DATASOURCE_NAME, ]:
                del configs[rmkey]
        return (configs, edp_configs)

    class Meta(object):
        name = _("Configure")
        help_text_template = "job_templates/_launch_job_configure_help.html"
예제 #14
0
class CreateNetworkIpam(forms.SelfHandlingForm):
    name = forms.CharField(label=_("Name"),
                           error_messages={
                               'required': _('This field is required.'),
                               'invalid': _("The string may only contain"
                                            " ASCII characters and numbers.")},
                           validators=[validators.validate_slug])

    dnsmethod = forms.ChoiceField(label=_('DNS Method'),
                               choices=[('default', _('Default')),
                                        ('vdns', _('Virtual DNS')),
                                        ('tenantdns', _('Tenant DNS')),
                                        ('none', _('None'))],
                               widget=forms.Select(attrs={
                                   'class': 'switchable',
                                   'data-slug': 'dnsmethod'}))

    vdns = forms.CharField(label=_("Virtual DNS"),
                          required=False,
                          help_text=_("FQ Name of Virtual DNS i.e. default-domain:vdns"),
                          widget=forms.TextInput(
                              attrs={'class': 'switched',
                                     'data-switch-on': 'dnsmethod',
                                     'data-dnsmethod-vdns': _('Virtual DNS')}))

    tenantdns = fields.IPField(label=_("Tenant DNS Server IP"),
                          required=False,
                          help_text=_("Tenant managed DNS Server's IP Address"),
                          version=fields.IPv4,
                          mask=False,
                          widget=forms.TextInput(
                              attrs={'class': 'switched',
                                     'data-switch-on': 'dnsmethod',
                                     'data-dnsmethod-tenantdns': _('Tenant DNS Server IP')}))

    ntpip = fields.IPField(label=_("NTP Server IP"),
                          required=False,
                          help_text=_("IP Address of the NTP Server"),
                          version=fields.IPv4,
                          mask=False,
                          widget=forms.TextInput())

    domainname = forms.CharField(label=_("Domain Name"),
                          required=False,
                          help_text=_("Domain Name i.e. openstack.org"),
                          widget=forms.TextInput())

    def clean(self):
        cleaned_data = super(CreateNetworkIpam, self).clean()
        name       = cleaned_data.get("name")
        dnsmethod  = cleaned_data.get("dnsmethod")
        vdns       = cleaned_data.get("vdns")
        tenantdns  = cleaned_data.get("tenantdns")
        ntpip      = cleaned_data.get("ntpip")
        domainname = cleaned_data.get("domainname")

        if dnsmethod == 'vdns' and not len(vdns):
            msg = _('Virtual DNS : Enter a valid Virtual DNS in FQN format')
            raise ValidationError(msg)

        if dnsmethod == 'tenantdns':
            if not tenantdns:
                msg = _('Tenant DNS Server IP : Enter Tenant DNS Server IP address')
                raise ValidationError(msg)
            elif not len(tenantdns):
                msg = _('Tenant DNS Server IP : Enter Tenant DNS Server IP address')
                raise ValidationError(msg)

        return cleaned_data

    def handle(self, request, data):
        params = {'name': data['name'],
                  'mgmt': {'ipam_method': None,
                           'dhcp_option_list': {'dhcp_option':[]}}}

        if data['domainname']:
            params['mgmt']['dhcp_option_list']['dhcp_option'].append(
                                                {'dhcp_option_name': '15',
                                                 'dhcp_option_value':
                                                  data['domainname']})

        if data['ntpip']:
            params['mgmt']['dhcp_option_list']['dhcp_option'].append(
                                                {'dhcp_option_name': '4',
                                                 'dhcp_option_value':
                                                  data['ntpip']})

        params['mgmt']['ipam_dns_server'] = {}
        params['mgmt']['ipam_dns_server']['tenant_dns_server_address'] = {}
        params['mgmt']['ipam_dns_server']['virtual_dns_server_name'] = None

        if data['dnsmethod'] == 'default':
            params['mgmt']['ipam_dns_method'] = 'default-dns-server'

        if data['dnsmethod'] == 'none':
            params['mgmt']['ipam_dns_method'] = 'none'

        if data['dnsmethod'] == 'tenantdns':
            params['mgmt']['ipam_dns_method'] = 'tenant-dns-server'
            if data['tenantdns']:
                params['mgmt']['ipam_dns_server']['tenant_dns_server_address']['ip_address'] = []
                params['mgmt']['ipam_dns_server']['tenant_dns_server_address']['ip_address'].append(data['tenantdns'])
            
        if data['dnsmethod'] == 'vdns':
            params['mgmt']['ipam_dns_method'] = 'virtual-dns-server'
            params['mgmt']['ipam_dns_server']['virtual_dns_server_name'] = data['vdns']
        try:
            ipam = ipam_create(request, **params)
            messages.success(request,
                             _('Successfully created network ipam: %s')
                               % data['name'])
            return ipam 
        except Exception:
            redirect = reverse("horizon:project:networking:index")
            exceptions.handle(request,
                              _('Unable to create network ipam.'),
                              redirect=redirect)
예제 #15
0
class AddRule(forms.SelfHandlingForm):
    id = forms.CharField(widget=forms.HiddenInput())
    rule_menu = forms.ChoiceField(
        label=_('Rule'),
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'data-slug': 'rule_menu'
        }))
    description = forms.CharField(
        label=_('Description'),
        required=False,
        max_length=255,
        widget=forms.Textarea(attrs={'rows': 2}),
        help_text=_('A brief description of the security group rule '
                    'you are adding'))

    # "direction" field is enabled only when custom mode.
    # It is because most common rules in local_settings.py is meaningful
    # when its direction is 'ingress'.
    direction = forms.ChoiceField(
        label=_('Direction'),
        required=False,
        widget=forms.ThemableSelectWidget(
            attrs={
                'class': 'switched',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-tcp': _('Direction'),
                'data-rule_menu-udp': _('Direction'),
                'data-rule_menu-icmp': _('Direction'),
                'data-rule_menu-custom': _('Direction'),
                'data-rule_menu-all_tcp': _('Direction'),
                'data-rule_menu-all_udp': _('Direction'),
                'data-rule_menu-all_icmp': _('Direction'),
            }))

    ip_protocol = forms.IntegerField(
        label=_('IP Protocol'),
        required=False,
        help_text=_("Enter an integer value between 0 and 255."),
        validators=[utils_validators.validate_ip_protocol],
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-custom': _('IP Protocol')
            }))

    port_or_range = forms.ChoiceField(
        label=_('Open Port'),
        choices=[('port', _('Port')), ('range', _('Port Range'))],
        widget=forms.ThemableSelectWidget(
            attrs={
                'class': 'switchable switched',
                'data-slug': 'range',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-tcp': _('Open Port'),
                'data-rule_menu-udp': _('Open Port')
            }))

    port = forms.IntegerField(
        label=_("Port"),
        required=False,
        help_text=_("Enter an integer value "
                    "between 1 and 65535."),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-required-when-shown': 'true',
                'data-switch-on': 'range',
                'data-range-port': _('Port')
            }),
        validators=[utils_validators.validate_port_range])

    from_port = forms.IntegerField(
        label=_("From Port"),
        required=False,
        help_text=_("Enter an integer value "
                    "between 1 and 65535."),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-required-when-shown': 'true',
                'data-switch-on': 'range',
                'data-range-range': _('From Port')
            }),
        validators=[utils_validators.validate_port_range])

    to_port = forms.IntegerField(
        label=_("To Port"),
        required=False,
        help_text=_("Enter an integer value "
                    "between 1 and 65535."),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-required-when-shown': 'true',
                'data-switch-on': 'range',
                'data-range-range': _('To Port')
            }),
        validators=[utils_validators.validate_port_range])

    icmp_type = forms.IntegerField(
        label=_("Type"),
        required=False,
        help_text=_("Enter a value for ICMP type "
                    "in the range (-1: 255)"),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-icmp': _('Type')
            }),
        validators=[utils_validators.validate_icmp_type_range])

    icmp_code = forms.IntegerField(
        label=_("Code"),
        required=False,
        help_text=_("Enter a value for ICMP code "
                    "in the range (-1: 255)"),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-icmp': _('Code')
            }),
        validators=[utils_validators.validate_icmp_code_range])

    remote = forms.ChoiceField(
        label=_('Remote'),
        choices=[('cidr', _('CIDR')), ('sg', _('Security Group'))],
        help_text=_('To specify an allowed IP '
                    'range, select &quot;CIDR&quot;. '
                    'To allow access from all '
                    'members of another security '
                    'group select &quot;Security '
                    'Group&quot;.'),
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'data-slug': 'remote'
        }))

    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, or "
                                     "2001:db8::/128)"),
                         version=forms.IPv4 | forms.IPv6,
                         mask=True,
                         widget=forms.TextInput(
                             attrs={
                                 'class': 'switched',
                                 'data-required-when-shown': 'true',
                                 'data-switch-on': 'remote',
                                 'data-remote-cidr': _('CIDR')
                             }))

    security_group = forms.ChoiceField(
        label=_('Security Group'),
        required=False,
        widget=forms.ThemableSelectWidget(
            attrs={
                'class': 'switched',
                'data-required-when-shown': 'true',
                'data-switch-on': 'remote',
                'data-remote-sg': _('Security Group')
            }))
    # When cidr is used ethertype is determined from IP version of cidr.
    # When source group, ethertype needs to be specified explicitly.
    ethertype = forms.ChoiceField(label=_('Ether Type'),
                                  required=False,
                                  choices=[('IPv4', _('IPv4')),
                                           ('IPv6', _('IPv6'))],
                                  widget=forms.ThemableSelectWidget(
                                      attrs={
                                          'class': 'switched',
                                          'data-slug': 'ethertype',
                                          'data-switch-on': 'remote',
                                          'data-remote-sg': _('Ether Type')
                                      }))

    def __init__(self, *args, **kwargs):
        sg_list = kwargs.pop('sg_list', [])
        super(AddRule, self).__init__(*args, **kwargs)
        # Determine if there are security groups available for the
        # remote group option; add the choices and enable the option if so.
        if sg_list:
            security_groups_choices = sg_list
        else:
            security_groups_choices = [("", _("No security groups available"))]
        self.fields['security_group'].choices = security_groups_choices

        # TODO(amotoki): settings.SECURITY_GROUP_RULES may contains 'backend'
        # parameter. If 'backend' is used, error message should be emitted.
        backend = 'neutron'

        rules_dict = settings.SECURITY_GROUP_RULES
        common_rules = [(k, rules_dict[k]['name']) for k in rules_dict
                        if rules_dict[k].get('backend', backend) == backend]
        common_rules.sort()
        custom_rules = [('tcp', _('Custom TCP Rule')),
                        ('udp', _('Custom UDP Rule')),
                        ('icmp', _('Custom ICMP Rule')),
                        ('custom', _('Other Protocol'))]
        self.fields['rule_menu'].choices = custom_rules + common_rules
        self.rules = rules_dict

        self.fields['direction'].choices = [('ingress', _('Ingress')),
                                            ('egress', _('Egress'))]
        self.fields['ip_protocol'].help_text = _(
            "Enter an integer value between -1 and 255 "
            "(-1 means wild card).")

        self.fields['port_or_range'].choices = [
            ('port', _('Port')),
            ('range', _('Port Range')),
            ('all', _('All ports')),
        ]

        if not setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
                                             'enable_ipv6'):
            self.fields['cidr'].version = forms.IPv4
            self.fields['ethertype'].widget = forms.TextInput(
                attrs={'readonly': 'readonly'})
            self.fields['ethertype'].initial = 'IPv4'

        try:
            is_desc_supported = api.neutron.is_extension_supported(
                self.request, 'standard-attr-description')
        except Exception:
            exceptions.handle(
                self.request,
                _('Failed to check if description field is supported.'))
            is_desc_supported = False
        if not is_desc_supported:
            del self.fields['description']

    def _update_and_pop_error(self, cleaned_data, key, value):
        cleaned_data[key] = value
        self.errors.pop(key, None)

    def _clean_rule_icmp(self, cleaned_data, rule_menu):
        icmp_type = cleaned_data.get("icmp_type", None)
        icmp_code = cleaned_data.get("icmp_code", None)

        self._update_and_pop_error(cleaned_data, 'ip_protocol', rule_menu)
        if icmp_type == -1 and icmp_code != -1:
            msg = _('ICMP code is provided but ICMP type is missing.')
            raise ValidationError(msg)
        if self.errors.get('icmp_type'):
            msg = _('The ICMP type not in range (-1, 255)')
            raise ValidationError(msg)
        if self.errors.get('icmp_code'):
            msg = _('The ICMP code not in range (-1, 255)')
            raise ValidationError(msg)

        self._update_and_pop_error(cleaned_data, 'from_port', icmp_type)
        self._update_and_pop_error(cleaned_data, 'to_port', icmp_code)
        self._update_and_pop_error(cleaned_data, 'port', None)

    def _clean_rule_tcp_udp(self, cleaned_data, rule_menu):
        port_or_range = cleaned_data.get("port_or_range")
        from_port = cleaned_data.get("from_port", None)
        to_port = cleaned_data.get("to_port", None)
        port = cleaned_data.get("port", None)

        self._update_and_pop_error(cleaned_data, 'ip_protocol', rule_menu)
        self._update_and_pop_error(cleaned_data, 'icmp_code', None)
        self._update_and_pop_error(cleaned_data, 'icmp_type', None)
        if port_or_range == 'all':
            self._update_and_pop_error(cleaned_data, 'port', None)
            self._update_and_pop_error(cleaned_data, 'from_port', None)
            self._update_and_pop_error(cleaned_data, 'to_port', None)
        elif port_or_range == "port":
            self._update_and_pop_error(cleaned_data, 'from_port', port)
            self._update_and_pop_error(cleaned_data, 'to_port', port)
            if port is None:
                msg = _('The specified port is invalid.')
                raise ValidationError(msg)
        else:
            self._update_and_pop_error(cleaned_data, 'port', None)
            if from_port is None:
                msg = _('The "from" port number is invalid.')
                raise ValidationError(msg)
            if to_port is None:
                msg = _('The "to" port number is invalid.')
                raise ValidationError(msg)
            if to_port < from_port:
                msg = _('The "to" port number must be greater than '
                        'or equal to the "from" port number.')
                raise ValidationError(msg)

    def _clean_rule_custom(self, cleaned_data, rule_menu):
        # custom IP protocol rule so we need to fill unused fields so
        # the validation works
        unused_fields = [
            'icmp_code', 'icmp_type', 'from_port', 'to_port', 'port'
        ]
        for unused_field in unused_fields:
            self._update_and_pop_error(cleaned_data, unused_field, None)

    def _apply_rule_menu(self, cleaned_data, rule_menu):
        cleaned_data['ip_protocol'] = self.rules[rule_menu]['ip_protocol']
        cleaned_data['from_port'] = int(self.rules[rule_menu]['from_port'])
        cleaned_data['to_port'] = int(self.rules[rule_menu]['to_port'])
        self._update_and_pop_error(cleaned_data, 'icmp_code', None)
        self._update_and_pop_error(cleaned_data, 'icmp_type', None)
        if rule_menu not in ['all_tcp', 'all_udp', 'all_icmp']:
            direction = self.rules[rule_menu].get('direction')
            cleaned_data['direction'] = direction

    def _clean_rule_menu(self, cleaned_data):
        rule_menu = cleaned_data.get('rule_menu')
        if rule_menu == 'icmp':
            self._clean_rule_icmp(cleaned_data, rule_menu)
        elif rule_menu in ('tcp', 'udp'):
            self._clean_rule_tcp_udp(cleaned_data, rule_menu)
        elif rule_menu == 'custom':
            self._clean_rule_custom(cleaned_data, rule_menu)
        else:
            self._apply_rule_menu(cleaned_data, rule_menu)

    def _adjust_ip_protocol_of_icmp(self, data):
        # Note that this needs to be called after IPv4/IPv6 is determined.
        try:
            ip_protocol = int(data['ip_protocol'])
        except ValueError:
            # string representation of IP protocol
            ip_protocol = data['ip_protocol']
        is_ipv6 = data['ethertype'] == 'IPv6'

        if isinstance(ip_protocol, int):
            # When IP protocol number is specified, we assume a user
            # knows more detail on IP protocol number,
            # so a warning message on a mismatch between IP proto number
            # and IP version is displayed.
            if is_ipv6 and ip_protocol == 1:
                msg = _('58 (ipv6-icmp) should be specified for IPv6 '
                        'instead of 1.')
                self._errors['ip_protocol'] = self.error_class([msg])
            elif not is_ipv6 and ip_protocol == 58:
                msg = _('1 (icmp) should be specified for IPv4 '
                        'instead of 58.')
                self._errors['ip_protocol'] = self.error_class([msg])
        else:
            # ICMPv6 uses different an IP protocol name and number.
            # To allow 'icmp' for both IPv4 and IPv6 in the form,
            # we need to replace 'icmp' with 'ipv6-icmp' based on IP version.
            if is_ipv6 and ip_protocol == 'icmp':
                data['ip_protocol'] = 'ipv6-icmp'

    def clean(self):
        cleaned_data = super(AddRule, self).clean()

        self._clean_rule_menu(cleaned_data)

        # NOTE(amotoki): There are two cases where cleaned_data['direction']
        # is empty: (1) Nova Security Group is used. Since "direction" is
        # HiddenInput, direction field exists but its value is ''.
        # (2) Template except all_* is used. In this case, the default value
        # is None. To make sure 'direction' field has 'ingress' or 'egress',
        # fill this field here if it is not specified.
        if not cleaned_data['direction']:
            cleaned_data['direction'] = 'ingress'

        remote = cleaned_data.get("remote")
        if remote == "cidr":
            self._update_and_pop_error(cleaned_data, 'security_group', None)
        else:
            self._update_and_pop_error(cleaned_data, 'cidr', None)

        # If cleaned_data does not contain a non-empty value, IPField already
        # has validated it, so skip the further validation for cidr.
        # In addition cleaned_data['cidr'] is None means source_group is used.
        if 'cidr' in cleaned_data and cleaned_data['cidr'] is not None:
            cidr = cleaned_data['cidr']
            if not cidr:
                msg = _('CIDR must be specified.')
                self._errors['cidr'] = self.error_class([msg])
            else:
                # If cidr is specified, ethertype is determined from IP address
                # version. It is used only when Neutron is enabled.
                ip_ver = netaddr.IPNetwork(cidr).version
                cleaned_data['ethertype'] = 'IPv6' if ip_ver == 6 else 'IPv4'

        self._adjust_ip_protocol_of_icmp(cleaned_data)

        return cleaned_data

    def handle(self, request, data):
        redirect = reverse("horizon:project:security_groups:detail",
                           args=[data['id']])
        params = {}
        if 'description' in data:
            params['description'] = data['description']
        try:
            rule = api.neutron.security_group_rule_create(
                request, filters.get_int_or_uuid(data['id']),
                data['direction'], data['ethertype'], data['ip_protocol'],
                data['from_port'], data['to_port'], data['cidr'],
                data['security_group'], **params)
            messages.success(request, _('Successfully added rule: %s') % rule)
            return rule
        except exceptions.Conflict as error:
            exceptions.handle(request, error, redirect=redirect)
        except Exception:
            exceptions.handle(request,
                              _('Unable to add rule to security group.'),
                              redirect=redirect)
예제 #16
0
class UpdateUserForm(BaseUserForm):
    # Hide the domain_id and domain_name by default
    domain_id = forms.CharField(label=_("Domain ID"),
                                required=False,
                                widget=forms.HiddenInput())
    domain_name = forms.CharField(label=_("Domain Name"),
                                  required=False,
                                  widget=forms.HiddenInput())
    id = forms.CharField(label=_("ID"), widget=forms.HiddenInput)
    name = forms.CharField(label=_("User Name"))
    email = forms.EmailField(
        label=_("Email"),
        required=False)
    password = forms.RegexField(
        label=_("Password"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        required=False,
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm Password"),
        widget=forms.PasswordInput(render_value=False),
        required=False)
    project = forms.ChoiceField(label=_("Primary Project"),
                                required=PROJECT_REQUIRED)
    no_autocomplete = True

    def __init__(self, request, *args, **kwargs):
        super(UpdateUserForm, self).__init__(request, *args, **kwargs)

        if api.keystone.keystone_can_edit_user() is False:
            for field in ('name', 'email', 'password', 'confirm_password'):
                self.fields.pop(field)
                # For keystone V3, display the two fields in read-only
        if api.keystone.VERSIONS.active >= 3:
            readonlyInput = forms.TextInput(attrs={'readonly': 'readonly'})
            self.fields["domain_id"].widget = readonlyInput
            self.fields["domain_name"].widget = readonlyInput

    # We have to protect the entire "data" dict because it contains the
    # password and confirm_password strings.
    @sensitive_variables('data', 'password')
    def handle(self, request, data):
        user = data.pop('id')

        # Throw away the password confirmation, we're done with it.
        data.pop('confirm_password', None)

        data.pop('domain_id')
        data.pop('domain_name')

        try:
            if "email" in data:
                data['email'] = data['email'] or None
            response = api.keystone.user_update(request, user, **data)
            messages.success(request,
                             _('User has been updated successfully.'))
        except Exception:
            response = exceptions.handle(request, ignore=True)
            messages.error(request, _('Unable to update the user.'))

        if isinstance(response, http.HttpResponse):
            return response
        else:
            return True
예제 #17
0
class AddRule(forms.SelfHandlingForm):
    id = forms.CharField(widget=forms.HiddenInput())
    rule_menu = forms.ChoiceField(
        label=_('Rule'),
        widget=forms.Select(attrs={
            'class': 'switchable',
            'data-slug': 'rule_menu'
        }))

    # "direction" field is enabled only when custom mode.
    # It is because most common rules in local_settings.py is meaningful
    # when its direction is 'ingress'.
    direction = forms.ChoiceField(
        label=_('Direction'),
        required=False,
        widget=forms.Select(
            attrs={
                'class': 'switched',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-tcp': _('Direction'),
                'data-rule_menu-udp': _('Direction'),
                'data-rule_menu-icmp': _('Direction'),
                'data-rule_menu-custom': _('Direction'),
                'data-rule_menu-all_tcp': _('Direction'),
                'data-rule_menu-all_udp': _('Direction'),
                'data-rule_menu-all_icmp': _('Direction'),
            }))

    ip_protocol = forms.IntegerField(
        label=_('IP Protocol'),
        required=False,
        help_text=_("Enter an integer value between 0 and 255 "
                    "(or -1 which means wildcard)."),
        validators=[utils_validators.validate_ip_protocol],
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-custom': _('IP Protocol')
            }))

    port_or_range = forms.ChoiceField(
        label=_('Open Port'),
        choices=[('port', _('Port')), ('range', _('Port Range'))],
        widget=forms.Select(
            attrs={
                'class': 'switchable switched',
                'data-slug': 'range',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-tcp': _('Open Port'),
                'data-rule_menu-udp': _('Open Port')
            }))

    port = forms.IntegerField(
        label=_("Port"),
        required=False,
        help_text=_("Enter an integer value "
                    "between 1 and 65535."),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'range',
                'data-range-port': _('Port')
            }),
        validators=[utils_validators.validate_port_range])

    from_port = forms.IntegerField(
        label=_("From Port"),
        required=False,
        help_text=_("Enter an integer value "
                    "between 1 and 65535."),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'range',
                'data-range-range': _('From Port')
            }),
        validators=[utils_validators.validate_port_range])

    to_port = forms.IntegerField(
        label=_("To Port"),
        required=False,
        help_text=_("Enter an integer value "
                    "between 1 and 65535."),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'range',
                'data-range-range': _('To Port')
            }),
        validators=[utils_validators.validate_port_range])

    icmp_type = forms.IntegerField(
        label=_("Type"),
        required=False,
        help_text=_("Enter a value for ICMP type "
                    "in the range (-1: 255)"),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-icmp': _('Type')
            }),
        validators=[utils_validators.validate_port_range])

    icmp_code = forms.IntegerField(
        label=_("Code"),
        required=False,
        help_text=_("Enter a value for ICMP code "
                    "in the range (-1: 255)"),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'rule_menu',
                'data-rule_menu-icmp': _('Code')
            }),
        validators=[utils_validators.validate_port_range])

    remote = forms.ChoiceField(label=_('Remote'),
                               choices=[('cidr', _('CIDR')),
                                        ('sg', _('Security Group'))],
                               help_text=_('To specify an allowed IP '
                                           'range, select &quot;CIDR&quot;. '
                                           'To allow access from all '
                                           'members of another security '
                                           'group select &quot;Security '
                                           'Group&quot;.'),
                               widget=forms.Select(attrs={
                                   'class': 'switchable',
                                   'data-slug': 'remote'
                               }))

    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=forms.IPv4 | forms.IPv6,
                         mask=True,
                         widget=forms.TextInput(
                             attrs={
                                 'class': 'switched',
                                 'data-switch-on': 'remote',
                                 'data-remote-cidr': _('CIDR')
                             }))

    security_group = forms.ChoiceField(
        label=_('Security Group'),
        required=False,
        widget=forms.Select(
            attrs={
                'class': 'switched',
                'data-switch-on': 'remote',
                'data-remote-sg': _('Security '
                                    'Group')
            }))
    # When cidr is used ethertype is determined from IP version of cidr.
    # When source group, ethertype needs to be specified explicitly.
    ethertype = forms.ChoiceField(label=_('Ether Type'),
                                  required=False,
                                  choices=[('IPv4', _('IPv4')),
                                           ('IPv6', _('IPv6'))],
                                  widget=forms.Select(
                                      attrs={
                                          'class': 'switched',
                                          'data-slug': 'ethertype',
                                          'data-switch-on': 'remote',
                                          'data-remote-sg': _('Ether Type')
                                      }))

    def __init__(self, *args, **kwargs):
        sg_list = kwargs.pop('sg_list', [])
        super(AddRule, self).__init__(*args, **kwargs)
        # Determine if there are security groups available for the
        # remote group option; add the choices and enable the option if so.
        if sg_list:
            security_groups_choices = sg_list
        else:
            security_groups_choices = [("", _("No security groups available"))]
        self.fields['security_group'].choices = security_groups_choices

        backend = api.network.security_group_backend(self.request)

        rules_dict = getattr(settings, 'SECURITY_GROUP_RULES', [])
        common_rules = [(k, rules_dict[k]['name']) for k in rules_dict
                        if rules_dict[k].get('backend', backend) == backend]
        common_rules.sort()
        custom_rules = [('tcp', _('Custom TCP Rule')),
                        ('udp', _('Custom UDP Rule')),
                        ('icmp', _('Custom ICMP Rule'))]
        if backend == 'neutron':
            custom_rules.append(('custom', _('Other Protocol')))
        self.fields['rule_menu'].choices = custom_rules + common_rules
        self.rules = rules_dict

        if backend == 'neutron':
            self.fields['direction'].choices = [('ingress', _('Ingress')),
                                                ('egress', _('Egress'))]
        else:
            # direction and ethertype are not supported in Nova secgroup.
            self.fields['direction'].widget = forms.HiddenInput()
            self.fields['ethertype'].widget = forms.HiddenInput()
            # ip_protocol field is to specify arbitrary protocol number
            # and it is available only for neutron security group.
            self.fields['ip_protocol'].widget = forms.HiddenInput()

    def _update_and_pop_error(self, cleaned_data, key, value):
        cleaned_data[key] = value
        self.errors.pop(key, None)

    def _clean_rule_icmp(self, cleaned_data, rule_menu):
        icmp_type = cleaned_data.get("icmp_type", None)
        icmp_code = cleaned_data.get("icmp_code", None)

        self._update_and_pop_error(cleaned_data, 'ip_protocol', rule_menu)
        if icmp_type is None:
            msg = _('The ICMP type is invalid.')
            raise ValidationError(msg)
        if icmp_code is None:
            msg = _('The ICMP code is invalid.')
            raise ValidationError(msg)
        if icmp_type not in range(-1, 256):
            msg = _('The ICMP type not in range (-1, 255)')
            raise ValidationError(msg)
        if icmp_code not in range(-1, 256):
            msg = _('The ICMP code not in range (-1, 255)')
            raise ValidationError(msg)
        self._update_and_pop_error(cleaned_data, 'from_port', icmp_type)
        self._update_and_pop_error(cleaned_data, 'to_port', icmp_code)
        self._update_and_pop_error(cleaned_data, 'port', None)

    def _clean_rule_tcp_udp(self, cleaned_data, rule_menu):
        port_or_range = cleaned_data.get("port_or_range")
        from_port = cleaned_data.get("from_port", None)
        to_port = cleaned_data.get("to_port", None)
        port = cleaned_data.get("port", None)

        self._update_and_pop_error(cleaned_data, 'ip_protocol', rule_menu)
        self._update_and_pop_error(cleaned_data, 'icmp_code', None)
        self._update_and_pop_error(cleaned_data, 'icmp_type', None)
        if port_or_range == "port":
            self._update_and_pop_error(cleaned_data, 'from_port', port)
            self._update_and_pop_error(cleaned_data, 'to_port', port)
            if port is None:
                msg = _('The specified port is invalid.')
                raise ValidationError(msg)
        else:
            self._update_and_pop_error(cleaned_data, 'port', None)
            if from_port is None:
                msg = _('The "from" port number is invalid.')
                raise ValidationError(msg)
            if to_port is None:
                msg = _('The "to" port number is invalid.')
                raise ValidationError(msg)
            if to_port < from_port:
                msg = _('The "to" port number must be greater than '
                        'or equal to the "from" port number.')
                raise ValidationError(msg)

    def _apply_rule_menu(self, cleaned_data, rule_menu):
        cleaned_data['ip_protocol'] = self.rules[rule_menu]['ip_protocol']
        cleaned_data['from_port'] = int(self.rules[rule_menu]['from_port'])
        cleaned_data['to_port'] = int(self.rules[rule_menu]['to_port'])
        if rule_menu not in ['all_tcp', 'all_udp', 'all_icmp']:
            direction = self.rules[rule_menu].get('direction')
            cleaned_data['direction'] = direction

    def _clean_rule_menu(self, cleaned_data):
        rule_menu = cleaned_data.get('rule_menu')
        if rule_menu == 'icmp':
            self._clean_rule_icmp(cleaned_data, rule_menu)
        elif rule_menu == 'tcp' or rule_menu == 'udp':
            self._clean_rule_tcp_udp(cleaned_data, rule_menu)
        elif rule_menu == 'custom':
            pass
        else:
            self._apply_rule_menu(cleaned_data, rule_menu)

    def clean(self):
        cleaned_data = super(AddRule, self).clean()

        self._clean_rule_menu(cleaned_data)

        # NOTE(amotoki): There are two cases where cleaned_data['direction']
        # is empty: (1) Nova Security Group is used. Since "direction" is
        # HiddenInput, direction field exists but its value is ''.
        # (2) Template except all_* is used. In this case, the default value
        # is None. To make sure 'direction' field has 'ingress' or 'egress',
        # fill this field here if it is not specified.
        if not cleaned_data['direction']:
            cleaned_data['direction'] = 'ingress'

        remote = cleaned_data.get("remote")
        if remote == "cidr":
            self._update_and_pop_error(cleaned_data, 'security_group', None)
        else:
            self._update_and_pop_error(cleaned_data, 'cidr', None)

        # If cleaned_data does not contain a non-empty value, IPField already
        # has validated it, so skip the further validation for cidr.
        # In addition cleaned_data['cidr'] is None means source_group is used.
        if 'cidr' in cleaned_data and cleaned_data['cidr'] is not None:
            cidr = cleaned_data['cidr']
            if not cidr:
                msg = _('CIDR must be specified.')
                self._errors['cidr'] = self.error_class([msg])
            else:
                # If cidr is specified, ethertype is determined from IP address
                # version. It is used only when Neutron is enabled.
                ip_ver = netaddr.IPNetwork(cidr).version
                cleaned_data['ethertype'] = 'IPv6' if ip_ver == 6 else 'IPv4'

        return cleaned_data

    def handle(self, request, data):
        try:
            rule = api.network.security_group_rule_create(
                request, filters.get_int_or_uuid(data['id']),
                data['direction'], data['ethertype'], data['ip_protocol'],
                data['from_port'], data['to_port'], data['cidr'],
                data['security_group'])
            messages.success(
                request,
                _('Successfully added rule: %s') % six.text_type(rule))
            return rule
        except Exception:
            redirect = reverse(
                "horizon:project:access_and_security:"
                "security_groups:detail",
                args=[data['id']])
            exceptions.handle(request,
                              _('Unable to add rule to security group.'),
                              redirect=redirect)
예제 #18
0
class CreateUserForm(BaseUserForm):
    # Hide the domain_id and domain_name by default
    domain_id = forms.CharField(label=_("Domain ID"),
                                required=False,
                                widget=forms.HiddenInput())
    domain_name = forms.CharField(label=_("Domain Name"),
                                  required=False,
                                  widget=forms.HiddenInput())
    name = forms.CharField(max_length=255, label=_("User Name"))
    email = forms.EmailField(
        label=_("Email"),
        required=False)
    password = forms.RegexField(
        label=_("Password"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm Password"),
        widget=forms.PasswordInput(render_value=False))
    project = forms.DynamicChoiceField(label=_("Primary Project"),
                                       required=PROJECT_REQUIRED,
                                       add_item_link=ADD_PROJECT_URL)
    role_id = forms.ChoiceField(label=_("Role"),
                                required=PROJECT_REQUIRED)
    no_autocomplete = True

    def __init__(self, *args, **kwargs):
        roles = kwargs.pop('roles')
        super(CreateUserForm, self).__init__(*args, **kwargs)
        role_choices = [(role.id, role.name) for role in roles]
        self.fields['role_id'].choices = role_choices

        # For keystone V3, display the two fields in read-only
        if api.keystone.VERSIONS.active >= 3:
            readonlyInput = forms.TextInput(attrs={'readonly': 'readonly'})
            self.fields["domain_id"].widget = readonlyInput
            self.fields["domain_name"].widget = readonlyInput

    # We have to protect the entire "data" dict because it contains the
    # password and confirm_password strings.
    @sensitive_variables('data')
    def handle(self, request, data):
        domain = api.keystone.get_default_domain(self.request)
        try:
            LOG.info('Creating user with name "%s"' % data['name'])
            if "email" in data:
                data['email'] = data['email'] or None
            new_user = api.keystone.user_create(request,
                                                name=data['name'],
                                                email=data['email'],
                                                password=data['password'],
                                                project=data['project'],
                                                enabled=True,
                                                domain=domain.id)
            messages.success(request,
                             _('User "%s" was successfully created.')
                             % data['name'])
            if data['project'] and data['role_id']:
                roles = api.keystone.roles_for_user(request,
                                        new_user.id,
                                        data['project']) or []
                assigned = [role for role in roles if role.id == str(
                    data['role_id'])]
                if not assigned:
                    try:
                        api.keystone.add_tenant_user_role(request,
                                                        data['project'],
                                                        new_user.id,
                                                        data['role_id'])
                    except Exception:
                        exceptions.handle(request,
                                        _('Unable to add user '
                                            'to primary project.'))
            return new_user
        except Exception:
            exceptions.handle(request, _('Unable to create user.'))
예제 #19
0
class TemplateForm(forms.SelfHandlingForm):
    class Meta:
        name = _('Select Template')
        help_text = _('From here you can select a template to launch '
                      'a stack.')

    template_source = forms.ChoiceField(
        label=_('Template Source'),
        choices=[('url', _('URL')), ('file', _('File')),
                 ('raw', _('Direct Input'))],
        widget=forms.Select(attrs={
            'class': 'switchable',
            'data-slug': 'source'
        }))
    template_upload = forms.FileField(
        label=_('Template File'),
        help_text=_('A local template to upload.'),
        widget=forms.FileInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'source',
                'data-source-file': _('Template File')
            }),
        required=False)
    template_url = forms.URLField(
        label=_('Template URL'),
        help_text=_('An external (HTTP) URL to load the template from.'),
        widget=forms.TextInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'source',
                'data-source-url': _('Template URL')
            }),
        required=False)
    template_data = forms.CharField(
        label=_('Template Data'),
        help_text=_('The raw contents of the template.'),
        widget=forms.widgets.Textarea(
            attrs={
                'class': 'switched',
                'data-switch-on': 'source',
                'data-source-raw': _('Template Data')
            }),
        required=False)

    def __init__(self, *args, **kwargs):
        self.next_view = kwargs.pop('next_view')
        super(TemplateForm, self).__init__(*args, **kwargs)

    def clean(self):
        cleaned = super(TemplateForm, self).clean()
        template_url = cleaned.get('template_url')
        template_data = cleaned.get('template_data')
        files = self.request.FILES
        has_upload = 'template_upload' in files

        # Uploaded file handler
        if has_upload and not template_url:
            log_template_name = self.request.FILES['template_upload'].name
            LOG.info('got upload %s' % log_template_name)

            tpl = self.request.FILES['template_upload'].read()
            if tpl.startswith('{'):
                try:
                    json.loads(tpl)
                except Exception as e:
                    msg = _('There was a problem parsing the template: %s') % e
                    raise forms.ValidationError(msg)
            cleaned['template_data'] = tpl

        # URL handler
        elif template_url and (has_upload or template_data):
            msg = _('Please specify a template using only one source method.')
            raise forms.ValidationError(msg)

        # Check for raw template input
        elif not template_url and not template_data:
            msg = _('You must specify a template via one of the '
                    'available sources.')
            raise forms.ValidationError(msg)

        # Validate the template and get back the params.
        kwargs = {}
        if cleaned['template_data']:
            kwargs['template'] = cleaned['template_data']
        else:
            kwargs['template_url'] = cleaned['template_url']

        try:
            validated = api.heat.template_validate(self.request, **kwargs)
            cleaned['template_validate'] = validated
        except Exception as e:
            msg = exception_to_validation_msg(e)
            if not msg:
                msg = _('An unknown problem occurred validating the template.')
                LOG.exception(msg)
            raise forms.ValidationError(msg)

        return cleaned

    def handle(self, request, data):
        kwargs = {
            'parameters': data['template_validate'],
            'template_data': data['template_data'],
            'template_url': data['template_url']
        }
        # NOTE (gabriel): This is a bit of a hack, essentially rewriting this
        # request so that we can chain it as an input to the next view...
        # but hey, it totally works.
        request.method = 'GET'
        return self.next_view.as_view()(request, **kwargs)
예제 #20
0
class AddInterface(forms.SelfHandlingForm):
    subnet_id = forms.ChoiceField(label=_("Subnet"))
    ip_address = forms.IPField(label=_("IP Address (optional)"),
                               required=False,
                               initial="",
                               help_text=_(
                                   "Specify an IP address for the interface "
                                   "created (e.g. 192.168.0.254)."),
                               version=forms.IPv4 | forms.IPv6,
                               mask=False)
    router_name = forms.CharField(
        label=_("Router Name"),
        widget=forms.TextInput(attrs={'readonly': 'readonly'}))
    router_id = forms.CharField(
        label=_("Router ID"),
        widget=forms.TextInput(attrs={'readonly': 'readonly'}))
    failure_url = 'horizon:project:routers:detail'

    def __init__(self, request, *args, **kwargs):
        super(AddInterface, self).__init__(request, *args, **kwargs)
        c = self.populate_subnet_id_choices(request)
        self.fields['subnet_id'].choices = c

    def populate_subnet_id_choices(self, request):
        tenant_id = self.request.user.tenant_id
        networks = []
        router_subnet_ids = []
        router_id = request.REQUEST.get('router_id',
                                        self.initial.get('router_id'))

        try:
            networks = api.neutron.network_list_for_tenant(request, tenant_id)
            if router_id:
                ports = api.neutron.port_list(request, device_id=router_id)
                router_subnet_ids = [
                    fixed_ip["subnet_id"] for port in ports
                    for fixed_ip in port.fixed_ips
                ]
        except Exception as e:
            msg = _('Failed to get network list %s') % e
            LOG.info(msg)
            messages.error(request, msg)
            if router_id:
                redirect = reverse(self.failure_url, args=[router_id])
            else:
                redirect = reverse('horizon:project:routers:index')
            exceptions.handle(request, msg, redirect=redirect)
            return

        choices = []
        for n in networks:
            net_name = n.name + ': ' if n.name else ''
            choices += [(subnet.id, '%s%s (%s)' %
                         (net_name, subnet.cidr, subnet.name or subnet.id))
                        for subnet in n['subnets']
                        if subnet.id not in router_subnet_ids]
        if choices:
            choices.insert(0, ("", _("Select Subnet")))
        else:
            choices.insert(0, ("", _("No subnets available")))
        return choices

    def handle(self, request, data):
        if data['ip_address']:
            port = self._add_interface_by_port(request, data)
        else:
            port = self._add_interface_by_subnet(request, data)
        msg = _('Interface added')
        if port:
            msg += ' ' + port.fixed_ips[0]['ip_address']
        LOG.debug(msg)
        messages.success(request, msg)
        return True

    def _add_interface_by_subnet(self, request, data):
        router_id = data['router_id']
        try:
            router_inf = api.neutron.router_add_interface(
                request, router_id, subnet_id=data['subnet_id'])
        except Exception as e:
            self._handle_error(request, router_id, e)
        try:
            port = api.neutron.port_get(request, router_inf['port_id'])
        except Exception:
            # Ignore an error when port_get() since it is just
            # to get an IP address for the interface.
            port = None
        return port

    def _add_interface_by_port(self, request, data):
        router_id = data['router_id']
        subnet_id = data['subnet_id']
        try:
            subnet = api.neutron.subnet_get(request, subnet_id)
        except Exception:
            msg = _('Unable to get subnet "%s"') % subnet_id
            self._handle_error(request, router_id, msg)
        try:
            ip_address = data['ip_address']
            body = {
                'network_id': subnet.network_id,
                'fixed_ips': [{
                    'subnet_id': subnet.id,
                    'ip_address': ip_address
                }]
            }
            port = api.neutron.port_create(request, **body)
        except Exception as e:
            self._handle_error(request, router_id, e)
        try:
            api.neutron.router_add_interface(request,
                                             router_id,
                                             port_id=port.id)
        except Exception as e:
            self._delete_port(request, port)
            self._handle_error(request, router_id, e)
        return port

    def _handle_error(self, request, router_id, reason):
        msg = _('Failed to add_interface: %s') % reason
        LOG.info(msg)
        redirect = reverse(self.failure_url, args=[router_id])
        exceptions.handle(request, msg, redirect=redirect)

    def _delete_port(self, request, port):
        try:
            api.neutron.port_delete(request, port.id)
        except Exception:
            msg = _('Failed to delete port %s') % port.id
            LOG.info(msg)
            exceptions.handle(request, msg)
예제 #21
0
class UpdateIKEPolicy(forms.SelfHandlingForm):
    name = forms.CharField(max_length=80, label=_("Name"), required=False)
    ikepolicy_id = forms.CharField(
        label=_("ID"), widget=forms.TextInput(attrs={'readonly': 'readonly'}))
    description = forms.CharField(required=False,
                                  max_length=80,
                                  label=_("Description"))
    # Currently this field has only one choice, so mark it as readonly.
    auth_algorithm = forms.ChoiceField(
        label=_("Authorization algorithm"),
        choices=[('sha1', _('sha1'))],
        widget=forms.ThemableSelectWidget(attrs={'readonly': 'readonly'}),
        required=False)
    encryption_algorithm = forms.ChoiceField(label=_("Encryption algorithm"),
                                             choices=[
                                                 ('3des', _('3des')),
                                                 ('aes-128', _('aes-128')),
                                                 ('aes-192', _('aes-192')),
                                                 ('aes-256', _('aes-256'))
                                             ],
                                             required=False)
    ike_version = forms.ChoiceField(label=_("IKE version"),
                                    choices=[('v1', _('v1')), ('v2', _('v2'))],
                                    required=False)
    # Currently this field has only one choice, so mark it as readonly.
    lifetime_units = forms.ChoiceField(
        label=_("Lifetime units for IKE keys"),
        choices=[('seconds', _('seconds'))],
        widget=forms.ThemableSelectWidget(attrs={'readonly': 'readonly'}),
        required=False)
    lifetime_value = forms.IntegerField(
        min_value=60,
        label=_("Lifetime value for IKE keys"),
        help_text=_("Equal to or greater than 60"),
        required=False)
    pfs = forms.ChoiceField(label=_("Perfect Forward Secrecy"),
                            choices=[('group2', _('group2')),
                                     ('group5', _('group5')),
                                     ('group14', _('group14'))],
                            required=False)
    # Currently this field has only one choice, so mark it as readonly.
    phase1_negotiation_mode = forms.ChoiceField(
        label=_("IKE Phase1 negotiation mode"),
        choices=[('main', 'main')],
        widget=forms.ThemableSelectWidget(attrs={'readonly': 'readonly'}),
        required=False)

    failure_url = 'horizon:project:vpn:index'

    def handle(self, request, context):
        try:
            data = {
                'ikepolicy': {
                    'name': context['name'],
                    'description': context['description'],
                    'auth_algorithm': context['auth_algorithm'],
                    'encryption_algorithm': context['encryption_algorithm'],
                    'ike_version': context['ike_version'],
                    'lifetime': {
                        'units': context['lifetime_units'],
                        'value': context['lifetime_value']
                    },
                    'pfs': context['pfs'],
                    'phase1_negotiation_mode':
                    context['phase1_negotiation_mode'],
                }
            }
            ikepolicy = api.vpn.ikepolicy_update(request,
                                                 context['ikepolicy_id'],
                                                 **data)
            msg = (_('IKE Policy %s was successfully updated.') %
                   context['name'])
            messages.success(request, msg)
            return ikepolicy
        except Exception as e:
            LOG.info('Failed to update IKE Policy %(id)s: %(exc)s', {
                'id': context['ikepolicy_id'],
                'exc': e
            })
            msg = _('Failed to update IKE Policy %s') % context['name']
            redirect = reverse(self.failure_url)
            exceptions.handle(request, msg, redirect=redirect)
예제 #22
0
class CreateForm(forms.SelfHandlingForm):
    name = forms.CharField(max_length=255, label=_("Router Name"))
    admin_state_up = forms.ChoiceField(label=_("Admin State"),
                                       choices=[(True, _('UP')),
                                                (False, _('DOWN'))],
                                       required=False)
    external_network = forms.ChoiceField(label=_("External Network"),
                                         required=True)
    mode = forms.ChoiceField(label=_("Router Type"))
    ha = forms.ChoiceField(label=_("High Availability Mode"))
    failure_url = 'horizon:project:routers:index'

    def __init__(self, request, *args, **kwargs):
        super(CreateForm, self).__init__(request, *args, **kwargs)
        self.dvr_allowed = api.neutron.get_feature_permission(
            self.request, "dvr", "create")
        if self.dvr_allowed:
            mode_choices = [('server_default', _('Use Server Default')),
                            ('centralized', _('Centralized')),
                            ('distributed', _('Distributed'))]
            self.fields['mode'].choices = mode_choices
        else:
            del self.fields['mode']

        self.ha_allowed = api.neutron.get_feature_permission(
            self.request, "l3-ha", "create")
        if self.ha_allowed:
            ha_choices = [('server_default', _('Use Server Default')),
                          ('enabled', _('Enable HA mode')),
                          ('disabled', _('Disable HA mode'))]
            self.fields['ha'].choices = ha_choices
        else:
            del self.fields['ha']
        networks = self._get_network_list(request)
        if networks:
            self.fields['external_network'].choices = networks
        else:
            del self.fields['external_network']

    def _get_network_list(self, request):
        search_opts = {'router:external': True}
        try:
            networks = api.neutron.network_list(request, **search_opts)
        except Exception:
            msg = _('Failed to get network list.')
            LOG.info(msg)
            messages.warning(request, msg)
            networks = []

        choices = [(network.id, network.name or network.id)
                   for network in networks]
        if choices:
            choices.insert(0, ("", _("Select network")))
        return choices

    def handle(self, request, data):
        try:
            params = {'name': data['name']}
            if 'admin_state_up' in data and data['admin_state_up']:
                params['admin_state_up'] = data['admin_state_up']
            if 'external_network' in data and data['external_network']:
                params['external_gateway_info'] = {
                    'network_id': data['external_network']
                }
            if (self.dvr_allowed and data['mode'] != 'server_default'):
                params['distributed'] = (data['mode'] == 'distributed')
            if (self.ha_allowed and data['ha'] != 'server_default'):
                params['ha'] = (data['ha'] == 'enabled')
            router = api.neutron.router_create(request, **params)
            message = _('Router %s was successfully created.') % data['name']
            messages.success(request, message)
            return router
        except Exception as exc:
            if exc.status_code == 409:
                msg = _('Quota exceeded for resource router.')
            else:
                msg = _('Failed to create router "%s".') % data['name']
            LOG.info(msg)
            redirect = reverse(self.failure_url)
            exceptions.handle(request, msg, redirect=redirect)
            return False
예제 #23
0
class OnBoardMEA(forms.SelfHandlingForm):
    name = forms.CharField(max_length=255, label=_("Name"))
    description = forms.CharField(
        widget=forms.widgets.Textarea(attrs={'rows': 4}),
        label=_("Description"),
        required=False)
    source_type = forms.ChoiceField(
        label=_('TOSCA Template Source'),
        required=False,
        choices=[('file', _('TOSCA Template File')),
                 ('raw', _('Direct Input'))],
        widget=forms.Select(attrs={
            'class': 'switchable',
            'data-slug': 'source'
        }))

    toscal_file = forms.FileField(
        label=_("TOSCA Template File"),
        help_text=_("A local TOSCA template file to upload."),
        widget=forms.FileInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'source',
                'data-source-file': _('TOSCA Template File')
            }),
        required=False)

    direct_input = forms.CharField(
        label=_('TOSCA YAML'),
        help_text=_('The YAML formatted contents of a TOSCA template.'),
        widget=forms.widgets.Textarea(
            attrs={
                'class': 'switched',
                'data-switch-on': 'source',
                'data-source-raw': _('TOSCA YAML')
            }),
        required=False)

    def __init__(self, request, *args, **kwargs):
        super(OnBoardMEA, self).__init__(request, *args, **kwargs)

    def clean(self):
        data = super(OnBoardMEA, self).clean()

        # The key can be missing based on particular upload
        # conditions. Code defensively for it here...
        toscal_file = data.get('toscal_file', None)
        toscal_raw = data.get('direct_input', None)
        source_type = data.get("source_type")
        if source_type == "file" and not toscal_file:
            raise ValidationError(_("No TOSCA template file selected."))
        if source_type == "raw" and not toscal_raw:
            raise ValidationError(_("No direct input specified."))

        if toscal_file and not toscal_file.name.endswith(('.yaml', '.csar')):
            raise ValidationError(
                _("Only .yaml or .csar file uploads \
                                    are supported"))

        try:
            if toscal_file:
                toscal_str = self.files['toscal_file'].read()
            else:
                toscal_str = data['direct_input']
            # toscal = yaml.loads(toscal_str)
            data['tosca'] = toscal_str
        except Exception as e:
            msg = _('There was a problem loading the namespace: %s.') % e
            raise forms.ValidationError(msg)

        return data

    def handle(self, request, data):
        try:
            toscal = data['tosca']
            mead_name = data['name']
            mead_description = data['description']
            tosca_arg = {
                'mead': {
                    'name': mead_name,
                    'description': mead_description,
                    'attributes': {
                        'mead': toscal
                    }
                }
            }
            mead_instance = api.apmec.create_mead(request, tosca_arg)
            messages.success(
                request,
                _('MEA Catalog entry %s has been created.') %
                mead_instance['mead']['name'])
            return toscal
        except Exception as e:
            msg = _('Unable to create TOSCA. %s')
            msg %= e.message.split('Failed validating', 1)[0]
            exceptions.handle(request, message=msg)
            return False
예제 #24
0
class AddTaskDetailsAction(workflows.Action):

    scheduleId = forms.IntegerField(label=_("ScheduleId)"),
                                    required=True,
                                    min_value=1,
                                    max_value=9999999,
                                    help_text=_("ScheduleId"))

    name = forms.CharField(label=_("Name"),
                           required=True,
                           max_length=80,
                           help_text=_("Name"))

    description = forms.CharField(label=_("Description"),
                                  required=True,
                                  max_length=120,
                                  help_text=_("Description"))

    hour = forms.IntegerField(label=_("Hour)"),
                              required=True,
                              min_value=1,
                              max_value=12,
                              help_text=_("1-12"))

    min = forms.IntegerField(label=_("Minute"),
                             required=True,
                             min_value=0,
                             max_value=59,
                             help_text=_("0 - 59"))

    period = forms.ChoiceField(label=_("Period"),
                               choices=[('AM', 'AM'), ('PM', 'PM')],
                               required=True,
                               help_text=_("AM or PM"))

    start = forms.DateField(
        label=_("Start date"),
        required=False,
        input_formats=("%Y-%m-%d", ),
        help_text=_("YYYY-MM-DD"),
        widget=forms.DateInput(attrs={'data-date-format': 'yyyy-mm-dd'}))

    end = forms.DateField(
        label=_("End date"),
        required=True,
        input_formats=("%Y-%m-%d", ),
        help_text=_("YYYY-MM-DD"),
        widget=forms.DateInput(attrs={'data-date-format': 'yyyy-mm-dd'}))

    enabled = forms.BooleanField(label=_("Enabled"),
                                 required=False,
                                 help_text=_("Enabled"))

    class Meta:
        name = _("Details")

    def __init__(self, request, context, *args, **kwargs):
        self.request = request
        self.context = context
        super(AddTaskDetailsAction, self).__init__(request, context, *args,
                                                   **kwargs)
예제 #25
0
파일: forms.py 프로젝트: tliu88/stx-horizon
class CreateForm(forms.SelfHandlingForm):
    name = forms.CharField(max_length="255", label=_("Server Group Name"))
    policy = forms.ChoiceField(label=_("Policy"),
                               required=False,
                               widget=forms.Select(attrs={
                                   'class': 'switchable',
                                   'data-slug': 'policy_ht'
                               }))

    is_best_effort = forms.BooleanField(label=_("Best Effort"), required=False)

    group_size = forms.IntegerField(
        min_value=1,
        label=_("Max Group Size (Instances)"),
        required=False,
        widget=forms.TextInput(
            attrs={
                'class': 'switchable switched',
                'data-switch-on': 'policy_ht',
                'data-policy_ht-anti-affinity': 'Max Group Size (Instances)',
                'data-policy_ht-affinity': 'Max Group Size (Instances)'
            }))

    group_size_ht = forms.IntegerField(
        label=_("Max Group Size (Instances)"),
        required=False,
        widget=forms.TextInput(
            attrs={
                'readonly': 'readonly',
                'class': 'switchable switched',
                'data-switch-on': 'policy_ht',
                'data-policy_ht-affinity-hyperthread':
                'Max Group Size (Instances)'
            }))

    def __init__(self, request, *args, **kwargs):
        super(CreateForm, self).__init__(request, *args, **kwargs)
        self.fields['policy'].choices = [("anti-affinity", "anti-affinity"),
                                         ("affinity", "affinity")]

    def handle(self, request, data):
        try:
            project_id = self.request.user.tenant_id
            policy = data['policy']
            policies = []
            if policy:
                policies.append(policy)
            metadata = {}
            if data['is_best_effort']:
                metadata['wrs-sg:best_effort'] = "true"
            group_size = data['group_size']
            group_size_ht = data['group_size_ht']
            if group_size:
                metadata['wrs-sg:group_size'] = str(group_size)
            elif group_size_ht:
                metadata['wrs-sg:group_size'] = str(group_size_ht)

            server_group = nova.server_group_create(request, data['name'],
                                                    project_id, metadata,
                                                    policies)

            return server_group

        except ValidationError as e:
            self.api_error(e.messages[0])
            return False
        except Exception:
            exceptions.handle(request, ignore=True)
            self.api_error(_("Unable to create server group."))
            return False
예제 #26
0
class UpdateProviderNetworkRange(forms.SelfHandlingForm):
    failure_url = 'horizon:admin:datanets:datanets:detail'
    providernet_id = forms.CharField(widget=forms.HiddenInput())
    providernet_range_id = forms.CharField(widget=forms.HiddenInput())
    name = forms.CharField(
        max_length=255,
        label=_("Name"),
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}))
    description = forms.CharField(max_length=255,
                                  label=_("Description"),
                                  required=False)
    minimum = forms.IntegerField(label=_("Minimum"), min_value=1)
    maximum = forms.IntegerField(label=_("Maximum"), min_value=1)
    shared = forms.BooleanField(widget=forms.HiddenInput(), required=False)
    tenant_id = forms.CharField(widget=forms.HiddenInput(), required=False)

    # VXLAN specific fields
    mode_widget = forms.TextInput(attrs={'readonly': 'readonly'})
    mode = forms.CharField(label=_("mode"), required=False, widget=mode_widget)
    group_widget = forms.TextInput(attrs={'readonly': 'readonly'})
    group = forms.CharField(max_length=255,
                            label=_("Multicast Group Address"),
                            required=False,
                            widget=group_widget)
    port_widget = forms.RadioSelect(attrs={'disabled': 'disabled'})
    port_choices = [('4789', _('IANA Assigned VXLAN UDP port (4789)')),
                    ('4790', _('IANA Assigned VXLAN-GPE UDP port (4790)')),
                    ('8472', _('Legacy VXLAN UDP port (8472)'))]
    port = forms.ChoiceField(label=_("UDP Port"),
                             required=False,
                             widget=port_widget,
                             choices=port_choices)
    ttl_widget = forms.TextInput(attrs={'readonly': 'readonly'})
    ttl = forms.IntegerField(label=_("TTL"), required=False, widget=ttl_widget)

    def __init__(self, request, *args, **kwargs):
        super(UpdateProviderNetworkRange,
              self).__init__(request, *args, **kwargs)
        initial = kwargs['initial']
        if 'mode' not in initial:
            del self.fields["mode"]
        if 'group' not in initial or initial.get('mode') == 'static':
            del self.fields["group"]
        if 'port' not in initial:
            del self.fields["port"]
        if 'ttl' not in initial:
            del self.fields["ttl"]

    def handle(self, request, data):
        try:
            params = {
                'description': data['description'],
                'minimum': data['minimum'],
                'maximum': data['maximum']
            }

            providernet_range = stx_api.neutron.provider_network_range_modify(
                request, data['providernet_range_id'], **params)
            msg = (_('Provider network range %s was successfully updated.') %
                   data['providernet_range_id'])
            LOG.debug(msg)
            messages.success(request, msg)
            return providernet_range
        except neutron_exceptions.NeutronClientException as e:
            LOG.info(str(e))
            redirect = reverse('horizon:admin:datanets:datanets:'
                               'detail',
                               args=(data['providernet_id'], ))
            exceptions.handle(request, str(e), redirect=redirect)
        except Exception:
            msg = (_('Failed to update provider network range %s') %
                   data['providernet_range_id'])
            LOG.info(msg)
            redirect = reverse(self.failure_url, args=[data['providernet_id']])
            exceptions.handle(request, msg, redirect=redirect)
예제 #27
0
파일: workflows.py 프로젝트: starlingx/gui
class UpdateHostInfoAction(workflows.Action):
    host_id = forms.CharField(widget=forms.widgets.HiddenInput)

    personality = forms.ChoiceField(
        label=_("Personality"),
        choices=PERSONALITY_CHOICES,
        widget=forms.Select(attrs={
            'class': 'switchable',
            'data-slug': 'personality'
        }))

    subfunctions = forms.ChoiceField(
        label=FIELD_LABEL_PERFORMANCE_PROFILE,
        choices=PERFORMANCE_CHOICES,
        widget=forms.Select(
            attrs={
                'class':
                'switched',
                'data-switch-on':
                'personality',
                'data-personality-' + stx_api.sysinv.PERSONALITY_WORKER:
                _("Performance Profile")
            }))

    hostname = forms.RegexField(
        label=_("Host Name"),
        max_length=255,
        required=False,
        regex=r'^[\w\.\-]+$',
        error_messages={
            'invalid':
            _('Name may only contain letters,'
              ' numbers, underscores, '
              'periods and hyphens.')
        },
        widget=forms.TextInput(
            attrs={
                'class':
                'switched',
                'data-switch-on':
                'personality',
                'data-personality-' + stx_api.sysinv.PERSONALITY_WORKER:
                _("Host Name")
            }))

    location = forms.CharField(label=_("Location"),
                               initial='location',
                               required=False,
                               help_text=_("Physical location of Host."))

    clock_synchronization = forms.ChoiceField(
        label=_("Clock Synchronization"),
        choices=stx_api.sysinv.CLOCK_SYNCHRONIZATION_CHOICES)

    cpuProfile = forms.ChoiceField(label=_("CPU Profile"), required=False)

    interfaceProfile = forms.ChoiceField(label=_("Interface Profile"),
                                         required=False)

    diskProfile = forms.ChoiceField(label=_("Storage Profile"), required=False)

    memoryProfile = forms.ChoiceField(label=_("Memory Profile"),
                                      required=False)

    ttys_dcd = forms.BooleanField(
        label=_("Serial Console Data Carrier Detect"),
        required=False,
        help_text=_("Enable serial line data carrier detection. "
                    "When selected, dropping carrier detect on the serial "
                    "port revoke any active session and a new login "
                    "process is initiated when a new connection is detected."))

    class Meta(object):
        name = _("Host Info")
        help_text = _(
            "From here you can update the configuration of the current host.\n"
            "Note: this will not affect the resources allocated to any"
            " existing"
            " instances using this host until the host is rebooted.")

    def __init__(self, request, *args, **kwargs):
        super(UpdateHostInfoAction, self).__init__(request, *args, **kwargs)

        # pesonality cannot be storage if ceph is not configured
        storage_backend = stx_api.sysinv.get_storage_backend(request)
        if stx_api.sysinv.STORAGE_BACKEND_CEPH not in storage_backend:
            self.fields['personality'].choices = \
                PERSONALITY_CHOICES_WITHOUT_STORAGE

        # All-in-one system, personality can only be controller or worker.
        systems = stx_api.sysinv.system_list(request)
        self.system_mode = systems[0].to_dict().get('system_mode')
        self.system_type = systems[0].to_dict().get('system_type')
        if self.system_type == constants.TS_AIO:
            self.fields['personality'].choices = \
                PERSONALITY_CHOICES_WITHOUT_STORAGE

        # hostname cannot be modified once it is set
        if self.initial['hostname']:
            self.fields['hostname'].widget.attrs['readonly'] = 'readonly'
            self.fields['hostname'].required = False

        # subfunctions cannot be modified once it is set
        if self.initial['subfunctions']:
            self.fields['subfunctions'].widget.attrs['readonly'] = 'readonly'
            self.fields['subfunctions'].required = False

        # personality cannot be modified once it is set
        host_id = self.initial['host_id']
        personality = self.initial['personality']

        mem_profile_configurable = False
        cpu_profile_configurable = False

        if personality and self.system_mode != constants.SYSTEM_MODE_SIMPLEX:
            self.fields['personality'].widget.attrs['readonly'] = 'readonly'
            self.fields['personality'].required = False
            self._personality = personality

            host = stx_api.sysinv.host_get(self.request, host_id)
            host.nodes = stx_api.sysinv.host_node_list(self.request, host.uuid)
            host.cpus = stx_api.sysinv.host_cpu_list(self.request, host.uuid)
            host.ports = stx_api.sysinv.host_port_list(self.request, host.uuid)
            host.disks = stx_api.sysinv.host_disk_list(self.request, host.uuid)

            if 'worker' in host.subfunctions:
                mem_profile_configurable = True
                cpu_profile_configurable = True
                host.memory = stx_api.sysinv.host_memory_list(
                    self.request, host.uuid)
            else:
                del self.fields['memoryProfile']

            if host.nodes and host.cpus and host.ports:
                # Populate Available Interface Profile Choices
                try:
                    avail_interface_profile_list = \
                        stx_api.sysinv.host_interfaceprofile_list(self.request)

                    interface_profile_tuple_list = [
                        ('', _("Copy from an available interface profile."))
                    ]
                    for ip in avail_interface_profile_list:
                        if ifprofile_applicable(request, host, ip):
                            interface_profile_tuple_list.append(
                                (ip.profilename, ip.profilename))

                except Exception:
                    exceptions.handle(
                        self.request,
                        _('Unable to retrieve list of interface profiles.'))
                    interface_profile_tuple_list = []

                self.fields[
                    'interfaceProfile'].choices = interface_profile_tuple_list
            else:
                self.fields[
                    'interfaceProfile'].widget = forms.widgets.HiddenInput()

            stor_model = sysinv.get_ceph_storage_model(request)
            if ((personality == 'storage' or
                 (personality == 'controller'
                  and stor_model == sysinv_const.CEPH_CONTROLLER_MODEL)
                 or 'worker' in host._subfunctions) and host.disks):
                # Populate Available Disk Profile Choices
                try:
                    disk_profile_tuple_list = [
                        ('', _("Copy from an available storage profile."))
                    ]
                    avail_disk_profile_list = \
                        stx_api.sysinv.host_diskprofile_list(self.request)
                    for dp in avail_disk_profile_list:
                        if diskprofile_applicable(host, dp):
                            disk_profile_tuple_list.append(
                                (dp.profilename, dp.profilename))

                except Exception as e:
                    LOG.exception(e)
                    exceptions.handle(
                        self.request,
                        _('Unable to retrieve list of storage profiles.'))
                    disk_profile_tuple_list = []

                self.fields['diskProfile'].choices = disk_profile_tuple_list
            else:
                self.fields['diskProfile'].widget = forms.widgets.HiddenInput()

            # Populate Available Cpu Profile Choices
            if cpu_profile_configurable and host.nodes and host.memory:
                try:
                    avail_cpu_profile_list = \
                        stx_api.sysinv.host_cpuprofile_list(self.request)

                    host_profile = icpu_utils.HostCpuProfile(
                        host.subfunctions, host.cpus, host.nodes)

                    cpu_profile_tuple_list = [
                        ('', _("Copy from an available cpu profile."))
                    ]
                    for ip in avail_cpu_profile_list:
                        nodes = stx_api.sysinv.host_node_list(
                            self.request, ip.uuid)
                        cpu_profile = icpu_utils.CpuProfile(ip.cpus, nodes)
                        if host_profile.profile_applicable(cpu_profile):
                            cpu_profile_tuple_list.append(
                                (ip.profilename, ip.profilename))

                except Exception:
                    exceptions.handle(
                        self.request,
                        _('Unable to retrieve list of cpu profiles.'))
                    cpu_profile_tuple_list = []

                self.fields['cpuProfile'].choices = cpu_profile_tuple_list

            else:
                self.fields['cpuProfile'].widget = forms.widgets.HiddenInput()

            if mem_profile_configurable and host.nodes and host.memory:
                # Populate Available Memory Profile Choices
                try:
                    avail_memory_profile_list = \
                        stx_api.sysinv.host_memprofile_list(self.request)
                    memory_profile_tuple_list = [
                        ('', _("Copy from an available memory profile."))
                    ]
                    for mp in avail_memory_profile_list:
                        if memoryprofile_applicable(host, host._subfunctions,
                                                    mp):
                            memory_profile_tuple_list.append(
                                (mp.profilename, mp.profilename))

                except Exception:
                    exceptions.handle(
                        self.request,
                        _('Unable to retrieve list of memory profiles.'))
                    memory_profile_tuple_list = []

                self.fields[
                    'memoryProfile'].choices = memory_profile_tuple_list

        else:
            self.fields['cpuProfile'].widget = forms.widgets.HiddenInput()
            self.fields['interfaceProfile'].widget = forms.widgets.HiddenInput(
            )
            self.fields['diskProfile'].widget = forms.widgets.HiddenInput()
            self.fields['memoryProfile'].widget = forms.widgets.HiddenInput()

    def clean_location(self):
        try:
            host_id = self.cleaned_data['host_id']
            host = stx_api.sysinv.host_get(self.request, host_id)
            location = host._location
            location['locn'] = self.cleaned_data.get('location')
            return location
        except Exception:
            msg = _('Unable to get host data')
            exceptions.check_message(["Connection", "refused"], msg)
            raise

    def clean(self):
        cleaned_data = super(UpdateHostInfoAction, self).clean()
        disabled = self.fields['personality'].widget.attrs.get('disabled')
        if disabled == 'disabled':
            if self.system_type == constants.TS_AIO:
                self._personality = 'controller'
            cleaned_data['personality'] = self._personality

        if cleaned_data['personality'] == stx_api.sysinv.PERSONALITY_STORAGE:
            self._subfunctions = stx_api.sysinv.PERSONALITY_STORAGE
            cleaned_data['subfunctions'] = self._subfunctions
        elif cleaned_data['personality'] == \
                stx_api.sysinv.PERSONALITY_CONTROLLER:
            if self.system_type == constants.TS_AIO:
                self._subfunctions = (stx_api.sysinv.PERSONALITY_CONTROLLER +
                                      ',' + stx_api.sysinv.PERSONALITY_WORKER)
            else:
                self._subfunctions = stx_api.sysinv.PERSONALITY_CONTROLLER
            cleaned_data['subfunctions'] = self._subfunctions

        return cleaned_data
예제 #28
0
class CreateProviderNetworkRange(forms.SelfHandlingForm):
    providernet_id = forms.CharField(widget=forms.HiddenInput())
    name = forms.CharField(max_length=255, label=_("Name"), required=False)
    description = forms.CharField(max_length=255,
                                  label=_("Description"),
                                  required=False)
    shared = forms.BooleanField(label=_("Shared"),
                                initial=False,
                                required=False,
                                widget=forms.CheckboxInput(
                                    attrs={
                                        'class': 'switchable',
                                        'data-hide-on-checked': 'true',
                                        'data-slug': 'is_shared'
                                    }))

    tenant_id = forms.ChoiceField(
        label=_("Project"),
        required=False,
        widget=forms.Select(attrs={
            'class': 'switched',
            'data-switch-on': 'is_shared'
        }))

    minimum = forms.IntegerField(label=_("Minimum"), min_value=1)
    maximum = forms.IntegerField(label=_("Maximum"), min_value=1)
    # VXLAN specific fields
    mode_choices = [('dynamic', _('Multicast VXLAN')),
                    ('static', _('Static VXLAN'))]
    mode = forms.ChoiceField(label=_("Mode"),
                             initial='dynamic',
                             required=False,
                             choices=mode_choices,
                             widget=forms.Select(attrs={
                                 'class': 'switchable',
                                 'data-slug': 'vxlan_mode'
                             }))
    group_help = (_("Specify the IPv4 or IPv6 multicast address for these "
                    "VXLAN instances"))
    group = forms.CharField(
        max_length=255,
        label=_("Multicast Group Address"),
        initial="239.0.0.1",
        required=False,
        help_text=group_help,
        widget=forms.TextInput(
            attrs={
                'class': 'switchable switched',
                'data-slug': 'vxlan_group',
                'data-switch-on': 'vxlan_mode',
                'data-vxlan_mode-dynamic': 'Multicast Group Address'
            }))
    port_choices = [('4789', _('IANA Assigned VXLAN UDP port (4789)')),
                    ('4790', _('IANA Assigned VXLAN-GPE UDP port (4790)')),
                    ('8472', _('Legacy VXLAN UDP port (8472)'))]
    port = forms.ChoiceField(label=_("UDP Port"),
                             required=True,
                             widget=forms.RadioSelect(),
                             choices=port_choices)
    ttl = forms.IntegerField(
        label=_("TTL"),
        required=False,
        initial=1,
        min_value=1,
        max_value=255,
        help_text=(
            _("Specify the time-to-live value for these VXLAN instances")))

    def __init__(self, request, *args, **kwargs):
        super(CreateProviderNetworkRange,
              self).__init__(request, *args, **kwargs)

        tenant_choices = [('', _("Select a project"))]
        tenants, has_more = api.keystone.tenant_list(request)  # noqa pylint: disable=unused-variable
        for tenant in tenants:
            if tenant.enabled:
                tenant_choices.append((tenant.id, tenant.name))
        self.fields['tenant_id'].choices = tenant_choices
        initial = kwargs['initial']
        if 'providernet_type' in initial:
            providernet_type = initial['providernet_type']
            if providernet_type != "vxlan":
                del self.fields["mode"]
                del self.fields["group"]
                del self.fields["port"]
                del self.fields["ttl"]

    def handle(self, request, data):
        try:
            params = {
                'providernet_id': data['providernet_id'],
                'name': data['name'],
                'description': data['description'],
                'minimum': data['minimum'],
                'maximum': data['maximum'],
                'shared': data['shared'],
                'tenant_id': data['tenant_id']
            }

            if not data['tenant_id']:
                params['shared'] = True

            if self.initial['providernet_type'] == "vxlan":
                params['mode'] = data['mode']
                if params['mode'] == 'dynamic':
                    params['group'] = data['group']
                params['port'] = int(data['port'])
                params['ttl'] = int(data['ttl'])

            providernet_range = stx_api.neutron.provider_network_range_create(
                request, **params)
            msg = (_('Provider network range %s was successfully created.') %
                   providernet_range['id'])
            LOG.debug(msg)
            messages.success(request, msg)
            return providernet_range
        except neutron_exceptions.NeutronClientException as e:
            LOG.info(str(e))
            redirect = reverse('horizon:admin:datanets:datanets:'
                               'detail',
                               args=(data['providernet_id'], ))
            exceptions.handle(request, str(e), redirect=redirect)
        except Exception:
            msg = _('Failed to create a provider'
                    ' network range for network %s') \
                % data['providernet_id']
            LOG.info(msg)
            redirect = reverse('horizon:admin:datanets:datanets:'
                               'detail',
                               args=(data['providernet_id'], ))
            exceptions.handle(request, msg, redirect=redirect)

    def clean(self):
        cleaned_data = super(CreateProviderNetworkRange, self).clean()
        if not cleaned_data["shared"] and not cleaned_data["tenant_id"]:
            msg = "Project must be specified for non-shared Segmentation Range"
            raise forms.ValidationError(msg)
        if cleaned_data["shared"]:
            cleaned_data["tenant_id"] = ""
예제 #29
0
class CustomizeAction(workflows.Action):
    class Meta(object):
        name = _("Post-Creation")
        help_text_template = ("project/instances/"
                              "_launch_customize_help.html")

    source_choices = [('', _('Select Script Source')),
                      ('raw', _('Direct Input')), ('file', _('File'))]

    attributes = {'class': 'switchable', 'data-slug': 'scriptsource'}
    script_source = forms.ChoiceField(
        label=_('Customization Script Source'),
        choices=source_choices,
        widget=forms.ThemableSelectWidget(attrs=attributes),
        required=False)

    script_help = _("A script or set of commands to be executed after the "
                    "instance has been built (max 16kb).")

    script_upload = forms.FileField(
        label=_('Script File'),
        help_text=script_help,
        widget=forms.FileInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'scriptsource',
                'data-scriptsource-file': _('Script File')
            }),
        required=False)

    script_data = forms.CharField(
        label=_('Script Data'),
        help_text=script_help,
        widget=forms.widgets.Textarea(
            attrs={
                'class': 'switched',
                'data-switch-on': 'scriptsource',
                'data-scriptsource-raw': _('Script Data')
            }),
        required=False)

    def __init__(self, *args):
        super(CustomizeAction, self).__init__(*args)

    def clean(self):
        cleaned = super(CustomizeAction, self).clean()

        files = self.request.FILES
        script = self.clean_uploaded_files('script', files)

        if script is not None:
            cleaned['script_data'] = script

        return cleaned

    def clean_uploaded_files(self, prefix, files):
        upload_str = prefix + "_upload"

        has_upload = upload_str in files
        if has_upload:
            upload_file = files[upload_str]
            log_script_name = upload_file.name
            LOG.info('got upload %s' % log_script_name)

            if upload_file._size > 16 * units.Ki:  # 16kb
                msg = _('File exceeds maximum size (16kb)')
                raise forms.ValidationError(msg)
            else:
                script = upload_file.read()
                if script != "":
                    try:
                        normalize_newlines(script)
                    except Exception as e:
                        msg = _('There was a problem parsing the'
                                ' %(prefix)s: %(error)s')
                        msg = msg % {
                            'prefix': prefix,
                            'error': six.text_type(e)
                        }
                        raise forms.ValidationError(msg)
                return script
        else:
            return None
예제 #30
0
파일: forms.py 프로젝트: termie/horizon
 def __init__(self, *args, **kwargs):
     super(FloatingIpAssociate, self).__init__(*args, **kwargs)
     instancelist = kwargs.get('initial', {}).get('instances', [])
     self.fields['instance_id'] = forms.ChoiceField(choices=instancelist,
                                                    label=_("Instance"))