Merge "Add Metadata page to angular Launch Instance wizard"

This commit is contained in:
Jenkins 2016-01-14 03:05:44 +00:00 committed by Gerrit Code Review
commit 2b0747ca11
8 changed files with 196 additions and 10 deletions

View File

@ -113,7 +113,8 @@
metadataDefs: {
flavor: null,
image: null,
volume: null
volume: null,
instance: null
},
networks: [],
neutronEnabled: false,
@ -123,6 +124,7 @@
volumeBootable: false,
volumes: [],
volumeSnapshots: [],
metadataTree: null,
/**
* api methods for UI controllers
@ -244,6 +246,7 @@
setFinalSpecNetworks(finalSpec);
setFinalSpecKeyPairs(finalSpec);
setFinalSpecSecurityGroups(finalSpec);
setFinalSpecMetadata(finalSpec);
return novaAPI.createServer(finalSpec).then(successMessage);
}
@ -513,13 +516,25 @@
angular.extend(model.novaLimits, data.data);
}
// Instance metadata
function setFinalSpecMetadata(finalSpec) {
if (model.metadataTree) {
var meta = model.metadataTree.getExisting();
if (!angular.equals({}, meta)) {
angular.forEach(meta, function(value, key) {
meta[key] = value + '';
});
finalSpec.meta = meta;
}
}
}
// Metadata Definitions
/**
* Metadata definitions provide supplemental information in detail
* rows and should not slow down any of the other load processes.
* All code should be written to treat metadata definitions as
* optional, because they are never guaranteed to exist.
* Metadata definitions provide supplemental information in source image detail
* rows and are used on the metadata tab for adding metadata to the instance.
*/
function getMetadataDefinitions() {
// Metadata definitions often apply to multiple
@ -528,7 +543,8 @@
var resourceTypes = {
flavor: 'OS::Nova::Flavor',
image: 'OS::Glance::Image',
volume: 'OS::Cinder::Volumes'
volume: 'OS::Cinder::Volumes',
instance: 'OS::Nova::Instance'
};
angular.forEach(resourceTypes, applyForResourceType);

View File

@ -215,7 +215,8 @@
expect(model.metadataDefs.flavor).toBeNull();
expect(model.metadataDefs.image).toBeNull();
expect(model.metadataDefs.volume).toBeNull();
expect(Object.keys(model.metadataDefs).length).toBe(3);
expect(model.metadataDefs.instance).toBeNull();
expect(Object.keys(model.metadataDefs).length).toBe(4);
});
it('defaults "allow create volume from image" to false', function() {
@ -230,6 +231,10 @@
expect(model.volumeBootable).toBe(false);
});
it('defaults "metadataTree" to null', function() {
expect(model.metadataTree).toBe(null);
});
it('initializes "nova limits" to empty object', function() {
expect(model.novaLimits).toEqual({});
});
@ -386,6 +391,7 @@
});
describe('Create Instance', function() {
var metadata;
beforeEach(function() {
// initialize some data
@ -400,6 +406,13 @@
model.newInstanceSpec.vol_delete_on_instance_delete = true;
model.newInstanceSpec.vol_device_name = "volTestName";
model.newInstanceSpec.vol_size = 10;
metadata = {'foo': 'bar'};
model.metadataTree = {
getExisting: function() {
return metadata;
}
};
});
it('should set final spec in format required by Nova (Neutron disabled)', function() {
@ -523,6 +536,24 @@
var finalSpec = model.createInstance();
expect(finalSpec.block_device_mapping_v2[0].device_name).toBeNull();
});
it('should not have meta property if no metadata specified', function() {
metadata = {};
var finalSpec = model.createInstance();
expect(finalSpec.meta).toBeUndefined();
model.metadataTree = null;
finalSpec = model.createInstance();
expect(finalSpec.meta).toBeUndefined();
});
it('should have meta property if metadata specified', function() {
var finalSpec = model.createInstance();
expect(finalSpec.meta).toBe(metadata);
});
});
});
});

View File

@ -79,6 +79,12 @@
templateUrl: basePath + 'configuration/configuration.html',
helpUrl: basePath + 'configuration/configuration.help.html',
formName: 'launchInstanceConfigurationForm'
},
{
title: gettext('Metadata'),
templateUrl: basePath + 'metadata/metadata.html',
helpUrl: basePath + 'metadata/metadata.help.html',
formName: 'launchInstanceMetadataForm'
}
],

View File

@ -47,9 +47,9 @@
expect(launchInstanceWorkflow.title).toBeDefined();
});
it('should have the seven steps defined', function () {
it('should have the eight steps defined', function () {
expect(launchInstanceWorkflow.steps).toBeDefined();
expect(launchInstanceWorkflow.steps.length).toBe(7);
expect(launchInstanceWorkflow.steps.length).toBe(8);
var forms = [
'launchInstanceDetailsForm',
@ -58,7 +58,8 @@
'launchInstanceNetworkForm',
'launchInstanceAccessAndSecurityForm',
'launchInstanceKeypairForm',
'launchInstanceConfigurationForm'
'launchInstanceConfigurationForm',
'launchInstanceMetadataForm'
];
forms.forEach(function(expectedForm, idx) {

View File

@ -0,0 +1,17 @@
<div>
<h1 translate>Metadata Help</h1>
<p translate>
You can add arbitrary metadata to your instance so that you can more easily identify it among other running instances. Metadata is a collection of key-value pairs associated with an instance. The maximum length for each metadata key and value is 255 characters.
</p>
<p>
<span translate>
The maximum number of key-value pairs that can be supplied per instance is determined by the compute provider.
</span>
<span ng-if="model.novaLimits.maxServerMeta > -1" translate>
This limit is currently set to {$ model.novaLimits.maxServerMeta $}.
</span>
<span ng-if="model.novaLimits.maxServerMeta <= -1" translate>
This limit is currently not set.
</span>
</p>
</div>

View File

@ -0,0 +1,14 @@
<div>
<h1 translate>Metadata</h1>
<div class="content">
<metadata-tree
ng-if="model.metadataDefs.instance && model.novaLimits"
available="::model.metadataDefs.instance"
existing="{}"
max-key-length="255"
max-value-length="255"
max-item-count="::model.novaLimits.maxServerMeta"
model="::model.metadataTree">
</metadata-tree>
</div>
</div>

View File

@ -0,0 +1,96 @@
/*
* Copyright 2015 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function() {
'use strict';
describe('Launch Instance Metadata Step', function() {
describe('metadata tree', function() {
var $scope, $element, model;
beforeEach(module('templates'));
beforeEach(module('horizon.dashboard.project.workflow.launch-instance'));
beforeEach(inject(function($injector) {
var $compile = $injector.get('$compile');
var $templateCache = $injector.get('$templateCache');
var basePath = $injector.get('horizon.dashboard.project.workflow.launch-instance.basePath');
var markup = $templateCache.get(basePath + 'metadata/metadata.html');
model = {
metadataDefs: { instance: false },
novaLimits: false
};
$scope = $injector.get('$rootScope').$new();
$scope.model = model;
$element = $compile(markup)($scope);
}));
it('should create metadata tree only after dependencies are received', function() {
expect($element.find('metadata-tree').length).toBe(0);
model.metadataDefs.instance = {};
$scope.$apply();
expect($element.find('metadata-tree').length).toBe(0);
model.novaLimits = {};
$scope.$apply();
expect($element.find('metadata-tree').length).toBe(1);
});
});
describe('metadata step help', function() {
var $scope, $element, model;
beforeEach(module('templates'));
beforeEach(module('horizon.dashboard.project.workflow.launch-instance'));
beforeEach(inject(function($injector) {
var $compile = $injector.get('$compile');
var $templateCache = $injector.get('$templateCache');
var basePath = $injector.get('horizon.dashboard.project.workflow.launch-instance.basePath');
var markup = $templateCache.get(basePath + 'metadata/metadata.help.html');
$scope = $injector.get('$rootScope').$new();
model = {
novaLimits: {
maxServerMeta: null
}
};
$scope.model = model;
$element = $compile(markup)($scope);
}));
it('should update message based on nova limit', function() {
expect($element.find('p+p>span').length).toBe(1);
model.novaLimits.maxServerMeta = -1;
$scope.$apply();
expect($element.find('p+p>span').length).toBe(2);
expect($element.find('p+p>span:last-child').text().trim())
.toBe('This limit is currently not set.');
model.novaLimits.maxServerMeta = 5;
$scope.$apply();
expect($element.find('p+p>span').length).toBe(2);
expect($element.find('p+p>span:last-child').text().trim())
.toMatch(/^This limit is currently set to/);
});
});
});
})();

View File

@ -0,0 +1,5 @@
---
features:
- Added the Metadata tab to the new Launch Instance workflow to allow adding
key-value metadata to an instance at launch. This includes any properties
from the OS::Nova::Instance namespace of the glance metadata definitions.