示例#1
0
    def __init__(self, request, *args, **kwargs):
        super(GeneralConfigAction, self).__init__(request, *args, **kwargs)

        hlps = helpers.Helpers(request)

        plugin, hadoop_version = (
            workflow_helpers.get_plugin_and_hadoop_version(request))

        if not saharaclient.SAHARA_AUTO_IP_ALLOCATION_ENABLED:
            pools = neutron.floating_ip_pools_list(request)
            pool_choices = [(pool.id, pool.name) for pool in pools]
            pool_choices.insert(0, (None, "Do not assign floating IPs"))

            self.fields['floating_ip_pool'] = forms.ChoiceField(
                label=_("Floating IP Pool"),
                choices=pool_choices,
                required=False)

        self.fields["use_autoconfig"] = forms.BooleanField(
            label=_("Auto-configure"),
            help_text=_("If selected, instances of a node group will be "
                        "automatically configured during cluster "
                        "creation. Otherwise you should manually specify "
                        "configuration values."),
            required=False,
            widget=forms.CheckboxInput(),
            initial=True,
        )

        self.fields["proxygateway"] = forms.BooleanField(
            label=_("Proxy Gateway"),
            widget=forms.CheckboxInput(),
            help_text=_("Sahara will use instances of this node group to "
                        "access other cluster instances."),
            required=False)

        self.fields['is_public'] = acl_utils.get_is_public_form(
            _("node group template"))
        self.fields['is_protected'] = acl_utils.get_is_protected_form(
            _("node group template"))

        self.fields["plugin_name"] = forms.CharField(
            widget=forms.HiddenInput(), initial=plugin)
        self.fields["hadoop_version"] = forms.CharField(
            widget=forms.HiddenInput(), initial=hadoop_version)

        self.fields["storage"].choices = storage_choices(request)

        node_parameters = hlps.get_general_node_group_configs(
            plugin, hadoop_version)
        for param in node_parameters:
            self.fields[param.name] = workflow_helpers.build_control(param)

        # when we copy or edit a node group template then
        # request contains valuable info in both GET and POST methods
        req = request.GET.copy()
        req.update(request.POST)
        if req.get("guide_template_type"):
            self.fields["guide_template_type"] = forms.CharField(
                required=False,
                widget=forms.HiddenInput(),
                initial=req.get("guide_template_type"))

        if is_cinder_enabled(request):
            volume_types = cinder.volume_type_list(request)
        else:
            volume_types = []

        self.fields['volume_type'].choices = [(None, _("No volume type"))] + \
                                             [(type.name, type.name)
                                              for type in volume_types]
示例#2
0
class CreateImageForm(CreateParent):
    name = forms.CharField(max_length=255, label=_("Name"))
    description = forms.CharField(max_length=255,
                                  widget=forms.Textarea(attrs={'rows': 4}),
                                  label=_("Description"),
                                  required=False)
    source_type = forms.ChoiceField(
        label=_('Image Source'),
        required=False,
        choices=[('url', _('Image Location')), ('file', _('Image File'))],
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'data-slug': 'source'
        }))
    image_url_attrs = {
        'class': 'switched',
        'data-switch-on': 'source',
        'data-source-url': _('Image Location'),
        'ng-model': 'ctrl.copyFrom',
        'ng-change': 'ctrl.selectImageFormat(ctrl.copyFrom)',
        'placeholder': 'http://example.com/image.img'
    }
    image_url = ImageURLField(label=_("Image Location"),
                              help_text=_("An external (HTTP/HTTPS) URL to "
                                          "load the image from."),
                              widget=forms.TextInput(attrs=image_url_attrs),
                              required=False)
    image_attrs = {
        'class': 'switched',
        'data-switch-on': 'source',
        'data-source-file': _('Image File'),
        'ng-model': 'ctrl.imageFile',
        'ng-change': 'ctrl.selectImageFormat(ctrl.imageFile.name)',
        'image-file-on-change': None
    }
    image_file = FileField(label=_("Image File"),
                           help_text=_("A local image to upload."),
                           widget=forms.FileInput(attrs=image_attrs),
                           required=False)
    kernel = forms.ChoiceField(
        label=_('Kernel'),
        required=False,
        widget=forms.ThemableSelectWidget(transform=lambda x: "%s (%s)" % (
            x.name, defaultfilters.filesizeformat(x.size))))
    ramdisk = forms.ChoiceField(
        label=_('Ramdisk'),
        required=False,
        widget=forms.ThemableSelectWidget(transform=lambda x: "%s (%s)" % (
            x.name, defaultfilters.filesizeformat(x.size))))
    disk_format = forms.ChoiceField(
        label=_('Format'),
        choices=[],
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'ng-model': 'ctrl.diskFormat'
        }))
    architecture = forms.CharField(
        max_length=255,
        label=_("Architecture"),
        help_text=_('CPU architecture of the image.'),
        required=False)
    min_disk = forms.IntegerField(
        label=_("Minimum Disk (GB)"),
        min_value=0,
        help_text=_('The minimum disk size required to boot the image. '
                    'If unspecified, this value defaults to 0 (no minimum).'),
        required=False)
    min_ram = forms.IntegerField(
        label=_("Minimum RAM (MB)"),
        min_value=0,
        help_text=_('The minimum memory size required to boot the image. '
                    'If unspecified, this value defaults to 0 (no minimum).'),
        required=False)
    is_copying = forms.BooleanField(
        label=_("Copy Data"),
        initial=True,
        required=False,
        help_text=_('Specify this option to copy image data to the image '
                    'service. If unspecified, image data will be used in its '
                    'current location.'),
        widget=forms.CheckboxInput(
            attrs={
                'class': 'switched',
                'data-source-url': _('Image Location'),
                'data-switch-on': 'source'
            }))
    is_public = forms.BooleanField(
        label=_("Public"),
        help_text=_('Make the image visible across projects.'),
        required=False)
    protected = forms.BooleanField(
        label=_("Protected"),
        help_text=_('Prevent the deletion of the image.'),
        required=False)

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

        if (api.glance.get_image_upload_mode() == 'off' or not policy.check(
            (("image", "upload_image"), ), request)):
            self._hide_file_source_type()
        if not policy.check((("image", "set_image_location"), ), request):
            self._hide_url_source_type()

        # GlanceV2 feature removals
        if api.glance.VERSIONS.active >= 2:
            # NOTE: GlanceV2 doesn't support copy-from feature, sorry!
            self._hide_is_copying()
            if not settings.IMAGES_ALLOW_LOCATION:
                self._hide_url_source_type()
                if (api.glance.get_image_upload_mode() == 'off'
                        or not policy.check(
                            (("image", "upload_image"), ), request)):
                    # Neither setting a location nor uploading image data is
                    # allowed, so throw an error.
                    msg = _('The current Horizon settings indicate no valid '
                            'image creation methods are available. Providing '
                            'an image location and/or uploading from the '
                            'local file system must be allowed to support '
                            'image creation.')
                    messages.error(request, msg)
                    raise ValidationError(msg)
        if not policy.check((("image", "publicize_image"), ), request):
            self._hide_is_public()

        self.fields['disk_format'].choices = \
            api.glance.get_image_formats(request)

        try:
            kernel_images = api.glance.image_list_detailed(
                request, filters={'disk_format': 'aki'})[0]
        except Exception:
            kernel_images = []
            msg = _('Unable to retrieve image list.')
            messages.error(request, msg)

        if kernel_images:
            choices = [('', _("Choose an image"))]
            for image in kernel_images:
                choices.append((image.id, image))
            self.fields['kernel'].choices = choices
        else:
            del self.fields['kernel']

        try:
            ramdisk_images = api.glance.image_list_detailed(
                request, filters={'disk_format': 'ari'})[0]
        except Exception:
            ramdisk_images = []
            msg = _('Unable to retrieve image list.')
            messages.error(request, msg)

        if ramdisk_images:
            choices = [('', _("Choose an image"))]
            for image in ramdisk_images:
                choices.append((image.id, image))
            self.fields['ramdisk'].choices = choices
        else:
            del self.fields['ramdisk']

    def _hide_file_source_type(self):
        self.fields['image_file'].widget = HiddenInput()
        source_type = self.fields['source_type']
        source_type.choices = [
            choice for choice in source_type.choices if choice[0] != 'file'
        ]
        if len(source_type.choices) == 1:
            source_type.widget = HiddenInput()

    def _hide_url_source_type(self):
        self.fields['image_url'].widget = HiddenInput()
        source_type = self.fields['source_type']
        source_type.choices = [
            choice for choice in source_type.choices if choice[0] != 'url'
        ]
        if len(source_type.choices) == 1:
            source_type.widget = HiddenInput()

    def _hide_is_public(self):
        self.fields['is_public'].widget = HiddenInput()
        self.fields['is_public'].initial = False

    def _hide_is_copying(self):
        self.fields['is_copying'].widget = HiddenInput()
        self.fields['is_copying'].initial = False

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

        # The image_file key can be missing based on particular upload
        # conditions. Code defensively for it here...
        source_type = data.get('source_type', None)
        image_file = data.get('image_file', None)
        image_url = data.get('image_url', None)

        if not image_url and not image_file:
            msg = _("An image file or an external location must be specified.")
            if source_type == 'file':
                raise ValidationError({'image_file': [
                    msg,
                ]})
            else:
                raise ValidationError({'image_url': [
                    msg,
                ]})
        else:
            return data

    def handle(self, request, data):
        meta = api.glance.create_image_metadata(data)

        # Add image source file or URL to metadata
        if (api.glance.get_image_upload_mode() != 'off' and policy.check(
            (("image", "upload_image"), ), request)
                and data.get('image_file', None)):
            meta['data'] = data['image_file']
        elif data.get('is_copying'):
            meta['copy_from'] = data['image_url']
        else:
            meta['location'] = data['image_url']

        try:
            image = api.glance.image_create(request, **meta)
            messages.info(
                request,
                _('Your image %s has been queued for creation.') %
                meta['name'])
            return image
        except Exception as e:
            msg = _('Unable to create new image')
            # TODO(nikunj2512): Fix this once it is fixed in glance client
            if hasattr(e, 'code') and e.code == 400:
                if "Invalid disk format" in e.details:
                    msg = _('Unable to create new image: Invalid disk format '
                            '%s for image.') % meta['disk_format']
                elif "Image name too long" in e.details:
                    msg = _('Unable to create new image: Image name too long.')
                elif "not supported" in e.details:
                    msg = _('Unable to create new image: URL scheme not '
                            'supported.')

            exceptions.handle(request, msg)

            return False
示例#3
0
class SetInstanceDetailsAction(workflows.Action):
    availability_zone = forms.ChoiceField(label=_("Availability Zone"),
                                          required=False)

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

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

    count = forms.IntegerField(label=_("Instance Count"),
                               min_value=1,
                               initial=1,
                               help_text=_("Number of instances to launch."))

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

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

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

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

    image_id = forms.ChoiceField(
        label=_("Image Name"),
        required=False,
        widget=forms.SelectWidget(
            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."))

    delete_on_terminate = forms.BooleanField(label=_("Delete on Terminate"),
                                             initial=False,
                                             required=False,
                                             help_text=_("Delete volume on "
                                                         "instance terminate"))

    class Meta:
        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 base.is_service_enabled(request, 'volume'):
            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

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

        count = cleaned_data.get('count', 1)
        # Prevent launching more instances than the quota allows
        usages = quotas.tenant_quota_usages(self.request)
        available_count = usages['instances']['available']
        if available_count < count:
            error_message = ungettext_lazy('The requested instance '
                                           'cannot be launched as you only '
                                           'have %(avail)i of your quota '
                                           'available. ',
                                           'The requested %(req)i instances '
                                           'cannot be launched as you only '
                                           'have %(avail)i of your quota '
                                           'available.',
                                           count)
            params = {'req': count,
                      'avail': available_count}
            raise forms.ValidationError(error_message % params)
        try:
            flavor_id = cleaned_data.get('flavor')
            # 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

        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])

        # Validate our instance source.
        source_type = self.data.get('source_type', None)

        if source_type in ('image_id', 'volume_image_id'):
            if source_type == 'volume_image_id':
                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])
            else:
                # Prevents trying to launch an image needing more resources.
                try:
                    image_id = cleaned_data.get('image_id')
                    # 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

                if image and flavor:
                    props_mapping = (("min_ram", "ram"), ("min_disk", "disk"))
                    for iprop, fprop in props_mapping:
                        if getattr(image, iprop) > 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.

                    volume_size = cleaned_data.get('volume_size')
                    if volume_size and source_type == 'volume_image_id':
                        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])

        elif source_type == 'instance_snapshot_id':
            if not cleaned_data['instance_snapshot_id']:
                msg = _("You must select a snapshot.")
                self._errors['instance_snapshot_id'] = self.error_class([msg])

        elif source_type == 'volume_id':
            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?
            if count > 1:
                msg = _('Launching multiple instances is only supported for '
                        'images and instance snapshots.')
                raise forms.ValidationError(msg)

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

        return cleaned_data

    def populate_flavor_choices(self, request, context):
        flavors = instance_utils.flavor_list(request)
        if flavors:
            return instance_utils.sort_flavor_list(request, flavors)
        return []

    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 = extra_context or {}
        try:
            extra['usages'] = api.nova.tenant_absolute_limits(self.request)
            extra['usages_json'] = json.dumps(extra['usages'])
            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)}
                         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:
            image.bytes = 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)
            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):
        try:
            volumes = [self._get_volume_display_name(v)
                       for v in cinder.volume_list(self.request)
                       if (v.status == api.cinder.VOLUME_STATE_AVAILABLE
                           and v.bootable == 'true')]
        except Exception:
            volumes = []
            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):
        try:
            snapshots = cinder.volume_snapshot_list(self.request)
            snapshots = [self._get_volume_display_name(s) for s in snapshots
                         if s.status == api.cinder.VOLUME_STATE_AVAILABLE]
        except Exception:
            snapshots = []
            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
