Exemplo n.º 1
0
class CreateFlavorInfoAction(workflows.Action):
    _flavor_id_regex = (r'^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
                        r'[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[0-9]+|auto$')
    _flavor_id_help_text = _("Flavor ID should be UUID4 or integer. "
                             "Leave this field blank or use 'auto' to set "
                             "a random UUID4.")
    name = forms.RegexField(label=_("Name"),
                            max_length=255,
                            regex=r'^[\w\.\- ]+$',
                            error_messages={
                                'invalid':
                                _('Name may only contain letters, numbers, '
                                  'underscores, periods and hyphens.')
                            })
    flavor_id = forms.RegexField(label=_("ID"),
                                 regex=_flavor_id_regex,
                                 required=False,
                                 initial='auto',
                                 help_text=_flavor_id_help_text)
    vcpus = forms.IntegerField(label=_("VCPUs"), min_value=1)
    memory_mb = forms.IntegerField(label=_("RAM (MB)"), min_value=1)
    disk_gb = forms.IntegerField(label=_("Root Disk (GB)"), min_value=0)
    eph_gb = forms.IntegerField(label=_("Ephemeral Disk (GB)"),
                                required=False,
                                initial=0,
                                min_value=0)
    swap_mb = forms.IntegerField(label=_("Swap Disk (MB)"),
                                 required=False,
                                 initial=0,
                                 min_value=0)

    class Meta(object):
        name = _("Flavor Information")
        help_text = _("Flavors define the sizes for RAM, disk, number of "
                      "cores, and other resources and can be selected when "
                      "users deploy instances.")

    def clean(self):
        cleaned_data = super(CreateFlavorInfoAction, self).clean()
        name = cleaned_data.get('name')
        flavor_id = cleaned_data.get('flavor_id')

        try:
            flavors = api.nova.flavor_list(self.request, None)
        except Exception:
            flavors = []
            msg = _('Unable to get flavor list')
            exceptions.check_message(["Connection", "refused"], msg)
            raise
        if flavors is not None:
            for flavor in flavors:
                if flavor.name == name:
                    raise forms.ValidationError(
                        _('The name "%s" is already used by another flavor.') %
                        name)
                if flavor.id == flavor_id:
                    raise forms.ValidationError(
                        _('The ID "%s" is already used by another flavor.') %
                        flavor_id)
        return cleaned_data
Exemplo n.º 2
0
class UpdateInstallParamsAction(workflows.Action):
    INSTALL_OUTPUT_CHOICES = (
        (stx_api.sysinv.INSTALL_OUTPUT_TEXT, _("text")),
        (stx_api.sysinv.INSTALL_OUTPUT_GRAPHICAL, _("graphical")),
    )

    boot_device = forms.RegexField(label=_("Boot Device"),
                                   max_length=255,
                                   regex=r'^[^/\s]|(/dev/disk/by-path/(.+))',
                                   error_messages={
                                       'invalid':
                                       _('Device path is relative to /dev')},
                                   help_text=_("Device for boot partition."))

    rootfs_device = forms.RegexField(label=_("Rootfs Device"),
                                     max_length=255,
                                     regex=r'^[^/\s]|(/dev/disk/by-path/(.+))',
                                     error_messages={
                                         'invalid':
                                         _('Device path is relative to /dev')},
                                     help_text=_("Device for rootfs "
                                                 "partition."))

    install_output = forms.ChoiceField(label=_("Installation Output"),
                                       choices=INSTALL_OUTPUT_CHOICES,
                                       widget=forms.Select(
                                           attrs={'class': 'switchable',
                                                  'data-slug': 'install_output'
                                                  }))

    console = forms.CharField(label=_("Console"),
                              required=False,
                              help_text=_("Console configuration "
                                          "(eg. 'ttyS0,115200' or "
                                          "empty for none)."))

    class Meta(object):
        name = _("Installation Parameters")
        help_text = _(
            "From here you can update the installation parameters of"
            " the current host.")

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

        host_id = self.initial['host_id']
        host = stx_api.sysinv.host_get(self.request, host_id)

        self.fields['boot_device'].initial = host.boot_device
        self.fields['rootfs_device'].initial = host.rootfs_device
        self.fields['install_output'].initial = host.install_output
        self.fields['console'].initial = host.console

    def clean(self):
        cleaned_data = super(UpdateInstallParamsAction, self).clean()
        return cleaned_data
class CreateFlavorInfoAction(workflows.Action):
    _flavor_id_regex = (r'^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
                        r'[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[0-9]+|auto$')
    _flavor_id_help_text = _("Flavor ID should be UUID4 or integer. "
                             "Leave this field blank or use 'auto' to set "
                             "a random UUID4.")
    name = forms.RegexField(label=_("Name"),
                            max_length=25,
                            regex=r'^[\w\.\- ]+$',
                            error_messages={
                                'invalid':
                                _('Name may only '
                                  'contain letters, numbers, underscores, '
                                  'periods and hyphens.')
                            })
    flavor_id = forms.RegexField(label=_("ID"),
                                 regex=_flavor_id_regex,
                                 required=False,
                                 initial='auto',
                                 help_text=_flavor_id_help_text)
    vcpus = forms.IntegerField(label=_("VCPUs"))
    memory_mb = forms.IntegerField(label=_("RAM MB"))
    disk_gb = forms.IntegerField(label=_("Root Disk GB"))
    #    eph_gb = forms.IntegerField(label=_("Ephemeral Disk GB"))
    #    swap_mb = forms.IntegerField(label=_("Swap Disk MB"))
    price = forms.CharField(label=_("set_price"))

    class Meta:
        name = _("Flavor Info")
        help_text = _("From here you can create a new "
                      "flavor to organize projects.")

    def clean(self):
        cleaned_data = super(CreateFlavorInfoAction, self).clean()
        name = cleaned_data.get('name')
        flavor_id = cleaned_data.get('flavor_id')

        try:
            flavors = api.nova.flavor_list(self.request, None)
        except Exception:
            flavors = []
            msg = _('Unable to get flavor list')
            exceptions.check_message(["Connection", "refused"], msg)
            raise
        if flavors is not None:
            for flavor in flavors:
                if flavor.name == name:
                    raise forms.ValidationError(
                        _('The name "%s" is already used by another flavor.') %
                        name)
                if flavor.id == flavor_id:
                    raise forms.ValidationError(
                        _('The ID "%s" is already used by another flavor.') %
                        flavor_id)
        return cleaned_data
