Merge "Submit generated template file directly"

This commit is contained in:
Zuul 2017-11-28 02:42:43 +00:00 committed by Gerrit Code Review
commit cb74de0857
11 changed files with 146 additions and 62 deletions

View File

@ -112,7 +112,7 @@ def _ignore_if(key, value):
@profiler.trace
def get_template_files(template_data=None, template_url=None):
def get_template_files(template_data=None, template_url=None, files=None):
if template_data:
tpl = template_data
elif template_url:
@ -125,7 +125,8 @@ def get_template_files(template_data=None, template_url=None):
if isinstance(tpl, six.binary_type):
tpl = tpl.decode('utf-8')
template = template_format.parse(tpl)
files = {}
if files is None:
files = {}
_get_file_contents(template, files)
return files, template
@ -138,6 +139,8 @@ def _get_file_contents(from_data, files):
for key, value in from_data.items():
if _ignore_if(key, value):
continue
if value in files:
continue
if not value.startswith(('http://', 'https://')):
raise exceptions.GetFileError(value, 'get_file')
if value not in files:

View File

@ -127,6 +127,10 @@ class TemplateForm(forms.SelfHandlingForm):
widget=forms.widgets.Textarea(attrs=attributes),
required=False)
referenced_files = forms.CharField(label=_('Referenced Files'),
widget=forms.widgets.HiddenInput,
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
@ -146,6 +150,12 @@ class TemplateForm(forms.SelfHandlingForm):
self.clean_uploaded_files('environment', _('environment'), cleaned,
files)
referenced_files = cleaned.get('referenced_files')
if referenced_files:
referenced_files = json.loads(referenced_files)
elif referenced_files == '':
referenced_files = {}
# Validate the template and get back the params.
kwargs = {}
if cleaned['environment_data']:
@ -153,7 +163,8 @@ class TemplateForm(forms.SelfHandlingForm):
try:
files, tpl =\
api.heat.get_template_files(cleaned.get('template_data'),
cleaned.get('template_url'))
cleaned.get('template_url'),
referenced_files)
kwargs['files'] = files
kwargs['template'] = tpl
validated = api.heat.template_validate(self.request, **kwargs)
@ -181,7 +192,6 @@ class TemplateForm(forms.SelfHandlingForm):
:rtype: dict
:return: cleaned dict including environment & template data
"""
upload_str = prefix + "_upload"
data_str = prefix + "_data"
url = cleaned.get(prefix + '_url')

View File

@ -4,4 +4,15 @@
{% block modal-body-right %}
<h3>{% trans "Description:" %}</h3>
<p>{% trans "Use one of the available template source options to specify the template to be used in creating this stack." %}</p>
<script type="text/javascript">
if (window.sessionStorage.generated == 'true'){
$("#id_template_data").val(window.sessionStorage.getItem("template"));
$("#id_referenced_files").val(window.sessionStorage.getItem("files"));
}
window.sessionStorage.setItem('generated', false);
// window.sessionStorage.removeItem('template');
</script>
{% endblock %}

View File

@ -0,0 +1,18 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{{ page_title }}{% endblock %}
{% block main %}{{ table.render }}{% endblock %}
{% block js %}
{% include "horizon/_scripts.html" %}
<script type="text/javascript">
$(document).ready(function(){
var session = window.sessionStorage;
if (session.getItem('generated') == 'true'){
$("#stacks__action_launch").attr('href', window.location.pathname+'select_template?template_source=raw');
$("#stacks__action_launch").click();
};
});
</script>
{% endblock %}

View File

@ -39,6 +39,7 @@ from horizon import views
class IndexView(tables.DataTableView):
table_class = project_tables.StacksTable
page_title = _("Stacks")
template_name = 'project/stacks/index.html'
def __init__(self, *args, **kwargs):
super(IndexView, self).__init__(*args, **kwargs)

View File

@ -12,23 +12,29 @@
import json
from openstack_dashboard import api
from openstack_dashboard import api as dashboard_api
from openstack_dashboard.api.neutron import neutronclient
from heat_dashboard import api
def get_resources(request):
volumes = [vol.to_dict() for vol in api.cinder.volume_list(request)]
volumes = [
vol.to_dict() for vol in dashboard_api.cinder.volume_list(request)]
volume_snapshots = [
volsnap.to_dict()
for volsnap in api.cinder.volume_snapshot_list(request)]
volume_types = [voltype.to_dict()
for voltype in api.cinder.volume_type_list(request)]
volume_backups = [volbackup.to_dict()
for volbackup in api.cinder.volume_backup_list(request)]
for volsnap in dashboard_api.cinder.volume_snapshot_list(request)]
volume_types = [
voltype.to_dict()
for voltype in dashboard_api.cinder.volume_type_list(request)]
volume_backups = [
volbackup.to_dict()
for volbackup in dashboard_api.cinder.volume_backup_list(request)]
images = [img.to_dict()
for img in api.glance.image_list_detailed(request)[0]]
images = [
img.to_dict()
for img in dashboard_api.glance.image_list_detailed(request)[0]]
neutron_client = neutronclient(request)
floatingips = neutron_client.list_floatingips().get('floatingips')
@ -41,13 +47,17 @@ def get_resources(request):
# qos_policies = neutron_client.list_security_groups().get('ports')
availability_zones = \
[az.to_dict() for az in api.nova.availability_zone_list(request)]
[az.to_dict()
for az in dashboard_api.nova.availability_zone_list(request)]
flavors = \
[flavor.to_dict() for flavor in api.nova.flavor_list(request)]
[flavor.to_dict()
for flavor in dashboard_api.nova.flavor_list(request)]
instances = \
[server.to_dict() for server in api.nova.server_list(request)[0]]
[server.to_dict()
for server in dashboard_api.nova.server_list(request)[0]]
keypairs = \
[keypair.to_dict() for keypair in api.nova.keypair_list(request)]
[keypair.to_dict()
for keypair in dashboard_api.nova.keypair_list(request)]
opts = {
'user_roles': request.user.roles,
@ -76,28 +86,31 @@ def get_resource_options(request):
volumes = [{'id': vol.id,
'name': vol.name if vol.name else '(%s)' % vol.id}
for vol in api.cinder.volume_list(request)]
for vol in dashboard_api.cinder.volume_list(request)]
volume_snapshots = [
{'id': volsnap.id,
'name': volsnap.name if volsnap.name else '(%s)' % volsnap.id[:6]}
for volsnap in api.cinder.volume_snapshot_list(request)]
for volsnap in dashboard_api.cinder.volume_snapshot_list(request)]
volume_types = [{
'id': voltype.id,
'name': voltype.name if voltype.name else '(%s)' % voltype.id[:6]}
for voltype in api.cinder.volume_type_list(request)]
volume_backups = [{'id': volbackup.id,
'name': volbackup.name
if volbackup.name else '(%s)' % volbackup.id[:6]}
for volbackup in api.cinder.volume_backup_list(request)]
for voltype in dashboard_api.cinder.volume_type_list(request)]
volume_backups = [
{'id': volbackup.id,
'name': volbackup.name
if volbackup.name else '(%s)' % volbackup.id[:6]}
for volbackup in dashboard_api.cinder.volume_backup_list(request)]
images = [{'id': img.id,
'name': img.name if img.name else '(%s)' % img.id[:6]}
for img in api.glance.image_list_detailed(request)[0]]
images = [
{'id': img.id,
'name': img.name if img.name else '(%s)' % img.id[:6]}
for img in dashboard_api.glance.image_list_detailed(request)[0]]
floatingips = [
{'id': fip.id, 'name': fip.floating_ip_address}
for fip in api.neutron.tenant_floating_ip_list(request, True)]
all_networks = api.neutron.network_list(request)
for fip in dashboard_api.neutron.tenant_floating_ip_list(
request, True)]
all_networks = dashboard_api.neutron.network_list(request)
networks = [{'id': nw.id,
'name': nw.name if nw.name else '(%s)' % nw.id[:6]}
for nw in all_networks if not nw['router:external']]
@ -108,44 +121,49 @@ def get_resource_options(request):
ports = [{'id': port.id,
'name': port.name if port.name else '(%s)' % port.id[:6]}
for port in api.neutron.port_list(request)]
for port in dashboard_api.neutron.port_list(request)]
security_groups = [
{'id': secgroup.id,
'name': secgroup.name
if secgroup.name else '(%s)' % secgroup.id[:6]}
for secgroup in api.neutron.security_group_list(request)]
all_subnets = api.neutron.subnet_list(request)
subnets = [{'id': subnet.id,
'name': subnet.name if subnet.name else '(%s)' % subnet.id[:6]}
for subnet in all_subnets]
for secgroup in dashboard_api.neutron.security_group_list(request)]
all_subnets = dashboard_api.neutron.subnet_list(request)
subnets = [
{'id': subnet.id,
'name': subnet.name if subnet.name else '(%s)' % subnet.id[:6]}
for subnet in all_subnets]
floating_subnets = [{'id': subnet.id, 'name': subnet.name}
for subnet in all_subnets
if subnet.network_id in floating_network_ids]
routers = [{'id': router.id,
'name': router.name if router.name else '(%s)' % router.id[:6]}
for router in api.neutron.router_list(request)]
routers = [
{'id': router.id,
'name': router.name if router.name else '(%s)' % router.id[:6]}
for router in dashboard_api.neutron.router_list(request)]
qos_policies = []
# qos_policies = [{'id': policy.id,
# 'name': policy.name
# if policy.name else '(%s)' % policy.id[:6]}
# for policy in api.neutron.policy_list(request)]
# qos_policies = [
# {'id': policy.id,
# 'name': policy.name
# if policy.name else '(%s)' % policy.id[:6]}
# for policy in dashboard_api.neutron.policy_list(request)]
availability_zones = [{'id': az.zoneName, 'name': az.zoneName}
for az in api.nova.availability_zone_list(request)]
availability_zones = [
{'id': az.zoneName, 'name': az.zoneName}
for az in dashboard_api.nova.availability_zone_list(request)]
flavors = [{'id': flavor.name, 'name': flavor.name}
for flavor in api.nova.flavor_list(request)]
for flavor in dashboard_api.nova.flavor_list(request)]
instances = [{'id': server.id,
'name': server.name
if server.name else '(%s)' % server.id[:6]}
for server in api.nova.server_list(request)[0]]
for server in dashboard_api.nova.server_list(request)[0]]
keypairs = [{'name': keypair.name}
for keypair in api.nova.keypair_list(request)]
for keypair in dashboard_api.nova.keypair_list(request)]
template_versions = [{'name': version.version, 'id': version.version}
for version in api.heat.template_version_list(request)
if version.type == 'hot']
template_versions = [
{'name': version.version, 'id': version.version}
for version in api.heat.template_version_list(request)
if version.type == 'hot']
opts = {
'auth': {

View File

@ -14,7 +14,7 @@
resource_options: {'auth': {'admin': false}},
template_version: null,
resource_outputs: {},
reference_file: {},
reference_files: {},
};
return {
@ -79,10 +79,13 @@
return Object.keys(globals.resource_icons);
},
set_reference_file: function(key, value){
globals.reference_file[key] = value;
globals.reference_files[key] = value;
},
get_reference_file: function(key){
return globals.reference_file[key];
return globals.reference_files[key];
},
get_reference_files: function(key){
return globals.reference_files;
},
};

View File

@ -5,8 +5,10 @@
.controller('horizon.dashboard.project.heat_dashboard.template_generator.TempModalController', ['$scope',
'$mdDialog', 'hotgenNotify', 'hotgenUtils', 'hotgenStates', 'hotgenGlobals',
'horizon.dashboard.project.heat_dashboard.template_generator.basePath',
function($scope, $mdDialog, hotgenNotify, hotgenUtils, hotgenStates, hotgenGlobals, basePath){
'horizon.dashboard.project.heat_dashboard.template_generator.projectPath',
function($scope, $mdDialog, hotgenNotify, hotgenUtils, hotgenStates, hotgenGlobals, basePath, projectPath){
$scope.basePath = basePath;
$scope.projectPath = projectPath;
$scope.dialogController = function ($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify) {
$scope.all_saved = false;
$scope.cancel = function() {
@ -22,11 +24,20 @@
hotgenNotify.show_success('Template is downloaded.');
};
$scope.save = function() {
hotgenNotify.show_warning('Not implemented yet. To submit to create a stack.')
$mdDialog.cancel();
$scope.redirect = function(){
var redirect = window.location.origin + projectPath + 'stacks/';
window.location.href = redirect;
};
$scope.save = function() {
var files = hotgenGlobals.get_reference_files();
sessionStorage.setItem('files', JSON.stringify(files));
sessionStorage.setItem('generated', true);
sessionStorage.setItem('template', $scope.template_contents);
$scope.redirect();
// $mdDialog.cancel();
};
$scope.extract_properties = function(resource_data){
for (var property in resource_data){
var func = null;

View File

@ -7,12 +7,13 @@
beforeEach(module('appTemplates'));
var hotgenGlobals, hotgenStates, hotgenNotify, basePath;
var hotgenGlobals, hotgenStates, hotgenNotify, basePath, projectPath;
beforeEach(inject(function($injector){
hotgenGlobals = $injector.get('hotgenGlobals');
hotgenStates = $injector.get('hotgenStates');
hotgenNotify = $injector.get('hotgenNotify');
basePath = $injector.get('horizon.dashboard.project.heat_dashboard.template_generator.basePath');
projectPath = $injector.get('horizon.dashboard.project.heat_dashboard.template_generator.projectPath');
}));
var $controller, controller, $scope, $rootScope, $mdDialog;
@ -83,9 +84,13 @@
it('$scope.dialogController save', function(){
$scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify);
$scope.redirect = jasmine.createSpy().and.callFake(function() {
return function(){return true};
});
$scope.save();
expect($mdDialog.cancel).toHaveBeenCalled();
expect($scope.redirect).toHaveBeenCalled();
});
it('$scope.dialogController extract_properties', function(){

View File

@ -20,8 +20,11 @@
});
}])
.config(['$provide', '$windowProvider', function($provide, $windowProvider){
var path = $windowProvider.$get().STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/';
$provide.constant('horizon.dashboard.project.heat_dashboard.template_generator.basePath', path);
var project_window = $windowProvider.$get();
var staticPath = project_window.STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/';
var projectPath = project_window.WEBROOT+'project/';
$provide.constant('horizon.dashboard.project.heat_dashboard.template_generator.basePath', staticPath);
$provide.constant('horizon.dashboard.project.heat_dashboard.template_generator.projectPath', projectPath);
}])
.constant('horizon.dashboard.project.heat_dashboard.template_generator.validationRules', {

View File

@ -35,7 +35,7 @@ from heat_dashboard.content.stacks import mappings
from heat_dashboard.content.stacks import tables
INDEX_TEMPLATE = 'horizon/common/_data_table_view.html'
INDEX_TEMPLATE = 'project/stacks/index.html'
INDEX_URL = reverse('horizon:project:stacks:index')
DETAIL_URL = 'horizon:project:stacks:detail'
@ -270,6 +270,7 @@ class StackTests(test.TestCase):
form_data = {'template_source': 'raw',
'template_data': template.data,
'referenced_files': {},
'method': forms.TemplateForm.__name__}
res = self.client.post(url, form_data)
self.assertTemplateUsed(res, 'project/stacks/create.html')