示例#4
0
class JobConfigAction(workflows.Action):
    MAIN_CLASS = "edp.java.main_class"
    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"

    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)

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

    streaming_mapper = forms.CharField(label=_("Mapper"))

    streaming_reducer = forms.CharField(label=_("Reducer"))

    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)

    def __init__(self, request, *args, **kwargs):
        super(JobConfigAction, self).__init__(request, *args, **kwargs)
        job_ex_id = request.REQUEST.get("job_execution_id")
        if job_ex_id is not None:
            job_ex_id = request.REQUEST.get("job_execution_id")
            job_ex = saharaclient.job_execution_get(request, job_ex_id)
            job_configs = 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.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])

    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):
        job_id = request.REQUEST.get("job_id") or request.REQUEST.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.iteritems():
            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.JAVA_OPTS
            ]:
                del configs[rmkey]
        return (configs, edp_configs)

    class Meta(object):
        name = _("Configure")
        help_text_template = (
            "project/data_processing.jobs/_launch_job_configure_help.html")
示例#5
0
class UpdateRule(forms.SelfHandlingForm):
    name = forms.CharField(max_length=80, label=_("Name"), required=False)
    description = forms.CharField(required=False,
                                  max_length=80,
                                  label=_("Description"))
    protocol = forms.ChoiceField(label=_("Protocol"),
                                 required=False,
                                 help_text=_('Protocol for the firewall rule'))
    action = forms.ChoiceField(label=_("Action"),
                               required=False,
                               help_text=_('Action for the firewall rule'))
    source_ip_address = forms.IPField(
        label=_("Source IP Address/Subnet"),
        version=forms.IPv4 | forms.IPv6,
        required=False,
        mask=True,
        help_text=_('Source IP address or subnet'))
    destination_ip_address = forms.IPField(
        label=_('Destination IP Address/Subnet'),
        version=forms.IPv4 | forms.IPv6,
        required=False,
        mask=True,
        help_text=_('Destination IP address or subnet'))
    source_port = forms.CharField(
        max_length=80,
        label=_("Source Port/Port Range"),
        required=False,
        validators=[port_validator],
        help_text=_('Source port (integer in [1, 65535] or range in a:b)'))
    destination_port = forms.CharField(
        max_length=80,
        label=_("Destination Port/Port Range"),
        required=False,
        validators=[port_validator],
        help_text=_('Destination port (integer in [1, 65535] or range'
                    ' in a:b)'))
    shared = forms.BooleanField(label=_("Shared"), required=False)
    enabled = forms.BooleanField(label=_("Enabled"), required=False)

    failure_url = 'horizon:project:firewalls:index'

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

        protocol = kwargs['initial']['protocol'].upper()
        action = kwargs['initial']['action'].upper()

        protocol_choices = [(protocol, protocol)]
        for tup in [('TCP', _('TCP')), ('UDP', _('UDP')), ('ICMP', _('ICMP'))]:
            if tup[0] != protocol:
                protocol_choices.append(tup)
        self.fields['protocol'].choices = protocol_choices

        action_choices = [(action, action)]
        for tup in [('ALLOW', _('ALLOW')), ('DENY', _('DENY'))]:
            if tup[0] != action:
                action_choices.append(tup)
        self.fields['action'].choices = action_choices

    def handle(self, request, context):
        rule_id = self.initial['rule_id']
        name_or_id = context.get('name') or rule_id
        for f in [
                'source_ip_address', 'destination_ip_address', 'source_port',
                'destination_port'
        ]:
            if not context[f]:
                context[f] = None
        try:
            rule = api.fwaas.rule_update(request, rule_id, **context)
            msg = _('Rule %s was successfully updated.') % name_or_id
            LOG.debug(msg)
            messages.success(request, msg)
            return rule
        except Exception as e:
            msg = _('Failed to update rule %(name)s: %(reason)s' % {
                'name': name_or_id,
                'reason': e
            })
            LOG.error(msg)
            redirect = reverse(self.failure_url)
            exceptions.handle(request, msg, redirect=redirect)
示例#6
0
class ProjectRequestForm(forms.SelfHandlingForm):

    prjaction = forms.ChoiceField(
        label=_('Project action'),
        choices = [
            ('newprj', _('Create new project')),
        ],
        widget=forms.Select(attrs={
            'class': 'switchable',
            'data-slug': 'actsource'
        })
    )
    
    newprj = forms.CharField(
        label=_('Personal project'),
        max_length=OS_SNAME_LEN,
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'switched',
            'data-switch-on': 'actsource',
            'data-actsource-newprj': _('Project name')
        })
    )
    prjdescr = forms.CharField(
        label=_("Project description"),
        required=False,
        widget=forms.widgets.Textarea(attrs={
            'class': 'switched',
            'data-switch-on': 'actsource',
            'data-actsource-newprj': _('Project description')
        })
    )
    prjpriv = forms.BooleanField(
        label=_("Private project"),
        required=False,
        initial=False,
        widget=forms.widgets.CheckboxInput(attrs={
            'class': 'switched',
            'data-switch-on': 'actsource',
            'data-actsource-newprj': _('Private project')
        })
    )
    
    selprj = forms.MultipleChoiceField(
        label=_('Available projects'),
        required=False,
        widget=forms.SelectMultiple(attrs={
            'class': 'switched',
            'data-switch-on': 'actsource',
            'data-actsource-selprj': _('Select existing project')
        }),
    )


    notes = forms.CharField(
        label=_('Notes'),
        required=False,
        widget=forms.widgets.Textarea()
    )

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

        auth_prjs = [
            pitem.name for pitem in self.request.user.authorized_tenants
        ]

        pendPReq = PrjRequest.objects.filter(registration__userid=self.request.user.id)
        self.pendingProjects = [ prjreq.project.projectname for prjreq in pendPReq ]
        excl_prjs = auth_prjs + self.pendingProjects

        prj_list = Project.objects.exclude(projectname__in=excl_prjs)
        prj_list = prj_list.filter(status__in=[PRJ_PUBLIC, PRJ_COURSE], projectid__isnull=False)

        prjEntries = [
            (prj_entry.projectname, prj_entry.projectname) for prj_entry in prj_list
        ]
        if len(prjEntries):
            self.fields['selprj'].choices = prjEntries
            self.fields['prjaction'].choices = [
                ('newprj', _('Create new project')),
                ('selprj', _('Select existing projects'))
            ]
        

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

        if data['prjaction'] == 'newprj':
            if not data['newprj']:
                raise ValidationError(_('Project name is required.'))
            tmpm = PRJ_REGEX.search(data['newprj'])
            if tmpm:
                raise ValidationError(_('Bad character "%s" for project name.') % tmpm.group(0))
        elif data['prjaction'] == 'selprj':
            if not data['selprj']:
                raise ValidationError(_('Missing selected project.'))

        return data

    @sensitive_variables('data')
    def handle(self, request, data):
    
        with transaction.atomic():
        
            registration = Registration.objects.filter(userid=request.user.id)[0]
        
            prj_action = data['prjaction']
            prjlist = list()
            if prj_action == 'selprj':
                for project in data['selprj']:
                    prjlist.append((project, "", PRJ_PUBLIC, False))
            
            elif prj_action == 'newprj':
                prjlist.append((
                    data['newprj'],
                    data['prjdescr'],
                    PRJ_PRIVATE if data['prjpriv'] else PRJ_PUBLIC,
                    True
                ))

        
            newprjlist = list()
            exstprjlist = list()
            for prjitem in prjlist:
        
                if prjitem[3]:
                    try:

                        prjArgs = {
                            'projectname' : prjitem[0],
                            'description' : prjitem[1],
                            'status' : prjitem[2]
                        }
                        project = Project.objects.create(**prjArgs)
                        newprjlist.append(project.projectname)

                    except IntegrityError:
                        messages.error(request, _("Project %s already exists") % prjitem[0])
                        LOG.error("Cannot create project %s" % prjitem[0])
                        return False
                
                elif prjitem[0] in self.pendingProjects:
                    continue
                else:
                    project = Project.objects.get(projectname=prjitem[0])
                    exstprjlist.append(project)
                        
                reqArgs = {
                    'registration' : registration,
                    'project' : project,
                    'flowstatus' : PSTATUS_PENDING,
                    'notes' : data['notes']
                }                
                reqPrj = PrjRequest(**reqArgs)
                reqPrj.save()

            #
            # Send notification to cloud admins for project creation
            #
            for prj_name in newprjlist:
                noti_params = {
                    'username' : request.user.username,
                    'project' : prj_name
                }
                notifyAdmin(request=self.request, action=NEWPRJ_REQ_TYPE, context=noti_params)

            #
            # Send notifications to project managers
            #
            for prj_item in exstprjlist:

                admin_emails = list()
                for prj_role in PrjRole.objects.filter(project=prj_item):
                    for email_obj in EMail.objects.filter(registration=prj_role.registration):
                        admin_emails.append(email_obj.email)

                noti_params = {
                    'username' : request.user.username,
                    'project' : prj_item.projectname
                }
                notifyProject(request=request, rcpt=admin_emails, action=MEMBER_REQUEST, 
                              context=noti_params)

        return True
示例#7
0
class CreateSubnetInfoAction(workflows.Action):
    with_subnet = forms.BooleanField(
        label=_("Create Subnet"),
        widget=forms.CheckboxInput(
            attrs={
                'class': 'switchable',
                'data-slug': 'with_subnet',
                'data-hide-tab': 'create_network__'
                'createsubnetdetail'
                'action',
                'data-hide-on-checked': 'false'
            }),
        initial=True,
        required=False)
    subnet_name = forms.CharField(
        max_length=255,
        widget=forms.TextInput(attrs={
            'class': 'switched',
            'data-switch-on': 'with_subnet',
        }),
        label=_("Subnet Name"),
        required=False)
    cidr = forms.IPField(label=_("Network Address"),
                         required=False,
                         initial="",
                         widget=forms.TextInput(
                             attrs={
                                 'class': 'switched',
                                 'data-switch-on': 'with_subnet',
                                 'data-is-required': 'true'
                             }),
                         help_text=_("Network address in CIDR format "
                                     "(e.g. 192.168.0.0/24, 2001:DB8::/48)"),
                         version=forms.IPv4 | forms.IPv6,
                         mask=True)
    ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
                                   widget=forms.Select(
                                       attrs={
                                           'class': 'switchable switched',
                                           'data-slug': 'ipversion',
                                           'data-switch-on': 'with_subnet'
                                       }),
                                   label=_("IP Version"))
    gateway_ip = forms.IPField(
        label=_("Gateway IP"),
        widget=forms.TextInput(attrs={
            'class': 'switched',
            'data-switch-on': 'with_subnet gateway_ip'
        }),
        required=False,
        initial="",
        help_text=_("IP address of Gateway (e.g. 192.168.0.254) "
                    "The default value is the first IP of the "
                    "network address "
                    "(e.g. 192.168.0.1 for 192.168.0.0/24, "
                    "2001:DB8::1 for 2001:DB8::/48). "
                    "If you use the default, leave blank. "
                    "If you do not want to use a gateway, "
                    "check 'Disable Gateway' below."),
        version=forms.IPv4 | forms.IPv6,
        mask=False)
    no_gateway = forms.BooleanField(label=_("Disable Gateway"),
                                    widget=forms.CheckboxInput(
                                        attrs={
                                            'class': 'switched switchable',
                                            'data-slug': 'gateway_ip',
                                            'data-switch-on': 'with_subnet',
                                            'data-hide-on-checked': 'true'
                                        }),
                                    initial=False,
                                    required=False)
    msg = _('Specify "Network Address" or ' 'clear "Create Subnet" checkbox.')

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

    def __init__(self, request, context, *args, **kwargs):
        super(CreateSubnetInfoAction, self).__init__(request, context, *args,
                                                     **kwargs)
        if not getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}).get(
                'enable_ipv6', True):
            self.fields['ip_version'].widget = forms.HiddenInput()
            self.fields['ip_version'].initial = 4

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

    def clean(self):
        cleaned_data = super(CreateSubnetInfoAction, self).clean()
        with_subnet = cleaned_data.get('with_subnet')
        if not with_subnet:
            return cleaned_data
        self._check_subnet_data(cleaned_data)
        return cleaned_data