Exemplo n.º 4
0
class AddMobileNumberForm(horizon_forms.SelfHandlingForm):

    mobile_number = horizon_forms.RegexField(
        label=_('Enter an M-Pesa enabled number'),
        required=True,
        widget=horizon_forms.TextInput(
            attrs={'placeholder': 'e.g. 0720123456'}),
        min_length=10,
        max_length=10,
        regex='^[0-9]+$',
        error_messages={
            'invalid': 'Please enter a valid phone number (e.g. 0720123456)'
        })

    def handle(self, request, data):
        try:
            MobileMoneyNumber.create(number=data['mobile_number'],
                                     tenant_id=request.user.tenant_id)
            messages.success(
                request,
                _('M-Pesa Number "%s" has been tied to your account.') %
                data['mobile_number'])

            return True
        except django_forms.ValidationError as e:
            self.api_error(e.messages[0])
        except IntegrityError:
            self.api_error('The number you entered is already in use.')
        except Exception:
            exceptions.handle(request, ignore=True)
Exemplo n.º 5
0
class CreateSpec(forms.SelfHandlingForm):
    key = forms.RegexField(max_length=255, label=_("Key"),
                           regex=KEY_NAME_REGEX,
                           error_messages=KEY_ERROR_MESSAGES)
    value = forms.CharField(max_length=255, label=_("Value"))

    def handle(self, request, data):
        group_type_id = self.initial['group_type_id']
        error_msg = _('key with name "%s" already exists.Use Edit to '
                      'update the value, else create key with different '
                      'name.') % data['key']
        try:
            specs_list = api.cinder.group_type_spec_list(self.request,
                                                         group_type_id)
            for spec in specs_list:
                if spec.key.lower() == data['key'].lower():
                    raise forms.ValidationError(error_msg)
            api.cinder.group_type_spec_set(request,
                                           group_type_id,
                                           {data['key']: data['value']})

            msg = _('Created group type spec "%s".') % data['key']
            messages.success(request, msg)
            return True
        except forms.ValidationError:
            messages.error(request, error_msg)
        except Exception:
            redirect = reverse("horizon:admin:group_types:index")
            exceptions.handle(request,
                              _("Unable to create group type spec."),
                              redirect=redirect)
