class AddProtocolForm(forms.SelfHandlingForm): idp_id = forms.CharField( label=_("Identity Provider ID"), widget=forms.TextInput(attrs={'readonly': 'readonly'})) id = forms.CharField(label=_("Protocol ID")) mapping_id = forms.ThemableChoiceField(label=_("Mapping ID")) def __init__(self, request, *args, **kwargs): super().__init__(request, *args, **kwargs) self.populate_mapping_id_choices(request) def populate_mapping_id_choices(self, request): try: mappings = api.keystone.mapping_list(request) except Exception as e: LOG.info('Failed to get mapping list %s', e) msg = _('Failed to get mapping list %s') % e messages.error(request, msg) choices = [(m.id, m.id) for m in mappings] choices.sort() if choices: choices.insert(0, ("", _("Select Mapping"))) else: choices.insert(0, ("", _("No mappings available"))) self.fields['mapping_id'].choices = choices def handle(self, request, data): try: new_mapping = api.keystone.protocol_create(request, data["id"], data["idp_id"], data["mapping_id"]) messages.success( request, _("Identity provider protocol created successfully.")) return new_mapping except exceptions.Conflict: msg = _('Protocol ID "%s" is already used.') % data["id"] messages.error(request, msg) except Exception: exceptions.handle( request, _("Unable to create identity provider protocol."))
class SetFlavorChoiceAction(workflows.Action): old_flavor_id = forms.CharField(required=False, widget=forms.HiddenInput()) old_flavor_name = forms.CharField( label=_("Old Flavor"), widget=forms.TextInput(attrs={'readonly': 'readonly'}), required=False, ) flavor = forms.ThemableChoiceField( label=_("New Flavor"), help_text=_("Choose the flavor to launch.")) class Meta(object): name = _("Flavor Choice") slug = 'flavor_choice' help_text_template = ("admin/vgpu/" "_flavors_and_quotas.html") def populate_flavor_choices(self, request, context): old_flavor_id = context.get('old_flavor_id') flavors = context.get('flavors').values() # Remove current flavor from the list of flavor choices flavors = [flavor for flavor in flavors if flavor.id != old_flavor_id] if len(flavors) > 1: flavors = instance_utils.sort_flavor_list(request, flavors) if flavors: flavors.insert(0, ("", _("Select a New Flavor"))) else: flavors.insert(0, ("", _("No flavors available"))) return flavors def get_help_text(self, extra_context=None): extra = {} if extra_context is None else dict(extra_context) try: extra['usages'] = api.nova.tenant_absolute_limits(self.request, reserved=True) extra['usages_json'] = json.dumps(extra['usages']) flavors = json.dumps( [f._info for f in instance_utils.flavor_list(self.request)]) extra['flavors'] = flavors extra['resize_instance'] = True except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetFlavorChoiceAction, self).get_help_text(extra)
class CreateVolumeTypeEncryption(forms.SelfHandlingForm): name = forms.CharField( label=_("Name"), required=False, widget=forms.TextInput(attrs={'readonly': 'readonly'})) provider = forms.CharField(max_length=255, label=_("Provider")) control_location = forms.ThemableChoiceField(label=_("Control Location"), choices=(('front-end', _('front-end')), ('back-end', _('back-end')))) cipher = forms.CharField(label=_("Cipher"), required=False) key_size = forms.IntegerField(label=_("Key Size (bits)"), required=False, min_value=1) volume_type_id = forms.CharField(widget=forms.HiddenInput()) def handle(self, request, data): try: # Set Cipher to None if empty if data['cipher'] == u'': data['cipher'] = None volume_type_id = data.pop('volume_type_id') volume_type_name = data.pop('name') # Create encryption for the volume type volume_type = cinder.\ volume_encryption_type_create(request, volume_type_id, data) messages.success( request, _('Successfully created encryption for ' 'volume type: %s') % volume_type_name) return volume_type except Exception as ex: redirect = reverse("horizon:admin:volume_types:index") exceptions.handle(request, _('Unable to create encrypted volume type: %s') % ex, redirect=redirect)
class SetGatewayForm(forms.SelfHandlingForm): network_id = forms.ThemableChoiceField(label=_("External Network")) failure_url = 'horizon:project:routers:index' def __init__(self, request, *args, **kwargs): super(SetGatewayForm, self).__init__(request, *args, **kwargs) c = self.populate_network_id_choices(request) self.fields['network_id'].choices = c def populate_network_id_choices(self, request): search_opts = {'router:external': True} try: networks = api.neutron.network_list(request, **search_opts) except Exception as e: LOG.info('Faield to get network list: %s', e) msg = _('Failed to get network list: %s') % e messages.error(request, msg) redirect = reverse(self.failure_url) exceptions.handle(request, msg, redirect=redirect) return choices = [(network.id, network.name or network.id) for network in networks] if choices: choices.insert(0, ("", _("Select network"))) else: choices.insert(0, ("", _("No networks available"))) return choices def handle(self, request, data): try: api.neutron.router_add_gateway(request, self.initial['router_id'], data['network_id']) msg = _('Gateway interface is added') messages.success(request, msg) return True except Exception as e: LOG.info('Failed to set gateway to router %(id)s: %(exc)s', {'id': self.initial['router_id'], 'exc': e}) msg = _('Failed to set gateway: %s') % e redirect = reverse(self.failure_url) exceptions.handle(request, msg, redirect=redirect)
class AddPort(forms.SelfHandlingForm): failure_url = 'horizon:project:firewalls_v2:index' port_id = forms.ThemableChoiceField( label=_("Ports"), required=False) def __init__(self, request, *args, **kwargs): super(AddPort, self).__init__(request, *args, **kwargs) try: tenant_id = self.request.user.tenant_id ports = api_fwaas_v2.fwg_port_list_for_tenant(request, tenant_id) initial_ports = self.initial['ports'] filtered_ports = [port for port in ports if port.id not in initial_ports] filtered_ports = sorted(filtered_ports, key=attrgetter('name')) except Exception: exceptions.handle(request, _('Unable to retrieve port list.')) ports = [] current_choices = [(p.id, p.name_or_id) for p in filtered_ports] self.fields['port_id'].choices = current_choices def handle(self, request, context): firewallgroup_id = self.initial['firewallgroup_id'] name_or_id = context.get('name') or firewallgroup_id body = _get_request_body(context, self.initial) add_port = context['port_id'] if add_port: ports = self.initial['ports'] ports.append(add_port) body['ports'] = ports try: firewallgroup = api_fwaas_v2.firewall_update( request, firewallgroup_id, **body) msg = _('FirewallGroup %s was successfully updated.') % name_or_id messages.success(request, msg) return firewallgroup except Exception as e: msg = (_('Failed to update firewallgroup %(name)s: %(reason)s') % {'name': name_or_id, 'reason': e}) redirect = reverse(self.failure_url) exceptions.handle(request, msg, redirect=redirect)
class CreateInstance(forms.SelfHandlingForm): controller = forms.ThemableChoiceField(label=_("Controller")) parameters = forms.CharField( widget=forms.widgets.Textarea(attrs={'rows': 2}), label=_("Parameters"), required=False) description = forms.CharField( widget=forms.widgets.Textarea(attrs={'rows': 4}), label=_("Description"), required=False) status = forms.CharField( max_length=255, label=_("Status"), initial='Stopped', widget=forms.HiddenInput( # hidden attrs={"ng-model": "status"})) def __init__(self, request, *args, **kwargs): super(CreateInstance, self).__init__(request, *args, **kwargs) controllers = json.loads(api.get_all_controllers(self.request).text) self.fields['controller'].choices = [(controller['id'], controller['controller_name']) for controller in controllers] @staticmethod def handle(request, data): try: response = api.add_instance(request, data) if 200 <= response.status_code < 300: messages.success(request, _("Instance successfully created.")) return data else: raise sdsexception.SdsException(response.text) except Exception as ex: redirect = reverse("horizon:crystal:controllers:index") error_message = "Unable to create instance.\t %s" % ex.message exceptions.handle(request, _(error_message), redirect=redirect)
class UpdateNetwork(forms.SelfHandlingForm): name = forms.CharField(label=_("Name"), required=False) tenant_id = forms.CharField(widget=forms.HiddenInput) network_id = forms.CharField( label=_("ID"), widget=forms.TextInput(attrs={'readonly': 'readonly'})) admin_state = forms.ThemableChoiceField(choices=[(True, _('UP')), (False, _('DOWN'))], label=_("Admin State")) shared = forms.BooleanField(label=_("Shared"), required=False) external = forms.BooleanField(label=_("External Network"), required=False) failure_url = 'horizon:admin:networks:index' def handle(self, request, data): try: params = { 'name': data['name'], 'admin_state_up': (data['admin_state'] == 'True'), 'shared': data['shared'], 'router:external': data['external'] } network = api.neutron.network_update(request, self.initial['network_id'], **params) msg = _('Network %s was successfully updated.') % data['name'] LOG.debug(msg) api.nova.systemlogs_create(request, data['name'], record_action.UPDATENETWORK, detail=msg) messages.success(request, msg) return network except Exception: msg = _('Failed to update network %s') % data['name'] LOG.info(msg) api.nova.systemlogs_create(request, data['name'], record_action.UPDATENETWORK, result=False, detail=msg) redirect = reverse(self.failure_url) exceptions.handle(request, msg, redirect=redirect)
class UpdateNetwork(forms.SelfHandlingForm): name = forms.CharField(label=_("Name"), required=False) tenant_id = forms.CharField(widget=forms.HiddenInput) network_id = forms.CharField(label=_("ID"), widget=forms.TextInput( attrs={'readonly': 'readonly'})) admin_state = forms.ThemableChoiceField( choices=[('True', _('UP')), ('False', _('DOWN'))], required=False, label=_("Admin State")) shared = forms.BooleanField(label=_("Shared"), required=False) failure_url = 'horizon:project:networks:index' def __init__(self, request, *args, **kwargs): super(UpdateNetwork, self).__init__(request, *args, **kwargs) if not policy.check((("network", "create_network:shared"),), request): self.fields['shared'].widget = forms.HiddenInput() def handle(self, request, data): try: params = {'admin_state_up': (data['admin_state'] == 'True'), 'name': data['name']} # Make sure we are not sending shared data when the user # doesnt'have admin rights because even if the user doesn't # change it neutron sends back a 403 error if policy.check((("network", "update_network:shared"),), request): params['shared'] = data['shared'] network = api.neutron.network_update(request, data['network_id'], **params) msg = _('Network %s was successfully updated.') % data['name'] LOG.debug(msg) messages.success(request, msg) return network except Exception: msg = _('Failed to update network %s') % data['name'] LOG.info(msg) redirect = reverse(self.failure_url) exceptions.handle(request, msg, redirect=redirect)
class DetachInterface(forms.SelfHandlingForm): instance_id = forms.CharField(widget=forms.HiddenInput()) port = forms.ThemableChoiceField(label=_("Port")) def __init__(self, request, *args, **kwargs): super(DetachInterface, self).__init__(request, *args, **kwargs) instance_id = self.initial.get("instance_id", None) ports = [] try: ports = api.neutron.port_list(request, device_id=instance_id) except Exception: exceptions.handle(request, _('Unable to retrieve ports ' 'information.')) choices = [] for port in ports: ips = [] for ip in port.fixed_ips: ips.append(ip['ip_address']) choices.append((port.id, ','.join(ips) or port.id)) if choices: choices.insert(0, ("", _("Select Port"))) else: choices.insert(0, ("", _("No Ports available"))) self.fields['port'].choices = choices def handle(self, request, data): instance_id = data['instance_id'] port = data.get('port') try: api.nova.interface_detach(request, instance_id, port) msg = _('Detached interface %(port)s for instance ' '%(instance)s.') % {'port': port, 'instance': instance_id} messages.success(request, msg) except Exception: redirect = reverse('horizon:project:instances:index') exceptions.handle(request, _("Unable to detach interface."), redirect=redirect) return True
class CreateQosSpec(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Name")) consumer = forms.ThemableChoiceField(label=_("Consumer"), choices=cinder.CONSUMER_CHOICES) def handle(self, request, data): try: qos_spec = cinder.qos_spec_create(request, data['name'], {'consumer': data['consumer']}) messages.success( request, _('Successfully created QoS Spec: %s') % data['name']) return qos_spec except Exception as ex: if getattr(ex, 'code', None) == 409: msg = _('QoS Spec name "%s" already ' 'exists.') % data['name'] self._errors['name'] = self.error_class([msg]) else: redirect = reverse("horizon:admin:volumes:index") exceptions.handle(request, _('Unable to create QoS Spec.'), redirect=redirect)
class UpdateNetwork(forms.SelfHandlingForm): name = forms.CharField(label=_("Name"), required=False) tenant_id = forms.CharField(widget=forms.HiddenInput) network_id = forms.CharField( label=_("ID"), widget=forms.TextInput(attrs={'readonly': 'readonly'})) admin_state = forms.ThemableChoiceField(choices=[(True, _('UP')), (False, _('DOWN'))], required=False, label=_("Admin State")) shared = forms.BooleanField(label=_("Shared"), required=False) failure_url = 'horizon:project:networks:index' def __init__(self, request, *args, **kwargs): super(UpdateNetwork, self).__init__(request, *args, **kwargs) if not policy.check((("network", "create_network:shared"), ), request): self.fields['shared'].widget = forms.CheckboxInput( attrs={'disabled': True}) self.fields['shared'].help_text = _( 'Non admin users are not allowed to set shared option.') def handle(self, request, data): try: params = { 'admin_state_up': (data['admin_state'] == 'True'), 'name': data['name'], 'shared': data['shared'] } network = api.neutron.network_update(request, data['network_id'], **params) msg = _('Network %s was successfully updated.') % data['name'] LOG.debug(msg) messages.success(request, msg) return network except Exception: msg = _('Failed to update network %s') % data['name'] LOG.info(msg) redirect = reverse(self.failure_url) exceptions.handle(request, msg, redirect=redirect)
class AttachInterface(forms.SelfHandlingForm): instance_id = forms.CharField(widget=forms.HiddenInput()) network = forms.ThemableChoiceField(label=_("Network")) def __init__(self, request, *args, **kwargs): super(AttachInterface, self).__init__(request, *args, **kwargs) networks = instance_utils.network_field_data(request, include_empty_option=True) self.fields['network'].choices = networks def handle(self, request, data): instance_id = data['instance_id'] network = data.get('network') try: api.nova.interface_attach(request, instance_id, net_id=network) msg = _('Attaching interface for instance %s.') % instance_id messages.success(request, msg) except Exception: redirect = reverse('horizon:project:instances:index') exceptions.handle(request, _("Unable to attach interface."), redirect=redirect) return True
class UpdateZone(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Name"), help_text=_("The name of the new zone.")) regions = forms.ThemableChoiceField(label=_("Region")) description = forms.CharField( widget=forms.widgets.Textarea(attrs={'rows': 4}), label=_("Description"), required=False) zone_id = forms.CharField(max_length=255, label=_("Zone ID"), widget=forms.HiddenInput()) def __init__(self, request, *args, **kwargs): super(UpdateZone, self).__init__(request, *args, **kwargs) self.fields['regions'].choices = [ (region['id'], region['name']) for region in json.loads( api.swift_list_regions(self.request).text) ] def handle(self, request, data): try: response = api.update_zone(request, data) if 200 <= response.status_code < 300: messages.success( request, _('Successfully updated node: %s') % data['zone_id']) return data else: raise sdsexception.SdsException(response.text) except Exception as ex: redirect = reverse("horizon:crystal:zones:index") error_message = "Unable to update zone.\t %s" % ex.message exceptions.handle(request, _(error_message), redirect=redirect)
def __init__(self, request, *args, **kwargs): super(CreatePort, self).__init__(request, *args, **kwargs) try: if api.neutron.is_extension_supported(request, 'binding'): neutron_settings = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}) supported_vnic_types = neutron_settings.get( 'supported_vnic_types', ['*']) if supported_vnic_types: if supported_vnic_types == ['*']: vnic_type_choices = VNIC_TYPES else: vnic_type_choices = [ vnic_type for vnic_type in VNIC_TYPES if vnic_type[0] in supported_vnic_types ] self.fields['binding__vnic_type'] = \ forms.ThemableChoiceField( choices=vnic_type_choices, label=_("Binding: VNIC Type"), help_text=_( "The VNIC type that is bound to the neutron " "port"), required=False) except Exception: msg = _("Unable to verify the VNIC types extension in Neutron") exceptions.handle(self.request, msg) try: if api.neutron.is_extension_supported(request, 'mac-learning'): self.fields['mac_state'] = forms.BooleanField( label=_("MAC Learning State"), initial=False, required=False) except Exception: msg = _("Unable to retrieve MAC learning state") exceptions.handle(self.request, msg)
class UpdateStatus(forms.SelfHandlingForm): status = forms.ThemableChoiceField(label=_("Status")) def __init__(self, request, *args, **kwargs): # Obtain the localized status to use as initial value, has to be done # before super() otherwise the initial value will get overwritten back # to the raw value current_status = kwargs['initial']['status'] choices = dict(STATUS_CHOICES) kwargs['initial']['status'] = choices[current_status] super(UpdateStatus, self).__init__(request, *args, **kwargs) self.fields['status'].choices = populate_status_choices( current_status, STATUS_CHOICES) def handle(self, request, data): # Obtain the localized status for including in the message for choice in self.fields['status'].choices: if choice[0] == data['status']: new_status = choice[1] break else: new_status = data['status'] try: cinder.volume_reset_state(request, self.initial['volume_id'], data['status']) messages.success(request, _('Successfully updated volume status to "%s".') % new_status) return True except Exception: redirect = reverse("horizon:admin:volumes:index") exceptions.handle(request, _('Unable to update volume status to "%s".') % new_status, redirect=redirect)
class EditQosSpecConsumer(forms.SelfHandlingForm): current_consumer = forms.CharField( label=_("Current consumer"), widget=forms.TextInput(attrs={'readonly': 'readonly'}), required=False) consumer_choice = forms.ThemableChoiceField( label=_("New QoS Spec Consumer"), choices=cinder.CONSUMER_CHOICES, help_text=_("Choose consumer for this QoS Spec.")) def __init__(self, request, *args, **kwargs): super(EditQosSpecConsumer, self).__init__(request, *args, **kwargs) consumer_field = self.fields['consumer_choice'] qos_spec = self.initial["qos_spec"] self.fields['current_consumer'].initial = qos_spec.consumer choices = [ choice for choice in cinder.CONSUMER_CHOICES if choice[0] != qos_spec.consumer ] choices.insert(0, ("", _("Select a new consumer"))) consumer_field.choices = choices def handle(self, request, data): qos_spec_id = self.initial['qos_spec_id'] new_consumer = data['consumer_choice'] # Update QOS Spec consumer information try: cinder.qos_spec_set_keys(request, qos_spec_id, {'consumer': new_consumer}) messages.success(request, _('Successfully modified QoS Spec consumer.')) return True except Exception: redirect = reverse("horizon:admin:volumes:index") exceptions.handle(request, _('Error editing QoS Spec consumer.'), redirect=redirect)
class RemovePort(forms.SelfHandlingForm): failure_url = 'horizon:project:firewalls_v2:index' port_id = forms.ThemableChoiceField(label=_("Ports"), required=False) def __init__(self, request, *args, **kwargs): super(RemovePort, self).__init__(request, *args, **kwargs) try: ports = self.initial['ports'] except Exception: exceptions.handle(request, _('Unable to retrieve port list.')) ports = [] current_choices = [(p, p) for p in ports] self.fields['port_id'].choices = current_choices def handle(self, request, context): firewallgroup_id = self.initial['id'] name_or_id = context.get('name') or firewallgroup_id body = _get_request_body(context, self.initial) remove_port = context['port_id'] if remove_port: ports = self.initial['ports'] ports.remove(remove_port) body['ports'] = ports try: firewallgroup = api_fwaas_v2.firewall_update( request, firewallgroup_id, **body) msg = _('FirewallGroup %s was successfully updated.') % name_or_id messages.success(request, msg) return firewallgroup except Exception as e: msg = (_('Failed to update firewallgroup %(name)s: %(reason)s') % { 'name': name_or_id, 'reason': e }) redirect = reverse(self.failure_url) exceptions.handle(request, msg, redirect=redirect)
class ThemableChoiceFieldForm(forms.SelfHandlingForm): # It's POSSIBLE to combine this with the test helper form above, but # I fear we'd run into collisions where one test's desired output is # actually within a separate widget's output. title_dic = { "label1": { "title": "This is choice 1" }, "label2": { "title": "This is choice 2" }, "label3": { "title": "This is choice 3" } } name = forms.CharField(max_length=255, label="Test Name", help_text="Please enter a name") test_choices = forms.ThemableChoiceField( label="Test Choices", required=False, help_text="Testing drop down choices", widget=forms.fields.ThemableSelectWidget( attrs={ 'class': 'switchable', 'data-slug': 'source' }, transform_html_attrs=title_dic.get)) def __init__(self, request, *args, **kwargs): super(ThemableChoiceFieldForm, self).__init__(request, *args, **kwargs) choices = ([('choice1', 'label1'), ('choice2', 'label2')]) self.fields['test_choices'].choices = choices def handle(self, request, data): return True
class CreateContainer(forms.SelfHandlingForm): ACCESS_CHOICES = ( ("private", _("Private")), ("public", _("Public")), ) parent = forms.CharField(max_length=255, required=False, widget=forms.HiddenInput) name = forms.CharField(max_length=255, label=_("Container Name"), validators=[no_slash_validator]) access = forms.ThemableChoiceField(label=_("Container Access"), choices=ACCESS_CHOICES) def handle(self, request, data): try: if not data['parent']: is_public = data["access"] == "public" metadata = ({'is_public': is_public}) # Create a container api.swift.swift_create_container(request, data["name"], metadata=metadata) messages.success(request, _("Container created successfully.")) else: # Create a pseudo-folder container, slash, remainder = data['parent'].partition("/") remainder = remainder.rstrip("/") subfolder_name = "/".join( [bit for bit in (remainder, data['name']) if bit]) api.swift.swift_create_subfolder(request, container, subfolder_name) messages.success(request, _("Folder created successfully.")) return True except Exception: exceptions.handle(request, _('Unable to create container.'))
class ManagePoliciesForm(forms.SelfHandlingForm): cluster_id = forms.CharField(widget=forms.HiddenInput()) policies = forms.ThemableChoiceField(label=_("Policies")) enabled = forms.BooleanField( label=_("Enabled"), initial=True, required=False, help_text=_("Whether the policy should be enabled once attached. " "Default to enabled.")) def __init__(self, request, *args, **kwargs): super(ManagePoliciesForm, self).__init__(request, *args, **kwargs) cluster_policies = senlin.cluster_policy_list( self.request, kwargs['initial']['cluster_id'], {}) cluster_policies_ids = [policy.id for policy in cluster_policies] policies = senlin.policy_list(self.request)[0] available_policies = [(policy.id, policy.name) for policy in policies if policy.id not in cluster_policies_ids] self.fields['policies'].choices = ( [("", _("Select Policy"))] + available_policies) def handle(self, request, data): try: params = {"enabled": data.pop('enabled')} attach = senlin.cluster_attach_policy( request, data["cluster_id"], data['policies'], params) msg = _('Attaching policy %(policy)s to cluster ' '%(cluster)s.') % {"policy": data['policies'], "cluster": data['cluster_id']} messages.success(request, msg) return attach except Exception: redirect = reverse(INDEX_URL) exceptions.handle(request, _("Unable to attach policy."), redirect=redirect)
class AddFirewallAction(workflows.Action): name = forms.CharField(max_length=80, label=_("Name"), required=False) description = forms.CharField(max_length=80, label=_("Description"), required=False) firewall_policy_id = forms.ThemableChoiceField(label=_("Policy")) admin_state_up = forms.BooleanField(label=_("Enable Admin State"), initial=True, required=False) def __init__(self, request, *args, **kwargs): super(AddFirewallAction, self).__init__(request, *args, **kwargs) firewall_policy_id_choices = [('', _("Select a Policy"))] try: tenant_id = self.request.user.tenant_id policies = api.fwaas.policy_list_for_tenant(request, tenant_id) policies = sorted(policies, key=lambda policy: policy.name) except Exception as e: exceptions.handle( request, _('Unable to retrieve policy list (%(error)s).') % {'error': str(e)}) policies = [] for p in policies: firewall_policy_id_choices.append((p.id, p.name_or_id)) self.fields['firewall_policy_id'].choices = firewall_policy_id_choices class Meta(object): name = _("Firewall") permissions = ('openstack.services.network', ) help_text = _("Create a firewall based on a policy.\n\n" "A firewall represents a logical firewall resource that " "a tenant can instantiate and manage. A firewall must " "be associated with one policy, all other fields are " "optional.")
class UpdateUserForm(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()) id = forms.CharField(label=_("ID"), 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.ThemableChoiceField(label=_("Primary Project"), required=PROJECT_REQUIRED) def __init__(self, request, *args, **kwargs): super(UpdateUserForm, self).__init__(request, *args, **kwargs) self.add_extra_fields() if api.keystone.keystone_can_edit_user() is False: for field in ('name', 'email'): 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 # For keystone V2.0, hide description field else: self.fields["description"].widget = forms.HiddenInput() def handle(self, request, data): user = data.pop('id') data.pop('domain_id') data.pop('domain_name') if not PROJECT_REQUIRED and 'project' not in self.changed_data: data.pop('project') if 'description' not in self.changed_data: data.pop('description') 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 exceptions.Conflict: msg = _('User name "%s" is already used.') % data['name'] messages.error(request, msg) return False 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(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.'))
class CreateForm(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Cluster Name")) profile_id = forms.ThemableChoiceField(label=_("Profile")) min_size = forms.IntegerField( label=_("Min Size"), required=False, initial=0, help_text=_("Min size of the cluster. Default to 0.")) max_size = forms.IntegerField( label=_("Max Size"), required=False, initial=-1, help_text=_("Max size of the cluster. Default to -1, " "means unlimited.")) desired_capacity = forms.IntegerField( label=_("Desired Capacity"), initial=0, help_text=_("Desired capacity of the cluster. Default to 0.")) # Hide the parent field parent = forms.ThemableChoiceField( label=_("Parent Cluster"), required=False, widget=forms.HiddenInput()) timeout = forms.IntegerField( label=_("Timeout"), required=False, help_text=_("Cluster creation timeout in seconds.")) metadata = forms.CharField( max_length=255, label=_("Metadata"), required=False, help_text=_("YAML formated metadata"), widget=forms.Textarea(attrs={'rows': 4})) def __init__(self, request, *args, **kwargs): super(CreateForm, self).__init__(request, *args, **kwargs) profiles = senlin.profile_list(request)[0] self.fields['profile_id'].choices = ( [("", _("Select Profile"))] + [(profile.id, profile.name) for profile in profiles]) def handle(self, request, data): try: # As we hide the parent field, use None here data['parent'] = None if not data['metadata']: metadata = {} else: try: metadata = yaml.safe_load(data['metadata']) except Exception as ex: raise Exception(_('The specified metadata is not a valid ' 'YAML format: %s') % ex) data['metadata'] = metadata cluster = senlin.cluster_create(request, **data) msg = _('Creating cluster "%s" successfully') % data['name'] messages.success(request, msg) return cluster except Exception: redirect = reverse(INDEX_URL) exceptions.handle(request, _("Unable to create cluster."), redirect=redirect)
class SetInstanceDetailsAction(workflows.Action): availability_zone = forms.ThemableChoiceField(label=_("Availability Zone"), required=False) name = forms.CharField(label=_("Instance Name"), max_length=255) flavor = forms.ThemableChoiceField(label=_("Flavor"), help_text=_("Size of image to launch.")) count = forms.IntegerField(label=_("Number of Instances"), min_value=1, initial=1) source_type = forms.ThemableChoiceField( label=_("Instance Boot Source"), help_text=_("Choose Your Boot Source " "Type.")) instance_snapshot_id = forms.ThemableChoiceField( label=_("Instance Snapshot"), required=False) volume_id = forms.ThemableChoiceField(label=_("Volume"), required=False) volume_snapshot_id = forms.ThemableChoiceField(label=_("Volume Snapshot"), required=False) image_id = forms.ChoiceField( label=_("Image Name"), required=False, widget=forms.ThemableSelectWidget( data_attrs=('volume_size',), transform=lambda x: ("%s (%s)" % (x.name, filesizeformat(x.bytes))))) volume_size = forms.IntegerField(label=_("Device size (GB)"), initial=1, min_value=0, required=False, help_text=_("Volume size in gigabytes " "(integer value).")) device_name = forms.CharField(label=_("Device Name"), required=False, initial="vda", help_text=_("Volume mount point (e.g. 'vda' " "mounts at '/dev/vda'). Leave " "this field blank to let the " "system choose a device name " "for you.")) vol_delete_on_instance_delete = forms.BooleanField( label=_("Delete Volume on Instance Delete"), initial=False, required=False, help_text=_("Delete volume when the instance is deleted")) class Meta(object): name = _("Details") help_text_template = ("project/instances/" "_launch_details_help.html") def __init__(self, request, context, *args, **kwargs): self._init_images_cache() self.request = request self.context = context super(SetInstanceDetailsAction, self).__init__( request, context, *args, **kwargs) # Hide the device field if the hypervisor doesn't support it. if not nova.can_set_mount_point(): self.fields['device_name'].widget = forms.widgets.HiddenInput() source_type_choices = [ ('', _("Select source")), ("image_id", _("Boot from image")), ("instance_snapshot_id", _("Boot from snapshot")), ] if cinder.is_volume_service_enabled(request): source_type_choices.append(("volume_id", _("Boot from volume"))) try: if api.nova.extension_supported("BlockDeviceMappingV2Boot", request): source_type_choices.append( ("volume_image_id", _("Boot from image (creates a new volume)"))) except Exception: exceptions.handle(request, _('Unable to retrieve extensions ' 'information.')) source_type_choices.append( ("volume_snapshot_id", _("Boot from volume snapshot (creates a new volume)"))) self.fields['source_type'].choices = source_type_choices @memoized.memoized_method def _get_flavor(self, flavor_id): try: # We want to retrieve details for a given flavor, # however flavor_list uses a memoized decorator # so it is used instead of flavor_get to reduce the number # of API calls. flavors = instance_utils.flavor_list(self.request) flavor = [x for x in flavors if x.id == flavor_id][0] except IndexError: flavor = None return flavor @memoized.memoized_method def _get_image(self, image_id): try: # We want to retrieve details for a given image, # however get_available_images uses a cache of image list, # so it is used instead of image_get to reduce the number # of API calls. images = image_utils.get_available_images( self.request, self.context.get('project_id'), self._images_cache) image = [x for x in images if x.id == image_id][0] except IndexError: image = None return image def _check_quotas(self, cleaned_data): count = cleaned_data.get('count', 1) # Prevent launching more instances than the quota allows usages = quotas.tenant_quota_usages( self.request, targets=('instances', 'cores', 'ram', 'volumes', )) available_count = usages['instances']['available'] if available_count < count: msg = (_('The requested instance(s) cannot be launched ' 'as your quota will be exceeded: Available: ' '%(avail)s, Requested: %(req)s.') % {'avail': available_count, 'req': count}) raise forms.ValidationError(msg) source_type = cleaned_data.get('source_type') if source_type in ('volume_image_id', 'volume_snapshot_id'): available_volume = usages['volumes']['available'] if available_volume < count: msg = (_('The requested instance cannot be launched. ' 'Requested volume exceeds quota: Available: ' '%(avail)s, Requested: %(req)s.') % {'avail': available_volume, 'req': count}) raise forms.ValidationError(msg) flavor_id = cleaned_data.get('flavor') flavor = self._get_flavor(flavor_id) count_error = [] # Validate cores and ram. available_cores = usages['cores']['available'] if flavor and available_cores < count * flavor.vcpus: count_error.append(_("Cores(Available: %(avail)s, " "Requested: %(req)s)") % {'avail': available_cores, 'req': count * flavor.vcpus}) available_ram = usages['ram']['available'] if flavor and available_ram < count * flavor.ram: count_error.append(_("RAM(Available: %(avail)s, " "Requested: %(req)s)") % {'avail': available_ram, 'req': count * flavor.ram}) if count_error: value_str = ", ".join(count_error) msg = (_('The requested instance cannot be launched. ' 'The following requested resource(s) exceed ' 'quota(s): %s.') % value_str) if count == 1: self._errors['flavor'] = self.error_class([msg]) else: self._errors['count'] = self.error_class([msg]) def _check_flavor_for_image(self, cleaned_data): # Prevents trying to launch an image needing more resources. image_id = cleaned_data.get('image_id') image = self._get_image(image_id) flavor_id = cleaned_data.get('flavor') flavor = self._get_flavor(flavor_id) if not image or not flavor: return props_mapping = (("min_ram", "ram"), ("min_disk", "disk")) for iprop, fprop in props_mapping: if (getattr(image, iprop) > 0 and getattr(flavor, fprop) > 0 and getattr(image, iprop) > getattr(flavor, fprop)): msg = (_("The flavor '%(flavor)s' is too small " "for requested image.\n" "Minimum requirements: " "%(min_ram)s MB of RAM and " "%(min_disk)s GB of Root Disk.") % {'flavor': flavor.name, 'min_ram': image.min_ram, 'min_disk': image.min_disk}) self._errors['image_id'] = self.error_class([msg]) break # Not necessary to continue the tests. def _check_volume_for_image(self, cleaned_data): image_id = cleaned_data.get('image_id') image = self._get_image(image_id) volume_size = cleaned_data.get('volume_size') if not image or not volume_size: return volume_size = int(volume_size) img_gigs = functions.bytes_to_gigabytes(image.size) smallest_size = max(img_gigs, image.min_disk) if volume_size < smallest_size: msg = (_("The Volume size is too small for the" " '%(image_name)s' image and has to be" " greater than or equal to " "'%(smallest_size)d' GB.") % {'image_name': image.name, 'smallest_size': smallest_size}) self._errors['volume_size'] = self.error_class([msg]) def _check_source_image(self, cleaned_data): if not cleaned_data.get('image_id'): msg = _("You must select an image.") self._errors['image_id'] = self.error_class([msg]) else: self._check_flavor_for_image(cleaned_data) def _check_source_volume_image(self, cleaned_data): volume_size = self.data.get('volume_size', None) if not volume_size: msg = _("You must set volume size") self._errors['volume_size'] = self.error_class([msg]) if float(volume_size) <= 0: msg = _("Volume size must be greater than 0") self._errors['volume_size'] = self.error_class([msg]) if not cleaned_data.get('image_id'): msg = _("You must select an image.") self._errors['image_id'] = self.error_class([msg]) return else: self._check_flavor_for_image(cleaned_data) self._check_volume_for_image(cleaned_data) def _check_source_instance_snapshot(self, cleaned_data): # using the array form of get blows up with KeyError # if instance_snapshot_id is nil if not cleaned_data.get('instance_snapshot_id'): msg = _("You must select a snapshot.") self._errors['instance_snapshot_id'] = self.error_class([msg]) def _check_source_volume(self, cleaned_data): if not cleaned_data.get('volume_id'): msg = _("You must select a volume.") self._errors['volume_id'] = self.error_class([msg]) # Prevent launching multiple instances with the same volume. # TODO(gabriel): is it safe to launch multiple instances with # a snapshot since it should be cloned to new volumes? count = cleaned_data.get('count', 1) if count > 1: msg = _('Launching multiple instances is only supported for ' 'images and instance snapshots.') raise forms.ValidationError(msg) def _check_source_volume_snapshot(self, cleaned_data): if not cleaned_data.get('volume_snapshot_id'): msg = _("You must select a snapshot.") self._errors['volume_snapshot_id'] = self.error_class([msg]) def _check_source(self, cleaned_data): # Validate our instance source. source_type = self.data.get('source_type', None) source_check_methods = { 'image_id': self._check_source_image, 'volume_image_id': self._check_source_volume_image, 'instance_snapshot_id': self._check_source_instance_snapshot, 'volume_id': self._check_source_volume, 'volume_snapshot_id': self._check_source_volume_snapshot } check_method = source_check_methods.get(source_type) if check_method: check_method(cleaned_data) def clean(self): cleaned_data = super(SetInstanceDetailsAction, self).clean() self._check_quotas(cleaned_data) self._check_source(cleaned_data) return cleaned_data def populate_flavor_choices(self, request, context): return instance_utils.flavor_field_data(request, False) def populate_availability_zone_choices(self, request, context): try: zones = api.nova.availability_zone_list(request) except Exception: zones = [] exceptions.handle(request, _('Unable to retrieve availability zones.')) zone_list = [(zone.zoneName, zone.zoneName) for zone in zones if zone.zoneState['available']] zone_list.sort() if not zone_list: zone_list.insert(0, ("", _("No availability zones found"))) elif len(zone_list) > 1: zone_list.insert(0, ("", _("Any Availability Zone"))) return zone_list def get_help_text(self, extra_context=None): extra = {} if extra_context is None else dict(extra_context) try: extra['usages'] = quotas.tenant_limit_usages(self.request) extra['usages_json'] = json.dumps(extra['usages']) extra['cinder_enabled'] = \ base.is_service_enabled(self.request, 'volume') flavors = json.dumps([f._info for f in instance_utils.flavor_list(self.request)]) extra['flavors'] = flavors images = image_utils.get_available_images( self.request, self.initial['project_id'], self._images_cache) if images is not None: attrs = [{'id': i.id, 'min_disk': getattr(i, 'min_disk', 0), 'min_ram': getattr(i, 'min_ram', 0), 'size': functions.bytes_to_gigabytes(i.size)} for i in images] extra['images'] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetInstanceDetailsAction, self).get_help_text(extra) def _init_images_cache(self): if not hasattr(self, '_images_cache'): self._images_cache = {} def _get_volume_display_name(self, volume): if hasattr(volume, "volume_id"): vol_type = "snap" visible_label = _("Snapshot") else: vol_type = "vol" visible_label = _("Volume") return (("%s:%s" % (volume.id, vol_type)), (_("%(name)s - %(size)s GB (%(label)s)") % {'name': volume.name, 'size': volume.size, 'label': visible_label})) def populate_image_id_choices(self, request, context): choices = [] images = image_utils.get_available_images(request, context.get('project_id'), self._images_cache) for image in images: if image.properties.get("image_type", '') != "snapshot": image.bytes = getattr( image, 'virtual_size', None) or image.size image.volume_size = max( image.min_disk, functions.bytes_to_gigabytes(image.bytes)) choices.append((image.id, image)) if context.get('image_id') == image.id and \ 'volume_size' not in context: context['volume_size'] = image.volume_size if choices: choices.sort(key=lambda c: c[1].name or '') choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices def populate_instance_snapshot_id_choices(self, request, context): images = image_utils.get_available_images(request, context.get('project_id'), self._images_cache) choices = [(image.id, image.name) for image in images if image.properties.get("image_type", '') == "snapshot"] if choices: choices.sort(key=operator.itemgetter(1)) choices.insert(0, ("", _("Select Instance Snapshot"))) else: choices.insert(0, ("", _("No snapshots available"))) return choices def populate_volume_id_choices(self, request, context): volumes = [] try: if cinder.is_volume_service_enabled(request): available = api.cinder.VOLUME_STATE_AVAILABLE volumes = [self._get_volume_display_name(v) for v in cinder.volume_list(self.request, search_opts=dict(status=available, bootable=True))] except Exception: exceptions.handle(self.request, _('Unable to retrieve list of volumes.')) if volumes: volumes.insert(0, ("", _("Select Volume"))) else: volumes.insert(0, ("", _("No volumes available"))) return volumes def populate_volume_snapshot_id_choices(self, request, context): snapshots = [] try: if cinder.is_volume_service_enabled(request): available = api.cinder.VOLUME_STATE_AVAILABLE snapshots = [self._get_volume_display_name(s) for s in cinder.volume_snapshot_list( self.request, search_opts=dict(status=available))] except Exception: exceptions.handle(self.request, _('Unable to retrieve list of volume ' 'snapshots.')) if snapshots: snapshots.insert(0, ("", _("Select Volume Snapshot"))) else: snapshots.insert(0, ("", _("No volume snapshots available"))) return snapshots
class CreateForm(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Volume Name"), required=False) description = forms.CharField(max_length=255, widget=forms.Textarea( attrs={'rows': 4}), label=_("Description"), required=False) volume_source_type = forms.ChoiceField( label=_("Volume Source"), required=False, widget=forms.ThemableSelectWidget(attrs={ 'class': 'switchable', 'data-slug': 'source'})) snapshot_source = forms.ChoiceField( label=_("Use snapshot as a source"), widget=forms.ThemableSelectWidget( attrs={'class': 'snapshot-selector'}, data_attrs=('size', 'name'), transform=lambda x: "%s (%s GiB)" % (x.name, x.size)), required=False) image_source = forms.ChoiceField( label=_("Use image as a source"), widget=forms.ThemableSelectWidget( attrs={'class': 'image-selector'}, data_attrs=('size', 'name', 'min_disk'), transform=lambda x: "%s (%s)" % (x.name, filesizeformat(x.bytes))), required=False) volume_source = forms.ChoiceField( label=_("Use a volume as source"), widget=forms.ThemableSelectWidget( attrs={'class': 'image-selector'}, data_attrs=('size', 'name'), transform=lambda x: "%s (%s GiB)" % (x.name, x.size)), required=False) type = forms.ChoiceField( label=_("Type"), required=False, widget=forms.ThemableSelectWidget( attrs={'class': 'switched', 'data-switch-on': 'source', 'data-source-no_source_type': _('Type'), 'data-source-image_source': _('Type')})) size = forms.IntegerField(min_value=1, initial=1, label=_("Size (GiB)")) availability_zone = forms.ChoiceField( label=_("Availability Zone"), required=False, widget=forms.ThemableSelectWidget( attrs={'class': 'switched', 'data-switch-on': 'source', 'data-source-no_source_type': _('Availability Zone'), 'data-source-image_source': _('Availability Zone')})) group = forms.ThemableChoiceField( label=_("Group"), required=False, help_text=_("Group which the new volume belongs to. Choose " "'No group' if the new volume belongs to no group.")) def prepare_source_fields_if_snapshot_specified(self, request): try: snapshot = self.get_snapshot(request, request.GET["snapshot_id"]) self.fields['name'].initial = snapshot.name self.fields['size'].initial = snapshot.size self.fields['snapshot_source'].choices = ((snapshot.id, snapshot),) try: # Set the volume type from the original volume orig_volume = cinder.volume_get(request, snapshot.volume_id) self.fields['type'].initial = orig_volume.volume_type except Exception: pass self.fields['size'].help_text = ( _('Volume size must be equal to or greater than the ' 'snapshot size (%sGiB)') % snapshot.size) self.fields['type'].widget = forms.widgets.HiddenInput() del self.fields['image_source'] del self.fields['volume_source'] del self.fields['volume_source_type'] del self.fields['availability_zone'] except Exception: exceptions.handle(request, _('Unable to load the specified snapshot.')) def prepare_source_fields_if_image_specified(self, request): self.fields['availability_zone'].choices = \ availability_zones(request) try: image = self.get_image(request, request.GET["image_id"]) image.bytes = image.size self.fields['name'].initial = image.name min_vol_size = functions.bytes_to_gigabytes( image.size) size_help_text = (_('Volume size must be equal to or greater ' 'than the image size (%s)') % filesizeformat(image.size)) properties = getattr(image, 'properties', {}) min_disk_size = (getattr(image, 'min_disk', 0) or properties.get('min_disk', 0)) if min_disk_size > min_vol_size: min_vol_size = min_disk_size size_help_text = (_('Volume size must be equal to or ' 'greater than the image minimum ' 'disk size (%sGiB)') % min_disk_size) self.fields['size'].initial = min_vol_size self.fields['size'].help_text = size_help_text self.fields['image_source'].choices = ((image.id, image),) del self.fields['snapshot_source'] del self.fields['volume_source'] del self.fields['volume_source_type'] except Exception: msg = _('Unable to load the specified image. %s') exceptions.handle(request, msg % request.GET['image_id']) def prepare_source_fields_if_volume_specified(self, request): self.fields['availability_zone'].choices = \ availability_zones(request) volume = None try: volume = self.get_volume(request, request.GET["volume_id"]) except Exception: msg = _('Unable to load the specified volume. %s') exceptions.handle(request, msg % request.GET['volume_id']) if volume is not None: self.fields['name'].initial = volume.name self.fields['description'].initial = volume.description min_vol_size = volume.size size_help_text = (_('Volume size must be equal to or greater ' 'than the origin volume size (%sGiB)') % volume.size) self.fields['size'].initial = min_vol_size self.fields['size'].help_text = size_help_text self.fields['volume_source'].choices = ((volume.id, volume),) self.fields['type'].initial = volume.type del self.fields['snapshot_source'] del self.fields['image_source'] del self.fields['volume_source_type'] def prepare_source_fields_default(self, request): source_type_choices = [] self.fields['availability_zone'].choices = \ availability_zones(request) try: available = api.cinder.VOLUME_STATE_AVAILABLE snapshots = cinder.volume_snapshot_list( request, search_opts=dict(status=available)) if snapshots: source_type_choices.append(("snapshot_source", _("Snapshot"))) choices = [('', _("Choose a snapshot"))] + \ [(s.id, s) for s in snapshots] self.fields['snapshot_source'].choices = choices else: del self.fields['snapshot_source'] except Exception: exceptions.handle(request, _("Unable to retrieve volume snapshots.")) images = utils.get_available_images(request, request.user.tenant_id) if images: source_type_choices.append(("image_source", _("Image"))) choices = [('', _("Choose an image"))] for image in images: image.bytes = image.size image.size = functions.bytes_to_gigabytes(image.bytes) choices.append((image.id, image)) self.fields['image_source'].choices = choices else: del self.fields['image_source'] volumes = self.get_volumes(request) if volumes: source_type_choices.append(("volume_source", _("Volume"))) choices = [('', _("Choose a volume"))] for volume in volumes: choices.append((volume.id, volume)) self.fields['volume_source'].choices = choices else: del self.fields['volume_source'] if source_type_choices: choices = ([('no_source_type', _("No source, empty volume"))] + source_type_choices) self.fields['volume_source_type'].choices = choices else: del self.fields['volume_source_type'] def _populate_group_choices(self, request): try: groups = cinder.group_list(request) except cinder_exc.VersionNotFoundForAPIMethod: del self.fields['group'] return except Exception: redirect = reverse("horizon:project:volumes:index") exceptions.handle(request, _('Unable to retrieve the volume group list.'), redirect=redirect) group_choices = [(g.id, g.name or g.id) for g in groups] group_choices.insert(0, ("", _("No group"))) self.fields['group'].choices = group_choices def __init__(self, request, *args, **kwargs): super(CreateForm, self).__init__(request, *args, **kwargs) volume_types = [] try: volume_types = cinder.volume_type_list(request) except Exception: redirect_url = reverse("horizon:project:volumes:index") error_message = _('Unable to retrieve the volume type list.') exceptions.handle(request, error_message, redirect=redirect_url) self.fields['type'].choices = [("", _("No volume type"))] + \ [(type.name, type.name) for type in volume_types] if 'initial' in kwargs and 'type' in kwargs['initial']: # if there is a default volume type to select, then remove # the first ""No volume type" entry self.fields['type'].choices.pop(0) if "snapshot_id" in request.GET: self.prepare_source_fields_if_snapshot_specified(request) elif 'image_id' in request.GET: self.prepare_source_fields_if_image_specified(request) elif 'volume_id' in request.GET: self.prepare_source_fields_if_volume_specified(request) else: self.prepare_source_fields_default(request) self._populate_group_choices(request) def clean(self): cleaned_data = super(CreateForm, self).clean() source_type = self.cleaned_data.get('volume_source_type') if (source_type == 'image_source' and not cleaned_data.get('image_source')): msg = _('Image source must be specified') self._errors['image_source'] = self.error_class([msg]) elif (source_type == 'snapshot_source' and not cleaned_data.get('snapshot_source')): msg = _('Snapshot source must be specified') self._errors['snapshot_source'] = self.error_class([msg]) elif (source_type == 'volume_source' and not cleaned_data.get('volume_source')): msg = _('Volume source must be specified') self._errors['volume_source'] = self.error_class([msg]) return cleaned_data def get_volumes(self, request): volumes = [] try: available = api.cinder.VOLUME_STATE_AVAILABLE volumes = cinder.volume_list(self.request, search_opts=dict(status=available)) except Exception: exceptions.handle(request, _('Unable to retrieve list of volumes.')) return volumes def handle(self, request, data): try: usages = quotas.tenant_quota_usages( self.request, targets=('volumes', 'gigabytes')) availableGB = usages['gigabytes']['available'] availableVol = usages['volumes']['available'] snapshot_id = None image_id = None volume_id = None source_type = data.get('volume_source_type', None) az = data.get('availability_zone', None) or None volume_type = data.get('type') if (data.get("snapshot_source", None) and source_type in ['', None, 'snapshot_source']): # Create from Snapshot snapshot = self.get_snapshot(request, data["snapshot_source"]) snapshot_id = snapshot.id if data['size'] < snapshot.size: error_message = (_('The volume size cannot be less than ' 'the snapshot size (%sGiB)') % snapshot.size) raise ValidationError(error_message) az = None volume_type = "" elif (data.get("image_source", None) and source_type in ['', None, 'image_source']): # Create from Snapshot image = self.get_image(request, data["image_source"]) image_id = image.id image_size = functions.bytes_to_gigabytes(image.size) if data['size'] < image_size: error_message = (_('The volume size cannot be less than ' 'the image size (%s)') % filesizeformat(image.size)) raise ValidationError(error_message) properties = getattr(image, 'properties', {}) min_disk_size = (getattr(image, 'min_disk', 0) or properties.get('min_disk', 0)) if min_disk_size > 0 and data['size'] < min_disk_size: error_message = (_('The volume size cannot be less than ' 'the image minimum disk size (%sGiB)') % min_disk_size) raise ValidationError(error_message) elif (data.get("volume_source", None) and source_type in ['', None, 'volume_source']): # Create from volume volume = self.get_volume(request, data["volume_source"]) volume_id = volume.id if data['size'] < volume.size: error_message = (_('The volume size cannot be less than ' 'the source volume size (%sGiB)') % volume.size) raise ValidationError(error_message) else: if type(data['size']) is str: data['size'] = int(data['size']) if availableGB < data['size']: error_message = _('A volume of %(req)iGiB cannot be created ' 'as you only have %(avail)iGiB of your ' 'quota available.') params = {'req': data['size'], 'avail': availableGB} raise ValidationError(error_message % params) elif availableVol <= 0: error_message = _('You are already using all of your available' ' volumes.') raise ValidationError(error_message) metadata = {} volume = cinder.volume_create(request, data['size'], data['name'], data['description'], volume_type, snapshot_id=snapshot_id, image_id=image_id, metadata=metadata, availability_zone=az, source_volid=volume_id, group_id=data.get('group') or None) message = _('Creating volume "%s"') % volume.name messages.info(request, message) return volume except ValidationError as e: self.api_error(e.messages[0]) return False except Exception: redirect = reverse("horizon:project:volumes:index") exceptions.handle(request, _("Unable to create volume."), redirect=redirect) @memoized def get_snapshot(self, request, id): return cinder.volume_snapshot_get(request, id) @memoized def get_image(self, request, id): return glance.image_get(request, id) @memoized def get_volume(self, request, id): return cinder.volume_get(request, id)
class AttachForm(forms.SelfHandlingForm): instance = forms.ThemableChoiceField(label=_("Attach to Instance"), help_text=_("Select an instance to " "attach to.")) device = forms.CharField(label=_("Device Name"), widget=forms.TextInput(attrs={'placeholder': '/dev/vdc'}), required=False, help_text=_("Actual device name may differ due " "to hypervisor settings. If not " "specified, then hypervisor will " "select a device name.")) def __init__(self, *args, **kwargs): super(AttachForm, self).__init__(*args, **kwargs) # Hide the device field if the hypervisor doesn't support it. if not nova.can_set_mount_point(): self.fields['device'].widget = forms.widgets.HiddenInput() # populate volume_id volume = kwargs.get('initial', {}).get("volume", None) if volume: volume_id = volume.id else: volume_id = None self.fields['volume_id'] = forms.CharField(widget=forms.HiddenInput(), initial=volume_id) # Populate instance choices instance_list = kwargs.get('initial', {}).get('instances', []) instances = [] for instance in instance_list: if instance.status in tables.VOLUME_ATTACH_READY_STATES and \ not any(instance.id == att["server_id"] for att in volume.attachments): instances.append((instance.id, '%s (%s)' % (instance.name, instance.id))) if instances: instances.insert(0, ("", _("Select an instance"))) else: instances = (("", _("No instances available")),) self.fields['instance'].choices = instances def handle(self, request, data): instance_choices = dict(self.fields['instance'].choices) instance_name = instance_choices.get(data['instance'], _("Unknown instance (None)")) # The name of the instance in the choices list has the ID appended to # it, so let's slice that off... instance_name = instance_name.rsplit(" (")[0] # api requires non-empty device name or None device = data.get('device') or None try: attach = api.nova.instance_volume_attach(request, data['volume_id'], data['instance'], device) volume = cinder.volume_get(request, data['volume_id']) message = _('Attaching volume %(vol)s to instance ' '%(inst)s on %(dev)s.') % {"vol": volume.name, "inst": instance_name, "dev": attach.device} messages.info(request, message) return True except Exception: redirect = reverse("horizon:project:volumes:index") exceptions.handle(request, _('Unable to attach volume.'), redirect=redirect)
class CreateEnvironmentForm(horizon_forms.SelfHandlingForm): name = forms.CharField(label=_("Environment Name"), help_text=ENV_NAME_HELP_TEXT, max_length=255) net_config = horizon_forms.ThemableChoiceField( label=_("Environment Default Network")) def __init__(self, request, *args, **kwargs): super(CreateEnvironmentForm, self).__init__(request, *args, **kwargs) env_fixed_network = getattr(settings, 'USE_FIXED_NETWORK', False) if env_fixed_network: net_choices = net.get_project_assigned_network(request) help_text = None if not net_choices: msg = _("Default network is either not specified for " "this project, or specified incorrectly, " "please contact administrator.") messages.error(request, msg) raise exceptions.ConfigurationError(msg) else: self.fields['net_config'].required = False self.fields['net_config'].widget.attrs['readonly'] = True else: net_choices = net.get_available_networks( request, murano_networks='translate') if net_choices is None: # NovaNetwork case net_choices = [((None, None), _('Unavailable'))] help_text = net.NN_HELP else: net_choices.insert(0, ((None, None), _('Create New'))) help_text = net.NEUTRON_NET_HELP self.fields['net_config'].choices = net_choices self.fields['net_config'].help_text = help_text def clean_name(self): cleaned_data = super(CreateEnvironmentForm, self).clean() env_name = cleaned_data.get('name') if not env_name.strip(): self._errors['name'] = self.error_class([ENV_NAME_HELP_TEXT]) return env_name def handle(self, request, data): try: net_config = ast.literal_eval(data.pop('net_config')) if net_config[0] is not None: data.update(net.generate_join_existing_net(net_config)) env = api.environment_create(request, data) request.session['env_id'] = env.id messages.success(request, u'Created environment "{0}"'.format(data['name'])) return True except exc.HTTPConflict: msg = _('Environment with specified name already exists') LOG.exception(msg) exceptions.handle(request, ignore=True) messages.error(request, msg) return False except Exception: msg = _('Failed to create environment') LOG.exception(msg) exceptions.handle(request) messages.error(request, msg) return False
class ManageQosSpecAssociation(forms.SelfHandlingForm): qos_spec_choice = forms.ThemableChoiceField( label=_("QoS Spec to be associated"), help_text=_("Choose associated QoS Spec.")) def __init__(self, request, *args, **kwargs): super(ManageQosSpecAssociation, self).__init__(request, *args, **kwargs) qos_spec_field = self.fields['qos_spec_choice'] qos_spec_field.choices = \ self.populate_qos_spec_choices() def populate_qos_spec_choices(self): # populate qos spec list box qos_specs = self.initial["qos_specs"] current_qos_spec = self.initial["cur_qos_spec_id"] qos_spec_list = [(qos_spec.id, qos_spec.name) for qos_spec in qos_specs if qos_spec.id != current_qos_spec] if current_qos_spec: # used to remove the current spec qos_spec_list.insert(0, ("-1", _("None (removes spec)"))) if qos_spec_list: qos_spec_list.insert(0, ("", _("Select a new QoS spec"))) else: qos_spec_list.insert(0, ("", _("No new QoS spec available"))) return qos_spec_list def handle(self, request, data): vol_type_id = self.initial['type_id'] new_qos_spec_id = data['qos_spec_choice'] # Update QOS Spec association information try: # NOTE - volume types can only be associated with # ONE QOS Spec at a time # first we need to un-associate the current QOS Spec, if it exists cur_qos_spec_id = self.initial['cur_qos_spec_id'] if cur_qos_spec_id: qos_spec = cinder.qos_spec_get(request, cur_qos_spec_id) cinder.qos_spec_disassociate(request, qos_spec, vol_type_id) # now associate with new QOS Spec, if user wants one associated if new_qos_spec_id != '-1': qos_spec = cinder.qos_spec_get(request, new_qos_spec_id) cinder.qos_spec_associate(request, qos_spec, vol_type_id) messages.success(request, _('Successfully updated QoS Spec association.')) return True except Exception: redirect = reverse("horizon:admin:volume_types:index") exceptions.handle(request, _('Error updating QoS Spec association.'), redirect=redirect)
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) @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 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']) 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])