示例#8
0
class CreateSubnetDetailAction(workflows.Action):
    enable_dhcp = forms.BooleanField(label=_("Enable DHCP"),
                                     initial=True,
                                     required=False)
    allocation_pools = forms.CharField(
        widget=forms.Textarea(),
        label=_("Allocation Pools"),
        help_text=_("IP address allocation pools. Each entry is "
                    "&lt;start_ip_address&gt;,&lt;end_ip_address&gt; "
                    "(e.g., 192.168.1.100,192.168.1.120) "
                    "and one entry per line."),
        required=False)
    dns_nameservers = forms.CharField(
        widget=forms.widgets.Textarea(),
        label=_("DNS Name Servers"),
        help_text=_("IP address list of DNS name servers for this subnet. "
                    "One entry per line."),
        required=False)
    host_routes = forms.CharField(
        widget=forms.widgets.Textarea(),
        label=_("Host Routes"),
        help_text=_("Additional routes announced to the hosts. "
                    "Each entry is &lt;destination_cidr&gt;,&lt;nexthop&gt; "
                    "(e.g., 192.168.200.0/24,10.56.1.254) "
                    "and one entry per line."),
        required=False)

    class Meta:
        name = _("Subnet Detail")
        help_text = _('You can specify additional attributes for the subnet.')

    def _convert_ip_address(self, ip, field_name):
        try:
            return netaddr.IPAddress(ip)
        except (netaddr.AddrFormatError, ValueError):
            msg = _('%(field_name)s: Invalid IP address '
                    '(value=%(ip)s)' % dict(field_name=field_name, ip=ip))
            raise forms.ValidationError(msg)

    def _convert_ip_network(self, network, field_name):
        try:
            return netaddr.IPNetwork(network)
        except (netaddr.AddrFormatError, ValueError):
            msg = _('%(field_name)s: Invalid IP address '
                    '(value=%(network)s)' %
                    dict(field_name=field_name, network=network))
            raise forms.ValidationError(msg)

    def _check_allocation_pools(self, allocation_pools):
        for p in allocation_pools.split('\n'):
            p = p.strip()
            if not p:
                continue
            pool = p.split(',')
            if len(pool) != 2:
                msg = _('Start and end addresses must be specified '
                        '(value=%s)') % p
                raise forms.ValidationError(msg)
            start, end = [
                self._convert_ip_address(ip, "allocation_pools") for ip in pool
            ]
            if start > end:
                msg = _('Start address is larger than end address '
                        '(value=%s)') % p
                raise forms.ValidationError(msg)

    def _check_dns_nameservers(self, dns_nameservers):
        for ns in dns_nameservers.split('\n'):
            ns = ns.strip()
            if not ns:
                continue
            self._convert_ip_address(ns, "dns_nameservers")

    def _check_host_routes(self, host_routes):
        for r in host_routes.split('\n'):
            r = r.strip()
            if not r:
                continue
            route = r.split(',')
            if len(route) != 2:
                msg = _('Host Routes format error: '
                        'Destination CIDR and nexthop must be specified '
                        '(value=%s)') % r
                raise forms.ValidationError(msg)
            self._convert_ip_network(route[0], "host_routes")
            self._convert_ip_address(route[1], "host_routes")

    def clean(self):
        cleaned_data = super(CreateSubnetDetailAction, self).clean()
        self._check_allocation_pools(cleaned_data.get('allocation_pools'))
        self._check_host_routes(cleaned_data.get('host_routes'))
        self._check_dns_nameservers(cleaned_data.get('dns_nameservers'))
        return cleaned_data
示例#9
0
class CreateSubnetInfoAction(workflows.Action):
    with_subnet = forms.BooleanField(label=_("Create Subnet"),
                                     initial=True,
                                     required=False)
    subnet_name = forms.CharField(max_length=255,
                                  label=_("Subnet Name"),
                                  help_text=_("Subnet Name. This field is "
                                              "optional."),
                                  required=False)
    cidr = fields.IPField(label=_("Network Address"),
                          required=False,
                          initial="",
                          help_text=_("Network address in CIDR format "
                                      "(e.g. 192.168.0.0/24)"),
                          version=fields.IPv4 | fields.IPv6,
                          mask=True)
    ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
                                   label=_("IP Version"))
    gateway_ip = fields.IPField(
        label=_("Gateway IP (optional)"),
        required=False,
        initial="",
        help_text=_("IP address of Gateway (e.g. 192.168.0.254) "
                    "The default value is the first IP of the "
                    "network address (e.g. 192.168.0.1 for "
                    "192.168.0.0/24). "
                    "If you use the default, leave blank. "
                    "If you want to use no gateway, "
                    "check 'Disable Gateway' below."),
        version=fields.IPv4 | fields.IPv6,
        mask=False)
    no_gateway = forms.BooleanField(label=_("Disable Gateway"),
                                    initial=False,
                                    required=False)

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

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

    def clean(self):
        cleaned_data = super(CreateSubnetInfoAction, self).clean()
        with_subnet = cleaned_data.get('with_subnet')
        if not with_subnet:
            return cleaned_data
        self._check_subnet_data(cleaned_data)
        return cleaned_data
示例#10
0
class TenantsTable(tables.DataTable):
    name = tables.Column('name',
                         verbose_name=_('Name'),
                         link=("horizon:identity:projects:detail"),
                         form_field=forms.CharField(max_length=64),
                         update_action=UpdateCell)
    description = tables.Column(lambda obj: getattr(obj, 'description', None),
                                verbose_name=_('Description'),
                                form_field=forms.CharField(
                                    widget=forms.Textarea(attrs={'rows': 4}),
                                    required=False),
                                update_action=UpdateCell)
    id = tables.Column('id', verbose_name=_('Project ID'))
    enabled = tables.Column('enabled',
                            verbose_name=_('Enabled'),
                            status=True,
                            filters=(filters.yesno, filters.capfirst),
                            form_field=forms.BooleanField(label=_('Enabled'),
                                                          required=False),
                            update_action=UpdateCell)

    if api.keystone.VERSIONS.active >= 3:
        domain_name = tables.Column('domain_name',
                                    verbose_name=_('Domain Name'))
        enabled = tables.Column('enabled',
                                verbose_name=_('Enabled'),
                                status=True,
                                filters=(filters.yesno, filters.capfirst),
                                form_field=forms.BooleanField(
                                    label=_('Enabled'), required=False),
                                update_action=UpdateCell)

    def get_project_detail_link(self, project):
        # this method is an ugly monkey patch, needed because
        # the column link method does not provide access to the request
        if policy.check((("identity", "identity:get_project"), ),
                        self.request,
                        target={"project": project}):
            return reverse("horizon:identity:projects:detail",
                           args=(project.id, ))
        return None

    def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs):
        super(TenantsTable,
              self).__init__(request,
                             data=data,
                             needs_form_wrapper=needs_form_wrapper,
                             **kwargs)
        # see the comment above about ugly monkey patches
        self.columns['name'].get_link_url = self.get_project_detail_link

    class Meta(object):
        name = "tenants"
        verbose_name = _("Projects")
        row_class = UpdateRow
        row_actions = (UpdateMembersLink, UpdateGroupsLink, UpdateProject,
                       UsageLink, ModifyQuotas, DeleteTenantsAction,
                       RescopeTokenToProject)
        table_actions = (TenantFilterAction, CreateProject,
                         DeleteTenantsAction)
        pagination_param = "tenant_marker"
示例#11
0
    def __init__(self, request, *args, **kwargs):
        super(CreateForm, self).__init__(request, *args, **kwargs)
        # NOTE(vkmc): choose only those share protocols that are enabled
        # FIXME(vkmc): this should be better implemented by having a
        # capabilities endpoint on the control plane.
        manila_features = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
        self.enabled_share_protocols = manila_features.get(
            'enabled_share_protocols',
            ['NFS', 'CIFS', 'GlusterFS', 'HDFS', 'CephFS', 'MapRFS'])
        self.enable_public_shares = manila_features.get(
            'enable_public_shares', True)
        share_networks = manila.share_network_list(request)
        share_types = manila.share_type_list(request)
        self.fields['share_type'].choices = (
            [("", "")] + [(st.name, st.name) for st in share_types])

        availability_zones = manila.availability_zone_list(request)
        self.fields['availability_zone'].choices = (
            [("", "")] + [(az.name, az.name) for az in availability_zones])

        if features.is_share_groups_enabled():
            share_groups = manila.share_group_list(request)
            self.fields['sg'] = forms.ChoiceField(
                label=_("Share Group"),
                choices=[("", "")] + [(sg.id, sg.name or sg.id)
                                      for sg in share_groups],
                required=False)

        self.sn_field_name_prefix = 'share-network-choices-'
        for st in share_types:
            extra_specs = st.get_keys()
            dhss = extra_specs.get('driver_handles_share_servers')
            # NOTE(vponomaryov): Set and tie share-network field only for
            # share types with enabled handling of share servers.
            if (isinstance(dhss, str) and dhss.lower() in ['true', '1']):
                sn_choices = (
                    [('', '')] +
                    [(sn.id, sn.name or sn.id) for sn in share_networks])
                sn_field_name = self.sn_field_name_prefix + st.name
                sn_field = forms.ChoiceField(
                    label=_("Share Network"), required=True,
                    choices=sn_choices,
                    widget=forms.Select(attrs={
                        'class': 'switched',
                        'data-switch-on': 'sharetype',
                        'data-sharetype-%s' % st.name: _("Share Network"),
                    }))
                self.fields[sn_field_name] = sn_field

        self.fields['share_source_type'] = forms.ChoiceField(
            label=_("Share Source"), required=False,
            widget=forms.Select(
                attrs={'class': 'switchable', 'data-slug': 'source'}))
        self.fields['snapshot'] = forms.ChoiceField(
            label=_("Use snapshot as a source"),
            widget=forms.fields.SelectWidget(
                attrs={'class': 'switched',
                       'data-switch-on': 'source',
                       'data-source-snapshot': _('Snapshot')},
                data_attrs=('size', 'name'),
                transform=lambda x: "%s (%sGiB)" % (x.name, x.size)),
            required=False)
        self.fields['metadata'] = forms.CharField(
            label=_("Metadata"), required=False,
            widget=forms.Textarea(attrs={'rows': 4}))

        if self.enable_public_shares:
            self.fields['is_public'] = forms.BooleanField(
                label=_("Make visible to users from all projects"),
                required=False)

        self.fields['share_proto'].choices = [(sp, sp) for sp in
                                              self.enabled_share_protocols]
        if ("snapshot_id" in request.GET or
                kwargs.get("data", {}).get("snapshot")):
            try:
                snapshot = self.get_snapshot(
                    request,
                    request.GET.get("snapshot_id",
                                    kwargs.get("data", {}).get("snapshot")))
                self.fields['name'].initial = snapshot.name
                self.fields['size'].initial = snapshot.size
                self.fields['snapshot'].choices = ((snapshot.id, snapshot),)
                try:
                    # Set the share type from the original share
                    orig_share = manila.share_get(request, snapshot.share_id)
                    # NOTE(vponomaryov): we should use share type name, not ID,
                    # because we use names in our choices above.
                    self.fields['share_type'].initial = (
                        orig_share.share_type_name)
                except Exception:
                    pass
                self.fields['size'].help_text = _(
                    'Share size must be equal to or greater than the snapshot '
                    'size (%sGiB)') % snapshot.size
                del self.fields['share_source_type']
            except Exception:
                exceptions.handle(request,
                                  _('Unable to load the specified snapshot.'))
        else:
            source_type_choices = []

            try:
                snapshot_list = manila.share_snapshot_list(request)
                snapshots = [s for s in snapshot_list
                             if s.status == 'available']
                if snapshots:
                    source_type_choices.append(("snapshot",
                                                _("Snapshot")))
                    choices = [('', _("Choose a snapshot"))] + \
                              [(s.id, s) for s in snapshots]
                    self.fields['snapshot'].choices = choices
                else:
                    del self.fields['snapshot']
            except Exception:
                exceptions.handle(request, _("Unable to retrieve "
                                             "share snapshots."))

            if source_type_choices:
                choices = ([('no_source_type',
                             _("No source, empty share"))] +
                           source_type_choices)
                self.fields['share_source_type'].choices = choices
            else:
                del self.fields['share_source_type']
示例#12
0
class CreateNetwork(forms.SelfHandlingForm):
    name = forms.CharField(max_length=255,
                           label=_("Name"),
                           required=False)
    tenant_id = forms.ChoiceField(label=_("Project"))
    if api.neutron.is_port_profiles_supported():
        widget = None
    else:
        widget = forms.HiddenInput()
    net_profile_id = forms.ChoiceField(label=_("Network Profile"),
                                       required=False,
                                       widget=widget)
    admin_state = forms.BooleanField(label=_("Admin State"),
                                     initial=True, required=False)
    shared = forms.BooleanField(label=_("Shared"),
                                initial=False, required=False)
    external = forms.BooleanField(label=_("External Network"),
                                  initial=False, required=False)

    @classmethod
    def _instantiate(cls, request, *args, **kwargs):
        return cls(request, *args, **kwargs)

    def __init__(self, request, *args, **kwargs):
        super(CreateNetwork, self).__init__(request, *args, **kwargs)
        tenant_choices = [('', _("Select a project"))]
        tenants, has_more = api.keystone.tenant_list(request)
        for tenant in tenants:
            if tenant.enabled:
                tenant_choices.append((tenant.id, tenant.name))
        self.fields['tenant_id'].choices = tenant_choices

        if api.neutron.is_port_profiles_supported():
            self.fields['net_profile_id'].choices = (
                self.get_network_profile_choices(request))

    def get_network_profile_choices(self, request):
        profile_choices = [('', _("Select a profile"))]
        for profile in self._get_profiles(request, 'network'):
            profile_choices.append((profile.id, profile.name))
        return profile_choices

    def _get_profiles(self, request, type_p):
        profiles = []
        try:
            profiles = api.neutron.profile_list(request, type_p)
        except Exception:
            msg = _('Network Profiles could not be retrieved.')
            exceptions.handle(request, msg)
        return profiles

    def handle(self, request, data):
        try:
            params = {'name': data['name'],
                      'tenant_id': data['tenant_id'],
                      'admin_state_up': data['admin_state'],
                      'shared': data['shared'],
                      'router:external': data['external']}
            if api.neutron.is_port_profiles_supported():
                params['net_profile_id'] = data['net_profile_id']
            network = api.neutron.network_create(request, **params)
            msg = _('Network %s was successfully created.') % data['name']
            LOG.debug(msg)
            messages.success(request, msg)
            return network
        except Exception:
            redirect = reverse('horizon:admin:networks:index')
            msg = _('Failed to create network %s') % data['name']
            exceptions.handle(request, msg, redirect=redirect)
示例#13
0
class CreateNetwork(forms.SelfHandlingForm):
    name = forms.CharField(max_length=255, label=_("Name"), required=False)
    tenant_id = forms.ThemableChoiceField(label=_("Project"))
    network_type = forms.ChoiceField(
        label=_("Provider Network Type"),
        help_text=_("The physical mechanism by which the virtual "
                    "network is implemented."),
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'data-slug': 'network_type'
        }))
    physical_network = forms.CharField(
        max_length=255,
        label=_("Physical Network"),
        help_text=_("The name of the physical network over which the "
                    "virtual network is implemented. Specify one of the "
                    "physical networks defined in your neutron deployment."),
        widget=forms.TextInput(attrs={
            'class': 'switched',
            'data-switch-on': 'network_type',
        }))
    segmentation_id = forms.IntegerField(
        label=_("Segmentation ID"),
        widget=forms.TextInput(attrs={
            'class': 'switched',
            'data-switch-on': 'network_type',
        }))
    admin_state = forms.BooleanField(label=_("Enable Admin State"),
                                     initial=True,
                                     required=False)
    shared = forms.BooleanField(label=_("Shared"),
                                initial=False,
                                required=False)
    external = forms.BooleanField(label=_("External Network"),
                                  initial=False,
                                  required=False)
    with_subnet = forms.BooleanField(label=_("Create Subnet"),
                                     widget=forms.CheckboxInput(
                                         attrs={
                                             'class':
                                             'switchable',
                                             'data-slug':
                                             'with_subnet',
                                             'data-hide-tab':
                                             'create_network__'
                                             'createsubnetinfo'
                                             'action,'
                                             'create_network__'
                                             'createsubnetdetail'
                                             'action',
                                             'data-hide-on-checked':
                                             'false'
                                         }),
                                     initial=True,
                                     required=False)
    az_hints = forms.MultipleChoiceField(
        label=_("Availability Zone Hints"),
        required=False,
        help_text=_("Availability zones where the DHCP agents may be "
                    "scheduled. Leaving this unset is equivalent to "
                    "selecting all availability zones"))

    @classmethod
    def _instantiate(cls, request, *args, **kwargs):
        return cls(request, *args, **kwargs)

    def __init__(self, request, *args, **kwargs):
        super(CreateNetwork, self).__init__(request, *args, **kwargs)
        tenant_choices = [('', _("Select a project"))]
        tenants, has_more = api.keystone.tenant_list(request)
        for tenant in tenants:
            if tenant.enabled:
                tenant_choices.append((tenant.id, tenant.name))
        self.fields['tenant_id'].choices = tenant_choices

        try:
            is_extension_supported = \
                api.neutron.is_extension_supported(request, 'provider')
        except Exception:
            msg = _("Unable to verify Neutron service providers")
            exceptions.handle(self.request, msg)
            self._hide_provider_network_type()
            is_extension_supported = False

        if is_extension_supported:
            neutron_settings = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK',
                                       {})
            self.seg_id_range = SEGMENTATION_ID_RANGE.copy()
            seg_id_range = neutron_settings.get('segmentation_id_range')
            if seg_id_range:
                self.seg_id_range.update(seg_id_range)

            self.provider_types = PROVIDER_TYPES.copy()
            extra_provider_types = neutron_settings.get('extra_provider_types')
            if extra_provider_types:
                self.provider_types.update(extra_provider_types)

            self.nettypes_with_seg_id = [
                net_type for net_type in self.provider_types
                if self.provider_types[net_type]['require_segmentation_id']
            ]
            self.nettypes_with_physnet = [
                net_type for net_type in self.provider_types
                if self.provider_types[net_type]['require_physical_network']
            ]

            supported_provider_types = neutron_settings.get(
                'supported_provider_types', DEFAULT_PROVIDER_TYPES)
            if supported_provider_types == ['*']:
                supported_provider_types = DEFAULT_PROVIDER_TYPES

            undefined_provider_types = [
                net_type for net_type in supported_provider_types
                if net_type not in self.provider_types
            ]
            if undefined_provider_types:
                LOG.error('Undefined provider network types are found: %s',
                          undefined_provider_types)

            seg_id_help = [
                _("For %(type)s networks, valid IDs are %(min)s to %(max)s.") %
                {
                    'type': net_type,
                    'min': self.seg_id_range[net_type][0],
                    'max': self.seg_id_range[net_type][1]
                } for net_type in self.nettypes_with_seg_id
            ]
            self.fields['segmentation_id'].help_text = ' '.join(seg_id_help)

            # Register network types which require segmentation ID
            attrs = dict(
                ('data-network_type-%s' % network_type, _('Segmentation ID'))
                for network_type in self.nettypes_with_seg_id)
            self.fields['segmentation_id'].widget.attrs.update(attrs)

            physical_networks = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK',
                                        {}).get('physical_networks', [])

            if physical_networks:
                self.fields['physical_network'] = forms.ThemableChoiceField(
                    label=_("Physical Network"),
                    choices=[(net, net) for net in physical_networks],
                    widget=forms.ThemableSelectWidget(
                        attrs={
                            'class': 'switched',
                            'data-switch-on': 'network_type',
                        }),
                    help_text=_("The name of the physical network over "
                                "which the virtual network is implemented."),
                )

            # Register network types which require physical network
            attrs = dict(
                ('data-network_type-%s' % network_type, _('Physical Network'))
                for network_type in self.nettypes_with_physnet)
            self.fields['physical_network'].widget.attrs.update(attrs)

            network_type_choices = [
                (net_type, self.provider_types[net_type]['display_name'])
                for net_type in supported_provider_types
            ]
            if len(network_type_choices) == 0:
                self._hide_provider_network_type()
            else:
                self.fields['network_type'].choices = network_type_choices

        try:
            if api.neutron.is_extension_supported(request,
                                                  'network_availability_zone'):
                zones = api.neutron.list_availability_zones(
                    self.request, 'network', 'available')
                self.fields['az_hints'].choices = [(zone['name'], zone['name'])
                                                   for zone in zones]
            else:
                del self.fields['az_hints']
        except Exception:
            msg = _('Failed to get availability zone list.')
            messages.warning(request, msg)
            del self.fields['az_hints']

    def _hide_provider_network_type(self):
        self.fields['network_type'].widget = forms.HiddenInput()
        self.fields['physical_network'].widget = forms.HiddenInput()
        self.fields['segmentation_id'].widget = forms.HiddenInput()
        self.fields['network_type'].required = False
        self.fields['physical_network'].required = False
        self.fields['segmentation_id'].required = False

    def handle(self, request, data):
        try:
            params = {
                'name': data['name'],
                'tenant_id': data['tenant_id'],
                'admin_state_up': data['admin_state'],
                'shared': data['shared'],
                'router:external': data['external']
            }
            if api.neutron.is_extension_supported(request, 'provider'):
                network_type = data['network_type']
                params['provider:network_type'] = network_type
                if network_type in self.nettypes_with_physnet:
                    params['provider:physical_network'] = (
                        data['physical_network'])
                if network_type in self.nettypes_with_seg_id:
                    params['provider:segmentation_id'] = (
                        data['segmentation_id'])
            if 'az_hints' in data and data['az_hints']:
                params['availability_zone_hints'] = data['az_hints']
            network = api.neutron.network_create(request, **params)
            LOG.debug('Network %s was successfully created.', data['name'])
            return network
        except Exception:
            redirect = reverse('horizon:admin:networks:index')
            msg = _('Failed to create network %s') % data['name']
            exceptions.handle(request, msg, redirect=redirect)

    def clean(self):
        cleaned_data = super(CreateNetwork, self).clean()
        if api.neutron.is_extension_supported(self.request, 'provider'):
            self._clean_physical_network(cleaned_data)
            self._clean_segmentation_id(cleaned_data)
        return cleaned_data

    def _clean_physical_network(self, data):
        network_type = data.get('network_type')
        if ('physical_network' in self._errors
                and network_type not in self.nettypes_with_physnet):
            # In this case the physical network is not required, so we can
            # ignore any errors.
            del self._errors['physical_network']

    def _clean_segmentation_id(self, data):
        network_type = data.get('network_type')
        if 'segmentation_id' in self._errors:
            if (network_type not in self.nettypes_with_seg_id
                    and not self.data.get("segmentation_id")):
                # In this case the segmentation ID is not required, so we can
                # ignore the field is required error.
                del self._errors['segmentation_id']
        elif network_type in self.nettypes_with_seg_id:
            seg_id = data.get('segmentation_id')
            seg_id_range = {
                'min': self.seg_id_range[network_type][0],
                'max': self.seg_id_range[network_type][1]
            }
            if seg_id < seg_id_range['min'] or seg_id > seg_id_range['max']:
                msg = (_('For a %(network_type)s network, valid segmentation '
                         'IDs are %(min)s through %(max)s.') % {
                             'network_type': network_type,
                             'min': seg_id_range['min'],
                             'max': seg_id_range['max']
                         })
                self._errors['segmentation_id'] = self.error_class([msg])
示例#14
0
class GeneralConfigAction(workflows.Action):
    nodegroup_name = forms.CharField(label=_("Template Name"))

    description = forms.CharField(label=_("Description"),
                                  required=False,
                                  widget=forms.Textarea(attrs={'rows': 4}))

    flavor = forms.ChoiceField(label=_("OpenStack Flavor"))

    availability_zone = forms.ChoiceField(
        label=_("Availability Zone"),
        help_text=_("Launch instances in this availability zone."),
        required=False,
        widget=forms.Select(attrs={"class": "availability_zone_field"}))

    storage = forms.ChoiceField(
        label=_("Storage location"),
        help_text=_("Choose a storage location"),
        choices=[],
        widget=forms.Select(attrs={
            "class": "storage_field switchable",
            'data-slug': 'storage_loc'
        }))

    volumes_per_node = forms.IntegerField(
        label=_("Volumes per node"),
        required=False,
        initial=1,
        widget=forms.TextInput(
            attrs={
                "class": "volume_per_node_field switched",
                "data-switch-on": "storage_loc",
                "data-storage_loc-cinder_volume": _('Volumes per node')
            }))

    volumes_size = forms.IntegerField(
        label=_("Volumes size (GB)"),
        required=False,
        initial=10,
        widget=forms.TextInput(
            attrs={
                "class": "volume_size_field switched",
                "data-switch-on": "storage_loc",
                "data-storage_loc-cinder_volume": _('Volumes size (GB)')
            }))

    volume_type = forms.ChoiceField(
        label=_("Volumes type"),
        required=False,
        widget=forms.Select(
            attrs={
                "class": "volume_type_field switched",
                "data-switch-on": "storage_loc",
                "data-storage_loc-cinder_volume": _('Volumes type')
            }))

    volume_local_to_instance = forms.BooleanField(
        label=_("Volume local to instance"),
        required=False,
        help_text=_("Instance and attached volumes will be created on the "
                    "same physical host"),
        widget=forms.CheckboxInput(
            attrs={
                "class": "volume_local_to_instance_field switched",
                "data-switch-on": "storage_loc",
                "data-storage_loc-cinder_volume": _('Volume local to instance')
            }))

    volumes_availability_zone = forms.ChoiceField(
        label=_("Volumes Availability Zone"),
        help_text=_("Create volumes in this availability zone."),
        required=False,
        widget=forms.Select(
            attrs={
                "class": "volumes_availability_zone_field switched",
                "data-switch-on": "storage_loc",
                "data-storage_loc-cinder_volume": _(
                    'Volumes Availability Zone')
            }))

    image = forms.DynamicChoiceField(label=_("Base Image"),
                                     required=False,
                                     add_item_link=BASE_IMAGE_URL)

    hidden_configure_field = forms.CharField(
        required=False,
        widget=forms.HiddenInput(attrs={"class": "hidden_configure_field"}))

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

        hlps = helpers.Helpers(request)

        plugin, hadoop_version = (
            workflow_helpers.get_plugin_and_hadoop_version(request))

        if not saharaclient.SAHARA_AUTO_IP_ALLOCATION_ENABLED:
            pools = neutron.floating_ip_pools_list(request)
            pool_choices = [(pool.id, pool.name) for pool in pools]
            pool_choices.insert(0, (None, "Do not assign floating IPs"))

            self.fields['floating_ip_pool'] = forms.ChoiceField(
                label=_("Floating IP Pool"),
                choices=pool_choices,
                required=False)

        self.fields["use_autoconfig"] = forms.BooleanField(
            label=_("Auto-configure"),
            help_text=_("If selected, instances of a node group will be "
                        "automatically configured during cluster "
                        "creation. Otherwise you should manually specify "
                        "configuration values."),
            required=False,
            widget=forms.CheckboxInput(),
            initial=True,
        )

        self.fields["proxygateway"] = forms.BooleanField(
            label=_("Proxy Gateway"),
            widget=forms.CheckboxInput(),
            help_text=_("Sahara will use instances of this node group to "
                        "access other cluster instances."),
            required=False)

        self.fields['is_public'] = acl_utils.get_is_public_form(
            _("node group template"))
        self.fields['is_protected'] = acl_utils.get_is_protected_form(
            _("node group template"))

        self.fields["plugin_name"] = forms.CharField(
            widget=forms.HiddenInput(), initial=plugin)
        self.fields["hadoop_version"] = forms.CharField(
            widget=forms.HiddenInput(), initial=hadoop_version)

        self.fields["storage"].choices = storage_choices(request)

        node_parameters = hlps.get_general_node_group_configs(
            plugin, hadoop_version)
        for param in node_parameters:
            self.fields[param.name] = workflow_helpers.build_control(param)

        # when we copy or edit a node group template then
        # request contains valuable info in both GET and POST methods
        req = request.GET.copy()
        req.update(request.POST)
        if req.get("guide_template_type"):
            self.fields["guide_template_type"] = forms.CharField(
                required=False,
                widget=forms.HiddenInput(),
                initial=req.get("guide_template_type"))

        if is_cinder_enabled(request):
            volume_types = cinder.volume_type_list(request)
        else:
            volume_types = []

        self.fields['volume_type'].choices = [(None, _("No volume type"))] + \
                                             [(type.name, type.name)
                                              for type in volume_types]

    def populate_flavor_choices(self, request, context):
        flavors = nova_utils.flavor_list(request)
        if flavors:
            return nova_utils.sort_flavor_list(request, flavors)
        return []

    def populate_availability_zone_choices(self, request, context):
        # The default is None, i.e. not specifying any availability zone
        az_list = [(None, _('No availability zone specified'))]
        az_list.extend([(az.zoneName, az.zoneName)
                        for az in nova_utils.availability_zone_list(request)
                        if az.zoneState['available']])
        return az_list

    def populate_volumes_availability_zone_choices(self, request, context):
        az_list = [(None, _('No availability zone specified'))]
        if is_cinder_enabled(request):
            az_list.extend([
                (az.zoneName, az.zoneName)
                for az in cinder_utils.availability_zone_list(request)
                if az.zoneState['available']
            ])
        return az_list

    def populate_image_choices(self, request, context):
        return workflow_helpers.populate_image_choices(self,
                                                       request,
                                                       context,
                                                       empty_choice=True)

    def get_help_text(self):
        extra = dict()
        plugin_name, hadoop_version = (
            workflow_helpers.get_plugin_and_hadoop_version(self.request))
        extra["plugin_name"] = plugin_name
        extra["hadoop_version"] = hadoop_version
        plugin = saharaclient.plugin_get_version_details(
            self.request, plugin_name, hadoop_version)
        extra["deprecated"] = workflow_helpers.is_version_of_plugin_deprecated(
            plugin, hadoop_version)
        return super(GeneralConfigAction, self).get_help_text(extra)

    class Meta(object):
        name = _("Configure Node Group Template")
        help_text_template = "nodegroup_templates/_configure_general_help.html"
示例#15
0
class UpdateVip(forms.SelfHandlingForm):
    name = forms.CharField(max_length=80, label=_("Name"))
    vip_id = forms.CharField(
        label=_("ID"), widget=forms.TextInput(attrs={'readonly': 'readonly'}))
    description = forms.CharField(required=False,
                                  max_length=80,
                                  label=_("Description"))
    pool_id = forms.ChoiceField(label=_("Pool"))
    session_persistence = forms.ChoiceField(required=False,
                                            initial={},
                                            label=_("Session Persistence"))

    cookie_name = forms.CharField(initial="",
                                  required=False,
                                  max_length=80,
                                  label=_("Cookie Name"),
                                  help_text=_(
                                      "Required for APP_COOKIE persistence;"
                                      " Ignored otherwise."))

    connection_limit = forms.IntegerField(
        min_value=-1,
        label=_("Connection Limit"),
        help_text=_("Maximum number of connections allowed "
                    "for the VIP or '-1' if the limit is not set"))
    admin_state_up = forms.BooleanField(label=_("Admin State"), required=False)

    failure_url = 'horizon:project:loadbalancers:index'

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

        pool_id_choices = []
        try:
            tenant_id = request.user.tenant_id
            pools = api.lbaas.pools_get(request, tenant_id=tenant_id)
        except Exception:
            pools = []
            exceptions.handle(request, _('Unable to retrieve pools list.'))
        pools = sorted(pools, key=lambda pool: pool.name)
        for p in pools:
            if (p.vip_id is None) or (p.id == kwargs['initial']['pool_id']):
                pool_id_choices.append((p.id, p.name))
        self.fields['pool_id'].choices = pool_id_choices

        session_persistence_choices = []
        for mode in ('SOURCE_IP', 'HTTP_COOKIE', 'APP_COOKIE'):
            session_persistence_choices.append((mode, mode))
        session_persistence_choices.append(('', _('No session persistence')))
        self.fields[
            'session_persistence'].choices = session_persistence_choices

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

        persistence = cleaned_data.get('session_persistence')
        if (persistence == 'APP_COOKIE'
                and not cleaned_data.get('cookie_name')):
            msg = _('Cookie name is required for APP_COOKIE persistence.')
            self._errors['cookie_name'] = self.error_class([msg])
        return cleaned_data

    def handle(self, request, context):
        if context['session_persistence']:
            stype = context['session_persistence']
            if stype == 'APP_COOKIE':
                cookie = context['cookie_name']
                context['session_persistence'] = {
                    'type': stype,
                    'cookie_name': cookie
                }
            else:
                context['session_persistence'] = {'type': stype}
        else:
            context['session_persistence'] = {}

        try:
            data = {
                'vip': {
                    'name': context['name'],
                    'description': context['description'],
                    'pool_id': context['pool_id'],
                    'session_persistence': context['session_persistence'],
                    'connection_limit': context['connection_limit'],
                    'admin_state_up': context['admin_state_up'],
                }
            }
            vip = api.lbaas.vip_update(request, context['vip_id'], **data)
            msg = _('VIP %s was successfully updated.') % context['name']
            LOG.debug(msg)
            messages.success(request, msg)
            return vip
        except Exception:
            msg = _('Failed to update VIP %s') % context['name']
            LOG.info(msg)
            redirect = reverse(self.failure_url)
            exceptions.handle(request, msg, redirect=redirect)
示例#16
0
class UpdateImageForm(forms.SelfHandlingForm):
    image_id = forms.CharField(widget=forms.HiddenInput())
    name = forms.CharField(max_length=255, label=_("Name"))
    description = forms.CharField(max_length=255, label=_("Description"),
                                  required=False)
    kernel = forms.CharField(
        max_length=36,
        label=_("Kernel ID"),
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}),
    )
    ramdisk = forms.CharField(
        max_length=36,
        label=_("Ramdisk ID"),
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}),
    )
    architecture = forms.CharField(
        label=_("Architecture"),
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}),
    )
    disk_format = forms.ChoiceField(
        label=_("Format"),
    )
    minimum_disk = forms.IntegerField(label=_("Minimum Disk (GB)"),
                                      min_value=0,
                                      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)"),
                                     min_value=0,
                                     help_text=_('The minimum memory size'
                                                 ' required to boot the'
                                                 ' image. If unspecified,'
                                                 ' this value defaults to'
                                                 ' 0 (no minimum).'),
                                     required=False)
    public = forms.BooleanField(label=_("Public"), required=False)
    protected = forms.BooleanField(label=_("Protected"), required=False)

    def __init__(self, request, *args, **kwargs):
        super(UpdateImageForm, self).__init__(request, *args, **kwargs)
        self.fields['disk_format'].choices = [(value, name) for value,
                                              name in IMAGE_FORMAT_CHOICES
                                              if value]
        if not policy.check((("image", "publicize_image"),), request):
            self.fields['public'].widget = forms.CheckboxInput(
                attrs={'readonly': 'readonly'})

    def handle(self, request, data):
        image_id = data['image_id']
        error_updating = _('Unable to update image "%s".')

        if data['disk_format'] in ['aki', 'ari', 'ami']:
            container_format = data['disk_format']
        else:
            container_format = 'bare'

        meta = {'is_public': data['public'],
                'protected': data['protected'],
                'disk_format': data['disk_format'],
                'container_format': container_format,
                'name': data['name'],
                'min_ram': (data['minimum_ram'] or 0),
                'min_disk': (data['minimum_disk'] or 0),
                'properties': {'description': data['description']}}
        if data['kernel']:
            meta['properties']['kernel_id'] = data['kernel']
        if data['ramdisk']:
            meta['properties']['ramdisk_id'] = data['ramdisk']
        if data['architecture']:
            meta['properties']['architecture'] = data['architecture']
        # Ensure we do not delete properties that have already been
        # set on an image.
        meta['purge_props'] = False

        try:
            image = api.glance.image_update(request, image_id, **meta)
            messages.success(request, _('Image was successfully updated.'))
            return image
        except Exception:
            exceptions.handle(request, error_updating % image_id)
示例#17
0
class CreateNetwork(forms.SelfHandlingForm):
    name = forms.CharField(max_length=255, label=_("Name"), required=False)
    tenant_id = forms.ThemableChoiceField(label=_("Project"))
    if api.neutron.is_port_profiles_supported():
        widget = None
    else:
        widget = forms.HiddenInput()
    net_profile_id = forms.ChoiceField(label=_("Network Profile"),
                                       required=False,
                                       widget=widget)
    network_type = forms.ChoiceField(
        label=_("Provider Network Type"),
        help_text=_("The physical mechanism by which the virtual "
                    "network is implemented."),
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'data-slug': 'network_type'
        }))
    physical_network = forms.CharField(
        max_length=255,
        label=_("Physical Network"),
        help_text=_("The name of the physical network over which the "
                    "virtual network is implemented."),
        initial='default',
        widget=forms.TextInput(attrs={
            'class': 'switched',
            'data-switch-on': 'network_type',
        }))
    segmentation_id = forms.IntegerField(
        label=_("Segmentation ID"),
        widget=forms.TextInput(attrs={
            'class': 'switched',
            'data-switch-on': 'network_type',
        }))
    admin_state = forms.ThemableChoiceField(choices=[(True, _('UP')),
                                                     (False, _('DOWN'))],
                                            label=_("Admin State"))
    shared = forms.BooleanField(label=_("Shared"),
                                initial=False,
                                required=False)
    external = forms.BooleanField(label=_("External Network"),
                                  initial=False,
                                  required=False)

    @classmethod
    def _instantiate(cls, request, *args, **kwargs):
        return cls(request, *args, **kwargs)

    def __init__(self, request, *args, **kwargs):
        super(CreateNetwork, self).__init__(request, *args, **kwargs)
        tenant_choices = [('', _("Select a project"))]
        tenants, has_more = api.keystone.tenant_list(request)
        for tenant in tenants:
            if tenant.enabled:
                tenant_choices.append((tenant.id, tenant.name))
        self.fields['tenant_id'].choices = tenant_choices

        if api.neutron.is_port_profiles_supported():
            self.fields['net_profile_id'].choices = (
                self.get_network_profile_choices(request))
        try:
            is_extension_supported = \
                api.neutron.is_extension_supported(request, 'provider')
        except Exception:
            msg = _("Unable to verify Neutron service providers")
            exceptions.handle(self.request, msg)
            self._hide_provider_network_type()
            is_extension_supported = False

        if is_extension_supported:
            neutron_settings = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK',
                                       {})
            self.seg_id_range = SEGMENTATION_ID_RANGE.copy()
            seg_id_range = neutron_settings.get('segmentation_id_range')
            if seg_id_range:
                self.seg_id_range.update(seg_id_range)

            self.provider_types = PROVIDER_TYPES.copy()
            extra_provider_types = neutron_settings.get('extra_provider_types')
            if extra_provider_types:
                self.provider_types.update(extra_provider_types)

            self.nettypes_with_seg_id = [
                net_type for net_type in self.provider_types
                if self.provider_types[net_type]['require_segmentation_id']
            ]
            self.nettypes_with_physnet = [
                net_type for net_type in self.provider_types
                if self.provider_types[net_type]['require_physical_network']
            ]

            supported_provider_types = neutron_settings.get(
                'supported_provider_types', DEFAULT_PROVIDER_TYPES)
            if supported_provider_types == ['*']:
                supported_provider_types = DEFAULT_PROVIDER_TYPES

            undefined_provider_types = [
                net_type for net_type in supported_provider_types
                if net_type not in self.provider_types
            ]
            if undefined_provider_types:
                LOG.error('Undefined provider network types are found: %s',
                          undefined_provider_types)

            seg_id_help = [
                _("For %(type)s networks, valid IDs are %(min)s to %(max)s.") %
                {
                    'type': net_type,
                    'min': self.seg_id_range[net_type][0],
                    'max': self.seg_id_range[net_type][1]
                } for net_type in self.nettypes_with_seg_id
            ]
            self.fields['segmentation_id'].help_text = ' '.join(seg_id_help)

            # Register network types which require segmentation ID
            attrs = dict(
                ('data-network_type-%s' % network_type, _('Segmentation ID'))
                for network_type in self.nettypes_with_seg_id)
            self.fields['segmentation_id'].widget.attrs.update(attrs)

            # Register network types which require physical network
            attrs = dict(
                ('data-network_type-%s' % network_type, _('Physical Network'))
                for network_type in self.nettypes_with_physnet)
            self.fields['physical_network'].widget.attrs.update(attrs)

            network_type_choices = [
                (net_type, self.provider_types[net_type]['display_name'])
                for net_type in supported_provider_types
            ]
            if len(network_type_choices) == 0:
                self._hide_provider_network_type()
            else:
                self.fields['network_type'].choices = network_type_choices

    def get_network_profile_choices(self, request):
        profile_choices = [('', _("Select a profile"))]
        for profile in self._get_profiles(request, 'network'):
            profile_choices.append((profile.id, profile.name))
        return profile_choices

    def _get_profiles(self, request, type_p):
        profiles = []
        try:
            profiles = api.neutron.profile_list(request, type_p)
        except Exception:
            msg = _('Network Profiles could not be retrieved.')
            exceptions.handle(request, msg)
        return profiles

    def _hide_provider_network_type(self):
        self.fields['network_type'].widget = forms.HiddenInput()
        self.fields['physical_network'].widget = forms.HiddenInput()
        self.fields['segmentation_id'].widget = forms.HiddenInput()
        self.fields['network_type'].required = False
        self.fields['physical_network'].required = False
        self.fields['segmentation_id'].required = False

    def handle(self, request, data):
        try:
            params = {
                'name': data['name'],
                'tenant_id': data['tenant_id'],
                'admin_state_up': (data['admin_state'] == 'True'),
                'shared': data['shared'],
                'router:external': data['external']
            }
            if api.neutron.is_port_profiles_supported():
                params['net_profile_id'] = data['net_profile_id']
            if api.neutron.is_extension_supported(request, 'provider'):
                network_type = data['network_type']
                params['provider:network_type'] = network_type
                if network_type in self.nettypes_with_physnet:
                    params['provider:physical_network'] = (
                        data['physical_network'])
                if network_type in self.nettypes_with_seg_id:
                    params['provider:segmentation_id'] = (
                        data['segmentation_id'])
            network = api.neutron.network_create(request, **params)
            msg = _('Network %s was successfully created.') % data['name']
            LOG.debug(msg)
            messages.success(request, msg)
            return network
        except Exception:
            redirect = reverse('horizon:admin:networks:index')
            msg = _('Failed to create network %s') % data['name']
            exceptions.handle(request, msg, redirect=redirect)

    def clean(self):
        cleaned_data = super(CreateNetwork, self).clean()
        if api.neutron.is_extension_supported(self.request, 'provider'):
            self._clean_physical_network(cleaned_data)
            self._clean_segmentation_id(cleaned_data)
        return cleaned_data

    def _clean_physical_network(self, data):
        network_type = data.get('network_type')
        if ('physical_network' in self._errors
                and network_type not in self.nettypes_with_physnet):
            # In this case the physical network is not required, so we can
            # ignore any errors.
            del self._errors['physical_network']

    def _clean_segmentation_id(self, data):
        network_type = data.get('network_type')
        if 'segmentation_id' in self._errors:
            if network_type not in self.nettypes_with_seg_id:
                # In this case the segmentation ID is not required, so we can
                # ignore any errors.
                del self._errors['segmentation_id']
        elif network_type in self.nettypes_with_seg_id:
            seg_id = data.get('segmentation_id')
            seg_id_range = {
                'min': self.seg_id_range[network_type][0],
                'max': self.seg_id_range[network_type][1]
            }
            if seg_id < seg_id_range['min'] or seg_id > seg_id_range['max']:
                msg = (_('For a %(network_type)s network, valid segmentation '
                         'IDs are %(min)s through %(max)s.') % {
                             'network_type': network_type,
                             'min': seg_id_range['min'],
                             'max': seg_id_range['max']
                         })
                self._errors['segmentation_id'] = self.error_class([msg])
示例#18
0
class CreateImageForm(forms.SelfHandlingForm):
    name = forms.CharField(max_length=255, label=_("Name"))
    description = forms.CharField(max_length=255, label=_("Description"),
                                  required=False)

    source_type = forms.ChoiceField(
        label=_('Image Source'),
        required=False,
        choices=[('url', _('Image Location')),
                 ('file', _('Image File'))],
        widget=forms.Select(attrs={
            'class': 'switchable',
            'data-slug': 'source'}))

    copy_from = forms.CharField(max_length=255,
                                label=_("Image Location"),
                                help_text=_("An external (HTTP) URL to load "
                                            "the image from."),
                                widget=forms.TextInput(attrs={
                                    'class': 'switched',
                                    'data-switch-on': 'source',
                                    'data-source-url': _('Image Location'),
                                    'ng-model': 'copyFrom',
                                    'ng-change':
                                    'selectImageFormat(copyFrom)'}),
                                required=False)
    image_file = forms.FileField(label=_("Image File"),
                                 help_text=_("A local image to upload."),
                                 widget=forms.FileInput(attrs={
                                     'class': 'switched',
                                     'data-switch-on': 'source',
                                     'data-source-file': _('Image File'),
                                     'ng-model': 'imageFile',
                                     'ng-change':
                                     'selectImageFormat(imageFile.name)',
                                     'image-file-on-change': None}),
                                 required=False)
    disk_format = forms.ChoiceField(label=_('Format'),
                                    choices=[],
                                    widget=forms.Select(attrs={
                                        'class': 'switchable',
                                        'ng-model': 'diskFormat'}))
    architecture = forms.CharField(max_length=255, label=_("Architecture"),
                                   required=False)
    minimum_disk = forms.IntegerField(
        label=_("Minimum Disk (GB)"),
        min_value=0,
        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)"),
        min_value=0,
        help_text=_('The minimum memory 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, request, *args, **kwargs):
        super(CreateImageForm, self).__init__(request, *args, **kwargs)
        if (not settings.HORIZON_IMAGES_ALLOW_UPLOAD or
                not policy.check((("image", "upload_image"),), request)):
            self._hide_file_source_type()
        if not policy.check((("image", "set_image_location"),), request):
            self._hide_url_source_type()
        if not policy.check((("image", "publicize_image"),), request):
            self._hide_is_public()
        self.fields['disk_format'].choices = IMAGE_FORMAT_CHOICES

    def _hide_file_source_type(self):
        self.fields['image_file'].widget = HiddenInput()
        source_type = self.fields['source_type']
        source_type.choices = [choice for choice in source_type.choices
                               if choice[0] != 'file']
        if len(source_type.choices) == 1:
            source_type.widget = HiddenInput()

    def _hide_url_source_type(self):
        self.fields['copy_from'].widget = HiddenInput()
        source_type = self.fields['source_type']
        source_type.choices = [choice for choice in source_type.choices
                               if choice[0] != 'url']
        if len(source_type.choices) == 1:
            source_type.widget = HiddenInput()

    def _hide_is_public(self):
        self.fields['is_public'].widget = HiddenInput()
        self.fields['is_public'].initial = False

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

        # The image_file key can be missing based on particular upload
        # conditions. Code defensively for it here...
        image_file = data.get('image_file', None)
        image_url = data.get('copy_from', None)

        if not image_url and not image_file:
            raise ValidationError(
                _("A image or external image location must be specified."))
        elif image_url and 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'],
                'properties': {}}

        if data['description']:
            meta['properties']['description'] = data['description']
        if data['architecture']:
            meta['properties']['architecture'] = data['architecture']
        if (settings.HORIZON_IMAGES_ALLOW_UPLOAD and
                policy.check((("image", "upload_image"),), request) and
                data.get('image_file', None)):
            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 Exception:
            exceptions.handle(request, _('Unable to create new image.'))
示例#19
0
class CreateSubnetDetailAction(workflows.Action):
    enable_dhcp = forms.BooleanField(label=_("Enable DHCP"),
                                     initial=True,
                                     required=False)
    ipv6_modes = forms.ChoiceField(
        label=_("IPv6 Address Configuration Mode"),
        widget=forms.Select(
            attrs={
                'class': 'switched',
                'data-switch-on': 'ipversion',
                'data-ipversion-6': _("IPv6 Address Configuration Mode"),
            }),
        initial=utils.IPV6_DEFAULT_MODE,
        required=False,
        help_text=_("Specifies how IPv6 addresses and additional information "
                    "are configured. We can specify SLAAC/DHCPv6 stateful/"
                    "DHCPv6 stateless provided by OpenStack, "
                    "or specify no option. "
                    "'No options specified' means addresses are configured "
                    "manually or configured by a non-OpenStack system."))
    allocation_pools = forms.CharField(
        widget=forms.Textarea(attrs={'rows': 4}),
        label=_("Allocation Pools"),
        help_text=_("IP address allocation pools. Each entry is: "
                    "start_ip_address,end_ip_address "
                    "(e.g., 192.168.1.100,192.168.1.120) "
                    "and one entry per line."),
        required=False)
    dns_nameservers = forms.CharField(
        widget=forms.widgets.Textarea(attrs={'rows': 4}),
        label=_("DNS Name Servers"),
        help_text=_("IP address list of DNS name servers for this subnet. "
                    "One entry per line."),
        required=False)
    host_routes = forms.CharField(
        widget=forms.widgets.Textarea(attrs={'rows': 4}),
        label=_("Host Routes"),
        help_text=_("Additional routes announced to the hosts. "
                    "Each entry is: destination_cidr,nexthop "
                    "(e.g., 192.168.200.0/24,10.56.1.254) "
                    "and one entry per line."),
        required=False)

    class Meta(object):
        name = _("Subnet Details")
        help_text = _('Specify additional attributes for the subnet.')

    def __init__(self, request, context, *args, **kwargs):
        super(CreateSubnetDetailAction, self).__init__(request, context, *args,
                                                       **kwargs)
        if not getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}).get(
                'enable_ipv6', True):
            self.fields['ipv6_modes'].widget = forms.HiddenInput()

    def populate_ipv6_modes_choices(self, request, context):
        return [(value, _("%s (Default)") %
                 label) if value == utils.IPV6_DEFAULT_MODE else (value, label)
                for value, label in utils.IPV6_MODE_CHOICES]

    def _convert_ip_address(self, ip, field_name):
        try:
            return netaddr.IPAddress(ip)
        except (netaddr.AddrFormatError, ValueError):
            msg = (_('%(field_name)s: Invalid IP address (value=%(ip)s)') % {
                'field_name': field_name,
                'ip': ip
            })
            raise forms.ValidationError(msg)

    def _convert_ip_network(self, network, field_name):
        try:
            return netaddr.IPNetwork(network)
        except (netaddr.AddrFormatError, ValueError):
            msg = (
                _('%(field_name)s: Invalid IP address (value=%(network)s)') % {
                    'field_name': field_name,
                    'network': network
                })
            raise forms.ValidationError(msg)

    def _check_allocation_pools(self, allocation_pools):
        for p in allocation_pools.split('\n'):
            p = p.strip()
            if not p:
                continue
            pool = p.split(',')
            if len(pool) != 2:
                msg = _('Start and end addresses must be specified '
                        '(value=%s)') % p
                raise forms.ValidationError(msg)
            start, end = [
                self._convert_ip_address(ip, "allocation_pools") for ip in pool
            ]
            if start > end:
                msg = _('Start address is larger than end address '
                        '(value=%s)') % p
                raise forms.ValidationError(msg)

    def _check_dns_nameservers(self, dns_nameservers):
        for ns in dns_nameservers.split('\n'):
            ns = ns.strip()
            if not ns:
                continue
            self._convert_ip_address(ns, "dns_nameservers")

    def _check_host_routes(self, host_routes):
        for r in host_routes.split('\n'):
            r = r.strip()
            if not r:
                continue
            route = r.split(',')
            if len(route) != 2:
                msg = _('Host Routes format error: '
                        'Destination CIDR and nexthop must be specified '
                        '(value=%s)') % r
                raise forms.ValidationError(msg)
            self._convert_ip_network(route[0], "host_routes")
            self._convert_ip_address(route[1], "host_routes")

    def clean(self):
        cleaned_data = super(CreateSubnetDetailAction, self).clean()
        self._check_allocation_pools(cleaned_data.get('allocation_pools'))
        self._check_host_routes(cleaned_data.get('host_routes'))
        self._check_dns_nameservers(cleaned_data.get('dns_nameservers'))
        return cleaned_data
示例#20
0
class CreateSubnetInfoAction(workflows.Action):
    subnet_name = forms.CharField(max_length=255,
                                  widget=forms.TextInput(attrs={
                                  }),
                                  label=_("Subnet Name"),
                                  required=False)

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

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

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

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

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

    check_subnet_range = True

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def clean(self):
        cleaned_data = super(CreateSubnetInfoAction, self).clean()
        with_subnet = cleaned_data.get('with_subnet')
        if not with_subnet:
            return cleaned_data
        self._check_subnet_data(cleaned_data)
        return cleaned_data
示例#21
0
class CreateForm(forms.SelfHandlingForm):
    name = forms.CharField(max_length=255,
                           label=_("Router Name"),
                           required=False)
    admin_state_up = forms.BooleanField(label=_("Enable Admin State"),
                                        initial=True,
                                        required=False)
    external_network = forms.ThemableChoiceField(label=_("External Network"),
                                                 required=False)
    enable_snat = forms.BooleanField(label=_("Enable SNAT"),
                                     initial=True,
                                     required=False)
    mode = forms.ThemableChoiceField(label=_("Router Type"))
    ha = forms.ThemableChoiceField(label=_("High Availability Mode"))
    az_hints = forms.MultipleChoiceField(
        label=_("Availability Zone Hints"),
        required=False,
        help_text=_("Availability Zones where the router may be scheduled. "
                    "Leaving this unset is equivalent to selecting all "
                    "Availability Zones"))
    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']

        self.enable_snat_allowed = self.initial['enable_snat_allowed']
        if (not networks or not self.enable_snat_allowed):
            del self.fields['enable_snat']

        try:
            az_supported = api.neutron.is_extension_supported(
                self.request, 'router_availability_zone')

            if az_supported:
                zones = api.neutron.list_availability_zones(
                    self.request, 'router', 'available')
                self.fields['az_hints'].choices = [(zone['name'], zone['name'])
                                                   for zone in zones]
            else:
                del self.fields['az_hints']
        except Exception:
            msg = _("Failed to get availability zone list.")
            exceptions.handle(self.request, msg)
            del self.fields['az_hints']

    def _get_network_list(self, request):
        search_opts = {'router:external': True}
        try:
            networks = api.neutron.network_list(request, **search_opts)
        except Exception as e:
            LOG.info('Failed to get network list: %s', e)
            msg = _('Failed to get network list.')
            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'],
                '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.enable_snat_allowed:
                    params['external_gateway_info']['enable_snat'] = \
                        data['enable_snat']
            if 'az_hints' in data and data['az_hints']:
                params['availability_zone_hints'] = data['az_hints']
            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:
            LOG.info('Failed to create router: %s', exc)
            if exc.status_code == 409:
                msg = _('Quota exceeded for resource router.')
            else:
                msg = _('Failed to create router "%s".') % data['name']
            redirect = reverse(self.failure_url)
            exceptions.handle(request, msg, redirect=redirect)
            return False
示例#22
0
class CreateNamespaceForm(forms.SelfHandlingForm):
    source_type = forms.ChoiceField(
        label=_('Namespace Definition Source'),
        choices=[('file', _('Metadata Definition File')),
                 ('raw', _('Direct Input'))],
        widget=forms.ThemableSelectWidget(attrs={
            'class': 'switchable',
            'data-slug': 'source'
        }))

    metadef_file = forms.FileField(
        label=_("Metadata Definition File"),
        help_text=_("A local metadata definition file to upload."),
        widget=forms.FileInput(
            attrs={
                'class': 'switched',
                'data-switch-on': 'source',
                'data-required-when-shown': 'true',
                'data-source-file': _('Metadata Definition File')
            }),
        required=False)

    direct_input = forms.CharField(
        label=_('Namespace JSON'),
        help_text=_('The JSON formatted contents of a namespace.'),
        widget=forms.widgets.Textarea(
            attrs={
                'class': 'switched',
                'data-switch-on': 'source',
                'data-required-when-shown': 'true',
                'data-source-raw': _('Namespace JSON')
            }),
        required=False)

    public = forms.BooleanField(label=_("Public"), required=False)
    protected = forms.BooleanField(label=_("Protected"), required=False)

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

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

        if metadata_raw and metadef_file:
            raise ValidationError(
                _("Cannot specify both file and direct input."))
        if not metadata_raw and not metadef_file:
            raise ValidationError(
                _("No input was provided for the namespace content."))
        try:
            if metadef_file:
                ns_str = self.files['metadef_file'].read()
            else:
                ns_str = data['direct_input']
            namespace = json.loads(ns_str)

            if data['public']:
                namespace['visibility'] = 'public'
            else:
                namespace['visibility'] = 'private'

            namespace['protected'] = data['protected']

            for protected_prop in constants.METADEFS_PROTECTED_PROPS:
                namespace.pop(protected_prop, None)

            data['namespace'] = namespace
        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:
            namespace = glance.metadefs_namespace_create(
                request, data['namespace'])
            messages.success(
                request,
                _('Namespace %s has been created.') % namespace['namespace'])
            return namespace
        except Exception as e:
            msg = _('Unable to create new namespace. %s')
            msg %= e.message.split('Failed validating', 1)[0]
            exceptions.handle(request, message=msg)
            return False
示例#23
0
class ImportImageForm(forms.SelfHandlingForm):
    name = forms.CharField(
        max_length="255",
        label=_("Name"),
        widget=forms.TextInput(attrs={'placeholder': 'ubuntu-base'}),
        required=True)
    image_file = forms.FileField(label=_("Image File"),
                                 help_text=("A local image to upload."),
                                 required=False)
    is_public = forms.BooleanField(label=_("Public"),
                                   required=False,
                                   initial=True)

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

    def clean(self):
        data = super(ImportImageForm, self).clean()
        # check validity of zip file
        zipbase = None
        try:
            zipbase = zipfile.ZipFile(data['image_file'])
            if BaseVMPackage.MANIFEST_FILENAME not in zipbase.namelist():
                msg = _('File is not valid (No manifest file)')
                raise ValidationError(msg)
            xml = zipbase.read(BaseVMPackage.MANIFEST_FILENAME)
            tree = etree.fromstring(
                xml, etree.XMLParser(schema=BaseVMPackage.schema))
        except Exception as e:
            msg = 'File is not valid (Not a zipped base VM)'
            raise ValidationError(_(msg))

        # Create attributes
        base_hashvalue = tree.get('hash_value')
        matching_base = find_basevm_by_sha256(self.request, base_hashvalue)
        if matching_base is not None:
            msg = "Base VM exists : UUID(%s)" % matching_base.id
            raise ValidationError(_(msg))

        disk_name = tree.find(BaseVMPackage.NSP + 'disk').get('path')
        memory_name = tree.find(BaseVMPackage.NSP + 'memory').get('path')
        diskhash_name = tree.find(BaseVMPackage.NSP + 'disk_hash').get('path')
        memoryhash_name = tree.find(BaseVMPackage.NSP +
                                    'memory_hash').get('path')

        temp_dir = mkdtemp(prefix="cloudlet-base-")
        LOG.info("Decompressing zipfile to temp dir(%s)\n" % (temp_dir))
        zipbase.extractall(temp_dir)
        disk_path = os.path.join(temp_dir, disk_name)
        memory_path = os.path.join(temp_dir, memory_name)
        diskhash_path = os.path.join(temp_dir, diskhash_name)
        memoryhash_path = os.path.join(temp_dir, memoryhash_name)
        data['base_hashvalue'] = base_hashvalue
        data['base_disk_path'] = disk_path
        data['base_memory_path'] = memory_path
        data['base_diskhash_path'] = diskhash_path
        data['base_memoryhash_path'] = memoryhash_path
        return data

    def handle(self, request, data):
        basevm_name = data['name']
        base_hashvalue = data['base_hashvalue']
        disk_path = data['base_disk_path']
        memory_path = data['base_memory_path']
        diskhash_path = data['base_diskhash_path']
        memoryhash_path = data['base_memoryhash_path']

        # upload base disk
        def _create_param(filepath, image_name, image_type, disk_size,
                          mem_size):
            properties = {
                "image_type": "snapshot",
                "image_location": "snapshot",
                CLOUDLET_TYPE.PROPERTY_KEY_CLOUDLET: "True",
                CLOUDLET_TYPE.PROPERTY_KEY_CLOUDLET_TYPE: image_type,
                CLOUDLET_TYPE.PROPERTY_KEY_BASE_UUID: base_hashvalue,
            }
            param = {
                "name": "%s" % image_name,
                "data": open(filepath, "rb"),
                "size": os.path.getsize(filepath),
                "is_public": True,
                "disk_format": "raw",
                "container_format": "bare",
                "min_disk": disk_size,
                "min_ram": mem_size,
                "properties": properties,
            }
            return param

        try:
            # create new flavor if nothing matches
            memory_header = elijah_memory_util._QemuMemoryHeader(
                open(memory_path))
            libvirt_xml_str = memory_header.xml
            cpu_count, memory_size_mb = get_resource_size(libvirt_xml_str)
            disk_gb = int(
                math.ceil(
                    os.path.getsize(disk_path) / 1024.0 / 1024.0 / 1024.0))
            flavors = api.nova.flavor_list(request)
            ref_flavors = find_matching_flavor(flavors, cpu_count,
                                               memory_size_mb, disk_gb)
            if len(ref_flavors) == 0:
                flavor_name = "cloudlet-flavor-%s" % basevm_name
                api.nova.flavor_create(self.request,
                                       flavor_name,
                                       memory_size_mb,
                                       cpu_count,
                                       disk_gb,
                                       is_public=True)
                msg = "Create new flavor %s with (cpu:%d, memory:%d, disk:%d)" %\
                    (flavor_name, cpu_count, memory_size_mb, disk_gb)
                LOG.info(msg)
            # upload Base VM
            disk_param = _create_param(disk_path, basevm_name + "-disk",
                                       CLOUDLET_TYPE.IMAGE_TYPE_BASE_DISK,
                                       disk_gb, memory_size_mb)
            memory_param = _create_param(memory_path, basevm_name + "-memory",
                                         CLOUDLET_TYPE.IMAGE_TYPE_BASE_MEM,
                                         disk_gb, memory_size_mb)
            diskhash_param = _create_param(
                diskhash_path, basevm_name + "-diskhash",
                CLOUDLET_TYPE.IMAGE_TYPE_BASE_DISK_HASH, disk_gb,
                memory_size_mb)
            memoryhash_param = _create_param(
                memoryhash_path, basevm_name + "-memhash",
                CLOUDLET_TYPE.IMAGE_TYPE_BASE_MEM_HASH, disk_gb,
                memory_size_mb)

            LOG.info("upload base memory to glance")
            glance_memory = api.glance.image_create(request, **memory_param)
            LOG.info("upload base disk hash to glance")
            glance_diskhash = api.glance.image_create(request,
                                                      **diskhash_param)
            LOG.info("upload base memory hash to glance")
            glance_memoryhash = api.glance.image_create(
                request, **memoryhash_param)

            glance_ref = {
                CLOUDLET_TYPE.IMAGE_TYPE_BASE_MEM:
                glance_memory.id,
                CLOUDLET_TYPE.IMAGE_TYPE_BASE_DISK_HASH:
                glance_diskhash.id,
                CLOUDLET_TYPE.IMAGE_TYPE_BASE_MEM_HASH:
                glance_memoryhash.id,
                CLOUDLET_TYPE.PROPERTY_KEY_BASE_RESOURCE:
                libvirt_xml_str.replace("\n", "")  # API cannot send '\n'
            }
            disk_param['properties'].update(glance_ref)
            LOG.info("upload base disk to glance")
            glance_memory = api.glance.image_create(request, **disk_param)

            LOG.info("SUCCESS")
            msg = "Your image %s has been queued for creation." % basevm_name
            messages.success(request, _(msg))
        except:
            exceptions.handle(request, _('Unable to import image.'))

        dirpath = os.path.dirname(disk_path)
        if os.path.exists(dirpath):
            shutil.rmtree(dirpath)
        return True
示例#24
0
class CreateStackForm(forms.SelfHandlingForm):

    param_prefix = '__param_'

    class Meta:
        name = _('Create Stack')

    template_data = forms.CharField(widget=forms.widgets.HiddenInput,
                                    required=False)
    template_url = forms.CharField(widget=forms.widgets.HiddenInput,
                                   required=False)
    parameters = forms.CharField(widget=forms.widgets.HiddenInput,
                                 required=True)
    stack_name = forms.RegexField(
        max_length='255',
        label=_('Stack Name'),
        help_text=_('Name of the stack to create.'),
        regex=r"^[a-zA-Z][a-zA-Z0-9_.-]*$",
        error_messages={
            'invalid':
            _('Name must start with a letter and may '
              'only contain letters, numbers, underscores, '
              'periods and hyphens.')
        },
        required=True)
    timeout_mins = forms.IntegerField(
        initial=60,
        label=_('Creation Timeout (minutes)'),
        help_text=_('Stack creation timeout in minutes.'),
        required=True)
    enable_rollback = forms.BooleanField(
        label=_('Rollback On Failure'),
        help_text=_('Enable rollback on create/update failure.'),
        required=False)

    def __init__(self, *args, **kwargs):
        parameters = kwargs.pop('parameters')
        # special case: load template data from API, not passed in params
        if (kwargs.get('validate_me')):
            parameters = kwargs.pop('validate_me')
        super(CreateStackForm, self).__init__(*args, **kwargs)
        self._build_parameter_fields(parameters)

    def _build_parameter_fields(self, template_validate):
        self.fields['password'] = forms.CharField(
            label=_('Password for user "%s"') % self.request.user.username,
            help_text=_('This is required for operations to be performed '
                        'throughout the lifecycle of the stack'),
            required=True,
            widget=forms.PasswordInput())

        self.help_text = template_validate['Description']

        params = template_validate.get('Parameters', {})

        for param_key, param in params.items():
            field_key = self.param_prefix + param_key
            field_args = {
                'initial': param.get('Default', None),
                'label': param_key,
                'help_text': param.get('Description', ''),
                'required': param.get('Default', None) is None
            }

            param_type = param.get('Type', None)

            if 'AllowedValues' in param:
                choices = map(lambda x: (x, x), param['AllowedValues'])
                field_args['choices'] = choices
                field = forms.ChoiceField(**field_args)

            elif param_type in ('CommaDelimitedList', 'String'):
                if 'MinLength' in param:
                    field_args['min_length'] = int(param['MinLength'])
                    field_args['required'] = param.get('MinLength', 0) > 0
                if 'MaxLength' in param:
                    field_args['max_length'] = int(param['MaxLength'])
                field = forms.CharField(**field_args)

            elif param_type == 'Number':
                if 'MinValue' in param:
                    field_args['min_value'] = int(param['MinValue'])
                if 'MaxValue' in param:
                    field_args['max_value'] = int(param['MaxValue'])
                field = forms.IntegerField(**field_args)

            self.fields[field_key] = field

    @sensitive_variables('password')
    def handle(self, request, data):
        prefix_length = len(self.param_prefix)
        params_list = [(k[prefix_length:], v) for (k, v) in data.iteritems()
                       if k.startswith(self.param_prefix)]
        fields = {
            'stack_name': data.get('stack_name'),
            'timeout_mins': data.get('timeout_mins'),
            'disable_rollback': not (data.get('enable_rollback')),
            'parameters': dict(params_list),
            'password': data.get('password')
        }

        if data.get('template_data'):
            fields['template'] = data.get('template_data')
        else:
            fields['template_url'] = data.get('template_url')

        try:
            api.heat.stack_create(self.request, **fields)
            messages.success(request, _("Stack creation started."))
            return True
        except Exception as e:
            msg = exception_to_validation_msg(e)
            exceptions.handle(request, msg or _('Stack creation failed.'))
示例#25
0
class UpdateImageForm(forms.SelfHandlingForm):
    image_id = forms.CharField(widget=forms.HiddenInput())
    name = forms.CharField(max_length=255, label=_("Name"))
    description = forms.CharField(max_length=255,
                                  widget=forms.Textarea(attrs={'rows': 4}),
                                  label=_("Description"),
                                  required=False)
    kernel = forms.CharField(
        max_length=36,
        label=_("Kernel ID"),
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}),
    )
    ramdisk = forms.CharField(
        max_length=36,
        label=_("Ramdisk ID"),
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}),
    )
    architecture = forms.CharField(
        label=_("Architecture"),
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}),
    )
    disk_format = forms.ThemableChoiceField(label=_("Format"), )
    min_disk = forms.IntegerField(
        label=_("Minimum Disk (GB)"),
        min_value=0,
        help_text=_('The minimum disk size required to boot the image. '
                    'If unspecified, this value defaults to 0 (no minimum).'),
        required=False)
    min_ram = forms.IntegerField(
        label=_("Minimum RAM (MB)"),
        min_value=0,
        help_text=_('The minimum memory 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, request, *args, **kwargs):
        super(UpdateImageForm, self).__init__(request, *args, **kwargs)
        self.fields['disk_format'].choices = [
            (value, name) for value, name in IMAGE_FORMAT_CHOICES if value
        ]
        if not policy.check((("image", "publicize_image"), ), request):
            self.fields['is_public'].widget = forms.CheckboxInput(
                attrs={
                    'readonly': 'readonly',
                    'disabled': 'disabled'
                })
            self.fields['is_public'].help_text = _(
                'Non admin users are not allowed to make images public.')

    def handle(self, request, data):
        image_id = data['image_id']
        error_updating = _('Unable to update image "%s".')
        meta = api.glance.create_image_metadata(data)

        try:
            image = api.glance.image_update(request, image_id, **meta)
            messages.success(request, _('Image was successfully updated.'))
            return image
        except Exception:
            exceptions.handle(request, error_updating % image_id)
示例#26
0
class CreateStackForm(forms.SelfHandlingForm):

    param_prefix = '__param_'

    class Meta(object):
        name = _('Create Stack')

    template_data = forms.CharField(
        widget=forms.widgets.HiddenInput,
        required=False)
    template_url = forms.CharField(
        widget=forms.widgets.HiddenInput,
        required=False)
    environment_data = forms.CharField(
        widget=forms.widgets.HiddenInput,
        required=False)
    parameters = forms.CharField(
        widget=forms.widgets.HiddenInput)
    stack_name = forms.RegexField(
        max_length=255,
        label=_('Stack Name'),
        help_text=_('Name of the stack to create.'),
        regex=r"^[a-zA-Z][a-zA-Z0-9_.-]*$",
        error_messages={'invalid':
                        _('Name must start with a letter and may '
                          'only contain letters, numbers, underscores, '
                          'periods and hyphens.')})
    timeout_mins = forms.IntegerField(
        initial=60,
        label=_('Creation Timeout (minutes)'),
        help_text=_('Stack creation timeout in minutes.'))
    enable_rollback = forms.BooleanField(
        label=_('Rollback On Failure'),
        help_text=_('Enable rollback on create/update failure.'),
        required=False)

    def __init__(self, *args, **kwargs):
        parameters = kwargs.pop('parameters')
        # special case: load template data from API, not passed in params
        if kwargs.get('validate_me'):
            parameters = kwargs.pop('validate_me')
        super(CreateStackForm, self).__init__(*args, **kwargs)

        if self._stack_password_enabled():
            self.fields['password'] = forms.CharField(
                label=_('Password for user "%s"') % self.request.user.username,
                help_text=_('This is required for operations to be performed '
                            'throughout the lifecycle of the stack'),
                widget=forms.PasswordInput())

        self._build_parameter_fields(parameters)

    def _stack_password_enabled(self):
        stack_settings = getattr(settings, 'OPENSTACK_HEAT_STACK', {})
        return stack_settings.get('enable_user_pass', True)

    def _build_parameter_fields(self, template_validate):
        self.help_text = template_validate['Description']

        params = template_validate.get('Parameters', {})
        if template_validate.get('ParameterGroups'):
            params_in_order = []
            for group in template_validate['ParameterGroups']:
                for param in group.get('parameters', []):
                    if param in params:
                        params_in_order.append((param, params[param]))
        else:
            # no parameter groups, simply sorted to make the order fixed
            params_in_order = sorted(params.items())
        for param_key, param in params_in_order:
            field = None
            field_key = self.param_prefix + param_key
            field_args = {
                'initial': param.get('Default', None),
                'label': param.get('Label', param_key),
                'help_text': html.escape(param.get('Description', '')),
                'required': param.get('Default', None) is None
            }

            param_type = param.get('Type', None)
            hidden = strutils.bool_from_string(param.get('NoEcho', 'false'))
            if 'CustomConstraint' in param:
                choices = self._populate_custom_choices(
                    param['CustomConstraint'])
                field_args['choices'] = choices
                field = forms.ChoiceField(**field_args)

            elif 'AllowedValues' in param:
                choices = map(lambda x: (x, x), param['AllowedValues'])
                field_args['choices'] = choices
                field = forms.ChoiceField(**field_args)

            elif param_type == 'Json' and 'Default' in param:
                field_args['initial'] = json.dumps(param['Default'])
                field = forms.CharField(**field_args)

            elif param_type in ('CommaDelimitedList', 'String', 'Json'):
                if 'MinLength' in param:
                    field_args['min_length'] = int(param['MinLength'])
                    field_args['required'] = field_args['min_length'] > 0
                if 'MaxLength' in param:
                    field_args['max_length'] = int(param['MaxLength'])
                if hidden:
                    field_args['widget'] = forms.PasswordInput()
                field = forms.CharField(**field_args)

            elif param_type == 'Number':
                if 'MinValue' in param:
                    field_args['min_value'] = int(param['MinValue'])
                if 'MaxValue' in param:
                    field_args['max_value'] = int(param['MaxValue'])
                field = forms.IntegerField(**field_args)

            # heat-api currently returns the boolean type in lowercase
            # (see https://bugs.launchpad.net/heat/+bug/1361448)
            # so for better compatibility both are checked here
            elif param_type in ('Boolean', 'boolean'):
                field = forms.BooleanField(**field_args)

            if field:
                self.fields[field_key] = field

    @sensitive_variables('password')
    def handle(self, request, data):
        prefix_length = len(self.param_prefix)
        params_list = [(k[prefix_length:], v) for (k, v) in six.iteritems(data)
                       if k.startswith(self.param_prefix)]
        fields = {
            'stack_name': data.get('stack_name'),
            'timeout_mins': data.get('timeout_mins'),
            'disable_rollback': not(data.get('enable_rollback')),
            'parameters': dict(params_list),
        }
        if data.get('password'):
            fields['password'] = data.get('password')

        if data.get('template_data'):
            fields['template'] = data.get('template_data')
        else:
            fields['template_url'] = data.get('template_url')

        if data.get('environment_data'):
            fields['environment'] = data.get('environment_data')

        try:
            api.heat.stack_create(self.request, **fields)
            messages.success(request, _("Stack creation started."))
            return True
        except Exception:
            exceptions.handle(request)

    def _populate_custom_choices(self, custom_type):
        if custom_type == 'neutron.network':
            return instance_utils.network_field_data(self.request, True)
        if custom_type == 'nova.keypair':
            return instance_utils.keypair_field_data(self.request, True)
        if custom_type == 'glance.image':
            return image_utils.image_field_data(self.request, True)
        if custom_type == 'nova.flavor':
            return instance_utils.flavor_field_data(self.request, True)
        return []
示例#27
0
文件: launch.py 项目: toha10/horizon
class JobConfigAction(workflows.Action):
    MAIN_CLASS = "edp.java.main_class"
    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"

    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)

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

    streaming_mapper = forms.CharField(label=_("Mapper"))

    streaming_reducer = forms.CharField(label=_("Reducer"))

    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)

    def __init__(self, request, *args, **kwargs):
        super(JobConfigAction, self).__init__(request, *args, **kwargs)
        job_ex_id = request.REQUEST.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.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])

    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):
        job_id = request.REQUEST.get("job_id") or request.REQUEST.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 six.iteritems(configs):
            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.JAVA_OPTS,
                    self.EDP_ADAPT_FOR_OOZIE, self.EDP_ADAPT_SPARK_SWIFT
            ]:
                del configs[rmkey]
        return (configs, edp_configs)

    class Meta(object):
        name = _("Configure")
        help_text_template = (
            "project/data_processing.jobs/_launch_job_configure_help.html")
示例#28
0
    def _build_parameter_fields(self, template_validate):
        self.help_text = template_validate['Description']

        params = template_validate.get('Parameters', {})
        if template_validate.get('ParameterGroups'):
            params_in_order = []
            for group in template_validate['ParameterGroups']:
                for param in group.get('parameters', []):
                    if param in params:
                        params_in_order.append((param, params[param]))
        else:
            # no parameter groups, simply sorted to make the order fixed
            params_in_order = sorted(params.items())
        for param_key, param in params_in_order:
            field = None
            field_key = self.param_prefix + param_key
            field_args = {
                'initial': param.get('Default', None),
                'label': param.get('Label', param_key),
                'help_text': html.escape(param.get('Description', '')),
                'required': param.get('Default', None) is None
            }

            param_type = param.get('Type', None)
            hidden = strutils.bool_from_string(param.get('NoEcho', 'false'))
            if 'CustomConstraint' in param:
                choices = self._populate_custom_choices(
                    param['CustomConstraint'])
                field_args['choices'] = choices
                field = forms.ChoiceField(**field_args)

            elif 'AllowedValues' in param:
                choices = map(lambda x: (x, x), param['AllowedValues'])
                field_args['choices'] = choices
                field = forms.ChoiceField(**field_args)

            elif param_type == 'Json' and 'Default' in param:
                field_args['initial'] = json.dumps(param['Default'])
                field = forms.CharField(**field_args)

            elif param_type in ('CommaDelimitedList', 'String', 'Json'):
                if 'MinLength' in param:
                    field_args['min_length'] = int(param['MinLength'])
                    field_args['required'] = field_args['min_length'] > 0
                if 'MaxLength' in param:
                    field_args['max_length'] = int(param['MaxLength'])
                if hidden:
                    field_args['widget'] = forms.PasswordInput()
                field = forms.CharField(**field_args)

            elif param_type == 'Number':
                if 'MinValue' in param:
                    field_args['min_value'] = int(param['MinValue'])
                if 'MaxValue' in param:
                    field_args['max_value'] = int(param['MaxValue'])
                field = forms.IntegerField(**field_args)

            # heat-api currently returns the boolean type in lowercase
            # (see https://bugs.launchpad.net/heat/+bug/1361448)
            # so for better compatibility both are checked here
            elif param_type in ('Boolean', 'boolean'):
                field = forms.BooleanField(**field_args)

            if field:
                self.fields[field_key] = field
示例#29
0
文件: forms.py 项目: yhu6/stx-horizon
class CreateUserForm(PasswordMixin, BaseUserForm, AddExtraColumnMixIn):
    # 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"))
    description = forms.CharField(
        widget=forms.widgets.Textarea(attrs={'rows': 4}),
        label=_("Description"),
        required=False)
    email = forms.EmailField(label=_("Email"), required=False)
    project = forms.ThemableDynamicChoiceField(label=_("Primary Project"),
                                               required=PROJECT_REQUIRED,
                                               add_item_link=ADD_PROJECT_URL)
    role_id = forms.ThemableChoiceField(label=_("Role"),
                                        required=PROJECT_REQUIRED)
    enabled = forms.BooleanField(label=_("Enabled"),
                                 required=False,
                                 initial=True)

    def __init__(self, *args, **kwargs):
        roles = kwargs.pop('roles')
        super(CreateUserForm, self).__init__(*args, **kwargs)
        # Reorder form fields from multiple inheritance
        ordering = [
            "domain_id", "domain_name", "name", "description", "email",
            "password", "confirm_password", "project", "role_id", "enabled"
        ]
        self.add_extra_fields(ordering)
        self.fields = collections.OrderedDict(
            (key, self.fields[key]) for key in ordering)
        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
        # For keystone V2.0, hide description field
        else:
            self.fields["description"].widget = forms.HiddenInput()

    # 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, False)
        try:
            LOG.info('Creating user with name "%s"', data['name'])
            desc = data["description"]
            if "email" in data:
                data['email'] = data['email'] or None

            # add extra information
            if api.keystone.VERSIONS.active >= 3:
                EXTRA_INFO = getattr(settings, 'USER_TABLE_EXTRA_INFO', {})
                kwargs = dict((key, data.get(key)) for key in EXTRA_INFO)
            else:
                kwargs = {}

            new_user = \
                api.keystone.user_create(request,
                                         name=data['name'],
                                         email=data['email'],
                                         description=desc or None,
                                         password=data['password'],
                                         project=data['project'] or None,
                                         enabled=data['enabled'],
                                         domain=domain.id,
                                         **kwargs)
            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 exceptions.Conflict:
            msg = _('User name "%s" is already used.') % data['name']
            messages.error(request, msg)
        except Exception:
            exceptions.handle(request, _('Unable to create user.'))
示例#30
0
class CreateImageForm(forms.SelfHandlingForm):
    name = forms.CharField(max_length="255", label=_("Name"), required=True)
    description = forms.CharField(widget=forms.widgets.Textarea(),
                                  label=_("Description"),
                                  required=False)

    source_type = forms.ChoiceField(
        label=_('Image Source'),
        choices=[('url', _('Image Location')), ('file', _('Image File'))],
        widget=forms.Select(attrs={
            'class': 'switchable',
            'data-slug': 'source'
        }))

    copy_from = forms.CharField(max_length="255",
                                label=_("Image Location"),
                                help_text=_("An external (HTTP) URL to load "
                                            "the image from."),
                                widget=forms.TextInput(
                                    attrs={
                                        'class': 'switched',
                                        'data-switch-on': 'source',
                                        'data-source-url': _('Image Location')
                                    }),
                                required=False)
    image_file = forms.FileField(label=_("Image File"),
                                 help_text=_("A local image to upload."),
                                 widget=forms.FileInput(
                                     attrs={
                                         'class': 'switched',
                                         'data-switch-on': 'source',
                                         'data-source-file': _('Image File')
                                     }),
                                 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'],
            'properties': {}
        }

        if data['description']:
            meta['properties']['description'] = data['description']
        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 Exception:
            exceptions.handle(request, _('Unable to create new image.'))