Exemplo n.º 6
0
class SetAccessControlsAction(workflows.Action):
    keypair = forms.ThemableDynamicChoiceField(
        label=_("Key Pair"),
        help_text=_("Key pair to use for "
                    "authentication."),
        add_item_link=KEYPAIR_IMPORT_URL)
    admin_pass = forms.RegexField(
        label=_("Admin Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_admin_pass = forms.CharField(
        label=_("Confirm Admin Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False))
    groups = forms.MultipleChoiceField(
        label=_("Security Groups"),
        required=False,
        initial=["default"],
        widget=forms.ThemableCheckboxSelectMultiple(),
        help_text=_("Launch instance in these "
                    "security groups."))

    class Meta(object):
        name = _("Access & Security")
        help_text = _("Control access to your instance via key pairs, "
                      "security groups, and other mechanisms.")

    def __init__(self, request, *args, **kwargs):
        super(SetAccessControlsAction, self).__init__(request, *args, **kwargs)
        if not api.nova.can_set_server_password():
            del self.fields['admin_pass']
            del self.fields['confirm_admin_pass']
        self.fields['keypair'].required = api.nova.requires_keypair()

    def populate_keypair_choices(self, request, context):
        keypairs = instance_utils.keypair_field_data(request, True)
        if len(keypairs) == 2:
            self.fields['keypair'].initial = keypairs[1][0]
        return keypairs

    def populate_groups_choices(self, request, context):
        try:
            groups = api.neutron.security_group_list(request)
            security_group_list = [(sg.id, sg.name) for sg in groups]
        except Exception:
            exceptions.handle(request,
                              _('Unable to retrieve list of security groups'))
            security_group_list = []
        return security_group_list

    def clean(self):
        '''Check to make sure password fields match.'''
        cleaned_data = super(SetAccessControlsAction, self).clean()
        if 'admin_pass' in cleaned_data:
            if cleaned_data['admin_pass'] != cleaned_data.get(
                    'confirm_admin_pass', None):
                raise forms.ValidationError(_('Passwords do not match.'))
        return cleaned_data
Exemplo n.º 7
0
class UpdateUserForm(BaseUserForm):
    # Hide the domain_id and domain_name by default
    domain_id = forms.CharField(label=_("Domain ID"),
                                required=False,
                                widget=forms.HiddenInput())
    domain_name = forms.CharField(label=_("Domain Name"),
                                  required=False,
                                  widget=forms.HiddenInput())
    id = forms.CharField(label=_("ID"), widget=forms.HiddenInput)
    name = forms.CharField(label=_("User Name"))
    email = forms.EmailField(label=_("Email"), required=False)
    password = forms.RegexField(
        label=_("Password"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        required=False,
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm Password"),
        widget=forms.PasswordInput(render_value=False),
        required=False)
    project = forms.ChoiceField(label=_("Primary Project"))

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

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

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

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

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

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

        if isinstance(response, http.HttpResponse):
            return response
        else:
            return True
class CreateUserForm(BaseUserForm):
    name = forms.CharField(label=_("User Name"))
    email = forms.EmailField(label=_("Email"))
    password = forms.RegexField(
        label=_("Password"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False))
    tenant_id = forms.ChoiceField(label=_("Primary Project"))

    def handle(self, request, data):
        try:
            LOG.info('Creating user with name "%s"' % data['name'])
            new_user = api.user_create(request, data['name'], data['email'],
                                       data['password'], data['tenant_id'],
                                       True)
            messages.success(
                request,
                _('User "%s" was successfully created.') % data['name'])
            try:
                default_role = api.keystone.get_default_role(request)
                if default_role:
                    api.add_tenant_user_role(request, data['tenant_id'],
                                             new_user.id, default_role.id)
            except:
                exceptions.handle(request,
                                  _('Unable to add user to primary project.'))
            return shortcuts.redirect('horizon:syspanel:users:index')
        except:
            exceptions.handle(request, _('Unable to create user.'))
            return shortcuts.redirect('horizon:syspanel:users:index')
Exemplo n.º 9
0
class CreateExtraSpec(forms.SelfHandlingForm):
    key = forms.RegexField(max_length=255,
                           label=_("Key"),
                           regex=KEY_NAME_REGEX,
                           error_messages=KEY_ERROR_MESSAGES)
    value = forms.CharField(max_length=255, label=_("Value"))

    def clean(self):
        data = super(CreateExtraSpec, self).clean()
        type_id = self.initial['type_id']
        extra_list = api.cinder.volume_type_extra_get(self.request, type_id)
        if "key" in data:
            for extra in extra_list:
                if extra.key.lower() == data['key'].lower():
                    error_msg = _('Key with name "%s" already exists. Use '
                                  'Edit to update the value, else create key '
                                  'with different name.') % data['key']
                    raise forms.ValidationError(error_msg)

        return data

    def handle(self, request, data):
        type_id = self.initial['type_id']
        try:
            api.cinder.volume_type_extra_set(request, type_id,
                                             {data['key']: data['value']})
            msg = _('Created extra spec "%s".') % data['key']
            messages.success(request, msg)
            return True
        except Exception:
            redirect = reverse("horizon:admin:volume_types:index")
            exceptions.handle(request,
                              _("Unable to create volume type extra spec."),
                              redirect=redirect)
Exemplo n.º 10
0
class CreateRuleInfoAction(workflows.Action):
    # Hide the domain_id and domain_name by default
    project_id = forms.CharField(label=_("Project ID"),
                                 required=False,
                                 widget=forms.HiddenInput())
    rulename = forms.RegexField(
        label=_("Rule Name"),
        max_length=64,
        help_text=_("Name of this sudo rule. "
                    "Must be a unique name within this project."),
        regex=LDAP_TEXT_VALIDATOR,
        error_messages=LDAP_TEXT_VALIDATOR_MESSAGES,
        required=True)
    commands = forms.CharField(
        widget=forms.widgets.Textarea(attrs={'rows': 4}),
        label=_("Commands"),
        help_text=_("List of permitted commands, one per line, "
                    "or ALL to permit all actions."),
        required=True)
    options = forms.CharField(widget=forms.widgets.Textarea(attrs={'rows': 2}),
                              label=_("Options"),
                              required=False)
    authrequired = forms.BooleanField(label=_("Passphrase required"),
                                      required=False,
                                      initial=False)

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

    class Meta(object):
        name = _("Rule")
        help_text = _("Create a rule to permit certain sudo commands.")
        slug = "rule_info"
Exemplo n.º 11
0
class DomainForm(forms.SelfHandlingForm):
    '''Base class for DomainCreate and DomainUpdate forms.

    Sets-up all of the common form fields.
    '''

    name = forms.RegexField(
        label=_("Domain Name"),
        regex=DOMAIN_NAME_REGEX,
        error_messages={'invalid': _('Enter a valid domain name.')},
    )

    email = forms.EmailField(
        label=_("Email"),
        max_length=255,
    )

    ttl = forms.IntegerField(
        label=_("TTL (seconds)"),
        min_value=0,
        max_value=MAX_TTL,
        required=False,
    )

    description = forms.CharField(
        label=_("Description"),
        required=False,
        max_length=160,
        widget=forms.Textarea(),
    )
Exemplo n.º 12
0
class ImportKeypair(forms.SelfHandlingForm):
    name = forms.RegexField(max_length=255,
                            label=_("Key Pair Name"),
                            regex=KEYPAIR_NAME_REGEX,
                            error_messages=KEYPAIR_ERROR_MESSAGES)
    key_type = forms.ChoiceField(label=_("Key Type"),
                                 widget=forms.SelectWidget(),
                                 choices=[('ssh', _("SSH Key")),
                                          ('x509', _("X509 Certificate"))],
                                 initial='ssh')
    public_key = forms.CharField(label=_("Public Key"),
                                 widget=forms.Textarea())

    def handle(self, request, data):
        try:
            # Remove any new lines in the ssh public key
            if data['key_type'] == 'ssh':
                data['public_key'] = NEW_LINES.sub("", data['public_key'])
            keypair = api.nova.keypair_import(request,
                                              data['name'],
                                              data['public_key'],
                                              data['key_type'])
            messages.success(request,
                             _('Successfully imported public key: %s')
                             % data['name'])
            return keypair
        except Exception:
            exceptions.handle(request, ignore=True)
            self.api_error(_('Unable to import key pair.'))
            return False
Exemplo n.º 13
0
class SetAccessControlsAction(workflows.Action):
    keypair = forms.DynamicChoiceField(
        label=_("Keypair"),
        required=False,
        help_text=_("Which keypair to use for "
                    "authentication."),
        widget=fields.SelectWidget(data_attrs=('provider', 'region',
                                               'instanceId'),
                                   transform=lambda x:
                                   ("%s (%s)(%s)" %
                                    (x.name, x.provider, x.region))),
        add_item_link=KEYPAIR_IMPORT_URL)
    admin_pass = forms.RegexField(
        label=_("Admin Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_admin_pass = forms.CharField(
        label=_("Confirm Admin Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False))
    groups = forms.MultipleChoiceField(label=_("Security Groups"),
                                       required=False,
                                       initial=["default"],
                                       widget=forms.CheckboxSelectMultiple(),
                                       help_text=_("Launch instance in these "
                                                   "security groups."))

    class Meta:
        name = _("Access & Security")
        help_text = _("Control access to your instance via keypairs, "
                      "security groups, and other mechanisms.")

    def populate_keypair_choices(self, request, context):
        try:
            keypairs = capi.keypairs(request)
            keypair_list = [(kp.id, kp) for kp in keypairs]
        except Exception:
            keypair_list = []
            exceptions.handle(request, _('Unable to retrieve keypairs.'))
        if keypair_list:
            keypair_list.insert(0, ("", _("Select a keypair")))
        else:
            keypair_list = (("", _("No keypairs available.")), )
        return keypair_list

    def populate_groups_choices(self, request, context):
        try:
            groups = capi.securitygroups(request)
            if groups:
                security_group_list = [(sg.id, sg.name) for sg in groups]
            else:
                security_group_list = []
        except Exception:
            exceptions.handle(request,
                              _('Unable to retrieve list of security groups'))
            security_group_list = []
        return security_group_list
Exemplo n.º 14
0
class PasswordForm(forms.SelfHandlingForm):
    current_password = forms.CharField(
        label=_("Current password"),
        strip=False,
        widget=forms.PasswordInput(render_value=False))
    new_password = forms.RegexField(
        label=_("New password"),
        strip=False,
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid':
                        validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm new password"),
        strip=False,
        widget=forms.PasswordInput(render_value=False))
    no_autocomplete = True

    def clean(self):
        '''Check to make sure password fields match.'''
        data = super(PasswordForm, self).clean()
        if 'new_password' in data:
            if data['new_password'] != data.get('confirm_password', None):
                raise ValidationError(_('Passwords do not match.'))
            if data.get('confirm_password', None) == \
                    data.get('current_password', None):
                raise ValidationError(_('Old password and new password '
                                        'must be different'))
        return data

    # We have to protect the entire "data" dict because it contains the
    # oldpassword and newpassword strings.
    @sensitive_variables('data')
    def handle(self, request, data):
        user_is_editable = api.keystone.keystone_can_edit_user()
        user_id = request.user.id
        user = api.keystone.user_get(self.request, user_id, admin=False)
        options = getattr(user, "options", {})
        lock_password = options.get("lock_password", False)
        if lock_password:
            messages.error(request, _('Password is locked.'))
            return False

        if user_is_editable:
            try:
                api.keystone.user_update_own_password(request,
                                                      data['current_password'],
                                                      data['new_password'])
                response = http.HttpResponseRedirect(settings.LOGOUT_URL)
                msg = _("Password changed. Please log in again to continue.")
                utils.add_logout_reason(request, response, msg)
                return response
            except Exception:
                exceptions.handle(request,
                                  _('Unable to change password.'))
                return False
        else:
            messages.error(request, _('Changing password is not supported.'))
            return False
Exemplo n.º 15
0
class SignupForm(SelfHandlingForm):

    username = forms.CharField(
        label=_("Username"),
        max_length=255,
        widget=forms.TextInput(attrs={
            'placeholder': _('Username'),
            'autofocus': 'autofocus'
        }))
    email = forms.EmailField(widget=forms.TextInput(
        attrs={
            'type': 'email',
            'placeholder': _('E-mail address')
        }))

    password = forms.RegexField(
        label=_("Password"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm Password"),
        widget=forms.PasswordInput(render_value=False))
    no_autocomplete = True

    def clean(self):
        '''Check to make sure password fields match.'''
        data = super(SignupForm, self).clean()

        # basic check for now
        if 'username' in data:
            if User.objects.filter(username=data['username'],
                                   email=data['email']).exists():
                raise validators.ValidationError(
                    _('Username or email exists in database.'))

        if 'password' in data:
            if data['password'] != data.get('confirm_password', None):
                raise validators.ValidationError(_('Passwords do not match.'))
            else:
                data.pop('confirm_password')
        return data

    def handle(self, request, data):

        try:
            user = User.objects.create_user(**data)
            messages.success(
                request,
                _("User account {} was successfuly created.".format(user)))

        except Exception as e:
            raise e
        else:
            data.pop('email')
            return LoginForm().handle(request, data)

        messages.error(request, _("Create Account failed."))
        return False
Exemplo n.º 16
0
class CreateKeypair(forms.SelfHandlingForm):
    name = forms.RegexField(max_length=255,
                            label=_("Key Pair Name"),
                            regex=KEYPAIR_NAME_REGEX,
                            error_messages=KEYPAIR_ERROR_MESSAGES)

    def handle(self, request, data):
        return True  # We just redirect to the download view.
Exemplo n.º 17
0
class RebuildInstanceForm(forms.SelfHandlingForm):
    instance_id = forms.CharField(widget=forms.HiddenInput())
    image = forms.ChoiceField(label=_("Select Image"),
                              widget=fields.SelectWidget(
                                  attrs={'class': 'image-selector'},
                                  data_attrs=('size', 'display-name'),
                                  transform=_image_choice_title))
    password = forms.RegexField(
        label=_("Rebuild Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm Rebuild Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False))

    def __init__(self, request, *args, **kwargs):
        super(RebuildInstanceForm, self).__init__(request, *args, **kwargs)
        instance_id = kwargs.get('initial', {}).get('instance_id')
        self.fields['instance_id'].initial = instance_id

        images = utils.get_available_images(request, request.user.tenant_id)
        choices = [(image.id, image.name) for image in images]
        if choices:
            choices.insert(0, ("", _("Select Image")))
        else:
            choices.insert(0, ("", _("No images available.")))
        self.fields['image'].choices = choices

    def clean(self):
        cleaned_data = super(RebuildInstanceForm, self).clean()
        if 'password' in cleaned_data:
            passwd = cleaned_data.get('password')
            confirm = cleaned_data.get('confirm_password')
            if passwd is not None and confirm is not None:
                if passwd != confirm:
                    raise forms.ValidationError(_("Passwords do not match."))
        return cleaned_data

    # We have to protect the entire "data" dict because it contains the
    # password and confirm_password strings.
    @sensitive_variables('data', 'password')
    def handle(self, request, data):
        instance = data.get('instance_id')
        image = data.get('image')
        password = data.get('password') or None
        try:
            api.nova.server_rebuild(request, instance, image, password)
            messages.success(request, _('Rebuilding instance %s.') % instance)
        except Exception:
            redirect = reverse('horizon:project:instances:index')
            exceptions.handle(request,
                              _("Unable to rebuild instance."),
                              redirect=redirect)
        return True
Exemplo n.º 18
0
class CreateFlavorTemplate(forms.SelfHandlingForm):
    name = forms.RegexField(label=_("Name"),
                            max_length=25,
                            regex=r'^[\w\.\- ]+$',
                            error_messages={
                                'invalid':
                                _('Name may only '
                                  'contain letters, numbers, underscores, '
                                  'periods and hyphens.')
                            })
    cpu = forms.IntegerField(label=_("VCPU"), min_value=0, initial=0)
    memory = forms.IntegerField(label=_("RAM (MB)"), min_value=0, initial=0)
    storage = forms.IntegerField(label=_("Root Disk (GB)"),
                                 min_value=0,
                                 initial=0)
    ephemeral_disk = forms.IntegerField(label=_("Ephemeral Disk (GB)"),
                                        min_value=0,
                                        initial=0)
    swap_disk = forms.IntegerField(label=_("Swap Disk (MB)"),
                                   min_value=0,
                                   initial=0)

    def clean(self):
        cleaned_data = super(CreateFlavorTemplate, self).clean()
        name = cleaned_data.get('name')
        flavor_template_id = self.initial.get('flavor_template_id', None)
        try:
            flavor_templates = tuskar.FlavorTemplate.list(self.request)
        except Exception:
            flavor_templates = []
            msg = _('Unable to get flavor templates list')
            exceptions.check_message(["Connection", "refused"], msg)
            raise
        # Check if there is no flavor template with the same name
        for flavor_template in flavor_templates:
            if (flavor_template.name == name
                    and flavor_template.id != flavor_template_id):
                raise forms.ValidationError(
                    _('The name "%s" is already used by another'
                      'flavor template.') % name)
        return cleaned_data

    def handle(self, request, data):
        try:
            tuskar.FlavorTemplate.create(request,
                                         name=data['name'],
                                         cpu=data['cpu'],
                                         memory=data['memory'],
                                         storage=data['storage'],
                                         ephemeral_disk=data['ephemeral_disk'],
                                         swap_disk=data['swap_disk'])
            msg = _('Created Flavor Template "%s".') % data['name']
            messages.success(request, msg)
            return True
        except Exception:
            exceptions.handle(request, _("Unable to create Flavor Template."))
Exemplo n.º 19
0
class PasswordForm(forms.SelfHandlingForm):
    current_password = forms.CharField(
        label=_("Current password"),
        widget=forms.PasswordInput(render_value=False))
    new_password = forms.RegexField(
        label=_("New password"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm new password"),
        widget=forms.PasswordInput(render_value=False))
    no_autocomplete = True

    def clean(self):
        '''Check to make sure password fields match.'''
        data = super(PasswordForm, self).clean()
        if 'new_password' in data:
            if data['new_password'] != data.get('confirm_password', None):
                raise ValidationError(_('Passwords do not match.'))
        return data

    # We have to protect the entire "data" dict because it contains the
    # oldpassword and newpassword strings.
    @sensitive_variables('data')
    def handle(self, request, data):
        user_is_editable = api.keystone.keystone_can_edit_user()

        if user_is_editable:
            try:
                api.keystone.user_update_own_password(request,
                                                      data['current_password'],
                                                      data['new_password'])
                response = http.HttpResponseRedirect(settings.LOGOUT_URL)
                msg = _("Password changed. Please log in again to continue.")
                utils.add_logout_reason(request, response, msg)
                api.nova.systemlogs_create(request, request.user.username,
                                           record_action.CHANGEPASSWORD)
                return response
            except Exception:
                msg = _('Unable to change password.')
                exceptions.handle(request, msg)
                api.nova.systemlogs_create(request,
                                           request.user.username,
                                           record_action.CHANGEPASSWORD,
                                           result=False,
                                           detail=msg)
                return False
        else:
            messages.error(request, _('Changing password is not supported.'))
            api.nova.systemlogs_create(request,
                                       request.user.username,
                                       record_action.CHANGEPASSWORD,
                                       result=False,
                                       detail=msg)
            return False
Exemplo n.º 20
0
class CreateUserAction(workflows.Action):
    username = forms.CharField(max_length=80, label=_("User Name"),
                               validators=[RegexValidator(r'^[\w]*$',
                                                          message='Username must be alphanumeric without spaces',
                                                          code='Invalid Username')]
                               )
    
    roles = forms.MultipleChoiceField(label=_("Roles"),
                                       required=False,
                                       initial=["default"],
                                       widget=forms.CheckboxSelectMultiple(),
                                       help_text=_("Create user with these "
                                                   "roles."))
    password = forms.RegexField(
        label=_("Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False))
    email = forms.EmailField(label=_("Email ID"),
             required=True)


    def populate_roles_choices(self, request, context):
        roles = []
        success = []
        try:
            if request.user.roles:
                for role in  request.user.roles:
                    if (role.name == "Tenant Admin") & (role.roletype == "Tenant Admin"):
                        success.append("Tenant Admin")
                    else:
                        success.append("Member")
                if "Tenant Admin" in success:
                    rolelist = roledetail.objects(tenantid=request.user.tenantid.id)
                    roles = [(role.id, role.name) for role in rolelist]
                else:   
                    rolelist = roledetail.objects(tenantid=request.user.tenantid.id)
                    for role in rolelist:
                        if (role.name == "Tenant Admin") & (role.roletype == "Tenant Admin"):
                            pass
                        else:
                            roles.append((role.id, role.name))
            else:
                roles = []
                                  
        except Exception, e:
            messages.error(request,_(e.message))
            LOG.error(e.message)
            roles = []
        return roles
Exemplo n.º 21
0
class ResetPasswordAction(workflows.Action):
    instance_id = forms.CharField(label=_("Instance ID"),
                                  widget=forms.HiddenInput(),
                                  required=False)

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

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

    validate_code = forms.CharField(max_length=64,
                                    label=_("Please Input Validate Code"),
                                    required=False)

    username = forms.CharField(max_length=64, label=_("User Name"), required=False)

    is_sync_set_root = forms.BooleanField(label=_("Sync set root/Administrator password"), initial=True, required=False)

    password = forms.RegexField(
        label=_("Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False, attrs={'placeholder': _('begin letter,8-64 bits,with number,letter and symbol')}),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})

    confirm_password = forms.CharField(
        label=_("Confirm Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False))

    is_reboot = forms.BooleanField(label=_("Reboot after reset password successfully"), initial=True, required=False) 

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

        self.fields["username"].initial = 'syscloud'

        is_allow_inject_passwd = context.get('is_allow_inject_passwd')
        if not is_allow_inject_passwd:
            del self.fields['username']
            del self.fields['is_sync_set_root']
            del self.fields['password']
            del self.fields['confirm_password']
            del self.fields['is_reboot']

    class Meta(object):
        name = _("Reset Password")
        slug = 'reset_password'
        help_text_template = ("instances/instances/"
                              "_reset_password.html")

    def clean(self):
        cleaned_data = super(ResetPasswordAction, self).clean()
        return cleaned_data

    '''
Exemplo n.º 22
0
class CreateCloudAction(workflows.Action):

    cloudtype = forms.ChoiceField(label=_("Platform"),
                                  required=True,
                                  widget=fields.SelectWidget(
                                      data_attrs=(
                                          'name',
                                          'type',
                                      ),
                                      transform=lambda x: ("%s " % (x.name))))

    cloudlist = forms.ChoiceField(label=_("Cloud Type"),
                                  required=True,
                                  widget=fields.SelectWidget(
                                      data_attrs=(
                                          'name',
                                          'type',
                                      ),
                                      transform=lambda x: ("%s " % (x.type))))
    cloudname = forms.CharField(label=_("Cloud Name"), max_length=80)

    cloud_id = forms.CharField(required=False, widget=forms.HiddenInput())
    publickey = forms.CharField(label=_("Public Key"), max_length=None)
    secretkey = forms.RegexField(
        label=_("Secret Key"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    endpoint = forms.CharField(max_length=80,
                               label=_("Endpoint(IP with HTTP)"))

    class Meta:
        name = _("ADD Cloud")

    def __init__(self, *args, **kwargs):
        super(CreateCloudAction, self).__init__(*args, **kwargs)
        try:
            region_list = get_regions_wo_connection()
            cloud_id = args[-1]["cloud_id"]
            cloud_obj = clouds.objects(id=cloud_id).first()
            self.fields['publickey'].label = _(cloud_obj.credential_fields[0])
            self.fields["secretkey"].label = _(cloud_obj.credential_fields[1])
            if cloud_obj.name == "Amazon":
                self.fields["endpoint"] = forms.ChoiceField(
                    label=_("Default Region"),
                    choices=region_list,
                    help_text=_("Select default region"))
                self.fields["endpoint"].label = _(
                    cloud_obj.credential_fields[2])
            else:
                self.fields["endpoint"].label = _(
                    cloud_obj.credential_fields[2])
        except Exception, e:
            messages.error(self.request, _(e.message))
            LOG.error(e.message)
Exemplo n.º 23
0
class CreateExtraSpec(forms.SelfHandlingForm):
    _extraspec_name_regex = re.compile(r"^[\w\.\-: ]+$", re.UNICODE)
    keys = forms.ChoiceField(label=_("Keys"),
                             widget=forms.Select(attrs={
                                 'class': 'switchable',
                                 'data-slug': 'keys'
                             }))
    key = forms.RegexField(max_length="255",
                           label=_("Key"),
                           required=False,
                           regex=_extraspec_name_regex,
                           error_messages={
                               'invalid':
                               _('Key Name may only contain letters, '
                                 'numbers, underscores, periods, colons, '
                                 'spaces and hyphens.')
                           },
                           widget=forms.TextInput(
                               attrs={
                                   'class': 'switched',
                                   'data-switch-on': 'keys',
                                   'data-keys-custom': _('Key')
                               }))
    value = forms.CharField(max_length="255", label=_("Value"))
    flavor_id = forms.CharField(widget=forms.widgets.HiddenInput)

    def __init__(self, *args, **kwargs):
        super(CreateExtraSpec, self).__init__(*args, **kwargs)
        key_settings = getattr(settings, 'FLAVOR_EXTRA_KEYS', {})
        key_list = key_settings.get('flavor_keys', [])
        self.fields['keys'].choices = key_list + [('custom', _('Other Key'))]

    def clean(self):
        cleaned_data = super(CreateExtraSpec, self).clean()
        keys = cleaned_data.get('keys', None)
        key = cleaned_data.get('key', None)
        if keys == 'custom' and key == "":
            msg = _('This field is required.')
            self._errors["key"] = self.error_class([msg])
        return cleaned_data

    def handle(self, request, data):
        if data["keys"] != 'custom':
            data['key'] = data['keys']
        try:
            api.nova.flavor_extra_set(request, data['flavor_id'],
                                      {data['key']: data['value']})
            msg = _('Created extra spec "%s".') % data['key']
            messages.success(request, msg)
            return True
        except Exception:
            exceptions.handle(request,
                              _("Unable to create flavor extra spec."))
Exemplo n.º 24
0
class CreateUserForm(BaseUserForm):
    name = forms.CharField(label=_("User Name"))
    email = forms.EmailField(label=_("Email"))
    secretkey = forms.CharField(label=_("Secret Key"), required=False)
    password = forms.RegexField(
            label=_("Password"),
            widget=forms.PasswordInput(render_value=False),
            regex=validators.password_validator(),
            error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
            label=_("Confirm Password"),
            required=False,
            widget=forms.PasswordInput(render_value=False))
    tenant_id = forms.DynamicChoiceField(label=_("Primary Project"),
                                         add_item_link=ADD_PROJECT_URL)
    role_id = forms.ChoiceField(label=_("Role"))

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

    # 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):
        try:
            LOG.info('Creating user with name "%s"' % data['name'])
            new_user = api.keystone.user_create_with_otp(request,
                                                data['name'],
                                                data['email'],
                                                data['secretkey'],
                                                data['password'],
                                                data['tenant_id'],
                                                True)
            messages.success(request,
                             _('User "%s" was successfully created.')
                             % data['name'])
            if data['role_id']:
                try:
                    api.keystone.add_tenant_user_role(request,
                                             data['tenant_id'],
                                             new_user.id,
                                             data['role_id'])
                except:
                    exceptions.handle(request,
                                      _('Unable to add user'
                                        'to primary project.'))
            return new_user
        except:
            exceptions.handle(request, _('Unable to create user.'))
Exemplo n.º 25
0
class CreateUserForm(BaseUserForm):

    failure_url = 'horizon:vsm:usermgmt:index'
    name = forms.CharField(label=_("User name"),
                           max_length=255,
                           min_length=1,
                           error_messages={
                               'required': _('This field is required.'),
                               'invalid': _("Please enter a vaild User Name")
                           },
                           validators=[
                               validate_user_name,
                           ])
    password = forms.RegexField(
        label=_("Password"),
        widget=forms.PasswordInput(render_value=False),
        regex=password_validate_regrex,
        required=False,
        max_length=255,
        min_length=8,
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.RegexField(
        label=_("Confirm Password"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        required=False,
        error_messages={'invalid': validators.password_validator_msg()})

    #    email = forms.CharField(label=_("Email"),
    #            max_length=255,
    #            min_length=1,
    #            required=False,
    #            error_messages={
    #                'required': _('This field is required.'),
    #                'invalid': _('Please enter an email address.'),
    #            },)

    def handle(self, request, data):
        pass
Exemplo n.º 26
0
class PasswordForm(forms.SelfHandlingForm):
    current_password = forms.CharField(
        label=_("Current password"),
        widget=forms.PasswordInput(render_value=False))
    new_password = forms.RegexField(
        label=_("New password"),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=_("Confirm new password"),
        widget=forms.PasswordInput(render_value=False))

    def clean(self):
        '''Check to make sure password fields match.'''
        data = super(forms.Form, self).clean()
        if 'new_password' in data:
            if data['new_password'] != data.get('confirm_password', None):
                raise ValidationError(_('Passwords do not match.'))
        return data

    # We have to protect the entire "data" dict because it contains the
    # oldpassword and newpassword strings.
    @sensitive_variables('data')
    def handle(self, request, data):
        user_is_editable = api.keystone.keystone_can_edit_user()

        if user_is_editable:
            try:
                api.keystone.user_update_own_password(request,
                                                      data['current_password'],
                                                      data['new_password'])
                #   response = http.HttpResponseRedirect(settings.LOGOUT_URL)
                response = http.HttpResponseRedirect('/horizon/auth/login')

                userid = request.user.id
                print "this is setting userid : '%s'" % userid
                print "this is setting data['new_password'] : '******'" % data[
                    'new_password']
                update_user_password(userid, data['new_password'])
                msg = _("Password changed. Please log in again to continue.")
                utils.add_logout_reason(request, response, msg)
                return response
            except Exception:
                exceptions.handle(request, _('Unable to change password.'))
                return False
        else:
            messages.error(request, _('Changing password is not supported.'))
            return False

        return True
Exemplo n.º 27
0
class Discover(forms.SelfHandlingForm):

    storage_system = forms.ChoiceField(label=_("Storage System"), required=True)
    ip = forms.RegexField(max_length=255, label=_("Network Range"),
                          regex=NETWORK_RANGE_REGEX,
                          error_messages=NETWORK_ERROR_MESSAGES, required=False)
    user = forms.CharField(max_length=255, label=_("User Name"), required=False)
    fsid = forms.CharField(max_length=255, label=_("Cluster fsid"),
                           required=False)
    key = forms.CharField(max_length=255, label=_("Password"), required=False)

    def __init__(self, request, *args, **kwargs):
        super(Discover, self).__init__(request, *args, **kwargs)
        storage_choices = [("", _("Select storage system")),
                           ("ceph", _("Ceph(None authentication)")),
                           ("cephx", _("Ceph(Cephx authentication)")),
                           ("swift", _("Swift(User/Password authentication)")),
                           ("swift_key", _("Swift(Keystone authentication)"))]

        self.fields['storage_system'].choices = storage_choices

    def handle(self, request, data):
        try:
            ip_cidr = data.pop("ip")
            storage_type = data.pop("storage_system")

            metadata = {}
            for k, v in data.iteritems():
                if v:
                    metadata[k] = v
            if storage_type == 'swift_key':
                metadata = {'preauthtoken':request.user.token.id,
                            'preauthurl':base.url_for(request, "object-store")}

            #NOTE(fengqian): Cephx also means ceph, hard code here.
            if storage_type in ('cephx', 'ceph'):
                storage_type = 'ceph'
            elif storage_type in ('swift', 'swift_key'):
                storage_type = 'swift'

            discover_data = api.sds.discover_storage(request, ip_cidr,
                                                    storage_type, metadata)
            messages.success(request,
                             _('Successfully discover storage system: %s') \
                             % ip_cidr)

            return discover_data
        except Exception:
            exceptions.handle(request,
                              _('Unable to discover storage system.'))
            return False
Exemplo n.º 28
0
class EditUserForm(forms.SelfHandlingForm):
    instance_id = forms.CharField(widget=forms.HiddenInput())
    user_name = forms.CharField(
        label=_("Name"),
        widget=forms.TextInput(attrs={'readonly': 'readonly'}))
    user_host = forms.CharField(
        label=_("Host"),
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}))
    new_name = forms.CharField(label=_("New Name"), required=False)
    new_password = forms.RegexField(
        label=_("New Password"),
        required=False,
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    new_host = forms.CharField(label=_("New Host"), required=False)

    validation_error_message = _('A new name or new password or '
                                 'new host must be specified.')

    def handle(self, request, data):
        instance = data.get('instance_id')
        try:
            api.trove.user_update_attributes(request,
                                             instance,
                                             data['user_name'],
                                             host=data['user_host'],
                                             new_name=data['new_name'],
                                             new_password=data['new_password'],
                                             new_host=data['new_host'])

            messages.success(request,
                             _('Updated user "%s".') % data['user_name'])
        except Exception as e:
            redirect = reverse("horizon:project:databases:detail",
                               args=(instance, ))
            exceptions.handle(request,
                              _('Unable to update user. %s') %
                              six.text_type(e),
                              redirect=redirect)
        return True

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

        if (not (cleaned_data['new_name'] or cleaned_data['new_password']
                 or cleaned_data['new_host'])):
            raise ValidationError(self.validation_error_message)

        return cleaned_data
Exemplo n.º 29
0
class PasswordForm(forms.SelfHandlingForm):
    action = reverse_lazy('horizon:settings:multisettings:password')
    description = 'Change your password'
    template = 'settings/multisettings/_collapse_form.html'

    current_password = forms.CharField(
        label=('Current password'),
        widget=forms.PasswordInput(render_value=False))
    new_password = forms.RegexField(
        label=('New password'),
        widget=forms.PasswordInput(render_value=False),
        regex=validators.password_validator(),
        error_messages={'invalid': validators.password_validator_msg()})
    confirm_password = forms.CharField(
        label=('Confirm new password'),
        widget=forms.PasswordInput(render_value=False))
    no_autocomplete = True

    def clean(self):
        '''Check to make sure password fields match.'''
        data = super(forms.Form, self).clean()
        if 'new_password' in data:
            if data['new_password'] != data.get('confirm_password', None):
                raise ValidationError(('Passwords do not match.'))
        return data

    # We have to protect the entire 'data' dict because it contains the
    # oldpassword and newpassword strings.
    @sensitive_variables('data')
    def handle(self, request, data):
        user_is_editable = api.keystone.keystone_can_edit_user()

        if user_is_editable:
            try:
                api.keystone.user_update_own_password(request,
                                                      data['current_password'],
                                                      data['new_password'])
                response = http.HttpResponseRedirect(settings.LOGOUT_URL)
                msg = ('Password changed. Please log in again to continue.')
                LOG.info(msg)
                utils.add_logout_reason(request, response, msg)
                response.set_cookie('logout_reason_level',
                                    'success',
                                    max_age=10)
                return response
            except Exception:
                exceptions.handle(request, ('Unable to change password.'))
                return False
        else:
            messages.error(request, ('Changing password is not supported.'))
            return False
Exemplo n.º 30
0
class RackCreateInfoAction(workflows.Action):
    name = forms.RegexField(label=_("Name"),
                            max_length=25,
                            regex=r'^[\w\.\- ]+$',
                            error_messages={
                                'invalid':
                                _('Name may only '
                                  'contain letters, numbers, underscores, '
                                  'periods and hyphens.')
                            })
    location = forms.CharField(label=_("Location"))
    # see GenericIPAddressField, but not for subnets:
    subnet = forms.CharField(label=_("IP Subnet"))
    resource_class_id = forms.ChoiceField(label=_("Resource Class"))

    def clean(self):
        cleaned_data = super(RackCreateInfoAction, self).clean()
        name = cleaned_data.get('name')
        rack_id = self.initial.get('rack_id', None)
        subnet = cleaned_data.get('subnet')
        try:
            racks = tuskar.Rack.list(self.request)
        except Exception:
            racks = []
            exceptions.check_message(['Connection', 'refused'],
                                     _("Unable to retrieve rack list."))
            raise

        # Validations: detect duplicates
        for rack in racks:
            other_record = rack_id != rack.id
            if rack.name == name and other_record:
                raise forms.ValidationError(
                    _('The name %s is already used by another rack.') % name)
            if rack.subnet == subnet and other_record:
                raise forms.ValidationError(
                    _('The subnet is already assigned to rack %s.') %
                    (rack.name))

        return cleaned_data

    def __init__(self, request, *args, **kwargs):
        super(RackCreateInfoAction, self).__init__(request, *args, **kwargs)
        resource_class_id_choices = [('', _("Select a Resource Class"))]
        for rc in tuskar.ResourceClass.list(request):
            resource_class_id_choices.append((rc.id, rc.name))
        self.fields['resource_class_id'].choices = resource_class_id_choices

    class Meta:
        name = _("Rack Settings")