Merge "Add Manage Security Groups action for container"
This commit is contained in:
commit
4d7dcaa3dd
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- >
|
||||
[`manage-security-groups <https://blueprints.launchpad.net/zun-ui/+spec/manage-security-groups>`_]
|
||||
Added Manage Security Groups action to manage associations between
|
||||
security groups and ports on container.
|
@ -10,16 +10,19 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon.utils.memoized import memoized_with_request
|
||||
import logging
|
||||
from openstack_dashboard.api import base
|
||||
|
||||
from neutronclient.v2_0 import client as neutron_client
|
||||
from zunclient import api_versions
|
||||
from zunclient.common import utils
|
||||
from zunclient.v1 import client as zun_client
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
CONTAINER_CREATE_ATTRS = zun_client.containers.CREATION_ATTRIBUTES
|
||||
@ -65,6 +68,33 @@ def zunclient(request_auth_params):
|
||||
return c
|
||||
|
||||
|
||||
def get_auth_params_from_request_neutron(request):
|
||||
"""Extracts properties needed by neutronclient call from the request object.
|
||||
|
||||
These will be used to memoize the calls to neutronclient.
|
||||
"""
|
||||
return (
|
||||
request.user.token.id,
|
||||
base.url_for(request, 'network'),
|
||||
base.url_for(request, 'identity')
|
||||
)
|
||||
|
||||
|
||||
@memoized_with_request(get_auth_params_from_request_neutron)
|
||||
def neutronclient(request_auth_params):
|
||||
token_id, neutron_url, auth_url = request_auth_params
|
||||
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
||||
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
|
||||
|
||||
LOG.debug('neutronclient connection created using the token "%s" and url'
|
||||
' "%s"' % (token_id, neutron_url))
|
||||
c = neutron_client.Client(token=token_id,
|
||||
auth_url=auth_url,
|
||||
endpoint_url=neutron_url,
|
||||
insecure=insecure, ca_cert=cacert)
|
||||
return c
|
||||
|
||||
|
||||
def _cleanup_params(attrs, check, **params):
|
||||
args = {}
|
||||
run = False
|
||||
@ -229,6 +259,14 @@ def container_network_detach(request, id):
|
||||
return {"container": id, "network": network}
|
||||
|
||||
|
||||
def port_update_security_groups(request):
|
||||
port = request.DATA.get("port") or None
|
||||
security_groups = request.DATA.get("security_groups") or None
|
||||
kwargs = {"security_groups": security_groups}
|
||||
neutronclient(request).update_port(port, body={"port": kwargs})
|
||||
return {"port": port, "security_group": security_groups}
|
||||
|
||||
|
||||
def image_list(request, limit=None, marker=None, sort_key=None,
|
||||
sort_dir=None, detail=True):
|
||||
return zunclient(request).images.list(limit, marker, sort_key,
|
||||
|
@ -90,6 +90,8 @@ class ContainerActions(generic.View):
|
||||
return client.container_network_attach(request, id)
|
||||
elif action == 'network_detach':
|
||||
return client.container_network_detach(request, id)
|
||||
elif action == 'port_update_security_groups':
|
||||
return client.port_update_security_groups(request)
|
||||
|
||||
@rest_utils.ajax(data_required=True)
|
||||
def delete(self, request, id, action):
|
||||
|
@ -45,6 +45,7 @@
|
||||
'horizon.dashboard.container.containers.execute.service',
|
||||
'horizon.dashboard.container.containers.kill.service',
|
||||
'horizon.dashboard.container.containers.refresh.service',
|
||||
'horizon.dashboard.container.containers.manage-security-groups.service',
|
||||
'horizon.dashboard.container.containers.resourceType'
|
||||
];
|
||||
|
||||
@ -64,6 +65,7 @@
|
||||
executeContainerService,
|
||||
killContainerService,
|
||||
refreshContainerService,
|
||||
manageSecurityGroupService,
|
||||
resourceType
|
||||
) {
|
||||
var containersResourceType = registry.getResourceType(resourceType);
|
||||
@ -103,6 +105,13 @@
|
||||
text: gettext('Update Container')
|
||||
}
|
||||
})
|
||||
.append({
|
||||
id: 'manageSecurityGroupService',
|
||||
service: manageSecurityGroupService,
|
||||
template: {
|
||||
text: gettext('Manage Security Groups')
|
||||
}
|
||||
})
|
||||
.append({
|
||||
id: 'startContainerAction',
|
||||
service: startContainerService,
|
||||
|
@ -89,6 +89,8 @@
|
||||
delete context.model.ports;
|
||||
delete context.model.availableNetworks;
|
||||
delete context.model.allocatedNetworks;
|
||||
delete context.model.availableSecurityGroups;
|
||||
delete context.model.allocatedSecurityGroups;
|
||||
delete context.model.availablePorts;
|
||||
context.model.hints = setSchedulerHints(context.model);
|
||||
delete context.model.availableHints;
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 horizon.dashboard.container.containers.manage-security-groups.delete.service
|
||||
* @description Service for the security group deletion for manage-security-groups modal
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.container.containers')
|
||||
.constant('horizon.dashboard.container.containers.manage-security-groups.delete.events',
|
||||
events())
|
||||
.factory('horizon.dashboard.container.containers.manage-security-groups.delete.service',
|
||||
service);
|
||||
|
||||
function events() {
|
||||
return {
|
||||
DELETE_SUCCESS: 'horizon.dashboard.container.containers.manage-security-groups.DELETE_SUCCESS'
|
||||
};
|
||||
}
|
||||
|
||||
service.$inject = [
|
||||
'horizon.framework.util.q.extensions',
|
||||
'horizon.dashboard.container.containers.manage-security-groups.delete.events'
|
||||
];
|
||||
|
||||
function service(
|
||||
$qExtensions,
|
||||
events
|
||||
) {
|
||||
var service = {
|
||||
allowed: allowed,
|
||||
perform: perform
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
function allowed() {
|
||||
return $qExtensions.booleanAsPromise(true);
|
||||
}
|
||||
|
||||
function perform(selected, scope) {
|
||||
scope.$emit(events.DELETE_SUCCESS, selected);
|
||||
return $qExtensions.booleanAsPromise(true);
|
||||
}
|
||||
}
|
||||
})();
|
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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 horizon.dashboard.container.containers.manage-security-groups
|
||||
* @description
|
||||
* Controller for the Manage Security Groups dialog.
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.container.containers')
|
||||
.controller('horizon.dashboard.container.containers.manage-security-groups',
|
||||
ManageSecurityGroupsController);
|
||||
|
||||
ManageSecurityGroupsController.$inject = [
|
||||
'$scope',
|
||||
'horizon.app.core.openstack-service-api.neutron',
|
||||
'horizon.app.core.openstack-service-api.security-group',
|
||||
'horizon.dashboard.container.containers.manage-security-groups.delete.service',
|
||||
'horizon.dashboard.container.containers.manage-security-groups.delete.events'
|
||||
];
|
||||
|
||||
function ManageSecurityGroupsController(
|
||||
$scope, neutron, securityGroup, deleteSecurityGroupService, events
|
||||
) {
|
||||
var ctrl = this;
|
||||
|
||||
// form settings to add association of port and security group into table ///////////
|
||||
// model template
|
||||
ctrl.modelTemplate = {
|
||||
id: "",
|
||||
port: "",
|
||||
port_name: "",
|
||||
security_group: "",
|
||||
security_group_name: ""
|
||||
};
|
||||
|
||||
// initiate model
|
||||
ctrl.model = angular.copy(ctrl.modelTemplate);
|
||||
|
||||
// for port selection
|
||||
ctrl.availablePorts = [
|
||||
{id: "", name: gettext("Select port.")}
|
||||
];
|
||||
|
||||
// for security group selection
|
||||
var message = {
|
||||
portNotSelected: gettext("Select port first."),
|
||||
portSelected: gettext("Select security group.")
|
||||
};
|
||||
ctrl.availableSecurityGroups = [
|
||||
{id: "", name: message.portNotSelected, selected: false}
|
||||
];
|
||||
ctrl.refreshAvailableSecurityGroups = refreshAvailableSecurityGroups;
|
||||
|
||||
// add association into table
|
||||
ctrl.addSecurityGroup = function(event) {
|
||||
ctrl.model.id = ctrl.model.port + " " + ctrl.model.security_group;
|
||||
ctrl.model.port_name = getPortName(ctrl.model.port);
|
||||
ctrl.model.security_group_name = getSecurityGroupName(ctrl.model.security_group);
|
||||
var model = angular.copy(ctrl.model);
|
||||
$scope.model.port_security_groups.push(model);
|
||||
|
||||
// clean up form
|
||||
ctrl.model = angular.copy(ctrl.modelTemplate);
|
||||
ctrl.disabledSecurityGroup = true;
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
refreshAvailableSecurityGroups();
|
||||
};
|
||||
|
||||
// get port name from available ports.
|
||||
function getPortName(port) {
|
||||
var result = "";
|
||||
ctrl.availablePorts.forEach(function (ap) {
|
||||
if (port === ap.id) {
|
||||
result = ap.name;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// get security group name from available security groups.
|
||||
function getSecurityGroupName(sg) {
|
||||
var result = "";
|
||||
ctrl.availableSecurityGroups.forEach(function (asg) {
|
||||
if (sg === asg.id) {
|
||||
result = asg.name;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// refresh available security group selection, according to addition/deletion of associations.
|
||||
ctrl.disabledSecurityGroup = true;
|
||||
function refreshAvailableSecurityGroups() {
|
||||
if (ctrl.model.port) {
|
||||
// if port is selected, enable port selection.
|
||||
ctrl.disabledSecurityGroup = false;
|
||||
} else {
|
||||
// otherwise disable port selection.
|
||||
ctrl.disabledSecurityGroup = true;
|
||||
}
|
||||
// set "selected" to true, if the security group already added into table.
|
||||
ctrl.availableSecurityGroups.forEach(function (sg) {
|
||||
sg.selected = false;
|
||||
ctrl.items.forEach(function (item) {
|
||||
if (sg.id === item.security_group && ctrl.model.port === item.port) {
|
||||
// mark already selected
|
||||
sg.selected = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// enable "Add Security Group" button, if both of port and security group are selected.
|
||||
ctrl.validateSecurityGroup = function () {
|
||||
return !(ctrl.model.port && ctrl.model.security_group);
|
||||
};
|
||||
|
||||
// retrieve available ports and security groups ///////////////////////////
|
||||
// get security groups first, then get networks
|
||||
securityGroup.query().then(onGetSecurityGroups).then(getNetworks);
|
||||
function onGetSecurityGroups(response) {
|
||||
angular.forEach(response.data.items, function (item) {
|
||||
ctrl.availableSecurityGroups.push({id: item.id, name: item.name, selected: false});
|
||||
// if association of port and security group in $scope.model.port_security_groups,
|
||||
// push it into table for update.
|
||||
if ($scope.model.port_security_groups.includes(item.id)) {
|
||||
ctrl.security_groups.push(item);
|
||||
}
|
||||
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
// get available neutron networks and ports
|
||||
function getNetworks() {
|
||||
return neutron.getNetworks().then(onGetNetworks).then(getPorts);
|
||||
}
|
||||
|
||||
function onGetNetworks(response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
function getPorts(networks) {
|
||||
networks.data.items.forEach(function(network) {
|
||||
return neutron.getPorts({network_id: network.id}).then(
|
||||
function(ports) {
|
||||
onGetPorts(ports, network);
|
||||
}
|
||||
);
|
||||
});
|
||||
return networks;
|
||||
}
|
||||
|
||||
function onGetPorts(ports, network) {
|
||||
ports.data.items.forEach(function(port) {
|
||||
// no device_owner or compute:kuryr means that the port can be associated
|
||||
// with security group
|
||||
if ((port.device_owner === "" || port.device_owner === "compute:kuryr") &&
|
||||
port.admin_state === "UP") {
|
||||
port.subnet_names = getPortSubnets(port, network.subnets);
|
||||
port.network_name = network.name;
|
||||
if ($scope.model.ports.includes(port.id)) {
|
||||
var portName = port.network_name + " - " + port.subnet_names + " - " + port.name;
|
||||
ctrl.availablePorts.push({
|
||||
id: port.id,
|
||||
name: portName});
|
||||
port.security_groups.forEach(function (sgId) {
|
||||
var sgName;
|
||||
ctrl.availableSecurityGroups.forEach(function (sg) {
|
||||
if (sgId === sg.id) {
|
||||
sgName = sg.name;
|
||||
}
|
||||
});
|
||||
$scope.model.port_security_groups.push({
|
||||
id: port.id + " " + sgId,
|
||||
port: port.id,
|
||||
port_name: portName,
|
||||
security_group: sgId,
|
||||
security_group_name: sgName
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// helper function to return an object of IP:NAME pairs for subnet mapping
|
||||
function getPortSubnets(port, subnets) {
|
||||
//var subnetNames = {};
|
||||
var subnetNames = "";
|
||||
port.fixed_ips.forEach(function (ip) {
|
||||
subnets.forEach(function (subnet) {
|
||||
if (ip.subnet_id === subnet.id) {
|
||||
//subnetNames[ip.ip_address] = subnet.name;
|
||||
if (subnetNames) {
|
||||
subnetNames += ", ";
|
||||
}
|
||||
subnetNames += ip.ip_address + ": " + subnet.name;
|
||||
}
|
||||
});
|
||||
});
|
||||
return subnetNames;
|
||||
}
|
||||
|
||||
// settings for table of added security groups ////////////////////////////
|
||||
ctrl.items = $scope.model.port_security_groups;
|
||||
ctrl.config = {
|
||||
selectAll: false,
|
||||
expand: false,
|
||||
trackId: 'id',
|
||||
columns: [
|
||||
{id: 'port_name', title: gettext('Port')},
|
||||
{id: 'security_group_name', title: gettext('Security Group')}
|
||||
]
|
||||
};
|
||||
ctrl.itemActions = [
|
||||
{
|
||||
id: 'deleteSecurityGroupAction',
|
||||
service: deleteSecurityGroupService,
|
||||
template: {
|
||||
type: "delete",
|
||||
text: gettext("Delete")
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// register watcher for security group deletion from table
|
||||
var deleteWatcher = $scope.$on(events.DELETE_SUCCESS, deleteSecurityGroup);
|
||||
$scope.$on('$destroy', function destroy() {
|
||||
deleteWatcher();
|
||||
});
|
||||
|
||||
// on delete security group from table
|
||||
function deleteSecurityGroup(event, deleted) {
|
||||
// delete security group from table
|
||||
ctrl.items.forEach(function (sg, index) {
|
||||
if (sg.id === deleted.port + " " + deleted.security_group) {
|
||||
delete ctrl.items.splice(index, 1);
|
||||
}
|
||||
});
|
||||
// enable deleted security group in selection
|
||||
refreshAvailableSecurityGroups();
|
||||
}
|
||||
}
|
||||
})();
|
@ -0,0 +1,43 @@
|
||||
<div ng-controller="horizon.dashboard.container.containers.manage-security-groups as ctrl">
|
||||
<p class="step-description" translate>
|
||||
Manage security group for ports.
|
||||
</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="port" translate>Port</label>
|
||||
<select class="form-control" id="port" name="port"
|
||||
ng-model="ctrl.model.port"
|
||||
ng-options="port.id as port.name for port in ctrl.availablePorts"
|
||||
ng-change="ctrl.refreshAvailableSecurityGroups()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="security_group" translate>Security Group</label>
|
||||
<select
|
||||
class="form-control" id="security_group" name="security_group"
|
||||
ng-model="ctrl.model.security_group"
|
||||
ng-options="sg.id as sg.name for sg in ctrl.availableSecurityGroups | filter:{selected: false}"
|
||||
ng-disabled="ctrl.disabledSecurityGroup">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary"
|
||||
ng-disabled="ctrl.validateSecurityGroup()"
|
||||
ng-click="ctrl.addSecurityGroup($event)">
|
||||
<span class="fa fa-arrow-down"></span>
|
||||
<translate>Add Security Group</translate>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hz-dynamic-table
|
||||
config="ctrl.config"
|
||||
items="ctrl.items"
|
||||
item-actions="ctrl.itemActions">
|
||||
</hz-dynamic-table>
|
||||
</div>
|
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* 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.container.containers")
|
||||
.factory("horizon.dashboard.container.containers.manage-security-groups.service",
|
||||
manageSecurityGroup);
|
||||
|
||||
manageSecurityGroup.$inject = [
|
||||
"horizon.app.core.openstack-service-api.neutron",
|
||||
"horizon.app.core.openstack-service-api.security-group",
|
||||
"horizon.app.core.openstack-service-api.zun",
|
||||
"horizon.dashboard.container.basePath",
|
||||
'horizon.dashboard.container.containers.resourceType',
|
||||
'horizon.dashboard.container.containers.validStates',
|
||||
'horizon.framework.util.actions.action-result.service',
|
||||
"horizon.framework.util.i18n.gettext",
|
||||
"horizon.framework.util.q.extensions",
|
||||
"horizon.framework.widgets.form.ModalFormService",
|
||||
"horizon.framework.widgets.toast.service"
|
||||
];
|
||||
|
||||
function manageSecurityGroup(
|
||||
neutron, securityGroup, zun, basePath, resourceType, validStates, actionResult,
|
||||
gettext, $qExtensions, modal, toast
|
||||
) {
|
||||
// title for dialog
|
||||
var title = gettext("Manage Security Groups: container %s");
|
||||
// schema
|
||||
var schema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
signal: {
|
||||
title: gettext("Manage Security Groups"),
|
||||
type: "string"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// form
|
||||
var form = [
|
||||
{
|
||||
type: 'section',
|
||||
htmlClass: 'row',
|
||||
items: [
|
||||
{
|
||||
type: "section",
|
||||
htmlClass: "col-xs-12",
|
||||
items: [
|
||||
{
|
||||
type: "template",
|
||||
/* eslint-disable max-len */
|
||||
templateUrl: basePath + "containers/actions/manage-security-groups/manage-security-groups.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// model
|
||||
var model = {};
|
||||
|
||||
var message = {
|
||||
success: gettext("Changes security groups %(sgs)s for port %(port)s was successfully submitted.")
|
||||
};
|
||||
|
||||
var service = {
|
||||
initAction: initAction,
|
||||
perform: perform,
|
||||
allowed: allowed
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
//////////////
|
||||
|
||||
function initAction() {
|
||||
}
|
||||
|
||||
function allowed(container) {
|
||||
return $qExtensions.booleanAsPromise(
|
||||
validStates.manage_security_groups.indexOf(container.status) >= 0
|
||||
);
|
||||
}
|
||||
|
||||
function perform(selected) {
|
||||
model.id = selected.id;
|
||||
model.name = selected.name;
|
||||
model.ports = [];
|
||||
Object.keys(selected.addresses).map(function(key) {
|
||||
selected.addresses[key].forEach(function (addr) {
|
||||
model.ports.push(addr.port);
|
||||
});
|
||||
});
|
||||
model.port_security_groups = [];
|
||||
|
||||
// modal config
|
||||
var config = {
|
||||
"title": interpolate(title, [model.name]),
|
||||
"submitText": gettext("Submit"),
|
||||
"schema": schema,
|
||||
"form": form,
|
||||
"model": model
|
||||
};
|
||||
return modal.open(config).then(submit);
|
||||
}
|
||||
|
||||
function submit(context) {
|
||||
var id = context.model.id;
|
||||
var portSgs = context.model.port_security_groups;
|
||||
var aggregatedPortSgs = {};
|
||||
// initialize port list
|
||||
model.ports.forEach(function (port) {
|
||||
aggregatedPortSgs[port] = [];
|
||||
});
|
||||
// add security groups for each port
|
||||
portSgs.forEach(function (portSg) {
|
||||
aggregatedPortSgs[portSg.port].push(portSg.security_group);
|
||||
});
|
||||
|
||||
Object.keys(aggregatedPortSgs).map(function (port) {
|
||||
return zun.updatePortSecurityGroup(id, port, aggregatedPortSgs[port]).then(function() {
|
||||
var sgs = gettext("(empty)");
|
||||
if (aggregatedPortSgs[port].length) {
|
||||
sgs = aggregatedPortSgs[port];
|
||||
}
|
||||
toast.add(
|
||||
'success',
|
||||
interpolate(message.success, {port: port, sgs: sgs}, true));
|
||||
var result = actionResult.getActionResult().updated(resourceType, id);
|
||||
return result.result;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
@ -65,52 +65,7 @@
|
||||
var title, submitText;
|
||||
title = gettext('Update Container');
|
||||
submitText = gettext('Update');
|
||||
var config = workflow.init('update', title, submitText);
|
||||
config.model.id = selected.id;
|
||||
|
||||
// load current data
|
||||
zun.getContainer(selected.id).then(onLoad);
|
||||
function onLoad(response) {
|
||||
config.model.name = response.data.name
|
||||
? response.data.name : "";
|
||||
config.model.image = response.data.image
|
||||
? response.data.image : "";
|
||||
config.model.image_driver = response.data.image_driver
|
||||
? response.data.image_driver : "docker";
|
||||
config.model.image_pull_policy = response.data.image_pull_policy
|
||||
? response.data.image_pull_policy : "";
|
||||
config.model.command = response.data.command
|
||||
? response.data.command : "";
|
||||
config.model.hostname = response.data.hostname
|
||||
? response.data.hostname : "";
|
||||
config.model.auto_remove = response.data.auto_remove
|
||||
? response.data.auto_remove : false;
|
||||
config.model.cpu = response.data.cpu
|
||||
? response.data.cpu : "";
|
||||
config.model.memory = response.data.memory
|
||||
? parseInt(response.data.memory, 10) : "";
|
||||
config.model.restart_policy = response.data.restart_policy.Name
|
||||
? response.data.restart_policy.Name : "";
|
||||
config.model.restart_policy_max_retry = response.data.restart_policy.MaximumRetryCount
|
||||
? parseInt(response.data.restart_policy.MaximumRetryCount, 10) : null;
|
||||
if (config.model.auto_remove) {
|
||||
config.model.exit_policy = "remove";
|
||||
} else {
|
||||
config.model.exit_policy = config.model.restart_policy;
|
||||
}
|
||||
config.model.runtime = response.data.runtime
|
||||
? response.data.runtime : "";
|
||||
config.model.allocatedNetworks = getAllocatedNetworks(response.data.addresses);
|
||||
config.model.workdir = response.data.workdir
|
||||
? response.data.workdir : "";
|
||||
config.model.environment = response.data.environment
|
||||
? hashToString(response.data.environment) : "";
|
||||
config.model.interactive = response.data.interactive
|
||||
? response.data.interactive : false;
|
||||
config.model.labels = response.data.labels
|
||||
? hashToString(response.data.labels) : "";
|
||||
}
|
||||
|
||||
var config = workflow.init('update', title, submitText, selected.id);
|
||||
return modal.open(config).then(submit);
|
||||
}
|
||||
|
||||
@ -183,37 +138,16 @@
|
||||
|
||||
function successAttach(response) {
|
||||
toast.add('success', interpolate(message.successAttach,
|
||||
[response.data.container, response.data.network]));
|
||||
[response.data.network, response.data.container]));
|
||||
var result = actionResult.getActionResult().updated(resourceType, response.data.container);
|
||||
return result.result;
|
||||
}
|
||||
|
||||
function successDetach(response) {
|
||||
toast.add('success', interpolate(message.successDetach,
|
||||
[response.data.container, response.data.network]));
|
||||
[response.data.network, response.data.container]));
|
||||
var result = actionResult.getActionResult().updated(resourceType, response.data.container);
|
||||
return result.result;
|
||||
}
|
||||
|
||||
function getAllocatedNetworks(addresses) {
|
||||
var allocated = [];
|
||||
Object.keys(addresses).forEach(function (id) {
|
||||
allocated.push(id);
|
||||
});
|
||||
return allocated;
|
||||
}
|
||||
|
||||
function hashToString(hash) {
|
||||
var str = "";
|
||||
for (var key in hash) {
|
||||
if (hash.hasOwnProperty(key)) {
|
||||
if (str.length > 0) {
|
||||
str += ",";
|
||||
}
|
||||
str += key + "=" + hash[key];
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
SecurityGroupsController.$inject = [
|
||||
'$scope',
|
||||
'horizon.app.core.openstack-service-api.security-group',
|
||||
'horizon.dashboard.container.basePath'
|
||||
];
|
||||
|
||||
@ -34,15 +33,11 @@
|
||||
* Allows selection of security groups.
|
||||
* @returns {undefined} No return value
|
||||
*/
|
||||
function SecurityGroupsController($scope, securityGroup, basePath) {
|
||||
var push = Array.prototype.push;
|
||||
|
||||
function SecurityGroupsController($scope, basePath) {
|
||||
var ctrl = this;
|
||||
var availableSecurityGroups = [];
|
||||
securityGroup.query().then(onGetSecurityGroups);
|
||||
|
||||
ctrl.tableData = {
|
||||
available: availableSecurityGroups,
|
||||
available: $scope.model.availableSecurityGroups,
|
||||
allocated: $scope.model.security_groups,
|
||||
displayedAvailable: [],
|
||||
displayedAllocated: []
|
||||
@ -75,19 +70,5 @@
|
||||
singleton: true
|
||||
}
|
||||
];
|
||||
|
||||
// Security Groups
|
||||
function onGetSecurityGroups(data) {
|
||||
angular.forEach(data.data.items, function addDefault(item) {
|
||||
// 'default' is a special security group in neutron. It can not be
|
||||
// deleted and is guaranteed to exist. It by default contains all
|
||||
// of the rules needed for an instance to reach out to the network
|
||||
// so the instance can provision itself.
|
||||
if (item.name === 'default') {
|
||||
$scope.model.security_groups.push(item);
|
||||
}
|
||||
});
|
||||
push.apply(availableSecurityGroups, data.data.items);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
@ -22,17 +22,23 @@
|
||||
workflow.$inject = [
|
||||
"horizon.app.core.openstack-service-api.cinder",
|
||||
"horizon.app.core.openstack-service-api.neutron",
|
||||
"horizon.app.core.openstack-service-api.security-group",
|
||||
'horizon.app.core.openstack-service-api.zun',
|
||||
"horizon.dashboard.container.basePath",
|
||||
"horizon.framework.util.i18n.gettext",
|
||||
'horizon.framework.util.q.extensions',
|
||||
"horizon.framework.widgets.metadata.tree.service"
|
||||
];
|
||||
|
||||
function workflow(cinder, neutron, basePath, gettext, treeService) {
|
||||
function workflow(
|
||||
cinder, neutron, securityGroup, zun, basePath, gettext,
|
||||
$qExtensions, treeService
|
||||
) {
|
||||
var workflow = {
|
||||
init: init
|
||||
};
|
||||
|
||||
function init(action, title, submitText) {
|
||||
function init(action, title, submitText, id) {
|
||||
var push = Array.prototype.push;
|
||||
var schema, form, model;
|
||||
var imageDrivers = [
|
||||
@ -495,8 +501,93 @@
|
||||
// available ports
|
||||
model.availablePorts = [];
|
||||
|
||||
// security groups
|
||||
model.availableSecurityGroups = [];
|
||||
model.allocatedSecurityGroups = [];
|
||||
|
||||
// get resources
|
||||
getContainer(action, id).then(function () {
|
||||
getVolumes();
|
||||
getNetworks();
|
||||
securityGroup.query().then(onGetSecurityGroups);
|
||||
});
|
||||
|
||||
// get container when action equals "update"
|
||||
function getContainer (action, id) {
|
||||
if (action === 'create') {
|
||||
return $qExtensions.booleanAsPromise(true);
|
||||
} else {
|
||||
return zun.getContainer(id).then(onGetContainer);
|
||||
}
|
||||
}
|
||||
|
||||
// get container for update
|
||||
function onGetContainer(response) {
|
||||
model.id = id;
|
||||
model.name = response.data.name
|
||||
? response.data.name : "";
|
||||
model.image = response.data.image
|
||||
? response.data.image : "";
|
||||
model.image_driver = response.data.image_driver
|
||||
? response.data.image_driver : "docker";
|
||||
model.image_pull_policy = response.data.image_pull_policy
|
||||
? response.data.image_pull_policy : "";
|
||||
model.command = response.data.command
|
||||
? response.data.command : "";
|
||||
model.hostname = response.data.hostname
|
||||
? response.data.hostname : "";
|
||||
model.runtime = response.data.runtime
|
||||
? response.data.runtime : "";
|
||||
model.cpu = response.data.cpu
|
||||
? response.data.cpu : "";
|
||||
model.memory = response.data.memory
|
||||
? parseInt(response.data.memory, 10) : "";
|
||||
model.restart_policy = response.data.restart_policy.Name
|
||||
? response.data.restart_policy.Name : "";
|
||||
model.restart_policy_max_retry = response.data.restart_policy.MaximumRetryCount
|
||||
? parseInt(response.data.restart_policy.MaximumRetryCount, 10) : null;
|
||||
if (config.model.auto_remove) {
|
||||
config.model.exit_policy = "remove";
|
||||
} else {
|
||||
config.model.exit_policy = config.model.restart_policy;
|
||||
}
|
||||
model.allocatedNetworks = getAllocatedNetworks(response.data.addresses);
|
||||
model.allocatedSecurityGroups = response.data.security_groups;
|
||||
model.workdir = response.data.workdir
|
||||
? response.data.workdir : "";
|
||||
model.environment = response.data.environment
|
||||
? hashToString(response.data.environment) : "";
|
||||
model.interactive = response.data.interactive
|
||||
? response.data.interactive : false;
|
||||
model.auto_remove = response.data.auto_remove
|
||||
? response.data.auto_remove : false;
|
||||
model.labels = response.data.labels
|
||||
? hashToString(response.data.labels) : "";
|
||||
return response;
|
||||
}
|
||||
|
||||
function getAllocatedNetworks(addresses) {
|
||||
var allocated = [];
|
||||
Object.keys(addresses).forEach(function (id) {
|
||||
allocated.push(id);
|
||||
});
|
||||
return allocated;
|
||||
}
|
||||
|
||||
function hashToString(hash) {
|
||||
var str = "";
|
||||
for (var key in hash) {
|
||||
if (hash.hasOwnProperty(key)) {
|
||||
if (str.length > 0) {
|
||||
str += ",";
|
||||
}
|
||||
str += key + "=" + hash[key];
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// get available cinder volumes
|
||||
getVolumes();
|
||||
function getVolumes() {
|
||||
return cinder.getVolumes().then(onGetVolumes);
|
||||
}
|
||||
@ -514,7 +605,6 @@
|
||||
}
|
||||
|
||||
// get available neutron networks and ports
|
||||
getNetworks();
|
||||
function getNetworks() {
|
||||
return neutron.getNetworks().then(onGetNetworks).then(getPorts);
|
||||
}
|
||||
@ -543,6 +633,7 @@
|
||||
}
|
||||
);
|
||||
});
|
||||
return networks;
|
||||
}
|
||||
|
||||
function onGetPorts(ports, network) {
|
||||
@ -569,6 +660,27 @@
|
||||
return subnetNames;
|
||||
}
|
||||
|
||||
// get security groups
|
||||
function onGetSecurityGroups(response) {
|
||||
angular.forEach(response.data.items, function (item) {
|
||||
// 'default' is a special security group in neutron. It can not be
|
||||
// deleted and is guaranteed to exist. It by default contains all
|
||||
// of the rules needed for an instance to reach out to the network
|
||||
// so the instance can provision itself.
|
||||
if (item.name === 'default' && action === "create") {
|
||||
model.security_groups.push(item);
|
||||
}
|
||||
// if network in model.allocatedSecurityGroups,
|
||||
// push it to mode.security_groups for update
|
||||
else if (model.allocatedSecurityGroups.includes(item.id)) {
|
||||
model.security_groups.push(item);
|
||||
}
|
||||
|
||||
});
|
||||
push.apply(model.availableSecurityGroups, response.data.items);
|
||||
return response;
|
||||
}
|
||||
|
||||
var config = {
|
||||
title: title,
|
||||
submitText: submitText,
|
||||
|
@ -68,7 +68,8 @@
|
||||
states.CREATED, states.CREATING, states.ERROR, states.RUNNING,
|
||||
states.STOPPED, states.UNKNOWN, states.DELETED
|
||||
],
|
||||
delete_stop: [states.RUNNING]
|
||||
delete_stop: [states.RUNNING],
|
||||
manage_security_groups: [states.CREATED, states.RUNNING, states.STOPPED, states.PAUSED]
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
resizeContainer: resizeContainer,
|
||||
attachNetwork: attachNetwork,
|
||||
detachNetwork: detachNetwork,
|
||||
updatePortSecurityGroup: updatePortSecurityGroup,
|
||||
pullImage: pullImage,
|
||||
getImages: getImages
|
||||
};
|
||||
@ -167,6 +168,15 @@
|
||||
.error(error(msg));
|
||||
}
|
||||
|
||||
function updatePortSecurityGroup(id, port, sgs) {
|
||||
var msg = interpolate(
|
||||
gettext('Unable to update security groups %(sgs)s for port %(port)s.'),
|
||||
{port: port, sgs: sgs}, true);
|
||||
return apiService.post(containersPath + id + '/port_update_security_groups',
|
||||
{port: port, security_groups: sgs})
|
||||
.error(error(msg));
|
||||
}
|
||||
|
||||
////////////
|
||||
// Images //
|
||||
////////////
|
||||
|
Loading…
x
Reference in New Issue
Block a user