Add create action to containers panel
This patch adds create button to containers table action, and container create form as workflow dialog. Implements: blueprint container-create Change-Id: I7e47e80109ed5b25b62f5fb774ec3a7610c8caef
This commit is contained in:
parent
552a9ee56f
commit
c955cba77c
@ -106,14 +106,14 @@ def bay_show(request, id):
|
||||
return magnumclient(request).bays.get(id)
|
||||
|
||||
|
||||
def container_create(request, bay_id, **kwargs):
|
||||
def container_create(request, bay_uuid, **kwargs):
|
||||
"""Creates a container object
|
||||
:param request: Request context
|
||||
:param bay_id: ID of a bay (Required)
|
||||
:param bay_uuid: ID of a bay (Required)
|
||||
:param kwargs: Image ID, Name, Command, Memory
|
||||
:returns: Container object
|
||||
"""
|
||||
return magnumclient(request).containers.create(bay_id=bay_id, **kwargs)
|
||||
return magnumclient(request).containers.create(bay_uuid=bay_uuid, **kwargs)
|
||||
|
||||
|
||||
def container_delete(request, id):
|
||||
|
@ -7,3 +7,4 @@
|
||||
|
||||
@import "baymodel/baymodel";
|
||||
@import "bay/bay";
|
||||
@import "containers/containers";
|
||||
|
@ -0,0 +1,2 @@
|
||||
// Custom Style Variables
|
||||
@import "create/info/info";
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright 2015 Cisco Systems, Inc.
|
||||
*
|
||||
* 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';
|
||||
|
||||
angular
|
||||
.module('horizon.dashboard.containers.containers')
|
||||
.factory('containerModel', containerModel);
|
||||
|
||||
containerModel.$inject = [
|
||||
'horizon.app.core.openstack-service-api.magnum'
|
||||
];
|
||||
|
||||
function containerModel(magnum) {
|
||||
var model = {
|
||||
newContainerSpec: {},
|
||||
|
||||
// API methods
|
||||
init: init,
|
||||
createContainer: createContainer
|
||||
};
|
||||
|
||||
function initNewContainerSpec() {
|
||||
model.newContainerSpec = {
|
||||
name: null,
|
||||
bay_uuid: null,
|
||||
image: null,
|
||||
memory: null,
|
||||
memorysize: null,
|
||||
memoryunit: "m",
|
||||
command: null
|
||||
};
|
||||
}
|
||||
|
||||
function init() {
|
||||
// Reset the new Bay spec
|
||||
initNewContainerSpec();
|
||||
}
|
||||
|
||||
function createContainer() {
|
||||
var finalSpec = angular.copy(model.newContainerSpec);
|
||||
|
||||
cleanNullProperties(finalSpec);
|
||||
|
||||
return magnum.createContainer(finalSpec);
|
||||
}
|
||||
|
||||
function cleanNullProperties(finalSpec) {
|
||||
// Initially clean fields that don't have any value.
|
||||
for (var key in finalSpec) {
|
||||
if (finalSpec.hasOwnProperty(key) && finalSpec[key] === null
|
||||
|| key === "memorysize" || key === "memoryunit") {
|
||||
delete finalSpec[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
})();
|
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright 2015 Cisco Systems, Inc.
|
||||
*
|
||||
* 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';
|
||||
|
||||
angular
|
||||
.module('horizon.dashboard.containers.containers')
|
||||
.factory('horizon.dashboard.containers.containers.workflow', containerWorkflow);
|
||||
|
||||
containerWorkflow.$inject = [
|
||||
'horizon.dashboard.containers.basePath',
|
||||
'horizon.app.core.workflow.factory'
|
||||
];
|
||||
|
||||
function containerWorkflow(basePath, dashboardWorkflow) {
|
||||
return dashboardWorkflow({
|
||||
title: gettext('Create Container'),
|
||||
|
||||
steps: [
|
||||
{
|
||||
title: gettext('Info'),
|
||||
templateUrl: basePath + 'containers/create/info/info.html',
|
||||
helpUrl: basePath + 'containers/create/info/info.help.html',
|
||||
formName: 'containerInfoForm'
|
||||
},
|
||||
{
|
||||
title: gettext('Spec'),
|
||||
templateUrl: basePath + 'containers/create/spec/spec.html',
|
||||
helpUrl: basePath + 'containers/create/spec/spec.help.html',
|
||||
formName: 'containerSpecForm'
|
||||
}
|
||||
],
|
||||
|
||||
btnText: {
|
||||
finish: gettext('Create')
|
||||
},
|
||||
|
||||
btnIcon: {
|
||||
finish: 'fa fa-cloud-download'
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright 2015 NEC Corporation
|
||||
*
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name createContainerInfoController
|
||||
* @ngController
|
||||
*
|
||||
* @description
|
||||
* Controller for the container info step in create workflow
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.containers.containers')
|
||||
.controller('createContainerInfoController', createContainerInfoController);
|
||||
|
||||
createContainerInfoController.$inject = [
|
||||
'$q',
|
||||
'$scope',
|
||||
'horizon.dashboard.containers.basePath',
|
||||
'horizon.app.core.openstack-service-api.magnum'
|
||||
];
|
||||
|
||||
function createContainerInfoController($q, $scope, basePath, magnum) {
|
||||
var ctrl = this;
|
||||
ctrl.bays = [{id:"", name: gettext("Choose a Bay")}];
|
||||
$scope.model.newContainerSpec.bay_uuid = "";
|
||||
$scope.baydetail = {
|
||||
name: "",
|
||||
id: "",
|
||||
baymodel: "",
|
||||
master_count: "",
|
||||
node_count: "",
|
||||
discovery_url: "",
|
||||
timeout: ""
|
||||
};
|
||||
|
||||
$scope.changeBay = function(){
|
||||
// show Bay Detail
|
||||
if(!$scope.model.newContainerSpec.bay_uuid){
|
||||
$("#bay_detail").hide();
|
||||
$("#bay_detail_none").show();
|
||||
} else {
|
||||
angular.forEach(ctrl.bays, function(bay, idx){
|
||||
if($scope.model.newContainerSpec.bay_uuid === bay.id){
|
||||
$("#bay_detail").show();
|
||||
$("#bay_detail_none").hide();
|
||||
$scope.baydetail.name = bay.name;
|
||||
$scope.baydetail.id = bay.id;
|
||||
$scope.baydetail.baymodel_id = bay.baymodel_id;
|
||||
$scope.baydetail.master_count = bay.master_count;
|
||||
$scope.baydetail.node_count = bay.node_count;
|
||||
$scope.baydetail.discovery_url = bay.discovery_url;
|
||||
$scope.baydetail.timeout = bay.timeout;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
$("#bay_detail").hide();
|
||||
$("#bay_detail_none").show();
|
||||
|
||||
function init() {
|
||||
magnum.getBays({paginate: false}).success(onGetBays);
|
||||
}
|
||||
|
||||
function onGetBays(response) {
|
||||
Array.prototype.push.apply(ctrl.bays, response.items);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<h3 translate>Description:</h3>
|
||||
<p translate>Specify container name and choose bay.</p>
|
||||
</div>
|
@ -0,0 +1,47 @@
|
||||
<div ng-controller="createContainerInfoController as ctrl">
|
||||
<h1 translate>Container Details</h1>
|
||||
|
||||
<div class="content">
|
||||
<div translate class="subtitle">Please provide the name of the Container.</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-field container-name">
|
||||
<label class="on-top" translate>Container Name</label>
|
||||
<input name="container-name" type="text" class="form-control input-sm"
|
||||
ng-model="model.newContainerSpec.name"
|
||||
placeholder="{$ 'Name of the container to create.'|translate $}">
|
||||
</div>
|
||||
<div class="form-field required container-model">
|
||||
<label class="on-top" translate>Bay</label>
|
||||
<select class="form-control" name="container-bay"
|
||||
ng-model="model.newContainerSpec.bay_uuid"
|
||||
ng-required="true"
|
||||
ng-options="bay.id as bay.name for bay in ctrl.bays"
|
||||
ng-change="changeBay()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 translate class="section-title">Bay Detail</h2>
|
||||
<div class="subtitle" id="bay_detail_none" translate>
|
||||
Choose a Bay
|
||||
</div>
|
||||
<div class="subtitle" id="bay_detail">
|
||||
<dl class=dl-horizontal>
|
||||
<dt translate>Name</dt>
|
||||
<dd>{$ baydetail.name $}</dd>
|
||||
<dt translate>ID</dt>
|
||||
<dd>{$ baydetail.id $}</dd>
|
||||
<dt translate>BayModel ID</dt>
|
||||
<dd>{$ baydetail.baymodel_id $}</dd>
|
||||
<dt translate>Master Count</dt>
|
||||
<dd>{$ baydetail.master_count $}</dd>
|
||||
<dt translate>Node Count</dt>
|
||||
<dd>{$ baydetail.node_count $}</dd>
|
||||
<dt translate>Timeout</dt>
|
||||
<dd>{$ baydetail.timeout $}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,13 @@
|
||||
.container-memory {
|
||||
.input-group {
|
||||
width: 100%;
|
||||
|
||||
.container-memorysize {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.container-memoryunit {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright 2015 Cisco Systems, Inc.
|
||||
*
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name containersContainerModalController
|
||||
* @ngController
|
||||
*
|
||||
* @description
|
||||
* Controller for the container create modal
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.containers.containers')
|
||||
.controller('containersContainerModalController', containersContainerModalController);
|
||||
|
||||
containersContainerModalController.$inject = [
|
||||
'$modal',
|
||||
'$window',
|
||||
'horizon.dashboard.containers.basePath',
|
||||
'horizon.app.core.openstack-service-api.magnum'
|
||||
];
|
||||
|
||||
function containersContainerModalController($modal, $window, basePath, magnum) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.openContainerCreateWizard = openContainerCreateWizard;
|
||||
|
||||
function openContainerCreateWizard(launchContext) {
|
||||
var options = {
|
||||
controller: 'ModalContainerController',
|
||||
backdrop: 'static',
|
||||
template: '<wizard ng-controller="createContainerWizardController"></wizard>',
|
||||
windowClass: 'modal-dialog-wizard',
|
||||
resolve: {
|
||||
launchContext: function() {
|
||||
return launchContext;
|
||||
}
|
||||
}
|
||||
};
|
||||
var launchInstanceModal = $modal.open(options);
|
||||
var handleModalClose = function (redirectPropertyName) {
|
||||
return function () {
|
||||
if (launchContext && launchContext[redirectPropertyName]) {
|
||||
$window.location.href = launchContext[redirectPropertyName];
|
||||
}
|
||||
};
|
||||
};
|
||||
launchInstanceModal.result.then(
|
||||
handleModalClose('successUrl'),
|
||||
handleModalClose('dismissUrl')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright 2015 NEC Corporation
|
||||
*
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name createContainerSpecController
|
||||
* @ngController
|
||||
*
|
||||
* @description
|
||||
* Controller for the container spec step in create workflow
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.containers.containers')
|
||||
.controller('createContainerSpecController', createContainerSpecController);
|
||||
|
||||
createContainerSpecController.$inject = [
|
||||
'$q',
|
||||
'$scope',
|
||||
'horizon.dashboard.containers.basePath',
|
||||
'horizon.app.core.openstack-service-api.magnum'
|
||||
];
|
||||
|
||||
function createContainerSpecController($q, $scope, basePath, magnum) {
|
||||
var ctrl = this;
|
||||
ctrl.memoryunits = [{unit: "b", label: gettext("bytes")},
|
||||
{unit: "k", label: gettext("KB")},
|
||||
{unit: "m", label: gettext("MB")},
|
||||
{unit: "g", label: gettext("GB")}];
|
||||
|
||||
$scope.changeMemory = function(){
|
||||
if($scope.model.newContainerSpec.memorysize > 0){
|
||||
$scope.model.newContainerSpec.memory = $scope.model.newContainerSpec.memorysize + $scope.model.newContainerSpec.memoryunit;
|
||||
}else{
|
||||
$scope.model.newContainerSpec.memory = "";
|
||||
}
|
||||
};
|
||||
$scope.changeMemoryUnit = function(){
|
||||
$scope.changeMemory();
|
||||
};
|
||||
$scope.changeMemorySize = function(){
|
||||
$scope.changeMemory();
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<h3 translate>Description:</h3>
|
||||
<p translate>Specify the specs for the container.</p>
|
||||
</div>
|
@ -0,0 +1,44 @@
|
||||
<div ng-controller="createContainerSpecController as ctrl">
|
||||
<h1 translate>Container Spec</h1>
|
||||
|
||||
<div class="content">
|
||||
<div translate class="subtitle">Please provide the specs for this Container.</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-field required container-image">
|
||||
<label class="on-top" translate>Image</label>
|
||||
<input name="container-image" type="text"
|
||||
class="form-control input-sm"
|
||||
ng-required="true"
|
||||
ng-model="model.newContainerSpec.image"
|
||||
placeholder="{$ 'Name of the container image.'|translate $}">
|
||||
</div>
|
||||
<div class="form-field container-memory">
|
||||
<label class="on-top" translate>Memory</label>
|
||||
<div class="input-group">
|
||||
<input name="container-memorysize" type="number" ng-pattern="/^[0-9]+$/"
|
||||
class="form-control form-inline input-sm container-memorysize"
|
||||
ng-model="model.newContainerSpec.memorysize"
|
||||
placeholder="{$ 'The container memory size.'|translate $}"
|
||||
ng-change="changeMemorySize()">
|
||||
<select name="container-memoryunit"
|
||||
class="form-control form-inline input-sm container-memoryunit"
|
||||
ng-options="mu.unit as mu.label for mu in ctrl.memoryunits"
|
||||
ng-model="model.newContainerSpec.memoryunit"
|
||||
ng-change="changeMemoryUnit()">
|
||||
</select>
|
||||
</div>
|
||||
<input name="container-memory" type="hidden"
|
||||
ng-model="model.newContainerSpec.memory">
|
||||
</div>
|
||||
<div class="form-field container-command">
|
||||
<label class="on-top" translate>Command</label>
|
||||
<input name="container-command" type="text"
|
||||
class="form-control input-sm"
|
||||
ng-model="model.newContainerSpec.command"
|
||||
placeholder="{$ 'Send command to the contaier in a line.'|translate $}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright 2015 Cisco Systems, Inc.
|
||||
*
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name createContainerWizardController
|
||||
* @ngController
|
||||
*
|
||||
* @description
|
||||
* Controller for the container create modal
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.containers.containers')
|
||||
.controller('createContainerWizardController', createContainerWizardController);
|
||||
|
||||
createContainerWizardController.$inject = [
|
||||
'$scope',
|
||||
'containerModel',
|
||||
'horizon.dashboard.containers.containers.workflow'
|
||||
];
|
||||
|
||||
function createContainerWizardController($scope, model, workflow) {
|
||||
$scope.workflow = workflow;
|
||||
$scope.model = model;
|
||||
$scope.model.init();
|
||||
$scope.submit = $scope.model.createContainer;
|
||||
}
|
||||
|
||||
})();
|
@ -20,6 +20,14 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="100" class="action-col">
|
||||
<action-list class="btn-addon">
|
||||
<a href="javascipt:void(0);"
|
||||
class="btn btn-default btn-sm btn-launch ng-scope"
|
||||
ng-controller="containersContainerModalController as modal"
|
||||
ng-click="modal.openContainerCreateWizard({successUrl: '/containers/containers/'})">
|
||||
<span class="fa fa-plus"> <translate>Create Container</translate></span>
|
||||
</a>
|
||||
</action-list>
|
||||
<action-list class="btn-addon">
|
||||
<action
|
||||
action-classes="'btn btn-default btn-sm btn-danger'"
|
||||
|
@ -34,6 +34,7 @@
|
||||
getBayModels: getBayModels,
|
||||
deleteBayModel: deleteBayModel,
|
||||
deleteBayModels: deleteBayModels,
|
||||
createContainer: createContainer,
|
||||
getContainers: getContainers,
|
||||
deleteContainer: deleteContainer,
|
||||
deleteContainers: deleteContainers,
|
||||
@ -104,6 +105,13 @@
|
||||
// Containers //
|
||||
////////////////
|
||||
|
||||
function createContainer(params) {
|
||||
return apiService.post('/api/containers/containers/', params)
|
||||
.error(function() {
|
||||
toastService.add('error', gettext('Unable to create Container.'));
|
||||
});
|
||||
}
|
||||
|
||||
function getContainers() {
|
||||
return apiService.get('/api/containers/containers/')
|
||||
.error(function() {
|
||||
|
@ -54,7 +54,7 @@ class MagnumApiTests(test.APITestCase):
|
||||
|
||||
def test_container_create(self):
|
||||
container = self.magnum_containers.first()
|
||||
form_data = {'bay_id': container['bay'],
|
||||
form_data = {'bay_uuid': container['bay'],
|
||||
'name': container['name']}
|
||||
|
||||
magnumclient = self.stub_magnumclient()
|
||||
|
Loading…
Reference in New Issue
Block a user