class ImportForm(forms.SelfHandlingForm): name = forms.CharField( label=_("Stack name"), required=True, max_length=80, help_text=_("Stack name should be unique in the project")) importing = forms.FileField(label=_('OVA File'), help_text=_('A local importing to upload.'), widget=forms.FileInput(), required=False) def clean(self): cleaned_data = super(ImportForm, self).clean() return cleaned_data def handle(self, request, data): try: context = {} if data: context['name'] = data.get("name", "") context['importing'] = data.get("importing", "") utils.importOVA(self, request, context) return True except Exception: print traceback.format_exc() exceptions.handle(request, _("Unable to add importing OVA")) return False
def __init__(self, request, *args, **kwargs): super(DecryptPasswordInstanceForm, self).__init__(request, *args, **kwargs) instance_id = kwargs.get('initial', {}).get('instance_id') self.fields['instance_id'].initial = instance_id keypair_name = kwargs.get('initial', {}).get('keypair_name') self.fields['keypair_name'].initial = keypair_name try: result = api.nova.get_password(request, instance_id) if not result: _unavailable = _("Instance Password is not set" " or is not yet available") self.fields['encrypted_password'].initial = _unavailable else: self.fields['encrypted_password'].initial = result self.fields['private_key_file'] = forms.FileField( label=_('Private Key File'), widget=forms.FileInput(), required=True) self.fields['private_key'] = forms.CharField( widget=forms.widgets.Textarea(), label=_("OR Copy/Paste your Private Key"), required=True) _attrs = {'readonly': 'readonly'} self.fields['decrypted_password'] = forms.CharField( widget=forms.widgets.TextInput(_attrs), label=_("Password"), required=False) except Exception: redirect = reverse('horizon:project:instances:index') _error = _("Unable to retrieve instance password.") exceptions.handle(request, _error, redirect=redirect)
class CreateForm(forms.SelfHandlingForm): definition_source = forms.ChoiceField( label=_('Definition Source'), choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'definitionsource' })) definition_upload = forms.FileField( label=_('Definition File'), help_text=_('A local definition to upload.'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'definitionsource', 'data-required-when-shown': 'true', 'data-definitionsource-file': _('Definition File') }), required=False) definition_data = forms.CharField( label=_('Definition Data'), help_text=_('The raw contents of the definition.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'definitionsource', 'data-required-when-shown': 'true', 'data-definitionsource-raw': _('Definition Data'), 'rows': 4 }), required=False) def clean(self): cleaned_data = super(CreateForm, self).clean() if cleaned_data.get('definition_upload'): files = self.request.FILES cleaned_data['definition'] = files['definition_upload'].read() elif cleaned_data.get('definition_data'): cleaned_data['definition'] = cleaned_data['definition_data'] else: raise forms.ValidationError( _('You must specify the definition source.')) return cleaned_data def handle(self, request, data): try: api.action_create(request, data['definition']) msg = _('Successfully created action.') messages.success(request, msg) return True except Exception: msg = _('Failed to create action.') redirect = reverse('horizon:mistral:actions:index') exceptions.handle(request, msg, redirect=redirect)
class UploadPatchForm(forms.SelfHandlingForm): failure_url = 'horizon:admin:software_management:index' patch_files = forms.FileField( label=_("Patch File(s)"), widget=forms.FileInput(attrs={ 'data-source-file': _('Patch File(s)'), 'multiple': "multiple" }), required=True) def __init__(self, *args, **kwargs): super(UploadPatchForm, self).__init__(*args, **kwargs) def clean(self): data = super(UploadPatchForm, self).clean() return data def handle(self, request, data): success_responses = [] failure_responses = [] for f in request.FILES.getlist('patch_files'): try: success_responses.append( stx_api.patch.upload_patch(request, f, f.name)) except Exception as ex: failure_responses.append(str(ex)) # Consolidate server responses into one success/error message # respectively if success_responses: if len(success_responses) == 1: messages.success(request, success_responses[0]) else: success_msg = "" for i in range(len(success_responses)): success_msg += str(i + 1) + ") " + success_responses[i] messages.success(request, success_msg) if failure_responses: if len(failure_responses) == 1: messages.error(request, failure_responses[0]) else: error_msg = "" for i in range(len(failure_responses)): error_msg += str(i + 1) + ") " + failure_responses[i] messages.error(request, error_msg) return True
class DeployVNF(forms.SelfHandlingForm): vnf_name = forms.CharField(max_length=255, label=_("VNF Name")) description = forms.CharField( widget=forms.widgets.Textarea(attrs={'rows': 4}), label=_("Description"), required=False) vnfd_id = forms.ChoiceField(label=_("VNF Catalog Name"), required=False) template_source = forms.ChoiceField( label=_('VNFD template Source'), required=False, choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'template' })) template_file = forms.FileField( label=_('VNFD template File'), help_text=_('VNFD template to create VNF'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'template', 'data-template-file': _('TOSCA Template File') }), required=False) template_input = forms.CharField( label=_('VNFD template'), help_text=_('The YAML formatted contents of VNFD template.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'template', 'data-template-raw': _('VNFD template') }), required=False) vim_id = forms.ChoiceField(label=_("VIM Name"), required=False) region_name = forms.CharField(label=_("Region Name"), required=False) source_type = forms.ChoiceField( label=_('Parameter Value Source'), required=False, choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source' })) param_file = forms.FileField( label=_('Parameter Value File'), help_text=_('A local Parameter Value file to upload.'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Parameter Value File') }), required=False) direct_input = forms.CharField( label=_('Parameter Value YAML'), help_text=_('The YAML formatted contents of Parameter Values.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('Parameter Values') }), required=False) config_type = forms.ChoiceField( label=_('Configuration Value Source'), required=False, choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'config' })) config_file = forms.FileField( label=_('Configuration Value File'), help_text=_('VNF Configuration file with YAML ' 'formatted contents to upload.'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'config', 'data-config-file': _('Configuration Value File') }), required=False) config_input = forms.CharField( label=_('Configuration Value YAML'), help_text=_('YAML formatted VNF configuration text.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'config', 'data-config-raw': _('Configuration Values') }), required=False) def __init__(self, request, *args, **kwargs): super(DeployVNF, self).__init__(request, *args, **kwargs) try: vnfd_list = api.tacker.vnfd_list(request, template_source='onboarded') available_choices_vnfd = [(vnf['id'], vnf['name']) for vnf in vnfd_list] except Exception as e: available_choices_vnfd = [] msg = _('Failed to retrieve available VNF Catalog names: %s') % e LOG.error(msg) try: vim_list = api.tacker.vim_list(request) available_choices_vims = [(vim['id'], vim['name']) for vim in vim_list] except Exception as e: available_choices_vims = [] msg = _('Failed to retrieve available VIM names: %s') % e LOG.error(msg) self.fields['vnfd_id'].choices = [('', _('Select a VNF Catalog Name')) ] + available_choices_vnfd self.fields['vim_id'].choices = [('', _('Select a VIM Name')) ] + available_choices_vims def clean(self): data = super(DeployVNF, self).clean() template_file = data.get('template_file', None) template_raw = data.get('template_input', None) if template_raw and template_file: raise ValidationError( _("Cannot specify both file and direct input.")) if template_file and not template_file.name.endswith('.yaml'): raise ValidationError(_("Please upload .yaml file only.")) if template_file: data['vnfd_template'] = yaml.load(template_file, Loader=yaml.SafeLoader) elif template_raw: data['vnfd_template'] = yaml.load(data['template_input'], Loader=yaml.SafeLoader) else: data['vnfd_template'] = None param_file = data.get('param_file', None) param_raw = data.get('direct_input', None) if param_raw and param_file: raise ValidationError( _("Cannot specify both file and direct input.")) if param_file and not param_file.name.endswith('.yaml'): raise ValidationError(_("Please upload .yaml file only.")) if param_file: data['param_values'] = self.files['param_file'].read() elif param_raw: data['param_values'] = data['direct_input'] else: data['param_values'] = None config_file = data.get('config_file', None) config_raw = data.get('config_input', None) if config_file and config_raw: raise ValidationError( _("Cannot specify both file and direct input.")) if config_file and not config_file.name.endswith('.yaml'): raise ValidationError(_("Only .yaml file uploads supported")) if config_file: data['config_values'] = self.files['config_file'].read() elif config_raw: data['config_values'] = data['config_input'] else: data['config_values'] = None return data def handle(self, request, data): try: vnf_name = data['vnf_name'] description = data['description'] vnfd_id = data.get('vnfd_id') vnfd_template = data.get('vnfd_template') vim_id = data['vim_id'] region_name = data['region_name'] param_val = data['param_values'] config_val = data['config_values'] if (vnfd_id == '') and (vnfd_template is None): raise ValidationError( _("Both VNFD id and template cannot be " "empty. Please specify one of them")) if (vnfd_id != '') and (vnfd_template is not None): raise ValidationError( _("Both VNFD id and template cannot be " "specified. Please specify any one")) vnf_arg = { 'vnf': { 'vnfd_id': vnfd_id, 'name': vnf_name, 'description': description, 'vim_id': vim_id, 'vnfd_template': vnfd_template } } if region_name: vnf_arg.setdefault('placement_attr', {})[region_name] = region_name vnf_attr = vnf_arg['vnf'].setdefault('attributes', {}) if param_val: vnf_attr['param_values'] = param_val if config_val: vnf_attr['config'] = config_val api.tacker.create_vnf(request, vnf_arg) messages.success( request, _('VNF %s create operation initiated.') % vnf_name) return True except Exception: exceptions.handle(request, _('Failed to create VNF.'))
class TemplateForm(forms.SelfHandlingForm): class Meta: name = _('Select Template') help_text = _('Select a template to launch a stack.') # TODO(jomara) - update URL choice for template & environment files # w/ client side download when applicable base_choices = [('file', _('File')), ('raw', _('Direct Input'))] url_choice = [('url', _('URL'))] attributes = {'class': 'switchable', 'data-slug': 'templatesource'} template_source = forms.ChoiceField(label=_('Template Source'), choices=base_choices + url_choice, widget=forms.Select(attrs=attributes)) attributes = create_upload_form_attributes('template', 'file', _('Template File')) template_upload = forms.FileField( label=_('Template File'), help_text=_('A local template to upload.'), widget=forms.FileInput(attrs=attributes), required=False) attributes = create_upload_form_attributes('template', 'url', _('Template URL')) template_url = forms.URLField( label=_('Template URL'), help_text=_('An external (HTTP) URL to load the template from.'), widget=forms.TextInput(attrs=attributes), required=False) attributes = create_upload_form_attributes('template', 'raw', _('Template Data')) template_data = forms.CharField( label=_('Template Data'), help_text=_('The raw contents of the template.'), widget=forms.widgets.Textarea(attrs=attributes), required=False) attributes = {'data-slug': 'envsource', 'class': 'switchable'} environment_source = forms.ChoiceField( label=_('Environment Source'), choices=base_choices, widget=forms.Select(attrs=attributes), required=False) attributes = create_upload_form_attributes('env', 'file', _('Environment File')) environment_upload = forms.FileField( label=_('Environment File'), help_text=_('A local environment to upload.'), widget=forms.FileInput(attrs=attributes), required=False) attributes = create_upload_form_attributes('env', 'raw', _('Environment Data')) environment_data = forms.CharField( label=_('Environment Data'), help_text=_('The raw contents of the environment file.'), widget=forms.widgets.Textarea(attrs=attributes), required=False) def __init__(self, *args, **kwargs): self.next_view = kwargs.pop('next_view') super(TemplateForm, self).__init__(*args, **kwargs) def clean(self): cleaned = super(TemplateForm, self).clean() files = self.request.FILES self.clean_uploaded_files('template', _('template'), cleaned, files) self.clean_uploaded_files('environment', _('environment'), cleaned, files) # Validate the template and get back the params. kwargs = {} if cleaned['template_data']: kwargs['template'] = cleaned['template_data'] else: kwargs['template_url'] = cleaned['template_url'] if cleaned['environment_data']: kwargs['environment'] = cleaned['environment_data'] try: validated = api.heat.template_validate(self.request, **kwargs) cleaned['template_validate'] = validated except Exception as e: raise forms.ValidationError(unicode(e)) return cleaned def clean_uploaded_files(self, prefix, field_label, cleaned, files): """Cleans Template & Environment data from form upload. Does some of the crunchy bits for processing uploads vs raw data depending on what the user specified. Identical process for environment data & template data. :type prefix: str :param prefix: prefix (environment, template) of field :type field_label: str :param field_label: translated prefix str for messages :type input_type: dict :param prefix: existing cleaned fields from form :rtype: dict :return: cleaned dict including environment & template data """ upload_str = prefix + "_upload" data_str = prefix + "_data" url = cleaned.get(prefix + '_url') data = cleaned.get(prefix + '_data') has_upload = upload_str in files # Uploaded file handler if has_upload and not url: log_template_name = files[upload_str].name LOG.info('got upload %s' % log_template_name) tpl = files[upload_str].read() if tpl.startswith('{'): try: json.loads(tpl) except Exception as e: msg = _('There was a problem parsing the' ' %(prefix)s: %(error)s') msg = msg % {'prefix': prefix, 'error': e} raise forms.ValidationError(msg) cleaned[data_str] = tpl # URL handler elif url and (has_upload or data): msg = _('Please specify a %s using only one source method.') msg = msg % field_label raise forms.ValidationError(msg) elif prefix == 'template': # Check for raw template input - blank environment allowed if not url and not data: msg = _('You must specify a template via one of the ' 'available sources.') raise forms.ValidationError(msg) def create_kwargs(self, data): kwargs = { 'parameters': data['template_validate'], 'environment_data': data['environment_data'], 'template_data': data['template_data'], 'template_url': data['template_url'] } if data.get('stack_id'): kwargs['stack_id'] = data['stack_id'] return kwargs def handle(self, request, data): kwargs = self.create_kwargs(data) # NOTE (gabriel): This is a bit of a hack, essentially rewriting this # request so that we can chain it as an input to the next view... # but hey, it totally works. request.method = 'GET' return self.next_view.as_view()(request, **kwargs)
class CreateImageForm(CreateParent): name = forms.CharField(max_length=255, label=_("Name")) description = forms.CharField(max_length=255, widget=forms.Textarea(attrs={'rows': 4}), label=_("Description"), required=False) source_type = forms.ChoiceField( label=_('Image Source'), required=False, choices=[('url', _('Image Location')), ('file', _('Image File'))], widget=forms.ThemableSelectWidget(attrs={ 'class': 'switchable', 'data-slug': 'source' })) image_url_attrs = { 'class': 'switched', 'data-switch-on': 'source', 'data-source-url': _('Image Location'), 'ng-model': 'ctrl.copyFrom', 'ng-change': 'ctrl.selectImageFormat(ctrl.copyFrom)', 'placeholder': 'http://example.com/image.img' } image_url = ImageURLField(label=_("Image Location"), help_text=_("An external (HTTP/HTTPS) URL to " "load the image from."), widget=forms.TextInput(attrs=image_url_attrs), required=False) image_attrs = { 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Image File'), 'ng-model': 'ctrl.imageFile', 'ng-change': 'ctrl.selectImageFormat(ctrl.imageFile.name)', 'image-file-on-change': None } image_file = FileField(label=_("Image File"), help_text=_("A local image to upload."), widget=forms.FileInput(attrs=image_attrs), required=False) kernel = forms.ChoiceField( label=_('Kernel'), required=False, widget=forms.ThemableSelectWidget(transform=lambda x: "%s (%s)" % ( x.name, defaultfilters.filesizeformat(x.size)))) ramdisk = forms.ChoiceField( label=_('Ramdisk'), required=False, widget=forms.ThemableSelectWidget(transform=lambda x: "%s (%s)" % ( x.name, defaultfilters.filesizeformat(x.size)))) disk_format = forms.ChoiceField( label=_('Format'), choices=[], widget=forms.ThemableSelectWidget(attrs={ 'class': 'switchable', 'ng-model': 'ctrl.diskFormat' })) architecture = forms.CharField( max_length=255, label=_("Architecture"), help_text=_('CPU architecture of the image.'), required=False) min_disk = forms.IntegerField( label=_("Minimum Disk (GB)"), min_value=0, help_text=_('The minimum disk size required to boot the image. ' 'If unspecified, this value defaults to 0 (no minimum).'), required=False) min_ram = forms.IntegerField( label=_("Minimum RAM (MB)"), min_value=0, help_text=_('The minimum memory size required to boot the image. ' 'If unspecified, this value defaults to 0 (no minimum).'), required=False) is_copying = forms.BooleanField( label=_("Copy Data"), initial=True, required=False, help_text=_('Specify this option to copy image data to the image ' 'service. If unspecified, image data will be used in its ' 'current location.'), widget=forms.CheckboxInput( attrs={ 'class': 'switched', 'data-source-url': _('Image Location'), 'data-switch-on': 'source' })) is_public = forms.BooleanField( label=_("Public"), help_text=_('Make the image visible across projects.'), required=False) protected = forms.BooleanField( label=_("Protected"), help_text=_('Prevent the deletion of the image.'), required=False) def __init__(self, request, *args, **kwargs): super().__init__(request, *args, **kwargs) if (api.glance.get_image_upload_mode() == 'off' or not policy.check( (("image", "upload_image"), ), request)): self._hide_file_source_type() if not policy.check((("image", "set_image_location"), ), request): self._hide_url_source_type() # GlanceV2 feature removals if api.glance.VERSIONS.active >= 2: # NOTE: GlanceV2 doesn't support copy-from feature, sorry! self._hide_is_copying() if not settings.IMAGES_ALLOW_LOCATION: self._hide_url_source_type() if (api.glance.get_image_upload_mode() == 'off' or not policy.check( (("image", "upload_image"), ), request)): # Neither setting a location nor uploading image data is # allowed, so throw an error. msg = _('The current Horizon settings indicate no valid ' 'image creation methods are available. Providing ' 'an image location and/or uploading from the ' 'local file system must be allowed to support ' 'image creation.') messages.error(request, msg) raise ValidationError(msg) if not policy.check((("image", "publicize_image"), ), request): self._hide_is_public() self.fields['disk_format'].choices = \ api.glance.get_image_formats(request) try: kernel_images = api.glance.image_list_detailed( request, filters={'disk_format': 'aki'})[0] except Exception: kernel_images = [] msg = _('Unable to retrieve image list.') messages.error(request, msg) if kernel_images: choices = [('', _("Choose an image"))] for image in kernel_images: choices.append((image.id, image)) self.fields['kernel'].choices = choices else: del self.fields['kernel'] try: ramdisk_images = api.glance.image_list_detailed( request, filters={'disk_format': 'ari'})[0] except Exception: ramdisk_images = [] msg = _('Unable to retrieve image list.') messages.error(request, msg) if ramdisk_images: choices = [('', _("Choose an image"))] for image in ramdisk_images: choices.append((image.id, image)) self.fields['ramdisk'].choices = choices else: del self.fields['ramdisk'] def _hide_file_source_type(self): self.fields['image_file'].widget = HiddenInput() source_type = self.fields['source_type'] source_type.choices = [ choice for choice in source_type.choices if choice[0] != 'file' ] if len(source_type.choices) == 1: source_type.widget = HiddenInput() def _hide_url_source_type(self): self.fields['image_url'].widget = HiddenInput() source_type = self.fields['source_type'] source_type.choices = [ choice for choice in source_type.choices if choice[0] != 'url' ] if len(source_type.choices) == 1: source_type.widget = HiddenInput() def _hide_is_public(self): self.fields['is_public'].widget = HiddenInput() self.fields['is_public'].initial = False def _hide_is_copying(self): self.fields['is_copying'].widget = HiddenInput() self.fields['is_copying'].initial = False def clean(self): data = super().clean() # The image_file key can be missing based on particular upload # conditions. Code defensively for it here... source_type = data.get('source_type', None) image_file = data.get('image_file', None) image_url = data.get('image_url', None) if not image_url and not image_file: msg = _("An image file or an external location must be specified.") if source_type == 'file': error_msg = { 'image_file': [ msg, ] } else: error_msg = { 'image_url': [ msg, ] } raise ValidationError(error_msg) return data def handle(self, request, data): meta = api.glance.create_image_metadata(data) # Add image source file or URL to metadata if (api.glance.get_image_upload_mode() != 'off' and policy.check( (("image", "upload_image"), ), request) and data.get('image_file', None)): meta['data'] = data['image_file'] elif data.get('is_copying'): meta['copy_from'] = data['image_url'] else: meta['location'] = data['image_url'] try: image = api.glance.image_create(request, **meta) messages.info( request, _('Your image %s has been queued for creation.') % meta['name']) return image except Exception as e: msg = _('Unable to create new image') # TODO(nikunj2512): Fix this once it is fixed in glance client if hasattr(e, 'code') and e.code == 400: if "Invalid disk format" in e.details: msg = _('Unable to create new image: Invalid disk format ' '%s for image.') % meta['disk_format'] elif "Image name too long" in e.details: msg = _('Unable to create new image: Image name too long.') elif "not supported" in e.details: msg = _('Unable to create new image: URL scheme not ' 'supported.') exceptions.handle(request, msg) return False
class TemplateForm(forms.SelfHandlingForm): class Meta: name = _('Select Template') help_text = _('From here you can select a template to launch ' 'a stack.') template_source = forms.ChoiceField(label=_('Template Source'), choices=[('url', _('URL')), ('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source'})) template_upload = forms.FileField( label=_('Template File'), help_text=_('A local template to upload.'), widget=forms.FileInput(attrs={'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Template File')}), required=False) template_url = forms.URLField( label=_('Template URL'), help_text=_('An external (HTTP) URL to load the template from.'), widget=forms.TextInput(attrs={'class': 'switched', 'data-switch-on': 'source', 'data-source-url': _('Template URL')}), required=False) template_data = forms.CharField( label=_('Template Data'), help_text=_('The raw contents of the template.'), widget=forms.widgets.Textarea(attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('Template Data')}), required=False) def __init__(self, *args, **kwargs): self.next_view = kwargs.pop('next_view') super(TemplateForm, self).__init__(*args, **kwargs) def clean(self): cleaned = super(TemplateForm, self).clean() template_url = cleaned.get('template_url') template_data = cleaned.get('template_data') files = self.request.FILES has_upload = 'template_upload' in files # Uploaded file handler if has_upload and not template_url: log_template_name = self.request.FILES['template_upload'].name LOG.info('got upload %s' % log_template_name) tpl = self.request.FILES['template_upload'].read() if tpl.startswith('{'): try: json.loads(tpl) except Exception as e: msg = _('There was a problem parsing the template: %s') % e raise forms.ValidationError(msg) cleaned['template_data'] = tpl # URL handler elif template_url and (has_upload or template_data): msg = _('Please specify a template using only one source method.') raise forms.ValidationError(msg) # Check for raw template input elif not template_url and not template_data: msg = _('You must specify a template via one of the ' 'available sources.') raise forms.ValidationError(msg) # Validate the template and get back the params. kwargs = {} if cleaned['template_data']: kwargs['template'] = cleaned['template_data'] else: kwargs['template_url'] = cleaned['template_url'] try: validated = api.heat.template_validate(self.request, **kwargs) cleaned['template_validate'] = validated except Exception as e: msg = exception_to_validation_msg(e) if not msg: msg = _('An unknown problem occurred validating the template.') LOG.exception(msg) raise forms.ValidationError(msg) return cleaned def handle(self, request, data): kwargs = {'parameters': data['template_validate'], 'template_data': data['template_data'], 'template_url': data['template_url']} # NOTE (gabriel): This is a bit of a hack, essentially rewriting this # request so that we can chain it as an input to the next view... # but hey, it totally works. request.method = 'GET' return self.next_view.as_view()(request, **kwargs)
class CreateImageForm(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Name")) description = forms.CharField(max_length=255, label=_("Description"), required=False) source_type = forms.ChoiceField( label=_('Image Source'), required=False, choices=[('url', _('Image Location')), ('file', _('Image File'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source'})) image_url = forms.CharField(max_length=255, label=_("Image Location"), help_text=_("An external (HTTP) URL to load " "the image from."), widget=forms.TextInput(attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-url': _('Image Location'), 'ng-model': 'copyFrom', 'ng-change': 'selectImageFormat(copyFrom)'}), required=False) image_file = forms.FileField(label=_("Image File"), help_text=_("A local image to upload."), widget=forms.FileInput(attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Image File'), 'ng-model': 'imageFile', 'ng-change': 'selectImageFormat(imageFile.name)', 'image-file-on-change': None}), required=False) disk_format = forms.ChoiceField(label=_('Format'), choices=[], widget=forms.Select(attrs={ 'class': 'switchable', 'ng-model': 'diskFormat'})) architecture = forms.CharField(max_length=255, label=_("Architecture"), initial='x86_64', required=False) os_type = forms.CharField(max_length=255, label=_("OS Type"), help_text=_('optional value: windows/linux'), initial='linux', required=True) minimum_disk = forms.IntegerField( label=_("Minimum Disk (GB)"), min_value=0, help_text=_('The minimum disk size required to boot the image. ' 'If unspecified, this value defaults to 0 (no minimum).'), initial=1, required=False) minimum_ram = forms.IntegerField( label=_("Minimum RAM (MB)"), min_value=0, help_text=_('The minimum memory size required to boot the image. ' 'If unspecified, this value defaults to 0 (no minimum).'), initial=1024, required=False) is_copying = forms.BooleanField( label=_("Copy Data"), initial=True, required=False, help_text=_('Specify this option to copy image data to the image ' 'service. If unspecified, image data will be used in its ' 'current location.'), widget=forms.CheckboxInput(attrs={ 'class': 'switched', 'data-source-url': _('Image Location'), 'data-switch-on': 'source'})) is_allow_inject_passwd = forms.BooleanField( label=_("Allow inject user password"), initial=True, required=False) is_public = forms.BooleanField(label=_("Public"), required=False) protected = forms.BooleanField(label=_("Protected"), required=False) def __init__(self, request, *args, **kwargs): super(CreateImageForm, self).__init__(request, *args, **kwargs) if (not settings.HORIZON_IMAGES_ALLOW_UPLOAD or not policy.check((("image", "upload_image"),), request)): self._hide_file_source_type() if not policy.check((("image", "set_image_location"),), request): self._hide_url_source_type() if not policy.check((("image", "publicize_image"),), request): self._hide_is_public() self.fields['disk_format'].choices = IMAGE_FORMAT_CHOICES self.fields['minimum_ram'].widget = forms.widgets.HiddenInput() def _hide_file_source_type(self): self.fields['image_file'].widget = HiddenInput() source_type = self.fields['source_type'] source_type.choices = [choice for choice in source_type.choices if choice[0] != 'file'] if len(source_type.choices) == 1: source_type.widget = HiddenInput() def _hide_url_source_type(self): self.fields['image_url'].widget = HiddenInput() source_type = self.fields['source_type'] source_type.choices = [choice for choice in source_type.choices if choice[0] != 'url'] if len(source_type.choices) == 1: source_type.widget = HiddenInput() def _hide_is_public(self): self.fields['is_public'].widget = HiddenInput() self.fields['is_public'].initial = False def clean(self): data = super(CreateImageForm, self).clean() # The image_file key can be missing based on particular upload # conditions. Code defensively for it here... image_file = data.get('image_file', None) image_url = data.get('image_url', None) if not image_url and not image_file: raise ValidationError( _("A image or external image location must be specified.")) elif image_url and image_file: raise ValidationError( _("Can not specify both image and external image location.")) else: return data def handle(self, request, data): # Glance does not really do anything with container_format at the # moment. It requires it is set to the same disk_format for the three # Amazon image types, otherwise it just treats them as 'bare.' As such # we will just set that to be that here instead of bothering the user # with asking them for information we can already determine. if data['disk_format'] in ('ami', 'aki', 'ari',): container_format = data['disk_format'] else: data['disk_format'] = 'raw' container_format = 'bare' data['minimum_ram'] = 512 meta = {'is_public': data['is_public'], 'protected': data['protected'], 'disk_format': data['disk_format'], 'container_format': container_format, 'min_disk': (data['minimum_disk'] or 0), 'min_ram': (data['minimum_ram'] or 0), 'name': data['name'], 'properties': {}} if data['description']: meta['properties']['description'] = data['description'] if data['architecture']: meta['properties']['architecture'] = data['architecture'] if data['os_type']: meta['properties']['os_type'] = data['os_type'] if (settings.HORIZON_IMAGES_ALLOW_UPLOAD and policy.check((("image", "upload_image"),), request) and data.get('image_file', None)): meta['data'] = self.files['image_file'] elif data['is_copying']: meta['copy_from'] = data['image_url'] else: meta['location'] = data['image_url'] meta['is_allow_inject_passwd'] = data['is_allow_inject_passwd'] try: image = api.glance.image_create(request, **meta) messages.success(request, _('Your image %s has been queued for creation.') % data['name']) return image except Exception as e: msg = _('Unable to create new image') # TODO(nikunj2512): Fix this once it is fixed in glance client if hasattr(e, 'code') and e.code == 400: if "Invalid disk format" in e.details: msg = _('Unable to create new image: Invalid disk format ' '%s for image.') % data['disk_format'] elif "Image name too long" in e.details: msg = _('Unable to create new image: Image name too long.') exceptions.handle(request, msg) return False
class CreateImageForm(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Name")) description = forms.CharField(widget=forms.widgets.Textarea(attrs={ 'class': 'modal-body-fixed-width', 'rows': 4 }), label=_("Description"), required=False) source_type = forms.ChoiceField( label=_('Image Source'), required=False, choices=[('url', _('Image Location')), ('file', _('Image File'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source' })) image_url_attrs = { 'class': 'switched', 'data-switch-on': 'source', 'data-source-url': _('Image Location'), 'ng-model': 'ctrl.copyFrom', 'ng-change': 'ctrl.selectImageFormat(ctrl.copyFrom)' } image_url = ImageURLField(label=_("Image Location"), help_text=_("An external (HTTP/HTTPS) URL to " "load the image from."), widget=forms.TextInput(attrs=image_url_attrs), required=False) image_attrs = { 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Image File'), 'ng-model': 'ctrl.imageFile', 'ng-change': 'ctrl.selectImageFormat(ctrl.imageFile.name)', 'image-file-on-change': None } image_file = forms.FileField(label=_("Image File"), help_text=_("A local image to upload."), widget=forms.FileInput(attrs=image_attrs), required=False) kernel = forms.ChoiceField( label=_('Kernel'), required=False, widget=forms.SelectWidget(transform=lambda x: "%s (%s)" % ( x.name, defaultfilters.filesizeformat(x.size)))) ramdisk = forms.ChoiceField( label=_('Ramdisk'), required=False, widget=forms.SelectWidget(transform=lambda x: "%s (%s)" % ( x.name, defaultfilters.filesizeformat(x.size)))) disk_format = forms.ChoiceField( label=_('Format'), choices=[], widget=forms.Select(attrs={ 'class': 'switchable', 'ng-model': 'ctrl.diskFormat' })) architecture = forms.CharField(max_length=255, label=_("Architecture"), required=False) minimum_disk = forms.IntegerField( label=_("Minimum Disk (GB)"), min_value=0, help_text=_('The minimum disk size required to boot the image. ' 'If unspecified, this value defaults to 0 (no minimum).'), required=False) minimum_ram = forms.IntegerField( label=_("Minimum RAM (MB)"), min_value=0, help_text=_('The minimum memory size required to boot the image. ' 'If unspecified, this value defaults to 0 (no minimum).'), required=False) is_copying = forms.BooleanField( label=_("Copy Data"), initial=True, required=False, help_text=_('Specify this option to copy image data to the image ' 'service. If unspecified, image data will be used in its ' 'current location.'), widget=forms.CheckboxInput( attrs={ 'class': 'switched', 'data-source-url': _('Image Location'), 'data-switch-on': 'source' })) is_public = forms.BooleanField(label=_("Public"), required=False) protected = forms.BooleanField(label=_("Protected"), required=False) def __init__(self, request, *args, **kwargs): super(CreateImageForm, self).__init__(request, *args, **kwargs) if (not settings.HORIZON_IMAGES_ALLOW_UPLOAD or not policy.check( (("image", "upload_image"), ), request)): self._hide_file_source_type() if not policy.check((("image", "set_image_location"), ), request): self._hide_url_source_type() if not policy.check((("image", "publicize_image"), ), request): self._hide_is_public() self.fields['disk_format'].choices = IMAGE_FORMAT_CHOICES try: kernel_images = api.glance.image_list_detailed( request, filters={'disk_format': 'aki'})[0] except Exception: kernel_images = [] msg = _('Unable to retrieve image list.') messages.error(request, msg) if kernel_images: choices = [('', _("Choose an image"))] for image in kernel_images: choices.append((image.id, image)) self.fields['kernel'].choices = choices else: del self.fields['kernel'] try: ramdisk_images = api.glance.image_list_detailed( request, filters={'disk_format': 'ari'})[0] except Exception: ramdisk_images = [] msg = _('Unable to retrieve image list.') messages.error(request, msg) if ramdisk_images: choices = [('', _("Choose an image"))] for image in ramdisk_images: choices.append((image.id, image)) self.fields['ramdisk'].choices = choices else: del self.fields['ramdisk'] def _hide_file_source_type(self): self.fields['image_file'].widget = HiddenInput() source_type = self.fields['source_type'] source_type.choices = [ choice for choice in source_type.choices if choice[0] != 'file' ] if len(source_type.choices) == 1: source_type.widget = HiddenInput() def _hide_url_source_type(self): self.fields['image_url'].widget = HiddenInput() source_type = self.fields['source_type'] source_type.choices = [ choice for choice in source_type.choices if choice[0] != 'url' ] if len(source_type.choices) == 1: source_type.widget = HiddenInput() def _hide_is_public(self): self.fields['is_public'].widget = HiddenInput() self.fields['is_public'].initial = False def clean(self): data = super(CreateImageForm, self).clean() # The image_file key can be missing based on particular upload # conditions. Code defensively for it here... image_file = data.get('image_file', None) image_url = data.get('image_url', None) if not image_url and not image_file: raise ValidationError( _("A image or external image location must be specified.")) elif image_url and image_file: raise ValidationError( _("Can not specify both image and external image location.")) else: return data def handle(self, request, data): meta = create_image_metadata(data, False) # Add image source file or URL to metadata if (settings.HORIZON_IMAGES_ALLOW_UPLOAD and policy.check( (("image", "upload_image"), ), request) and data.get('image_file', None)): meta['data'] = self.files['image_file'] elif data['is_copying']: meta['copy_from'] = data['image_url'] else: meta['location'] = data['image_url'] try: image = api.glance.image_create(request, **meta) messages.success( request, _('Your image %s has been queued for creation.') % meta['name']) return image except Exception as e: msg = _('Unable to create new image') # TODO(nikunj2512): Fix this once it is fixed in glance client if hasattr(e, 'code') and e.code == 400: if "Invalid disk format" in e.details: msg = _('Unable to create new image: Invalid disk format ' '%s for image.') % meta['disk_format'] elif "Image name too long" in e.details: msg = _('Unable to create new image: Image name too long.') elif "not supported" in e.details: msg = _('Unable to create new image: URL scheme not ' 'supported.') exceptions.handle(request, msg) return False
class CreateScriptForm(forms.SelfHandlingForm): help_text = _('Create a new rating script.') name = forms.CharField(label=_("Name")) source_choices = [('raw', _('Direct Input')), ('file', _('File'))] script_source = forms.ChoiceField( label=_('Rating Script Source'), choices=source_choices, widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'scriptsource'})) script_help = _("A script or set of python commands to modify rating " "calculations.") script_upload = forms.FileField( label=_('Script File'), help_text=script_help, widget=forms.FileInput(attrs={ 'class': 'switched', 'data-switch-on': 'scriptsource', 'data-scriptsource-file': _('Script File')}), required=False) script_data = forms.CharField( label=_('Script Data'), help_text=script_help, widget=forms.widgets.Textarea(attrs={ 'class': 'switched', 'data-switch-on': 'scriptsource', 'data-scriptsource-raw': _('Script Data')}), required=False) class Meta(object): name = _('Create Script') def clean(self): cleaned = super(CreateScriptForm, self).clean() files = self.request.FILES script = self.clean_uploaded_files('script', files) if script is not None: cleaned['script_data'] = script return cleaned def clean_uploaded_files(self, prefix, files): upload_str = prefix + "_upload" has_upload = upload_str in files if has_upload: upload_file = files[upload_str] log_script_name = upload_file.name LOG.info('got upload %s' % log_script_name) script = upload_file.read() if script != "": try: normalize_newlines(script) except Exception as e: msg = _('There was a problem parsing the' ' %(prefix)s: %(error)s') msg = msg % {'prefix': prefix, 'error': e} raise forms.ValidationError(msg) return script else: return None def handle(self, request, data): name = data['name'] LOG.info('Creating script with name %s' % (name)) ck_client = api.cloudkittyclient(request) return ck_client.rating.pyscripts.create_script( name=name, data=data['script_data'])
class ImportOpaqueData(forms.SelfHandlingForm): name = forms.RegexField(required=False, max_length=255, label=_("Data Name"), regex=shared_forms.NAME_REGEX, error_messages=shared_forms.ERROR_MESSAGES) source_type = forms.ChoiceField( label=_('Source'), required=False, choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.ThemableSelectWidget(attrs={ 'class': 'switchable', 'data-slug': 'source' })) object_file = forms.FileField(label=_("Choose file"), help_text=_("A local file to upload."), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('File') }), required=False) direct_input = forms.CharField( label=_('Object Bytes'), help_text=_('The bytes of the object, represented in hex.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('Bytes') }), required=False) def __init__(self, request, *args, **kwargs): super(ImportOpaqueData, self).__init__(request, *args, **kwargs) def clean(self): data = super(ImportOpaqueData, self).clean() # The data can be missing based on particular upload # conditions. Code defensively for it here... data_file = data.get('object_file', None) data_raw = data.get('direct_input', None) if data_raw and data_file: raise forms.ValidationError( _("Cannot specify both file and direct input.")) if not data_raw and not data_file: raise forms.ValidationError( _("No input was provided for the object value.")) try: if data_file: data_bytes = self.files['object_file'].read() else: data_str = data['direct_input'] data_bytes = binascii.unhexlify(data_str) data['object_bytes'] = base64.b64encode(data_bytes) except Exception as e: msg = _('There was a problem loading the object: %s. ' 'Is the object valid and in the correct format?') % e raise forms.ValidationError(msg) return data def handle(self, request, data): try: data_bytes = data.get('object_bytes') data_uuid = client.import_object( request, data=data_bytes, name=data['name'], object_type=opaque_data.OpaqueData) if data['name']: data_identifier = data['name'] else: data_identifier = data_uuid messages.success( request, _('Successfully imported object: %s') % data_identifier) return data_uuid except Exception as e: msg = _('Unable to import object: %s') messages.error(msg % e) exceptions.handle(request, ignore=True) self.api_error(_('Unable to import object.')) return False
class ImportX509Certificate(forms.SelfHandlingForm): name = forms.RegexField(required=False, max_length=255, label=_("Certificate Name"), regex=NAME_REGEX, error_messages=ERROR_MESSAGES) source_type = forms.ChoiceField( label=_('Source'), required=False, choices=[('file', _('Import File')), ('raw', _('Direct Input'))], widget=forms.ThemableSelectWidget(attrs={ 'class': 'switchable', 'data-slug': 'source' })) cert_file = forms.FileField( label=_("Choose file"), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('PEM Certificate File') }), required=False) direct_input = forms.CharField( label=_('PEM Certificate'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('PEM Certificate') }), required=False) def clean(self): data = super(ImportX509Certificate, self).clean() # The cert can be missing based on particular upload # conditions. Code defensively for it here... cert_file = data.get('cert_file', None) cert_raw = data.get('direct_input', None) if cert_raw and cert_file: raise forms.ValidationError( _("Cannot specify both file and direct input.")) if not cert_raw and not cert_file: raise forms.ValidationError( _("No input was provided for the certificate value.")) try: if cert_file: cert_pem = self.files['cert_file'].read() else: cert_pem = str(data['direct_input']) cert_obj = load_pem_x509_certificate(cert_pem.encode('utf-8'), default_backend()) cert_der = cert_obj.public_bytes(Encoding.DER) except Exception as e: msg = _('There was a problem loading the certificate: %s. ' 'Is the certificate valid and in PEM format?') % e raise forms.ValidationError(msg) data['cert_data'] = base64.b64encode(cert_der).decode('utf-8') return data def handle(self, request, data): try: cert_pem = data.get('cert_data') cert_uuid = client.import_object(request, data=cert_pem, name=data['name'], object_type=x_509.X509) if data['name']: identifier = data['name'] else: identifier = cert_uuid messages.success( request, _('Successfully imported certificate: %s') % identifier) return cert_uuid except Exception as e: msg = _('Unable to import certificate: %s') messages.error(request, msg % e) exceptions.handle(request, ignore=True) self.api_error(_('Unable to import certificate.')) return False
class CreateProfileForm(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Name")) source_type = forms.ThemableChoiceField( label=_('Spec Source'), required=False, choices=[('file', _('File')), ('yaml', _('YAML'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source'})) spec_file = forms.FileField( label=_("Spec File"), widget=forms.FileInput(attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Spec File')}), required=False, help_text=_("The spec file used to create the profile.")) spec_yaml = forms.CharField( label=_("Spec YAML"), required=False, widget=forms.Textarea(attrs={ 'rows': 6, 'class': 'switched', 'data-switch-on': 'source', 'data-source-yaml': _('Spec YAML')}), help_text=_("The spec yaml used to create the profile.")) metadata = forms.CharField( label=_("Metadata"), required=False, widget=forms.Textarea(attrs={'rows': 4}), help_text=_("YAML formatted metadata.")) def clean(self): data = super(CreateProfileForm, self).clean() spec_file = data.get('spec_file', None) spec_yaml = data.get('spec_yaml', None) if not spec_file and not spec_yaml: raise ValidationError( _("A spec file or yaml must be specified.")) elif spec_file and spec_yaml: raise ValidationError( _("Can not specify both sepc file and yaml.")) else: return data def handle(self, request, data): source_type = data.get('source_type') if source_type == "yaml": spec = data.get("spec_yaml") else: spec = self.files['spec_file'].read() opts = _populate_profile_params( name=data.get('name'), spec=spec, metadata=data.get('metadata') ) try: profile = senlin.profile_create(request, **opts) messages.success(request, _('Your profile %s has been created.') % opts['name']) return profile except ValidationError as e: self.api_error(e.messages[0]) return False except Exception: redirect = reverse(INDEX_URL) msg = _('Unable to create new profile') exceptions.handle(request, msg, redirect=redirect) return False
class CreateForm(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Name"), help_text=_('Cron Trigger name.'), required=True) workflow_id = forms.ChoiceField( label=_('Workflow ID'), help_text=_('Select Workflow ID.'), widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'workflow_select' })) input_source = forms.ChoiceField( label=_('Input'), help_text=_('JSON of input values defined in the workflow. ' 'Select either file or raw content.'), choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'inputsource' })) input_upload = forms.FileField( label=_('Input File'), help_text=_('A local input to upload.'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'inputsource', 'data-required-when-shown': 'true', 'data-inputsource-file': _('Input File') }), required=False) input_data = forms.CharField( label=_('Input Data'), help_text=_('The raw contents of the input.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'inputsource', 'data-required-when-shown': 'true', 'data-inputsource-raw': _('Input Data'), 'rows': 4 }), required=False) params_source = forms.ChoiceField( label=_('Params'), help_text=_('JSON of params values defined in the workflow. ' 'Select either file or raw content.'), choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'paramssource' })) params_upload = forms.FileField( label=_('Params File'), help_text=_('A local input to upload.'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'paramssource', 'data-required-when-shown': 'true', 'data-paramssource-file': _('Params File') }), required=False) params_data = forms.CharField( label=_('Params Data'), help_text=_('The raw contents of the params.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'paramssource', 'data-required-when-shown': 'true', 'data-paramssource-raw': _('Params Data'), 'rows': 4 }), required=False) first_time = forms.CharField( label=_('First Time (YYYY-MM-DD HH:MM)'), help_text=_('Date and time of the first execution.'), widget=forms.widgets.TextInput(), required=False) schedule_count = forms.CharField( label=_('Count'), help_text=_('Number of desired executions.'), widget=forms.widgets.TextInput(), required=False) schedule_pattern = forms.CharField( label=_('Pattern (* * * * *)'), help_text=_('Cron Trigger pattern, mind the space between each char.'), widget=forms.widgets.TextInput(), required=False) def __init__(self, request, *args, **kwargs): super(CreateForm, self).__init__(request, *args, **kwargs) workflow_list = api.workflow_list(request) workflow_id_list = [] for wf in workflow_list: workflow_id_list.append( (wf.id, "{id} ({name})".format(id=wf.id, name=wf.name))) self.fields['workflow_id'].choices = workflow_id_list def clean(self): cleaned_data = super(CreateForm, self).clean() cleaned_data['input'] = "" cleaned_data['params'] = "" if cleaned_data.get('input_upload'): files = self.request.FILES cleaned_data['input'] = files['input_upload'].read() elif cleaned_data.get('input_data'): cleaned_data['input'] = cleaned_data['input_data'] del (cleaned_data['input_upload']) del (cleaned_data['input_data']) if len(cleaned_data['input']) > 0: try: cleaned_data['input'] = json.loads(cleaned_data['input']) except Exception as e: msg = _('Input is invalid JSON: %s') % str(e) raise forms.ValidationError(msg) if cleaned_data.get('params_upload'): files = self.request.FILES cleaned_data['params'] = files['params_upload'].read() elif cleaned_data.get('params_data'): cleaned_data['params'] = cleaned_data['params_data'] del (cleaned_data['params_upload']) del (cleaned_data['params_data']) if len(cleaned_data['params']) > 0: try: cleaned_data['params'] = json.loads(cleaned_data['params']) except Exception as e: msg = _('Params is invalid JSON: %s') % str(e) raise forms.ValidationError(msg) return cleaned_data @handle_errors(_("Unable to create Cron Trigger"), []) def handle(self, request, data): data['input'] = convert_empty_string_to_none(data['input']) data['params'] = convert_empty_string_to_none(data['params']) data['schedule_pattern'] = convert_empty_string_to_none( data['schedule_pattern']) data['first_time'] = convert_empty_string_to_none(data['first_time']) data['schedule_count'] = convert_empty_string_to_none( data['schedule_count']) try: api.cron_trigger_create( request, data['name'], data['workflow_id'], data['input'], data['params'], data['schedule_pattern'], data['first_time'], data['schedule_count'], ) msg = _('Successfully created Cron Trigger.') messages.success(request, msg) return True finally: pass
class CreateServiceChainNodeForm(forms.SelfHandlingForm): name = forms.CharField(max_length=80, label=_("Name")) description = forms.CharField( max_length=80, label=_("Description"), required=False) service_type = forms.ChoiceField( label=_("Service Type"), choices=SERVICE_TYPES) config_type = forms.ChoiceField(label=_("Config Type"), choices=[('file', 'Heat Template'), ('string', 'Config String')], widget=forms.Select(attrs={'class': 'switchable', 'data-slug': 'source'})) template_file = forms.FileField(label=_('Configuration File'), help_text=_('A local Heat template file to upload.'), required=False, widget=forms.FileInput(attrs={'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _("Configuration File")})) template_string = forms.CharField(label=_("Configuration String"), help_text=_('A local Heat template string.'), widget=forms.Textarea(attrs={'class': 'switched', 'data-switch-on': 'source', 'data-source-string': _("Configuration String")}), required=False) def clean(self): cleaned_data = super(CreateServiceChainNodeForm, self).clean() files = self.request.FILES template_str = None if 'template_file' in files: temp = files['template_file'].read() try: template_str = json.loads(temp) except Exception: msg = _('Invalid file format.') raise forms.ValidationError(msg) else: try: tstr = cleaned_data["template_string"] if bool(tstr): template_str = json.loads(tstr) except Exception: msg = _("Invalid template string.") raise forms.ValidationError(msg) if template_str is not None: cleaned_data['config'] = template_str else: msg = _("Please choose a template file or enter template string.") raise forms.ValidationError(msg) return cleaned_data def handle(self, request, context): url = reverse("horizon:project:network_services:index") try: try: del context['template_string'] del context['template_file'] del context['config_type'] except KeyError: pass context['config'] = json.dumps(context['config']) client.create_servicechain_node(request, **context) msg = _("Service Chain Node Created Successfully!") LOG.debug(msg) return http.HttpResponseRedirect(url) except Exception as e: msg = _("Failed to create Service Chain Node. %s") % (str(e)) LOG.error(msg) exceptions.handle(request, msg, redirect=shortcuts.redirect)
class UploadFileForm(forms.SelfHandlingForm): name = forms.ChoiceField(label=_('Name'), choices=[]) description = forms.CharField(widget=forms.widgets.Textarea(attrs={ 'class': 'modal-body-fixed-width', 'rows': 4 }), label=_("Description"), required=False) image_file = forms.FileField( label=_("Load File"), help_text=_("A local file to upload."), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Load File'), 'ng-model': 'File', 'ng-change': 'selectImageFormat(File.name)', 'image-file-on-change': None }), required=False) #is_public = forms.BooleanField(label=_("Public"), required=False) #protected = forms.BooleanField(label=_("Protected"), required=False) def __init__(self, request, *args, **kwargs): super(UploadFileForm, self).__init__(request, *args, **kwargs) if (api.glance.get_image_upload_mode() == 'off' or not policy.check( (("image", "upload_image"), ), request)): self._hide_file_source_type() if not policy.check((("image", "publicize_image"), ), request): self._hide_is_public() self.fields['name'].choices = NAME_CHOICES def _hide_file_source_type(self): self.fields['image_file'].widget = HiddenInput() def _hide_is_public(self): self.fields['is_public'].widget = HiddenInput() self.fields['is_public'].initial = False def clean(self): data = super(UploadFileForm, self).clean() image_file = data.get('image_file', None) if not image_file: raise ValidationError(_("A file location must be specified.")) else: return data def handle(self, request, data): container_format = 'bare' data['is_public'] = True data['disk_format'] = 'raw' properties = {} if data.get('description'): properties['description'] = data['description'] properties['image_type'] = 'file' meta = { 'public': 'public', 'protected': False, 'disk_format': data['disk_format'], 'container_format': container_format, 'min_disk': 0, 'min_ram': 0, 'name': data['name'], #'properties': {'image_type': 'file'}, 'data': self.files['image_file'] } meta.update(properties) LOG.info("properties ========================%s" % meta) try: image = api.glance.image_create(request, **meta) messages.success( request, _('Your file %s has been queued for upload.') % data['name']) return image except Exception: exceptions.handle(request, _('Unable to upload the file.'))
class ImportKey(forms.SelfHandlingForm): algorithm = forms.CharField(label=_("Algorithm"), help_text=ALG_HELP_TEXT) bit_length = forms.IntegerField(label=_("Bit Length"), min_value=0, help_text=LENGTH_HELP_TEXT) name = forms.RegexField(required=False, max_length=255, label=_("Key Name"), regex=NAME_REGEX, error_messages=ERROR_MESSAGES) source_type = forms.ChoiceField( label=_('Source'), required=False, choices=[('file', _('Key File')), ('raw', _('Direct Input'))], widget=forms.ThemableSelectWidget(attrs={ 'class': 'switchable', 'data-slug': 'source' })) key_file = forms.FileField(label=_("Choose file"), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Key File') }), required=False) direct_input = forms.CharField(label=_('Key Value'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('Key Value') }), required=False) def __init__(self, request, *args, **kwargs): algorithms = kwargs.pop('algorithms', None) super(ImportKey, self).__init__(request, *args, **kwargs) self.fields['algorithm'].widget = ListTextWidget(data_list=algorithms, name='algorithms') @abc.abstractmethod def clean_key_data(self, key_pem): """This should be implemented for the specific key import form""" return def clean(self): data = super(ImportKey, self).clean() # The key can be missing based on particular upload # conditions. Code defensively for it here... key_file = data.get('key_file', None) key_raw = data.get('direct_input', None) if key_raw and key_file: raise forms.ValidationError( _("Cannot specify both file and direct input.")) if not key_raw and not key_file: raise forms.ValidationError( _("No input was provided for the key value.")) try: if key_file: key_pem = self.files['key_file'].read() else: key_pem = data['direct_input'] data['key_data'] = self.clean_key_data(key_pem) except Exception as e: msg = _('There was a problem loading the key: %s. ' 'Is the key valid and in the correct format?') % e raise forms.ValidationError(msg) return data def handle(self, request, data, key_type): try: key_uuid = client.import_object(request, algorithm=data['algorithm'], bit_length=data['bit_length'], key=data['key_data'], name=data['name'], object_type=key_type) if data['name']: key_identifier = data['name'] else: key_identifier = key_uuid messages.success( request, _('Successfully imported key: %s') % key_identifier) return key_uuid except Exception as e: msg = _('Unable to import key: %s') messages.error(request, msg % e) exceptions.handle(request, ignore=True) self.api_error(_('Unable to import key.')) return False
class DefinitionForm(forms.SelfHandlingForm): definition_source = forms.ChoiceField( label=_('Definition Source'), choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'definitionsource' })) definition_upload = forms.FileField( label=_('Definition File'), help_text=_('A local definition to upload.'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'definitionsource', 'data-required-when-shown': 'true', 'data-definitionsource-file': _('Definition File') }), required=False) definition_data = forms.CharField( label=_('Definition Data'), help_text=_('The raw contents of the definition.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'definitionsource', 'data-required-when-shown': 'true', 'data-definitionsource-raw': _('Definition Data'), 'rows': 4 }), required=False) def __init__(self, *args, **kwargs): self.next_view = kwargs.pop('next_view') super(DefinitionForm, self).__init__(*args, **kwargs) def clean(self): cleaned_data = super(DefinitionForm, self).clean() if cleaned_data.get('definition_upload'): files = self.request.FILES cleaned_data['definition'] = files['definition_upload'].read() elif cleaned_data.get('definition_data'): cleaned_data['definition'] = cleaned_data['definition_data'] else: raise forms.ValidationError( _('You must specify the definition source.')) try: validated = api.workbook_validate(self.request, cleaned_data['definition']) except Exception as e: raise forms.ValidationError(six.text_type(e)) if not validated.get('valid'): raise forms.ValidationError( validated.get('error', _('Validated failed'))) return cleaned_data def handle(self, request, data): kwargs = {'definition': data['definition']} request.method = 'GET' return self.next_view.as_view()(request, **kwargs)
class CreateNamespaceForm(forms.SelfHandlingForm): source_type = forms.ChoiceField( label=_('Namespace Definition Source'), required=False, choices=[('file', _('Metadata Definition File')), ('raw', _('Direct Input'))], widget=forms.Select( attrs={'class': 'switchable', 'data-slug': 'source'})) metadef_file = forms.FileField( label=_("Metadata Definition File"), help_text=_("A local metadata definition file to upload."), widget=forms.FileInput( attrs={'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Metadata Definition File')}), required=False) direct_input = forms.CharField( label=_('Namespace JSON'), help_text=_('The JSON formatted contents of a namespace.'), widget=forms.widgets.Textarea( attrs={'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('Namespace JSON')}), required=False) public = forms.BooleanField(label=_("Public"), required=False) protected = forms.BooleanField(label=_("Protected"), required=False) def __init__(self, request, *args, **kwargs): super(CreateNamespaceForm, self).__init__(request, *args, **kwargs) def clean(self): data = super(CreateNamespaceForm, self).clean() # The key can be missing based on particular upload # conditions. Code defensively for it here... metadef_file = data.get('metadef_file', None) metadata_raw = data.get('direct_input', None) if metadata_raw and metadef_file: raise ValidationError( _("Cannot specify both file and direct input.")) if not metadata_raw and not metadef_file: raise ValidationError( _("No input was provided for the namespace content.")) try: if metadef_file: ns_str = self.files['metadef_file'].read() else: ns_str = data['direct_input'] namespace = json.loads(ns_str) if data['public']: namespace['visibility'] = 'public' else: namespace['visibility'] = 'private' namespace['protected'] = data['protected'] for protected_prop in constants.METADEFS_PROTECTED_PROPS: namespace.pop(protected_prop, None) data['namespace'] = namespace except Exception as e: msg = _('There was a problem loading the namespace: %s.') % e raise forms.ValidationError(msg) return data def handle(self, request, data): try: namespace = glance.metadefs_namespace_create(request, data['namespace']) messages.success(request, _('Namespace %s has been created.') % namespace['namespace']) return namespace except Exception as e: msg = _('Unable to create new namespace. %s') msg %= e.message.split('Failed validating', 1)[0] exceptions.handle(request, message=msg) return False
class OnBoardVNF(forms.SelfHandlingForm): name = forms.CharField(max_length=80, label=_("Name"), required=False) source_type = forms.ChoiceField( label=_('TOSCA Template Source'), required=False, choices=[('file', _('TOSCA Template File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source' })) toscal_file = forms.FileField( label=_("TOSCA Template File"), help_text=_("A local TOSCA template file to upload."), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('TOSCA Template File') }), required=False) direct_input = forms.CharField( label=_('TOSCA YAML'), help_text=_('The YAML formatted contents of a TOSCA template.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('TOSCA YAML') }), required=False) def __init__(self, request, *args, **kwargs): super(OnBoardVNF, self).__init__(request, *args, **kwargs) def clean(self): data = super(OnBoardVNF, self).clean() # The key can be missing based on particular upload # conditions. Code defensively for it here... toscal_file = data.get('toscal_file', None) toscal_raw = data.get('direct_input', None) if toscal_raw and toscal_file: raise ValidationError( _("Cannot specify both file and direct input.")) if not toscal_raw and not toscal_file: raise ValidationError( _("No input was provided for the namespace content.")) try: if toscal_file: toscal_str = self.files['toscal_file'].read() else: toscal_str = data['direct_input'] #toscal = yaml.loads(toscal_str) data['tosca'] = toscal_str except Exception as e: msg = _('There was a problem loading the namespace: %s.') % e raise forms.ValidationError(msg) return data def handle(self, request, data): try: toscal = data['tosca'] print "VNFD TOSCA: " + toscal tosca_arg = {'vnfd': {'vnfd': toscal}} vnfd_instance = api.tacker.create_vnfd(request, tosca_arg) print "VNFD Instance: " + str(vnfd_instance) print "VNFD name: " + vnfd_instance['vnfd']['name'] messages.success( request, _('VNF Catalog entry %s has been created.') % vnfd_instance['vnfd']['name']) return toscal except Exception as e: msg = _('Unable to create TOSCA. %s') msg %= e.message.split('Failed validating', 1)[0] exceptions.handle(request, message=msg) return False
class DeployMECA(forms.SelfHandlingForm): mca_name = forms.CharField(max_length=255, label=_("MECA Name")) description = forms.CharField( widget=forms.widgets.Textarea(attrs={'rows': 4}), label=_("Description"), required=False) mcad_id = forms.ChoiceField(label=_("MECA Catalog Name")) vim_id = forms.ChoiceField(label=_("VIM Name"), required=False) source_type = forms.ChoiceField( label=_('Parameter Value Source'), required=False, choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source' })) param_file = forms.FileField( label=_('Parameter Value File'), help_text=_('A local Parameter Value file to upload.'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Parameter Value File') }), required=False) direct_input = forms.CharField( label=_('Parameter Value YAML'), help_text=_('The YAML formatted contents of Parameter Values.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('Parameter Values') }), required=False) config_type = forms.ChoiceField( label=_('Configuration Value Source'), required=False, choices=[('file', _('File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'config' })) config_file = forms.FileField( label=_('Configuration Value File'), help_text=_('MECA Configuration file with YAML ' 'formatted contents to upload.'), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'config', 'data-config-file': _('Configuration Value File') }), required=False) config_input = forms.CharField( label=_('Configuration Value YAML'), help_text=_('YAML formatted MECA configuration text.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'config', 'data-config-raw': _('Configuration Values') }), required=False) def __init__(self, request, *args, **kwargs): super(DeployMECA, self).__init__(request, *args, **kwargs) try: mecad_list = api.apmec.mecad_list(request) available_choices_mecad = [(meca['id'], meca['name']) for meca in mecad_list] except Exception as e: available_choices_mecad = [] msg = _('Failed to retrieve available MECA Catalog nameca: %s') % e LOG.error(msg) try: vim_list = api.apmec.vim_list(request) available_choices_vims = [(vim['id'], vim['name']) for vim in vim_list] except Exception as e: available_choices_vims = [] msg = _('Failed to retrieve available VIM nameca: %s') % e LOG.error(msg) self.fields['mecad_id'].choices = [ ('', _('Select a MECA Catalog Name')) ] + available_choices_mecad self.fields['vim_id'].choices = [('', _('Select a VIM Name')) ] + available_choices_vims def clean(self): data = super(DeployMECA, self).clean() param_file = data.get('param_file', None) param_raw = data.get('direct_input', None) if param_raw and param_file: raise ValidationError( _("Cannot specify both file and direct input.")) if param_file and not param_file.name.endswith('.yaml'): raise ValidationError(_("Please upload .yaml file only.")) if param_file: data['param_values'] = self.files['param_file'].read() elif param_raw: data['param_values'] = data['direct_input'] else: data['param_values'] = None config_file = data.get('config_file', None) config_raw = data.get('config_input', None) if config_file and config_raw: raise ValidationError( _("Cannot specify both file and direct input.")) if config_file and not config_file.name.endswith('.yaml'): raise ValidationError(_("Only .yaml file uploads supported")) if config_file: data['config_values'] = self.files['config_file'].read() elif config_raw: data['config_values'] = data['config_input'] else: data['config_values'] = None return data def handle(self, request, data): try: meca_name = data['meca_name'] description = data['description'] mecad_id = data['mecad_id'] vim_id = data['vim_id'] param_val = data['param_values'] config_val = data['config_values'] meca_arg = { 'meca': { 'mecad_id': mecad_id, 'name': meca_name, 'description': description, 'vim_id': vim_id } } meca_attr = meca_arg['meca'].setdefault('attributes', {}) if param_val: meca_attr['param_values'] = param_val if config_val: meca_attr['config'] = config_val api.apmec.create_meca(request, meca_arg) mecasages.success( request, _('MECA %s create operation initiated.') % meca_name) return True except Exception as e: exceptions.handle(request, _('Failed to create MECA: %s') % e.message)
class AddCertificateAction(workflows.Action): multipart = True name = forms.CharField(max_length=255, label=_("Name")) key_source_choices = [('', _('Select Key Source')), ('raw', _('Direct Input')), ('file', _('File'))] cert_source_choices = [('', _('Select Certificate Source')), ('raw', _('Direct Input')), ('file', _('File'))] attributes = {'class': 'switchable', 'data-slug': 'keysource'} key_source = forms.ChoiceField(label=_('Key Source'), choices=key_source_choices, widget=forms.Select(attrs=attributes), required=True) key_file_help = _("Choose a file containing your private key.") key_paste_help = _("Paste a private key (max 16kb).") key_upload = forms.FileField(label=_('Key File'), help_text=key_file_help, widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'keysource', 'data-keysource-file': _('Key File') }), required=False) key_data = forms.CharField(label=_('Key Data'), help_text=key_paste_help, widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'keysource', 'data-keysource-raw': _('Key Data') }), required=False) passphrase = forms.CharField(max_length=255, widget=forms.PasswordInput(), label=_("Key Passphrase"), required=False) attributes = {'class': 'switchable', 'data-slug': 'certsource'} cert_source = forms.ChoiceField(label=_('Cert Source'), choices=cert_source_choices, widget=forms.Select(attrs=attributes), required=True) cert_file_help = _("Choose a file containing your certificate.") cert_paste_help = _("Paste a certificate (max 16kb).") cert_upload = forms.FileField( label=_('Cert File'), help_text=cert_file_help, widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'certsource', 'data-certsource-file': _('Cert File') }), required=False) cert_data = forms.CharField(label=_('Cert Data'), help_text=cert_paste_help, widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'certsource', 'data-certsource-raw': _('Cert Data') }), required=False) def __init__(self, request, *args, **kwargs): super(AddCertificateAction, self).__init__(request, *args, **kwargs) def clean(self): cleaned_data = super(AddCertificateAction, self).clean() files = self.request.FILES LOG.info("In cleanup files %s cleaned_date %s", files, cleaned_data) key = self.clean_uploaded_files('key', files) LOG.info("key: %s", key) if key is not None: cleaned_data['key_data'] = key cert = self.clean_uploaded_files('cert', files) LOG.info("cert: %s", cert) if cert is not None: cleaned_data['cert_data'] = cert return cleaned_data def clean_uploaded_files(self, prefix, files): upload_str = prefix + "_upload" has_upload = upload_str in files if has_upload: upload_file = files[upload_str] log_script_name = upload_file.name LOG.info('got upload %s' % log_script_name) if upload_file._size > 16 * 1024: # 16kb msg = _('File exceeds maximum size (16kb)') raise forms.ValidationError(msg) else: script = upload_file.read() LOG.info("script: %s", script) if script != "": try: normalize_newlines(script) except Exception as e: msg = _('There was a problem parsing the' ' %(prefix)s: %(error)s') msg = msg % {'prefix': prefix, 'error': e} raise forms.ValidationError(msg) return script else: return None class Meta(object): name = _("Add New Certificate") permissions = ('openstack.services.network', ) help_text = _("Use PEM for key and certificate format")
class OnBoardVNF(forms.SelfHandlingForm): name = forms.CharField(max_length=255, label=_("Name")) description = forms.CharField( widget=forms.widgets.Textarea(attrs={'rows': 4}), label=_("Description"), required=False) source_type = forms.ChoiceField( label=_('TOSCA Template Source'), required=False, choices=[('file', _('TOSCA Template File')), ('raw', _('Direct Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source' })) toscal_file = forms.FileField( label=_("TOSCA Template File"), help_text=_("A local TOSCA template file to upload."), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('TOSCA Template File') }), required=False) direct_input = forms.CharField( label=_('TOSCA YAML'), help_text=_('The YAML formatted contents of a TOSCA template.'), widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-raw': _('TOSCA YAML') }), required=False) def __init__(self, request, *args, **kwargs): super(OnBoardVNF, self).__init__(request, *args, **kwargs) def clean(self): data = super(OnBoardVNF, self).clean() # The key can be missing based on particular upload # conditions. Code defensively for it here... toscal_file = data.get('toscal_file', None) toscal_raw = data.get('direct_input', None) source_type = data.get("source_type") if source_type == "file" and not toscal_file: raise ValidationError(_("No TOSCA template file selected.")) if source_type == "raw" and not toscal_raw: raise ValidationError(_("No direct input specified.")) if toscal_file and not toscal_file.name.endswith(('.yaml', '.csar')): raise ValidationError( _("Only .yaml or .csar file uploads \ are supported")) try: if toscal_file: toscal_str = self.files['toscal_file'].read() else: toscal_str = data['direct_input'] # toscal = yaml.loads(toscal_str) data['tosca'] = toscal_str except Exception as e: msg = _('There was a problem loading the namespace: %s.') % e raise forms.ValidationError(msg) return data def handle(self, request, data): try: toscal = data['tosca'] vnfd_name = data['name'] vnfd_description = data['description'] tosca_arg = { 'vnfd': { 'name': vnfd_name, 'description': vnfd_description, 'attributes': { 'vnfd': toscal } } } vnfd_instance = api.tacker.create_vnfd(request, tosca_arg) messages.success( request, _('VNF Catalog entry %s has been created.') % vnfd_instance['vnfd']['name']) return toscal except Exception as e: msg = _('Unable to create TOSCA. %s') msg %= e.message.split('Failed validating', 1)[0] exceptions.handle(request, message=msg) return False
class CreateImageForm(forms.SelfHandlingForm): name = forms.CharField(max_length="255", label=_("Name"), required=True) description = forms.CharField(widget=forms.widgets.Textarea(), label=_("Description"), required=False) source_type = forms.ChoiceField( label=_('Image Source'), choices=[('url', _('Image Location')), ('file', _('Image File'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source' })) copy_from = forms.CharField(max_length="255", label=_("Image Location"), help_text=_("An external (HTTP) URL to load " "the image from."), widget=forms.TextInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-url': _('Image Location') }), required=False) image_file = forms.FileField(label=_("Image File"), help_text=_("A local image to upload."), widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Image File') }), required=False) disk_format = forms.ChoiceField( label=_('Format'), required=True, choices=[('', ''), ('aki', _('AKI - Amazon Kernel ' 'Image')), ('ami', _('AMI - Amazon Machine ' 'Image')), ('ari', _('ARI - Amazon Ramdisk ' 'Image')), ('iso', _('ISO - Optical Disk Image')), ('qcow2', _('QCOW2 - QEMU Emulator')), ('raw', 'Raw'), ('vdi', 'VDI'), ('vhd', 'VHD'), ('vmdk', 'VMDK')], widget=forms.Select(attrs={'class': 'switchable'})) minimum_disk = forms.IntegerField(label=_("Minimum Disk (GB)"), help_text=_( 'The minimum disk size' ' required to boot the' ' image. If unspecified, this' ' value defaults to 0' ' (no minimum).'), required=False) minimum_ram = forms.IntegerField(label=_("Minimum Ram (MB)"), help_text=_('The minimum disk size' ' required to boot the' ' image. If unspecified, this' ' value defaults to 0 (no' ' minimum).'), required=False) is_public = forms.BooleanField(label=_("Public"), required=False) protected = forms.BooleanField(label=_("Protected"), required=False) def __init__(self, *args, **kwargs): super(CreateImageForm, self).__init__(*args, **kwargs) if not settings.HORIZON_IMAGES_ALLOW_UPLOAD: self.fields['image_file'].widget = HiddenInput() def clean(self): data = super(CreateImageForm, self).clean() if not data['copy_from'] and not data['image_file']: raise ValidationError( _("A image or external image location must be specified.")) elif data['copy_from'] and data['image_file']: raise ValidationError( _("Can not specify both image and external image location.")) else: return data def handle(self, request, data): # Glance does not really do anything with container_format at the # moment. It requires it is set to the same disk_format for the three # Amazon image types, otherwise it just treats them as 'bare.' As such # we will just set that to be that here instead of bothering the user # with asking them for information we can already determine. if data['disk_format'] in ( 'ami', 'aki', 'ari', ): container_format = data['disk_format'] else: container_format = 'bare' meta = { 'is_public': data['is_public'], 'protected': data['protected'], 'disk_format': data['disk_format'], 'container_format': container_format, 'min_disk': (data['minimum_disk'] or 0), 'min_ram': (data['minimum_ram'] or 0), 'name': data['name'], 'properties': {} } if data['description']: meta['properties']['description'] = data['description'] if settings.HORIZON_IMAGES_ALLOW_UPLOAD and data['image_file']: meta['data'] = self.files['image_file'] else: meta['copy_from'] = data['copy_from'] try: image = api.glance.image_create(request, **meta) messages.success( request, _('Your image %s has been queued for creation.' % data['name'])) return image except: exceptions.handle(request, _('Unable to create new image.'))
class CreateImageForm(forms.SelfHandlingForm): name = forms.CharField(max_length="255", label=_("Name"), required=True) description = forms.CharField(widget=forms.widgets.Textarea( attrs={'class': 'modal-body-fixed-width'}), label=_("Description"), required=False) source_type = forms.ChoiceField( label=_('Image Source'), required=False, choices=[('url', _('Image Location')), ('file', _('Image File'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source'})) copy_from = forms.CharField(max_length="255", label=_("Image Location"), help_text=_("An external (HTTP) URL to load " "the image from."), widget=forms.TextInput(attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-url': _('Image Location')}), required=False) image_file = forms.FileField(label=_("Image File"), help_text=_("A local image to upload."), widget=forms.FileInput(attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-file': _('Image File')}), required=False) disk_format = forms.ChoiceField(label=_('Format'), required=True, choices=[], widget=forms.Select(attrs={'class': 'switchable'})) architecture = forms.CharField(max_length="255", label=_("Architecture"), required=False) minimum_disk = forms.IntegerField(label=_("Minimum Disk (GB)"), help_text=_('The minimum disk size' ' required to boot the' ' image. If unspecified, this' ' value defaults to 0' ' (no minimum).'), required=False) minimum_ram = forms.IntegerField(label=_("Minimum Ram (MB)"), help_text=_('The minimum memory size' ' required to boot the' ' image. If unspecified, this' ' value defaults to 0 (no' ' minimum).'), required=False) is_public = forms.BooleanField(label=_("Public"), required=False) protected = forms.BooleanField(label=_("Protected"), required=False) def __init__(self, request, *args, **kwargs): super(CreateImageForm, self).__init__(request, *args, **kwargs) if (not settings.HORIZON_IMAGES_ALLOW_UPLOAD or not policy.check((("image", "upload_image"),), request)): self._hide_file_source_type() if not policy.check((("image", "set_image_location"),), request): self._hide_url_source_type() if not policy.check((("image", "publicize_image"),), request): self._hide_is_public() self.fields['disk_format'].choices = IMAGE_FORMAT_CHOICES def _hide_file_source_type(self): self.fields['image_file'].widget = HiddenInput() source_type = self.fields['source_type'] source_type.choices = [choice for choice in source_type.choices if choice[0] != 'file'] if len(source_type.choices) == 1: source_type.widget = HiddenInput() def _hide_url_source_type(self): self.fields['copy_from'].widget = HiddenInput() source_type = self.fields['source_type'] source_type.choices = [choice for choice in source_type.choices if choice[0] != 'url'] if len(source_type.choices) == 1: source_type.widget = HiddenInput() def _hide_is_public(self): self.fields['is_public'].widget = HiddenInput() self.fields['is_public'].initial = False def clean(self): data = super(CreateImageForm, self).clean() # The image_file key can be missing based on particular upload # conditions. Code defensively for it here... image_file = data.get('image_file', None) image_url = data.get('copy_from', None) if not image_url and not image_file: raise ValidationError( _("A image or external image location must be specified.")) elif image_url and image_file: raise ValidationError( _("Can not specify both image and external image location.")) else: return data def handle(self, request, data): # Glance does not really do anything with container_format at the # moment. It requires it is set to the same disk_format for the three # Amazon image types, otherwise it just treats them as 'bare.' As such # we will just set that to be that here instead of bothering the user # with asking them for information we can already determine. if data['disk_format'] in ('ami', 'aki', 'ari',): container_format = data['disk_format'] else: container_format = 'bare' meta = {'is_public': data['is_public'], 'protected': data['protected'], 'disk_format': data['disk_format'], 'container_format': container_format, 'min_disk': (data['minimum_disk'] or 0), 'min_ram': (data['minimum_ram'] or 0), 'name': data['name'], 'properties': {}} if data['description']: meta['properties']['description'] = data['description'] if data['architecture']: meta['properties']['architecture'] = data['architecture'] if (settings.HORIZON_IMAGES_ALLOW_UPLOAD and policy.check((("image", "upload_image"),), request) and data.get('image_file', None)): meta['data'] = self.files['image_file'] else: meta['copy_from'] = data['copy_from'] try: image = api.glance.image_create(request, **meta) messages.success(request, _('Your image %s has been queued for creation.') % data['name']) return image except Exception: exceptions.handle(request, _('Unable to create new image.'))
class CreateForm(forms.SelfHandlingForm): source = forms.ChoiceField(label=_('Source'), choices=[('app_file', _('App File')), ('input', _('Input'))], widget=forms.Select(attrs={ 'class': 'switchable', 'data-slug': 'source' })) app_file = forms.FileField( label=_("Local app file location"), required=False, widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'source', 'data-source-app_file': _('Local app file location') })) name = forms.CharField(label=_("Application Name"), required=False, max_length=100) languagepack = forms.CharField(label=_("Languagepack"), required=False) git_url = forms.URLField(label=_("Source repository"), required=False) run_cmd = forms.CharField(label=_("Application entry point"), required=False) unittest_cmd = forms.CharField(label=_("Command to execute unit tests"), required=False) port = forms.IntegerField(label=_("The port your application listens on"), min_value=0, required=False) param_file = forms.FileField( label=_("A yaml file containing custom parameters"), required=False) def clean(self): cleaned_data = super(CreateForm, self).clean() import_type = cleaned_data.get('source') if import_type == 'app_file' and not cleaned_data.get('app_file'): msg = _('Please supply an app file') raise forms.ValidationError(msg) elif import_type == 'input': if not (cleaned_data.get('name')): msg = _('Please supply a name') raise forms.ValidationError(msg) elif not cleaned_data.get('languagepack'): msg = _('Please supply a languagepack') raise forms.ValidationError(msg) elif not cleaned_data.get('git_url'): msg = _('Please supply a github url') raise forms.ValidationError(msg) elif not cleaned_data.get('run_cmd'): msg = _('Please supply a run command') raise forms.ValidationError(msg) return cleaned_data def handle(self, request, data): LOG.info('CreateApplication %s' % data) solum = solumclient(request) app_data = None if data['source'] == 'app_file': inf = data['app_file'].read() app_data = yaml.load(inf) if 'repo_token' not in app_data: app_data['repo_token'] = '' else: app_data = { 'version': 1, 'description': 'default app description', 'source': { 'repository': '', 'revision': 'master', 'repo_token': '' }, 'workflow_config': { 'test_cmd': '', 'run_cmd': '' } } if data['name']: app_data['name'] = data['name'] if data['languagepack']: app_data['languagepack'] = data['languagepack'] if data['git_url']: app_data['source'] = dict() app_data['source']['repository'] = data['git_url'] app_data['source']['revision'] = 'master' if data['run_cmd']: if app_data.get('workflow_config') is None: app_data['workflow_config'] = dict() if not app_data['workflow_config']['run_cmd']: app_data['workflow_config']['run_cmd'] = data['run_cmd'] if data['unittest_cmd']: if app_data.get('workflow_config') is None: app_data['workflow_config'] = dict() if not app_data['workflow_config']['test_cmd']: app_data['workflow_config']['test_cmd'] = data['unittest_cmd'] if not app_data.get('ports'): app_data['ports'] = [] if data['port']: app_data['ports'].append(data['port']) else: app_data['ports'].append(80) if data['param_file']: param_def = data['param_file'].read() app_data['parameters'] = yaml.load(param_def) try: solum.apps.create(**app_data) messages.success(request, _('Application was successfully created.')) return True except Exception: msg = _('Unable to create application.') redirect = reverse("horizon:solum:applications:index") exceptions.handle(request, msg, redirect=redirect) return False
class CustomizeAction(workflows.Action): class Meta(object): name = _("Post-Creation") help_text_template = ("project/instances/" "_launch_customize_help.html") source_choices = [('', _('Select Script Source')), ('raw', _('Direct Input')), ('file', _('File'))] attributes = {'class': 'switchable', 'data-slug': 'scriptsource'} script_source = forms.ChoiceField(label=_('Customization Script Source'), choices=source_choices, widget=forms.Select(attrs=attributes), required=False) script_help = _("A script or set of commands to be executed after the " "instance has been built (max 16kb).") script_upload = forms.FileField( label=_('Script File'), help_text=script_help, widget=forms.FileInput( attrs={ 'class': 'switched', 'data-switch-on': 'scriptsource', 'data-scriptsource-file': _('Script File') }), required=False) script_data = forms.CharField( label=_('Script Data'), help_text=script_help, widget=forms.widgets.Textarea( attrs={ 'class': 'switched', 'data-switch-on': 'scriptsource', 'data-scriptsource-raw': _('Script Data') }), required=False) def __init__(self, *args): super(CustomizeAction, self).__init__(*args) def clean(self): cleaned = super(CustomizeAction, self).clean() files = self.request.FILES script = self.clean_uploaded_files('script', files) if script is not None: cleaned['script_data'] = script return cleaned def clean_uploaded_files(self, prefix, files): upload_str = prefix + "_upload" has_upload = upload_str in files if has_upload: upload_file = files[upload_str] log_script_name = upload_file.name LOG.info('got upload %s' % log_script_name) if upload_file._size > 16 * units.Ki: # 16kb msg = _('File exceeds maximum size (16kb)') raise forms.ValidationError(msg) else: script = upload_file.read() if script != "": try: normalize_newlines(script) except Exception as e: msg = _('There was a problem parsing the' ' %(prefix)s: %(error)s') msg = msg % { 'prefix': prefix, 'error': six.text_type(e) } raise forms.ValidationError(msg) return script else: return None
class TemplateForm(forms.SelfHandlingForm): class Meta(object): name = _('Select Template') help_text = _('Select a template to launch a stack.') # TODO(jomara) - update URL choice for template & environment files # w/ client side download when applicable base_choices = [('file', _('File')), ('raw', _('Direct Input'))] url_choice = [('url', _('URL'))] attributes = {'class': 'switchable', 'data-slug': 'templatesource'} template_source = forms.ChoiceField(label=_('Template Source'), choices=base_choices + url_choice, widget=forms.Select(attrs=attributes)) attributes = create_upload_form_attributes('template', 'file', _('Template File')) template_upload = forms.FileField( label=_('Template File'), help_text=_('A local template to upload.'), widget=forms.FileInput(attrs=attributes), required=False) attributes = create_upload_form_attributes('template', 'url', _('Template URL')) template_url = forms.URLField( label=_('Template URL'), help_text=_('An external (HTTP) URL to load the template from.'), widget=forms.TextInput(attrs=attributes), required=False) picklist = getattr(settings, 'OPENSTACK_HEAT_STACK_LIST', None) if (picklist != None): choices = [('', '')] base = (picklist) try: html_page = urllib2.urlopen(base) soup = BeautifulSoup(html_page, "html.parser") for link in soup.findAll('a'): choices.append( [urlparse.urljoin(base, link.get('href')), link.text]) template_url = forms.ChoiceField( label=_('Template URL'), choices=choices, widget=forms.Select(attrs=attributes), required=False) except: pass attributes = create_upload_form_attributes('template', 'raw', _('Template Data')) template_data = forms.CharField( label=_('Template Data'), help_text=_('The raw contents of the template.'), widget=forms.widgets.Textarea(attrs=attributes), required=False) attributes = {'data-slug': 'envsource', 'class': 'switchable'} environment_source = forms.ChoiceField( label=_('Environment Source'), choices=base_choices, widget=forms.Select(attrs=attributes), required=False) attributes = create_upload_form_attributes('env', 'file', _('Environment File')) environment_upload = forms.FileField( label=_('Environment File'), help_text=_('A local environment to upload.'), widget=forms.FileInput(attrs=attributes), required=False) attributes = create_upload_form_attributes('env', 'raw', _('Environment Data')) environment_data = forms.CharField( label=_('Environment Data'), help_text=_('The raw contents of the environment file.'), widget=forms.widgets.Textarea(attrs=attributes), required=False) if django.VERSION >= (1, 9): # Note(Itxaka): On django>=1.9 Charfield has an strip option that # we need to set to False as to not hit # https://bugs.launchpad.net/python-heatclient/+bug/1546166 environment_data.strip = False template_data.strip = False def __init__(self, *args, **kwargs): self.next_view = kwargs.pop('next_view') super(TemplateForm, self).__init__(*args, **kwargs) def clean(self): cleaned = super(TemplateForm, self).clean() files = self.request.FILES self.clean_uploaded_files('template', _('template'), cleaned, files) self.clean_uploaded_files('environment', _('environment'), cleaned, files) # Validate the template and get back the params. kwargs = {} if cleaned['environment_data']: kwargs['environment'] = cleaned['environment_data'] try: files, tpl =\ api.heat.get_template_files(cleaned.get('template_data'), cleaned.get('template_url')) kwargs['files'] = files kwargs['template'] = tpl validated = api.heat.template_validate(self.request, **kwargs) cleaned['template_validate'] = validated cleaned['template_validate']['files'] = files cleaned['template_validate']['template'] = tpl except Exception as e: raise forms.ValidationError(six.text_type(e)) return cleaned def clean_uploaded_files(self, prefix, field_label, cleaned, files): """Cleans Template & Environment data from form upload. Does some of the crunchy bits for processing uploads vs raw data depending on what the user specified. Identical process for environment data & template data. :type prefix: str :param prefix: prefix (environment, template) of field :type field_label: str :param field_label: translated prefix str for messages :type input_type: dict :param prefix: existing cleaned fields from form :rtype: dict :return: cleaned dict including environment & template data """ upload_str = prefix + "_upload" data_str = prefix + "_data" url = cleaned.get(prefix + '_url') data = cleaned.get(prefix + '_data') has_upload = upload_str in files # Uploaded file handler if has_upload and not url: log_template_name = files[upload_str].name LOG.info('got upload %s' % log_template_name) tpl = files[upload_str].read() if tpl.startswith('{'): try: json.loads(tpl) except Exception as e: msg = _('There was a problem parsing the' ' %(prefix)s: %(error)s') msg = msg % {'prefix': prefix, 'error': six.text_type(e)} raise forms.ValidationError(msg) cleaned[data_str] = tpl # URL handler elif url and (has_upload or data): msg = _('Please specify a %s using only one source method.') msg = msg % field_label raise forms.ValidationError(msg) elif prefix == 'template': # Check for raw template input - blank environment allowed if not url and not data: msg = _('You must specify a template via one of the ' 'available sources.') raise forms.ValidationError(msg) def create_kwargs(self, data): kwargs = { 'parameters': data['template_validate'], 'environment_data': data['environment_data'] } if data.get('stack_id'): kwargs['stack_id'] = data['stack_id'] return kwargs def handle(self, request, data): kwargs = self.create_kwargs(data) # NOTE (gabriel): This is a bit of a hack, essentially rewriting this # request so that we can chain it as an input to the next view... # but hey, it totally works. request.method = 'GET' return self.next_view.as_view()(request, **kwargs)