mirror of
https://github.com/portainer/portainer.git
synced 2025-07-23 07:19:41 +02:00
refactor(templates): refactor controller code and create required services (#580)
This commit is contained in:
parent
06a484880b
commit
2f3475b96a
10 changed files with 421 additions and 249 deletions
|
@ -1,6 +1,6 @@
|
|||
angular.module('templates', [])
|
||||
.controller('TemplatesController', ['$scope', '$q', '$state', '$filter', '$anchorScroll', 'Config', 'Info', 'Container', 'ContainerHelper', 'Image', 'ImageHelper', 'Volume', 'Network', 'Templates', 'TemplateHelper', 'Messages', 'Pagination',
|
||||
function ($scope, $q, $state, $filter, $anchorScroll, Config, Info, Container, ContainerHelper, Image, ImageHelper, Volume, Network, Templates, TemplateHelper, Messages, Pagination) {
|
||||
.controller('TemplatesController', ['$scope', '$q', '$state', '$anchorScroll', 'Config', 'ContainerService', 'ImageService', 'NetworkService', 'TemplateService', 'TemplateHelper', 'VolumeService', 'Messages', 'Pagination',
|
||||
function ($scope, $q, $state, $anchorScroll, Config, ContainerService, ImageService, NetworkService, TemplateService, TemplateHelper, VolumeService, Messages, Pagination) {
|
||||
$scope.state = {
|
||||
selectedTemplate: null,
|
||||
showAdvancedOptions: false,
|
||||
|
@ -9,233 +9,118 @@ function ($scope, $q, $state, $filter, $anchorScroll, Config, Info, Container, C
|
|||
$scope.formValues = {
|
||||
network: "",
|
||||
name: "",
|
||||
ports: []
|
||||
};
|
||||
|
||||
var selectedItem = -1;
|
||||
|
||||
$scope.changePaginationCount = function() {
|
||||
Pagination.setPaginationCount('templates', $scope.state.pagination_count);
|
||||
};
|
||||
|
||||
$scope.addPortBinding = function() {
|
||||
$scope.formValues.ports.push({ hostPort: '', containerPort: '', protocol: 'tcp' });
|
||||
$scope.state.selectedTemplate.Ports.push({ hostPort: '', containerPort: '', protocol: 'tcp' });
|
||||
};
|
||||
|
||||
$scope.removePortBinding = function(index) {
|
||||
$scope.formValues.ports.splice(index, 1);
|
||||
$scope.state.selectedTemplate.Ports.splice(index, 1);
|
||||
};
|
||||
|
||||
// TODO: centralize, already present in createContainerController
|
||||
function createContainer(config) {
|
||||
Container.create(config, function (d) {
|
||||
if (d.message) {
|
||||
$('#createContainerSpinner').hide();
|
||||
Messages.error('Error', {}, d.message);
|
||||
} else {
|
||||
Container.start({id: d.Id}, {}, function (cd) {
|
||||
if (cd.message) {
|
||||
$('#createContainerSpinner').hide();
|
||||
Messages.error('Error', {}, cd.message);
|
||||
} else {
|
||||
$('#createContainerSpinner').hide();
|
||||
Messages.send('Container Started', d.Id);
|
||||
$state.go('containers', {}, {reload: true});
|
||||
}
|
||||
}, function (e) {
|
||||
$('#createContainerSpinner').hide();
|
||||
Messages.error("Failure", e, 'Unable to start container');
|
||||
});
|
||||
}
|
||||
}, function (e) {
|
||||
$('#createContainerSpinner').hide();
|
||||
Messages.error("Failure", e, 'Unable to create container');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// TODO: centralize, already present in createContainerController
|
||||
function pullImageAndCreateContainer(imageConfig, containerConfig) {
|
||||
Image.create(imageConfig, function (data) {
|
||||
var err = data.length > 0 && data[data.length - 1].hasOwnProperty('error');
|
||||
if (err) {
|
||||
var detail = data[data.length - 1];
|
||||
$('#createContainerSpinner').hide();
|
||||
Messages.error("Error", {}, detail.error);
|
||||
} else {
|
||||
createContainer(containerConfig);
|
||||
}
|
||||
}, function (e) {
|
||||
$('#createContainerSpinner').hide();
|
||||
Messages.error("Failure", e, "Unable to pull image");
|
||||
});
|
||||
}
|
||||
|
||||
function getInitialConfiguration() {
|
||||
return {
|
||||
Env: [],
|
||||
OpenStdin: false,
|
||||
Tty: false,
|
||||
ExposedPorts: {},
|
||||
HostConfig: {
|
||||
RestartPolicy: {
|
||||
Name: 'no'
|
||||
},
|
||||
PortBindings: {},
|
||||
Binds: [],
|
||||
NetworkMode: $scope.formValues.network.Name,
|
||||
Privileged: false
|
||||
},
|
||||
Volumes: {},
|
||||
name: $scope.formValues.name
|
||||
};
|
||||
}
|
||||
|
||||
function preparePortBindings(config, ports) {
|
||||
var bindings = {};
|
||||
ports.forEach(function (portBinding) {
|
||||
if (portBinding.containerPort) {
|
||||
var key = portBinding.containerPort + "/" + portBinding.protocol;
|
||||
var binding = {};
|
||||
if (portBinding.hostPort && portBinding.hostPort.indexOf(':') > -1) {
|
||||
var hostAndPort = portBinding.hostPort.split(':');
|
||||
binding.HostIp = hostAndPort[0];
|
||||
binding.HostPort = hostAndPort[1];
|
||||
} else {
|
||||
binding.HostPort = portBinding.hostPort;
|
||||
}
|
||||
bindings[key] = [binding];
|
||||
config.ExposedPorts[key] = {};
|
||||
}
|
||||
});
|
||||
config.HostConfig.PortBindings = bindings;
|
||||
}
|
||||
|
||||
function createConfigFromTemplate(template) {
|
||||
var containerConfig = getInitialConfiguration();
|
||||
containerConfig.Image = template.image;
|
||||
if (template.env) {
|
||||
template.env.forEach(function (v) {
|
||||
if (v.value || v.set) {
|
||||
var val;
|
||||
if (v.type && v.type === 'container') {
|
||||
if ($scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM' && $scope.formValues.network.Scope === 'global') {
|
||||
val = $filter('swarmcontainername')(v.value);
|
||||
} else {
|
||||
var container = v.value;
|
||||
val = container.NetworkSettings.Networks[Object.keys(container.NetworkSettings.Networks)[0]].IPAddress;
|
||||
}
|
||||
} else {
|
||||
val = v.set ? v.set : v.value;
|
||||
}
|
||||
containerConfig.Env.push(v.name + "=" + val);
|
||||
}
|
||||
});
|
||||
}
|
||||
preparePortBindings(containerConfig, $scope.formValues.ports);
|
||||
prepareImageConfig(containerConfig, template);
|
||||
return containerConfig;
|
||||
}
|
||||
|
||||
function prepareImageConfig(config, template) {
|
||||
var image = template.image;
|
||||
var registry = template.registry || '';
|
||||
var imageConfig = ImageHelper.createImageConfigForContainer(image, registry);
|
||||
config.Image = imageConfig.fromImage + ':' + imageConfig.tag;
|
||||
$scope.imageConfig = imageConfig;
|
||||
}
|
||||
|
||||
function prepareVolumeQueries(template, containerConfig) {
|
||||
var volumeQueries = [];
|
||||
if (template.volumes) {
|
||||
template.volumes.forEach(function (vol) {
|
||||
volumeQueries.push(
|
||||
Volume.create({}, function (d) {
|
||||
if (d.message) {
|
||||
Messages.error("Unable to create volume", {}, d.message);
|
||||
} else {
|
||||
Messages.send("Volume created", d.Name);
|
||||
containerConfig.Volumes[vol] = {};
|
||||
containerConfig.HostConfig.Binds.push(d.Name + ':' + vol);
|
||||
}
|
||||
}, function (e) {
|
||||
Messages.error("Failure", e, "Unable to create volume");
|
||||
}).$promise
|
||||
);
|
||||
});
|
||||
}
|
||||
return volumeQueries;
|
||||
}
|
||||
|
||||
$scope.createTemplate = function() {
|
||||
$('#createContainerSpinner').show();
|
||||
var template = $scope.state.selectedTemplate;
|
||||
var containerConfig = createConfigFromTemplate(template);
|
||||
var createVolumeQueries = prepareVolumeQueries(template, containerConfig);
|
||||
$q.all(createVolumeQueries).then(function (d) {
|
||||
pullImageAndCreateContainer($scope.imageConfig, containerConfig);
|
||||
var templateConfiguration = createTemplateConfiguration(template);
|
||||
|
||||
VolumeService.createAutoGeneratedLocalVolumes(template.Volumes)
|
||||
.then(function success(data) {
|
||||
TemplateService.updateContainerConfigurationWithVolumes(templateConfiguration.container, template, data);
|
||||
return ImageService.pullImage(templateConfiguration.image);
|
||||
})
|
||||
.then(function success(data) {
|
||||
return ContainerService.createAndStartContainer(templateConfiguration.container);
|
||||
})
|
||||
.then(function success(data) {
|
||||
Messages.send('Container Started', data.Id);
|
||||
$state.go('containers', {}, {reload: true});
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Messages.error('Failure', err, err.msg);
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createContainerSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.selectTemplate = function(id) {
|
||||
$('#template_' + id).toggleClass("container-template--selected");
|
||||
if (selectedItem === id) {
|
||||
selectedItem = -1;
|
||||
$scope.state.selectedTemplate = null;
|
||||
var selectedItem = -1;
|
||||
$scope.selectTemplate = function(idx) {
|
||||
$('#template_' + idx).toggleClass("container-template--selected");
|
||||
if (selectedItem === idx) {
|
||||
unselectTemplate();
|
||||
} else {
|
||||
$('#template_' + selectedItem).toggleClass("container-template--selected");
|
||||
selectedItem = id;
|
||||
var selectedTemplate = $scope.templates[id];
|
||||
$scope.state.selectedTemplate = selectedTemplate;
|
||||
$scope.formValues.ports = selectedTemplate.ports ? TemplateHelper.getPortBindings(selectedTemplate.ports) : [];
|
||||
$anchorScroll('selectedTemplate');
|
||||
selectTemplate(idx);
|
||||
}
|
||||
};
|
||||
|
||||
function unselectTemplate() {
|
||||
selectedItem = -1;
|
||||
$scope.state.selectedTemplate = null;
|
||||
}
|
||||
|
||||
function selectTemplate(idx) {
|
||||
$('#template_' + selectedItem).toggleClass("container-template--selected");
|
||||
selectedItem = idx;
|
||||
var selectedTemplate = $scope.templates[idx];
|
||||
$scope.state.selectedTemplate = selectedTemplate;
|
||||
$anchorScroll('selectedTemplate');
|
||||
}
|
||||
|
||||
function createTemplateConfiguration(template) {
|
||||
var network = $scope.formValues.network;
|
||||
var name = $scope.formValues.name;
|
||||
var containerMapping = determineContainerMapping(network);
|
||||
return TemplateService.createTemplateConfiguration(template, name, network, containerMapping);
|
||||
}
|
||||
|
||||
function determineContainerMapping(network) {
|
||||
var endpointProvider = $scope.applicationState.endpoint.mode.provider;
|
||||
var containerMapping = 'BY_CONTAINER_IP';
|
||||
if (endpointProvider === 'DOCKER_SWARM' && network.Scope === 'global') {
|
||||
containerMapping = 'BY_SWARM_CONTAINER_NAME';
|
||||
} else if (network.Name !== "bridge") {
|
||||
containerMapping = 'BY_CONTAINER_NAME';
|
||||
}
|
||||
}
|
||||
|
||||
function filterNetworksBasedOnProvider(networks) {
|
||||
var endpointProvider = $scope.applicationState.endpoint.mode.provider;
|
||||
if (endpointProvider === 'DOCKER_SWARM' || endpointProvider === 'DOCKER_SWARM_MODE') {
|
||||
networks = NetworkService.filterGlobalNetworks(networks);
|
||||
$scope.globalNetworkCount = networks.length;
|
||||
NetworkService.addPredefinedLocalNetworks(networks);
|
||||
} else {
|
||||
$scope.formValues.network = _.find(networks, function(o) { return o.Name === "bridge"; });
|
||||
}
|
||||
return networks;
|
||||
}
|
||||
|
||||
function initTemplates() {
|
||||
Templates.get(function (data) {
|
||||
$scope.templates = data.map(function(tpl,index){
|
||||
tpl.index = index;
|
||||
return tpl;
|
||||
Config.$promise.then(function (c) {
|
||||
$q.all({
|
||||
templates: TemplateService.getTemplates(),
|
||||
containers: ContainerService.getContainers(0, c.hiddenLabels),
|
||||
networks: NetworkService.getNetworks()
|
||||
})
|
||||
.then(function success(data) {
|
||||
$scope.templates = data.templates;
|
||||
$scope.runningContainers = data.containers;
|
||||
$scope.availableNetworks = filterNetworksBasedOnProvider(data.networks);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
$scope.templates = [];
|
||||
Messages.error("Failure", err, "An error occured during apps initialization.");
|
||||
})
|
||||
.finally(function final(){
|
||||
$('#loadTemplatesSpinner').hide();
|
||||
});
|
||||
$('#loadTemplatesSpinner').hide();
|
||||
}, function (e) {
|
||||
$('#loadTemplatesSpinner').hide();
|
||||
Messages.error("Failure", e, "Unable to retrieve apps list");
|
||||
$scope.templates = [];
|
||||
});
|
||||
}
|
||||
|
||||
Config.$promise.then(function (c) {
|
||||
var containersToHideLabels = c.hiddenLabels;
|
||||
Network.query({}, function (d) {
|
||||
var networks = d;
|
||||
if ($scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM' || $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') {
|
||||
networks = d.filter(function (network) {
|
||||
if (network.Scope === 'global') {
|
||||
return network;
|
||||
}
|
||||
});
|
||||
$scope.globalNetworkCount = networks.length;
|
||||
networks.push({Scope: "local", Name: "bridge"});
|
||||
networks.push({Scope: "local", Name: "host"});
|
||||
networks.push({Scope: "local", Name: "none"});
|
||||
} else {
|
||||
$scope.formValues.network = _.find(networks, function(o) { return o.Name === "bridge"; });
|
||||
}
|
||||
$scope.availableNetworks = networks;
|
||||
}, function (e) {
|
||||
Messages.error("Failure", e, "Unable to retrieve networks");
|
||||
});
|
||||
Container.query({all: 0}, function (d) {
|
||||
var containers = d;
|
||||
if (containersToHideLabels) {
|
||||
containers = ContainerHelper.hideContainers(d, containersToHideLabels);
|
||||
}
|
||||
$scope.runningContainers = containers;
|
||||
}, function (e) {
|
||||
Messages.error("Failure", e, "Unable to retrieve running containers");
|
||||
});
|
||||
initTemplates();
|
||||
});
|
||||
initTemplates();
|
||||
}]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue