mirror of https://github.com/portainer/portainer
refactor(global): service separation #552
parent
0abe8883d1
commit
fe0bf77bbb
27
app/app.js
27
app/app.js
|
@ -1,5 +1,8 @@
|
||||||
|
angular.module('portainer.filters', []);
|
||||||
|
angular.module('portainer.rest', ['ngResource']);
|
||||||
|
angular.module('portainer.services', []);
|
||||||
|
angular.module('portainer.helpers', []);
|
||||||
angular.module('portainer', [
|
angular.module('portainer', [
|
||||||
'portainer.templates',
|
|
||||||
'ui.bootstrap',
|
'ui.bootstrap',
|
||||||
'ui.router',
|
'ui.router',
|
||||||
'ui.select',
|
'ui.select',
|
||||||
|
@ -9,9 +12,11 @@ angular.module('portainer', [
|
||||||
'angularUtils.directives.dirPagination',
|
'angularUtils.directives.dirPagination',
|
||||||
'LocalStorageModule',
|
'LocalStorageModule',
|
||||||
'angular-jwt',
|
'angular-jwt',
|
||||||
'portainer.services',
|
'portainer.templates',
|
||||||
'portainer.helpers',
|
|
||||||
'portainer.filters',
|
'portainer.filters',
|
||||||
|
'portainer.rest',
|
||||||
|
'portainer.helpers',
|
||||||
|
'portainer.services',
|
||||||
'auth',
|
'auth',
|
||||||
'dashboard',
|
'dashboard',
|
||||||
'container',
|
'container',
|
||||||
|
@ -19,29 +24,29 @@ angular.module('portainer', [
|
||||||
'containerLogs',
|
'containerLogs',
|
||||||
'containers',
|
'containers',
|
||||||
'createContainer',
|
'createContainer',
|
||||||
|
'createNetwork',
|
||||||
|
'createService',
|
||||||
|
'createVolume',
|
||||||
'docker',
|
'docker',
|
||||||
'endpoint',
|
'endpoint',
|
||||||
'endpointInit',
|
'endpointInit',
|
||||||
'endpoints',
|
'endpoints',
|
||||||
'events',
|
'events',
|
||||||
'images',
|
|
||||||
'image',
|
'image',
|
||||||
|
'images',
|
||||||
'main',
|
'main',
|
||||||
|
'network',
|
||||||
|
'networks',
|
||||||
|
'node',
|
||||||
'service',
|
'service',
|
||||||
'services',
|
'services',
|
||||||
'settings',
|
'settings',
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'createService',
|
|
||||||
'stats',
|
'stats',
|
||||||
'swarm',
|
'swarm',
|
||||||
'network',
|
|
||||||
'networks',
|
|
||||||
'node',
|
|
||||||
'createNetwork',
|
|
||||||
'task',
|
'task',
|
||||||
'templates',
|
'templates',
|
||||||
'volumes',
|
'volumes'])
|
||||||
'createVolume'])
|
|
||||||
.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'localStorageServiceProvider', 'jwtOptionsProvider', function ($stateProvider, $urlRouterProvider, $httpProvider, localStorageServiceProvider, jwtOptionsProvider) {
|
.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'localStorageServiceProvider', 'jwtOptionsProvider', function ($stateProvider, $urlRouterProvider, $httpProvider, localStorageServiceProvider, jwtOptionsProvider) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
angular.module('portainer.helpers')
|
||||||
|
.factory('ContainerHelper', [function ContainerHelperFactory() {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
hideContainers: function(containers, containersToHideLabels) {
|
||||||
|
return containers.filter(function (container) {
|
||||||
|
var filterContainer = false;
|
||||||
|
containersToHideLabels.forEach(function(label, index) {
|
||||||
|
if (_.has(container.Labels, label.name) &&
|
||||||
|
container.Labels[label.name] === label.value) {
|
||||||
|
filterContainer = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!filterContainer) {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,30 @@
|
||||||
|
angular.module('portainer.helpers')
|
||||||
|
.factory('ImageHelper', [function ImageHelperFactory() {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
createImageConfigForCommit: function(imageName, registry) {
|
||||||
|
var imageNameAndTag = imageName.split(':');
|
||||||
|
var image = imageNameAndTag[0];
|
||||||
|
if (registry) {
|
||||||
|
image = registry + '/' + imageNameAndTag[0];
|
||||||
|
}
|
||||||
|
var imageConfig = {
|
||||||
|
repo: image,
|
||||||
|
tag: imageNameAndTag[1] ? imageNameAndTag[1] : 'latest'
|
||||||
|
};
|
||||||
|
return imageConfig;
|
||||||
|
},
|
||||||
|
createImageConfigForContainer: function (imageName, registry) {
|
||||||
|
var imageNameAndTag = imageName.split(':');
|
||||||
|
var image = imageNameAndTag[0];
|
||||||
|
if (registry) {
|
||||||
|
image = registry + '/' + imageNameAndTag[0];
|
||||||
|
}
|
||||||
|
var imageConfig = {
|
||||||
|
fromImage: image,
|
||||||
|
tag: imageNameAndTag[1] ? imageNameAndTag[1] : 'latest'
|
||||||
|
};
|
||||||
|
return imageConfig;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,32 @@
|
||||||
|
angular.module('portainer.helpers')
|
||||||
|
.factory('InfoHelper', [function InfoHelperFactory() {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
determineEndpointMode: function(info) {
|
||||||
|
var mode = {
|
||||||
|
provider: '',
|
||||||
|
role: ''
|
||||||
|
};
|
||||||
|
if (_.startsWith(info.ServerVersion, 'swarm')) {
|
||||||
|
mode.provider = "DOCKER_SWARM";
|
||||||
|
if (info.SystemStatus[0][1] === 'primary') {
|
||||||
|
mode.role = "PRIMARY";
|
||||||
|
} else {
|
||||||
|
mode.role = "REPLICA";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!info.Swarm || _.isEmpty(info.Swarm.NodeID)) {
|
||||||
|
mode.provider = "DOCKER_STANDALONE";
|
||||||
|
} else {
|
||||||
|
mode.provider = "DOCKER_SWARM_MODE";
|
||||||
|
if (info.Swarm.ControlAvailable) {
|
||||||
|
mode.role = "MANAGER";
|
||||||
|
} else {
|
||||||
|
mode.role = "WORKER";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,23 @@
|
||||||
|
angular.module('portainer.helpers')
|
||||||
|
.factory('LabelHelper', [function LabelHelperFactory() {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
fromLabelHashToKeyValue: function(labels) {
|
||||||
|
if (labels) {
|
||||||
|
return Object.keys(labels).map(function(key) {
|
||||||
|
return {key: key, value: labels[key], originalKey: key, originalValue: labels[key], added: true};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
fromKeyValueToLabelHash: function(labelKV) {
|
||||||
|
var labels = {};
|
||||||
|
if (labelKV) {
|
||||||
|
labelKV.forEach(function(label) {
|
||||||
|
labels[label.key] = label.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,14 @@
|
||||||
|
angular.module('portainer.helpers')
|
||||||
|
.factory('NodeHelper', [function NodeHelperFactory() {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
nodeToConfig: function(node) {
|
||||||
|
return {
|
||||||
|
Name: node.Spec.Name,
|
||||||
|
Role: node.Spec.Role,
|
||||||
|
Labels: node.Spec.Labels,
|
||||||
|
Availability: node.Spec.Availability
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,17 @@
|
||||||
|
angular.module('portainer.helpers')
|
||||||
|
.factory('ServiceHelper', [function ServiceHelperFactory() {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
serviceToConfig: function(service) {
|
||||||
|
return {
|
||||||
|
Name: service.Spec.Name,
|
||||||
|
Labels: service.Spec.Labels,
|
||||||
|
TaskTemplate: service.Spec.TaskTemplate,
|
||||||
|
Mode: service.Spec.Mode,
|
||||||
|
UpdateConfig: service.Spec.UpdateConfig,
|
||||||
|
Networks: service.Spec.Networks,
|
||||||
|
EndpointSpec: service.Spec.EndpointSpec
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,40 @@
|
||||||
|
angular.module('portainer.helpers')
|
||||||
|
.factory('TemplateHelper', [function TemplateHelperFactory() {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
getPortBindings: function(ports) {
|
||||||
|
var bindings = [];
|
||||||
|
ports.forEach(function (port) {
|
||||||
|
var portAndProtocol = _.split(port, '/');
|
||||||
|
var binding = {
|
||||||
|
containerPort: portAndProtocol[0],
|
||||||
|
protocol: portAndProtocol[1]
|
||||||
|
};
|
||||||
|
bindings.push(binding);
|
||||||
|
});
|
||||||
|
return bindings;
|
||||||
|
},
|
||||||
|
//Not used atm, may prove useful later
|
||||||
|
getVolumeBindings: function(volumes) {
|
||||||
|
var bindings = [];
|
||||||
|
volumes.forEach(function (volume) {
|
||||||
|
bindings.push({ containerPath: volume });
|
||||||
|
});
|
||||||
|
return bindings;
|
||||||
|
},
|
||||||
|
//Not used atm, may prove useful later
|
||||||
|
getEnvBindings: function(env) {
|
||||||
|
var bindings = [];
|
||||||
|
env.forEach(function (envvar) {
|
||||||
|
var binding = {
|
||||||
|
name: envvar.name
|
||||||
|
};
|
||||||
|
if (envvar.set) {
|
||||||
|
binding.value = envvar.set;
|
||||||
|
}
|
||||||
|
bindings.push(binding);
|
||||||
|
});
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,20 @@
|
||||||
|
function ContainerViewModel(data) {
|
||||||
|
this.Id = data.Id;
|
||||||
|
this.Status = data.Status;
|
||||||
|
this.State = data.State;
|
||||||
|
this.Names = data.Names;
|
||||||
|
// Unavailable in Docker < 1.10
|
||||||
|
if (data.NetworkSettings && !_.isEmpty(data.NetworkSettings.Networks)) {
|
||||||
|
this.IP = data.NetworkSettings.Networks[Object.keys(data.NetworkSettings.Networks)[0]].IPAddress;
|
||||||
|
}
|
||||||
|
this.Image = data.Image;
|
||||||
|
this.Command = data.Command;
|
||||||
|
this.Checked = false;
|
||||||
|
this.Ports = [];
|
||||||
|
for (var i = 0; i < data.Ports.length; ++i) {
|
||||||
|
var p = data.Ports[i];
|
||||||
|
if (p.PublicPort) {
|
||||||
|
this.Ports.push({ host: p.IP, private: p.PrivatePort, public: p.PublicPort });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
function createEventDetails(event) {
|
||||||
|
var eventAttr = event.Actor.Attributes;
|
||||||
|
var details = '';
|
||||||
|
switch (event.Type) {
|
||||||
|
case 'container':
|
||||||
|
switch (event.Action) {
|
||||||
|
case 'stop':
|
||||||
|
details = 'Container ' + eventAttr.name + ' stopped';
|
||||||
|
break;
|
||||||
|
case 'destroy':
|
||||||
|
details = 'Container ' + eventAttr.name + ' deleted';
|
||||||
|
break;
|
||||||
|
case 'create':
|
||||||
|
details = 'Container ' + eventAttr.name + ' created';
|
||||||
|
break;
|
||||||
|
case 'start':
|
||||||
|
details = 'Container ' + eventAttr.name + ' started';
|
||||||
|
break;
|
||||||
|
case 'kill':
|
||||||
|
details = 'Container ' + eventAttr.name + ' killed';
|
||||||
|
break;
|
||||||
|
case 'die':
|
||||||
|
details = 'Container ' + eventAttr.name + ' exited with status code ' + eventAttr.exitCode;
|
||||||
|
break;
|
||||||
|
case 'commit':
|
||||||
|
details = 'Container ' + eventAttr.name + ' committed';
|
||||||
|
break;
|
||||||
|
case 'restart':
|
||||||
|
details = 'Container ' + eventAttr.name + ' restarted';
|
||||||
|
break;
|
||||||
|
case 'pause':
|
||||||
|
details = 'Container ' + eventAttr.name + ' paused';
|
||||||
|
break;
|
||||||
|
case 'unpause':
|
||||||
|
details = 'Container ' + eventAttr.name + ' unpaused';
|
||||||
|
break;
|
||||||
|
case 'attach':
|
||||||
|
details = 'Container ' + eventAttr.name + ' attached';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (event.Action.indexOf('exec_create') === 0) {
|
||||||
|
details = 'Exec instance created';
|
||||||
|
} else if (event.Action.indexOf('exec_start') === 0) {
|
||||||
|
details = 'Exec instance started';
|
||||||
|
} else {
|
||||||
|
details = 'Unsupported event';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'image':
|
||||||
|
switch (event.Action) {
|
||||||
|
case 'delete':
|
||||||
|
details = 'Image deleted';
|
||||||
|
break;
|
||||||
|
case 'tag':
|
||||||
|
details = 'New tag created for ' + eventAttr.name;
|
||||||
|
break;
|
||||||
|
case 'untag':
|
||||||
|
details = 'Image untagged';
|
||||||
|
break;
|
||||||
|
case 'pull':
|
||||||
|
details = 'Image ' + event.Actor.ID + ' pulled';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
details = 'Unsupported event';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'network':
|
||||||
|
switch (event.Action) {
|
||||||
|
case 'create':
|
||||||
|
details = 'Network ' + eventAttr.name + ' created';
|
||||||
|
break;
|
||||||
|
case 'destroy':
|
||||||
|
details = 'Network ' + eventAttr.name + ' deleted';
|
||||||
|
break;
|
||||||
|
case 'connect':
|
||||||
|
details = 'Container connected to ' + eventAttr.name + ' network';
|
||||||
|
break;
|
||||||
|
case 'disconnect':
|
||||||
|
details = 'Container disconnected from ' + eventAttr.name + ' network';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
details = 'Unsupported event';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'volume':
|
||||||
|
switch (event.Action) {
|
||||||
|
case 'create':
|
||||||
|
details = 'Volume ' + event.Actor.ID + ' created';
|
||||||
|
break;
|
||||||
|
case 'destroy':
|
||||||
|
details = 'Volume ' + event.Actor.ID + ' deleted';
|
||||||
|
break;
|
||||||
|
case 'mount':
|
||||||
|
details = 'Volume ' + event.Actor.ID + ' mounted';
|
||||||
|
break;
|
||||||
|
case 'unmount':
|
||||||
|
details = 'Volume ' + event.Actor.ID + ' unmounted';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
details = 'Unsupported event';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
details = 'Unsupported event';
|
||||||
|
}
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
function EventViewModel(data) {
|
||||||
|
// Type, Action, Actor unavailable in Docker < 1.10
|
||||||
|
this.Time = data.time;
|
||||||
|
if (data.Type) {
|
||||||
|
this.Type = data.Type;
|
||||||
|
this.Details = createEventDetails(data);
|
||||||
|
} else {
|
||||||
|
this.Type = data.status;
|
||||||
|
this.Details = data.from;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
function ImageViewModel(data) {
|
||||||
|
this.Id = data.Id;
|
||||||
|
this.Tag = data.Tag;
|
||||||
|
this.Repository = data.Repository;
|
||||||
|
this.Created = data.Created;
|
||||||
|
this.Checked = false;
|
||||||
|
this.RepoTags = data.RepoTags;
|
||||||
|
this.VirtualSize = data.VirtualSize;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
function NodeViewModel(data) {
|
||||||
|
this.Model = data;
|
||||||
|
this.Id = data.ID;
|
||||||
|
this.Version = data.Version.Index;
|
||||||
|
this.Name = data.Spec.Name;
|
||||||
|
this.Role = data.Spec.Role;
|
||||||
|
this.CreatedAt = data.CreatedAt;
|
||||||
|
this.UpdatedAt = data.UpdatedAt;
|
||||||
|
this.Availability = data.Spec.Availability;
|
||||||
|
|
||||||
|
var labels = data.Spec.Labels;
|
||||||
|
if (labels) {
|
||||||
|
this.Labels = Object.keys(labels).map(function(key) {
|
||||||
|
return { key: key, value: labels[key], originalKey: key, originalValue: labels[key], added: true };
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.Labels = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Hostname = data.Description.Hostname;
|
||||||
|
this.PlatformArchitecture = data.Description.Platform.Architecture;
|
||||||
|
this.PlatformOS = data.Description.Platform.OS;
|
||||||
|
this.CPUs = data.Description.Resources.NanoCPUs;
|
||||||
|
this.Memory = data.Description.Resources.MemoryBytes;
|
||||||
|
this.EngineVersion = data.Description.Engine.EngineVersion;
|
||||||
|
this.EngineLabels = data.Description.Engine.Labels;
|
||||||
|
this.Plugins = data.Description.Engine.Plugins;
|
||||||
|
this.Status = data.Status.State;
|
||||||
|
|
||||||
|
if (data.ManagerStatus) {
|
||||||
|
this.Leader = data.ManagerStatus.Leader;
|
||||||
|
this.Reachability = data.ManagerStatus.Reachability;
|
||||||
|
this.ManagerAddr = data.ManagerStatus.Addr;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
function ServiceViewModel(data) {
|
||||||
|
this.Model = data;
|
||||||
|
this.Id = data.ID;
|
||||||
|
this.Name = data.Spec.Name;
|
||||||
|
this.Image = data.Spec.TaskTemplate.ContainerSpec.Image;
|
||||||
|
this.Version = data.Version.Index;
|
||||||
|
if (data.Spec.Mode.Replicated) {
|
||||||
|
this.Mode = 'replicated' ;
|
||||||
|
this.Replicas = data.Spec.Mode.Replicated.Replicas;
|
||||||
|
} else {
|
||||||
|
this.Mode = 'global';
|
||||||
|
}
|
||||||
|
this.Labels = data.Spec.Labels;
|
||||||
|
if (data.Spec.TaskTemplate.ContainerSpec) {
|
||||||
|
this.ContainerLabels = data.Spec.TaskTemplate.ContainerSpec.Labels;
|
||||||
|
}
|
||||||
|
if (data.Spec.TaskTemplate.ContainerSpec.Env) {
|
||||||
|
this.Env = data.Spec.TaskTemplate.ContainerSpec.Env;
|
||||||
|
}
|
||||||
|
if (data.Endpoint.Ports) {
|
||||||
|
this.Ports = data.Endpoint.Ports;
|
||||||
|
}
|
||||||
|
if (data.Spec.UpdateConfig) {
|
||||||
|
this.UpdateParallelism = (typeof data.Spec.UpdateConfig.Parallelism !== undefined) ? data.Spec.UpdateConfig.Parallelism || 0 : 1;
|
||||||
|
this.UpdateDelay = data.Spec.UpdateConfig.Delay || 0;
|
||||||
|
this.UpdateFailureAction = data.Spec.UpdateConfig.FailureAction || 'pause';
|
||||||
|
} else {
|
||||||
|
this.UpdateParallelism = 1;
|
||||||
|
this.UpdateDelay = 0;
|
||||||
|
this.UpdateFailureAction = 'pause';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Checked = false;
|
||||||
|
this.Scale = false;
|
||||||
|
this.EditName = false;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
function TaskViewModel(data, node_data) {
|
||||||
|
this.Id = data.ID;
|
||||||
|
this.Created = data.CreatedAt;
|
||||||
|
this.Updated = data.UpdatedAt;
|
||||||
|
this.Slot = data.Slot;
|
||||||
|
this.Status = data.Status.State;
|
||||||
|
this.Image = data.Spec.ContainerSpec ? data.Spec.ContainerSpec.Image : '';
|
||||||
|
if (node_data) {
|
||||||
|
for (var i = 0; i < node_data.length; ++i) {
|
||||||
|
if (data.NodeID === node_data[i].ID) {
|
||||||
|
this.Node = node_data[i].Description.Hostname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Auth', ['$resource', 'AUTH_ENDPOINT', function AuthFactory($resource, AUTH_ENDPOINT) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(AUTH_ENDPOINT, {}, {
|
||||||
|
login: {
|
||||||
|
method: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,4 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Config', ['$resource', 'CONFIG_ENDPOINT', function ConfigFactory($resource, CONFIG_ENDPOINT) {
|
||||||
|
return $resource(CONFIG_ENDPOINT).get();
|
||||||
|
}]);
|
|
@ -0,0 +1,37 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Container', ['$resource', 'Settings', function ContainerFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/containers/:id/:action', {
|
||||||
|
name: '@name'
|
||||||
|
}, {
|
||||||
|
query: {method: 'GET', params: {all: 0, action: 'json', filters: '@filters' }, isArray: true},
|
||||||
|
get: {method: 'GET', params: {action: 'json'}},
|
||||||
|
stop: {method: 'POST', params: {id: '@id', t: 5, action: 'stop'}},
|
||||||
|
restart: {method: 'POST', params: {id: '@id', t: 5, action: 'restart'}},
|
||||||
|
kill: {method: 'POST', params: {id: '@id', action: 'kill'}},
|
||||||
|
pause: {method: 'POST', params: {id: '@id', action: 'pause'}},
|
||||||
|
unpause: {method: 'POST', params: {id: '@id', action: 'unpause'}},
|
||||||
|
changes: {method: 'GET', params: {action: 'changes'}, isArray: true},
|
||||||
|
stats: {method: 'GET', params: {id: '@id', stream: false, action: 'stats'}, timeout: 5000},
|
||||||
|
start: {
|
||||||
|
method: 'POST', params: {id: '@id', action: 'start'},
|
||||||
|
transformResponse: genericHandler
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
method: 'POST', params: {action: 'create'},
|
||||||
|
transformResponse: genericHandler
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
method: 'DELETE', params: {id: '@id', v: 0},
|
||||||
|
transformResponse: genericHandler
|
||||||
|
},
|
||||||
|
rename: {
|
||||||
|
method: 'POST', params: {id: '@id', action: 'rename', name: '@name'},
|
||||||
|
transformResponse: genericHandler
|
||||||
|
},
|
||||||
|
exec: {
|
||||||
|
method: 'POST', params: {id: '@id', action: 'exec'},
|
||||||
|
transformResponse: genericHandler
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,7 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('ContainerCommit', ['$resource', 'Settings', function ContainerCommitFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/commit', {}, {
|
||||||
|
commit: {method: 'POST', params: {container: '@id', repo: '@repo', tag: '@tag'}}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,20 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('ContainerLogs', ['$http', 'Settings', function ContainerLogsFactory($http, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
get: function (id, params, callback) {
|
||||||
|
$http({
|
||||||
|
method: 'GET',
|
||||||
|
url: Settings.url + '/containers/' + id + '/logs',
|
||||||
|
params: {
|
||||||
|
'stdout': params.stdout || 0,
|
||||||
|
'stderr': params.stderr || 0,
|
||||||
|
'timestamps': params.timestamps || 0,
|
||||||
|
'tail': params.tail || 'all'
|
||||||
|
}
|
||||||
|
}).success(callback).error(function (data, status, headers, config) {
|
||||||
|
console.log(error, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,15 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('ContainerTop', ['$http', 'Settings', function ($http, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
get: function (id, params, callback, errorCallback) {
|
||||||
|
$http({
|
||||||
|
method: 'GET',
|
||||||
|
url: Settings.url + '/containers/' + id + '/top',
|
||||||
|
params: {
|
||||||
|
ps_args: params.ps_args
|
||||||
|
}
|
||||||
|
}).success(callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,13 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Endpoints', ['$resource', 'ENDPOINTS_ENDPOINT', function EndpointsFactory($resource, ENDPOINTS_ENDPOINT) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(ENDPOINTS_ENDPOINT + '/:id/:action', {}, {
|
||||||
|
create: { method: 'POST' },
|
||||||
|
query: { method: 'GET', isArray: true },
|
||||||
|
get: { method: 'GET', params: { id: '@id' } },
|
||||||
|
update: { method: 'PUT', params: { id: '@id' } },
|
||||||
|
remove: { method: 'DELETE', params: { id: '@id'} },
|
||||||
|
getActiveEndpoint: { method: 'GET', params: { id: '0' } },
|
||||||
|
setActiveEndpoint: { method: 'POST', params: { id: '@id', action: 'active' } }
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,10 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Events', ['$resource', 'Settings', function EventFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/events', {}, {
|
||||||
|
query: {
|
||||||
|
method: 'GET', params: {since: '@since', until: '@until'},
|
||||||
|
isArray: true, transformResponse: jsonObjectsToArrayHandler
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,10 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Exec', ['$resource', 'Settings', function ExecFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/exec/:id/:action', {}, {
|
||||||
|
resize: {
|
||||||
|
method: 'POST', params: {id: '@id', action: 'resize', h: '@height', w: '@width'},
|
||||||
|
transformResponse: genericHandler
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,25 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Image', ['$resource', 'Settings', function ImageFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/images/:id/:action', {}, {
|
||||||
|
query: {method: 'GET', params: {all: 0, action: 'json'}, isArray: true},
|
||||||
|
get: {method: 'GET', params: {action: 'json'}},
|
||||||
|
search: {method: 'GET', params: {action: 'search'}},
|
||||||
|
history: {method: 'GET', params: {action: 'history'}, isArray: true},
|
||||||
|
insert: {method: 'POST', params: {id: '@id', action: 'insert'}},
|
||||||
|
tag: {method: 'POST', params: {id: '@id', action: 'tag', force: 0, repo: '@repo', tag: '@tag'}},
|
||||||
|
inspect: {method: 'GET', params: {id: '@id', action: 'json'}},
|
||||||
|
push: {
|
||||||
|
method: 'POST', params: {action: 'push', id: '@tag'},
|
||||||
|
isArray: true, transformResponse: jsonObjectsToArrayHandler
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
method: 'POST', params: {action: 'create', fromImage: '@fromImage', tag: '@tag'},
|
||||||
|
isArray: true, transformResponse: jsonObjectsToArrayHandler
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
method: 'DELETE', params: {id: '@id'},
|
||||||
|
isArray: true, transformResponse: deleteImageHandler
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,5 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Info', ['$resource', 'Settings', function InfoFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/info', {});
|
||||||
|
}]);
|
|
@ -0,0 +1,12 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Network', ['$resource', 'Settings', function NetworkFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/networks/:id/:action', {id: '@id'}, {
|
||||||
|
query: {method: 'GET', isArray: true},
|
||||||
|
get: {method: 'GET'},
|
||||||
|
create: {method: 'POST', params: {action: 'create'}, transformResponse: genericHandler},
|
||||||
|
remove: { method: 'DELETE', transformResponse: genericHandler },
|
||||||
|
connect: {method: 'POST', params: {action: 'connect'}},
|
||||||
|
disconnect: {method: 'POST', params: {action: 'disconnect'}}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,10 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Node', ['$resource', 'Settings', function NodeFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/nodes/:id/:action', {}, {
|
||||||
|
query: {method: 'GET', isArray: true},
|
||||||
|
get: {method: 'GET', params: {id: '@id'}},
|
||||||
|
update: { method: 'POST', params: {id: '@id', action: 'update', version: '@version'} },
|
||||||
|
remove: { method: 'DELETE', params: {id: '@id'} }
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,11 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Service', ['$resource', 'Settings', function ServiceFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/services/:id/:action', {}, {
|
||||||
|
get: { method: 'GET', params: {id: '@id'} },
|
||||||
|
query: { method: 'GET', isArray: true },
|
||||||
|
create: { method: 'POST', params: {action: 'create'} },
|
||||||
|
update: { method: 'POST', params: {id: '@id', action: 'update', version: '@version'} },
|
||||||
|
remove: { method: 'DELETE', params: {id: '@id'} }
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,7 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Swarm', ['$resource', 'Settings', function SwarmFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/swarm', {}, {
|
||||||
|
get: {method: 'GET'}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,8 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Task', ['$resource', 'Settings', function TaskFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/tasks/:id', {}, {
|
||||||
|
get: { method: 'GET', params: {id: '@id'} },
|
||||||
|
query: { method: 'GET', isArray: true, params: {filters: '@filters'} }
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,6 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Templates', ['$resource', 'TEMPLATES_ENDPOINT', function TemplatesFactory($resource, TEMPLATES_ENDPOINT) {
|
||||||
|
return $resource(TEMPLATES_ENDPOINT, {}, {
|
||||||
|
get: {method: 'GET', isArray: true}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,12 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Users', ['$resource', 'USERS_ENDPOINT', function UsersFactory($resource, USERS_ENDPOINT) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(USERS_ENDPOINT + '/:username/:action', {}, {
|
||||||
|
create: { method: 'POST' },
|
||||||
|
get: { method: 'GET', params: { username: '@username' } },
|
||||||
|
update: { method: 'PUT', params: { username: '@username' } },
|
||||||
|
checkPassword: { method: 'POST', params: { username: '@username', action: 'passwd' } },
|
||||||
|
checkAdminUser: { method: 'GET', params: { username: 'admin', action: 'check' } },
|
||||||
|
initAdminUser: { method: 'POST', params: { username: 'admin', action: 'init' } }
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,5 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Version', ['$resource', 'Settings', function VersionFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/version', {});
|
||||||
|
}]);
|
|
@ -0,0 +1,12 @@
|
||||||
|
angular.module('portainer.rest')
|
||||||
|
.factory('Volume', ['$resource', 'Settings', function VolumeFactory($resource, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return $resource(Settings.url + '/volumes/:name/:action', {name: '@name'}, {
|
||||||
|
query: {method: 'GET'},
|
||||||
|
get: {method: 'GET'},
|
||||||
|
create: {method: 'POST', params: {action: 'create'}, transformResponse: genericHandler},
|
||||||
|
remove: {
|
||||||
|
method: 'DELETE', transformResponse: genericHandler
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}]);
|
|
@ -0,0 +1,33 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('Authentication', ['$q', '$rootScope', 'Auth', 'jwtHelper', 'LocalStorage', 'StateManager', function AuthenticationFactory($q, $rootScope, Auth, jwtHelper, LocalStorage, StateManager) {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
init: function() {
|
||||||
|
var jwt = LocalStorage.getJWT();
|
||||||
|
if (jwt) {
|
||||||
|
var tokenPayload = jwtHelper.decodeToken(jwt);
|
||||||
|
$rootScope.username = tokenPayload.username;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
login: function(username, password) {
|
||||||
|
return $q(function (resolve, reject) {
|
||||||
|
Auth.login({username: username, password: password}).$promise
|
||||||
|
.then(function(data) {
|
||||||
|
LocalStorage.storeJWT(data.jwt);
|
||||||
|
$rootScope.username = username;
|
||||||
|
resolve();
|
||||||
|
}, function() {
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
logout: function() {
|
||||||
|
StateManager.clean();
|
||||||
|
LocalStorage.clean();
|
||||||
|
},
|
||||||
|
isAuthenticated: function() {
|
||||||
|
var jwt = LocalStorage.getJWT();
|
||||||
|
return jwt && !jwtHelper.isTokenExpired(jwt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,84 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('EndpointService', ['$q', 'Endpoints', 'FileUploadService', function EndpointServiceFactory($q, Endpoints, FileUploadService) {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
getActive: function() {
|
||||||
|
return Endpoints.getActiveEndpoint().$promise;
|
||||||
|
},
|
||||||
|
setActive: function(endpointID) {
|
||||||
|
return Endpoints.setActiveEndpoint({id: endpointID}).$promise;
|
||||||
|
},
|
||||||
|
endpoint: function(endpointID) {
|
||||||
|
return Endpoints.get({id: endpointID}).$promise;
|
||||||
|
},
|
||||||
|
endpoints: function() {
|
||||||
|
return Endpoints.query({}).$promise;
|
||||||
|
},
|
||||||
|
updateEndpoint: function(ID, name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, type) {
|
||||||
|
var endpoint = {
|
||||||
|
id: ID,
|
||||||
|
Name: name,
|
||||||
|
URL: type === 'local' ? ("unix://" + URL) : ("tcp://" + URL),
|
||||||
|
TLS: TLS
|
||||||
|
};
|
||||||
|
var deferred = $q.defer();
|
||||||
|
Endpoints.update({}, endpoint, function success(data) {
|
||||||
|
FileUploadService.uploadTLSFilesForEndpoint(ID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
|
||||||
|
deferred.notify({upload: false});
|
||||||
|
deferred.resolve(data);
|
||||||
|
}, function error(err) {
|
||||||
|
deferred.notify({upload: false});
|
||||||
|
deferred.reject({msg: 'Unable to upload TLS certs', err: err});
|
||||||
|
});
|
||||||
|
}, function error(err) {
|
||||||
|
deferred.reject({msg: 'Unable to update endpoint', err: err});
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
},
|
||||||
|
deleteEndpoint: function(endpointID) {
|
||||||
|
return Endpoints.remove({id: endpointID}).$promise;
|
||||||
|
},
|
||||||
|
createLocalEndpoint: function(name, URL, TLS, active) {
|
||||||
|
var endpoint = {
|
||||||
|
Name: "local",
|
||||||
|
URL: "unix:///var/run/docker.sock",
|
||||||
|
TLS: false
|
||||||
|
};
|
||||||
|
return Endpoints.create({active: active}, endpoint).$promise;
|
||||||
|
},
|
||||||
|
createRemoteEndpoint: function(name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, active) {
|
||||||
|
var endpoint = {
|
||||||
|
Name: name,
|
||||||
|
URL: 'tcp://' + URL,
|
||||||
|
TLS: TLS
|
||||||
|
};
|
||||||
|
var deferred = $q.defer();
|
||||||
|
Endpoints.create({active: active}, endpoint, function success(data) {
|
||||||
|
var endpointID = data.Id;
|
||||||
|
if (TLS) {
|
||||||
|
deferred.notify({upload: true});
|
||||||
|
FileUploadService.uploadTLSFilesForEndpoint(endpointID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
|
||||||
|
deferred.notify({upload: false});
|
||||||
|
if (active) {
|
||||||
|
Endpoints.setActiveEndpoint({}, {id: endpointID}, function success(data) {
|
||||||
|
deferred.resolve(data);
|
||||||
|
}, function error(err) {
|
||||||
|
deferred.reject({msg: 'Unable to create endpoint', err: err});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
deferred.resolve(data);
|
||||||
|
}
|
||||||
|
}, function error(err) {
|
||||||
|
deferred.notify({upload: false});
|
||||||
|
deferred.reject({msg: 'Unable to upload TLS certs', err: err});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
deferred.resolve(data);
|
||||||
|
}
|
||||||
|
}, function error(err) {
|
||||||
|
deferred.reject({msg: 'Unable to create endpoint', err: err});
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,44 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('FileUploadService', ['$q', 'Upload', function FileUploadFactory($q, Upload) {
|
||||||
|
'use strict';
|
||||||
|
function uploadFile(url, file) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
Upload.upload({
|
||||||
|
url: url,
|
||||||
|
data: { file: file }
|
||||||
|
}).then(function success(data) {
|
||||||
|
deferred.resolve(data);
|
||||||
|
}, function error(e) {
|
||||||
|
deferred.reject(e);
|
||||||
|
}, function progress(evt) {
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
uploadTLSFilesForEndpoint: function(endpointID, TLSCAFile, TLSCertFile, TLSKeyFile) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
var queue = [];
|
||||||
|
|
||||||
|
if (TLSCAFile !== null) {
|
||||||
|
var uploadTLSCA = uploadFile('api/upload/tls/' + endpointID + '/ca', TLSCAFile);
|
||||||
|
queue.push(uploadTLSCA);
|
||||||
|
}
|
||||||
|
if (TLSCertFile !== null) {
|
||||||
|
var uploadTLSCert = uploadFile('api/upload/tls/' + endpointID + '/cert', TLSCertFile);
|
||||||
|
queue.push(uploadTLSCert);
|
||||||
|
}
|
||||||
|
if (TLSKeyFile !== null) {
|
||||||
|
var uploadTLSKey = uploadFile('api/upload/tls/' + endpointID + '/key', TLSKeyFile);
|
||||||
|
queue.push(uploadTLSKey);
|
||||||
|
}
|
||||||
|
$q.all(queue).then(function (data) {
|
||||||
|
deferred.resolve(data);
|
||||||
|
}, function (err) {
|
||||||
|
deferred.reject(err);
|
||||||
|
}, function update(evt) {
|
||||||
|
deferred.notify(evt);
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,55 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('LineChart', ['Settings', function LineChartFactory(Settings) {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
build: function (id, data, getkey) {
|
||||||
|
var chart = new Chart($(id).get(0).getContext("2d"));
|
||||||
|
var map = {};
|
||||||
|
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var c = data[i];
|
||||||
|
var key = getkey(c);
|
||||||
|
|
||||||
|
var count = map[key];
|
||||||
|
if (count === undefined) {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
count += 1;
|
||||||
|
map[key] = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
var labels = [];
|
||||||
|
data = [];
|
||||||
|
var keys = Object.keys(map);
|
||||||
|
var max = 1;
|
||||||
|
|
||||||
|
for (i = keys.length - 1; i > -1; i--) {
|
||||||
|
var k = keys[i];
|
||||||
|
labels.push(k);
|
||||||
|
data.push(map[k]);
|
||||||
|
if (map[k] > max) {
|
||||||
|
max = map[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var steps = Math.min(max, 10);
|
||||||
|
var dataset = {
|
||||||
|
fillColor: "rgba(151,187,205,0.5)",
|
||||||
|
strokeColor: "rgba(151,187,205,1)",
|
||||||
|
pointColor: "rgba(151,187,205,1)",
|
||||||
|
pointStrokeColor: "#fff",
|
||||||
|
data: data
|
||||||
|
};
|
||||||
|
chart.Line({
|
||||||
|
labels: labels,
|
||||||
|
datasets: [dataset]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scaleStepWidth: Math.ceil(max / steps),
|
||||||
|
pointDotRadius: 1,
|
||||||
|
scaleIntegersOnly: true,
|
||||||
|
scaleOverride: true,
|
||||||
|
scaleSteps: steps
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,30 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('LocalStorage', ['localStorageService', function LocalStorageFactory(localStorageService) {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
storeEndpointState: function(state) {
|
||||||
|
localStorageService.set('ENDPOINT_STATE', state);
|
||||||
|
},
|
||||||
|
getEndpointState: function() {
|
||||||
|
return localStorageService.get('ENDPOINT_STATE');
|
||||||
|
},
|
||||||
|
storeJWT: function(jwt) {
|
||||||
|
localStorageService.set('JWT', jwt);
|
||||||
|
},
|
||||||
|
getJWT: function() {
|
||||||
|
return localStorageService.get('JWT');
|
||||||
|
},
|
||||||
|
deleteJWT: function() {
|
||||||
|
localStorageService.remove('JWT');
|
||||||
|
},
|
||||||
|
storePaginationCount: function(key, count) {
|
||||||
|
localStorageService.cookie.set('pagination_' + key, count);
|
||||||
|
},
|
||||||
|
getPaginationCount: function(key) {
|
||||||
|
return localStorageService.cookie.get('pagination_' + key);
|
||||||
|
},
|
||||||
|
clean: function() {
|
||||||
|
localStorageService.clearAll();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,38 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('Messages', ['$sanitize', function MessagesFactory($sanitize) {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
send: function (title, text) {
|
||||||
|
$.gritter.add({
|
||||||
|
title: $sanitize(title),
|
||||||
|
text: $sanitize(text),
|
||||||
|
time: 2000,
|
||||||
|
before_open: function () {
|
||||||
|
if ($('.gritter-item-wrapper').length === 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: function (title, e, fallbackText) {
|
||||||
|
var msg = fallbackText;
|
||||||
|
if (e.data && e.data.message) {
|
||||||
|
msg = e.data.message;
|
||||||
|
} else if (e.message) {
|
||||||
|
msg = e.message;
|
||||||
|
} else if (e.data && e.data.length > 0 && e.data[0].message) {
|
||||||
|
msg = e.data[0].message;
|
||||||
|
}
|
||||||
|
$.gritter.add({
|
||||||
|
title: $sanitize(title),
|
||||||
|
text: $sanitize(msg),
|
||||||
|
time: 10000,
|
||||||
|
before_open: function () {
|
||||||
|
if ($('.gritter-item-wrapper').length === 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,17 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('Pagination', ['LocalStorage', 'Settings', function PaginationFactory(LocalStorage, Settings) {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
getPaginationCount: function(key) {
|
||||||
|
var storedCount = LocalStorage.getPaginationCount(key);
|
||||||
|
var paginationCount = Settings.pagination_count;
|
||||||
|
if (storedCount !== null) {
|
||||||
|
paginationCount = storedCount;
|
||||||
|
}
|
||||||
|
return '' + paginationCount;
|
||||||
|
},
|
||||||
|
setPaginationCount: function(key, count) {
|
||||||
|
LocalStorage.storePaginationCount(key, count);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,17 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('Settings', ['DOCKER_ENDPOINT', 'DOCKER_PORT', 'UI_VERSION', 'PAGINATION_MAX_ITEMS', function SettingsFactory(DOCKER_ENDPOINT, DOCKER_PORT, UI_VERSION, PAGINATION_MAX_ITEMS) {
|
||||||
|
'use strict';
|
||||||
|
var url = DOCKER_ENDPOINT;
|
||||||
|
if (DOCKER_PORT) {
|
||||||
|
url = url + DOCKER_PORT + '\\' + DOCKER_PORT;
|
||||||
|
}
|
||||||
|
var firstLoad = (localStorage.getItem('firstLoad') || 'true') === 'true';
|
||||||
|
return {
|
||||||
|
displayAll: true,
|
||||||
|
endpoint: DOCKER_ENDPOINT,
|
||||||
|
uiVersion: UI_VERSION,
|
||||||
|
url: url,
|
||||||
|
firstLoad: firstLoad,
|
||||||
|
pagination_count: PAGINATION_MAX_ITEMS
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,46 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('StateManager', ['$q', 'Info', 'InfoHelper', 'Version', 'LocalStorage', function StateManagerFactory($q, Info, InfoHelper, Version, LocalStorage) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var state = {
|
||||||
|
loading: true,
|
||||||
|
application: {},
|
||||||
|
endpoint: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: function() {
|
||||||
|
var endpointState = LocalStorage.getEndpointState();
|
||||||
|
if (endpointState) {
|
||||||
|
state.endpoint = endpointState;
|
||||||
|
}
|
||||||
|
state.loading = false;
|
||||||
|
},
|
||||||
|
clean: function() {
|
||||||
|
state.endpoint = {};
|
||||||
|
},
|
||||||
|
updateEndpointState: function(loading) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
if (loading) {
|
||||||
|
state.loading = true;
|
||||||
|
}
|
||||||
|
$q.all([Info.get({}).$promise, Version.get({}).$promise])
|
||||||
|
.then(function success(data) {
|
||||||
|
var endpointMode = InfoHelper.determineEndpointMode(data[0]);
|
||||||
|
var endpointAPIVersion = parseFloat(data[1].ApiVersion);
|
||||||
|
state.endpoint.mode = endpointMode;
|
||||||
|
state.endpoint.apiVersion = endpointAPIVersion;
|
||||||
|
LocalStorage.storeEndpointState(state.endpoint);
|
||||||
|
state.loading = false;
|
||||||
|
deferred.resolve();
|
||||||
|
}, function error(err) {
|
||||||
|
state.loading = false;
|
||||||
|
deferred.reject({msg: 'Unable to connect to the Docker endpoint', err: err});
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
},
|
||||||
|
getState: function() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -1,170 +0,0 @@
|
||||||
angular.module('portainer.helpers', [])
|
|
||||||
.factory('InfoHelper', [function InfoHelperFactory() {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
determineEndpointMode: function(info) {
|
|
||||||
var mode = {
|
|
||||||
provider: '',
|
|
||||||
role: ''
|
|
||||||
};
|
|
||||||
if (_.startsWith(info.ServerVersion, 'swarm')) {
|
|
||||||
mode.provider = "DOCKER_SWARM";
|
|
||||||
if (info.SystemStatus[0][1] === 'primary') {
|
|
||||||
mode.role = "PRIMARY";
|
|
||||||
} else {
|
|
||||||
mode.role = "REPLICA";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!info.Swarm || _.isEmpty(info.Swarm.NodeID)) {
|
|
||||||
mode.provider = "DOCKER_STANDALONE";
|
|
||||||
} else {
|
|
||||||
mode.provider = "DOCKER_SWARM_MODE";
|
|
||||||
if (info.Swarm.ControlAvailable) {
|
|
||||||
mode.role = "MANAGER";
|
|
||||||
} else {
|
|
||||||
mode.role = "WORKER";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('LabelHelper', [function LabelHelperFactory() {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
fromLabelHashToKeyValue: function(labels) {
|
|
||||||
if (labels) {
|
|
||||||
return Object.keys(labels).map(function(key) {
|
|
||||||
return {key: key, value: labels[key], originalKey: key, originalValue: labels[key], added: true};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
fromKeyValueToLabelHash: function(labelKV) {
|
|
||||||
var labels = {};
|
|
||||||
if (labelKV) {
|
|
||||||
labelKV.forEach(function(label) {
|
|
||||||
labels[label.key] = label.value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return labels;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('ImageHelper', [function ImageHelperFactory() {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
createImageConfigForCommit: function(imageName, registry) {
|
|
||||||
var imageNameAndTag = imageName.split(':');
|
|
||||||
var image = imageNameAndTag[0];
|
|
||||||
if (registry) {
|
|
||||||
image = registry + '/' + imageNameAndTag[0];
|
|
||||||
}
|
|
||||||
var imageConfig = {
|
|
||||||
repo: image,
|
|
||||||
tag: imageNameAndTag[1] ? imageNameAndTag[1] : 'latest'
|
|
||||||
};
|
|
||||||
return imageConfig;
|
|
||||||
},
|
|
||||||
createImageConfigForContainer: function (imageName, registry) {
|
|
||||||
var imageNameAndTag = imageName.split(':');
|
|
||||||
var image = imageNameAndTag[0];
|
|
||||||
if (registry) {
|
|
||||||
image = registry + '/' + imageNameAndTag[0];
|
|
||||||
}
|
|
||||||
var imageConfig = {
|
|
||||||
fromImage: image,
|
|
||||||
tag: imageNameAndTag[1] ? imageNameAndTag[1] : 'latest'
|
|
||||||
};
|
|
||||||
return imageConfig;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('ContainerHelper', [function ContainerHelperFactory() {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
hideContainers: function(containers, containersToHideLabels) {
|
|
||||||
return containers.filter(function (container) {
|
|
||||||
var filterContainer = false;
|
|
||||||
containersToHideLabels.forEach(function(label, index) {
|
|
||||||
if (_.has(container.Labels, label.name) &&
|
|
||||||
container.Labels[label.name] === label.value) {
|
|
||||||
filterContainer = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!filterContainer) {
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('ServiceHelper', [function ServiceHelperFactory() {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
serviceToConfig: function(service) {
|
|
||||||
return {
|
|
||||||
Name: service.Spec.Name,
|
|
||||||
Labels: service.Spec.Labels,
|
|
||||||
TaskTemplate: service.Spec.TaskTemplate,
|
|
||||||
Mode: service.Spec.Mode,
|
|
||||||
UpdateConfig: service.Spec.UpdateConfig,
|
|
||||||
Networks: service.Spec.Networks,
|
|
||||||
EndpointSpec: service.Spec.EndpointSpec
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('NodeHelper', [function NodeHelperFactory() {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
nodeToConfig: function(node) {
|
|
||||||
return {
|
|
||||||
Name: node.Spec.Name,
|
|
||||||
Role: node.Spec.Role,
|
|
||||||
Labels: node.Spec.Labels,
|
|
||||||
Availability: node.Spec.Availability
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('TemplateHelper', [function TemplateHelperFactory() {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
getPortBindings: function(ports) {
|
|
||||||
var bindings = [];
|
|
||||||
ports.forEach(function (port) {
|
|
||||||
var portAndProtocol = _.split(port, '/');
|
|
||||||
var binding = {
|
|
||||||
containerPort: portAndProtocol[0],
|
|
||||||
protocol: portAndProtocol[1]
|
|
||||||
};
|
|
||||||
bindings.push(binding);
|
|
||||||
});
|
|
||||||
return bindings;
|
|
||||||
},
|
|
||||||
//Not used atm, may prove useful later
|
|
||||||
getVolumeBindings: function(volumes) {
|
|
||||||
var bindings = [];
|
|
||||||
volumes.forEach(function (volume) {
|
|
||||||
bindings.push({ containerPath: volume });
|
|
||||||
});
|
|
||||||
return bindings;
|
|
||||||
},
|
|
||||||
//Not used atm, may prove useful later
|
|
||||||
getEnvBindings: function(env) {
|
|
||||||
var bindings = [];
|
|
||||||
env.forEach(function (envvar) {
|
|
||||||
var binding = {
|
|
||||||
name: envvar.name
|
|
||||||
};
|
|
||||||
if (envvar.set) {
|
|
||||||
binding.value = envvar.set;
|
|
||||||
}
|
|
||||||
bindings.push(binding);
|
|
||||||
});
|
|
||||||
return bindings;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
|
@ -1,594 +0,0 @@
|
||||||
angular.module('portainer.services', ['ngResource', 'ngSanitize'])
|
|
||||||
.factory('Container', ['$resource', 'Settings', function ContainerFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// Resource for interacting with the docker containers
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-1-containers
|
|
||||||
return $resource(Settings.url + '/containers/:id/:action', {
|
|
||||||
name: '@name'
|
|
||||||
}, {
|
|
||||||
query: {method: 'GET', params: {all: 0, action: 'json', filters: '@filters' }, isArray: true},
|
|
||||||
get: {method: 'GET', params: {action: 'json'}},
|
|
||||||
stop: {method: 'POST', params: {id: '@id', t: 5, action: 'stop'}},
|
|
||||||
restart: {method: 'POST', params: {id: '@id', t: 5, action: 'restart'}},
|
|
||||||
kill: {method: 'POST', params: {id: '@id', action: 'kill'}},
|
|
||||||
pause: {method: 'POST', params: {id: '@id', action: 'pause'}},
|
|
||||||
unpause: {method: 'POST', params: {id: '@id', action: 'unpause'}},
|
|
||||||
changes: {method: 'GET', params: {action: 'changes'}, isArray: true},
|
|
||||||
stats: {method: 'GET', params: {id: '@id', stream: false, action: 'stats'}, timeout: 5000},
|
|
||||||
start: {
|
|
||||||
method: 'POST', params: {id: '@id', action: 'start'},
|
|
||||||
transformResponse: genericHandler
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
method: 'POST', params: {action: 'create'},
|
|
||||||
transformResponse: genericHandler
|
|
||||||
},
|
|
||||||
remove: {
|
|
||||||
method: 'DELETE', params: {id: '@id', v: 0},
|
|
||||||
transformResponse: genericHandler
|
|
||||||
},
|
|
||||||
rename: {
|
|
||||||
method: 'POST', params: {id: '@id', action: 'rename', name: '@name'},
|
|
||||||
transformResponse: genericHandler
|
|
||||||
},
|
|
||||||
exec: {
|
|
||||||
method: 'POST', params: {id: '@id', action: 'exec'},
|
|
||||||
transformResponse: genericHandler
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Service', ['$resource', 'Settings', function ServiceFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// https://docs.docker.com/engine/reference/api/docker_remote_api_<%= remoteApiVersion %>/#/3-9-services
|
|
||||||
return $resource(Settings.url + '/services/:id/:action', {}, {
|
|
||||||
get: { method: 'GET', params: {id: '@id'} },
|
|
||||||
query: { method: 'GET', isArray: true },
|
|
||||||
create: { method: 'POST', params: {action: 'create'} },
|
|
||||||
update: { method: 'POST', params: {id: '@id', action: 'update', version: '@version'} },
|
|
||||||
remove: { method: 'DELETE', params: {id: '@id'} }
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Task', ['$resource', 'Settings', function TaskFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// https://docs.docker.com/engine/reference/api/docker_remote_api_<%= remoteApiVersion %>/#/3-9-services
|
|
||||||
return $resource(Settings.url + '/tasks/:id', {}, {
|
|
||||||
get: { method: 'GET', params: {id: '@id'} },
|
|
||||||
query: { method: 'GET', isArray: true, params: {filters: '@filters'} }
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Exec', ['$resource', 'Settings', function ExecFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// https://docs.docker.com/engine/reference/api/docker_remote_api_<%= remoteApiVersion %>/#/exec-resize
|
|
||||||
return $resource(Settings.url + '/exec/:id/:action', {}, {
|
|
||||||
resize: {
|
|
||||||
method: 'POST', params: {id: '@id', action: 'resize', h: '@height', w: '@width'},
|
|
||||||
transformResponse: genericHandler
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('ContainerCommit', ['$resource', '$http', 'Settings', function ContainerCommitFactory($resource, $http, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#create-a-new-image-from-a-container-s-changes
|
|
||||||
return $resource(Settings.url + '/commit', {}, {
|
|
||||||
commit: {method: 'POST', params: {container: '@id', repo: '@repo', tag: '@tag'}}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('ContainerLogs', ['$resource', '$http', 'Settings', function ContainerLogsFactory($resource, $http, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#get-container-logs
|
|
||||||
return {
|
|
||||||
get: function (id, params, callback) {
|
|
||||||
$http({
|
|
||||||
method: 'GET',
|
|
||||||
url: Settings.url + '/containers/' + id + '/logs',
|
|
||||||
params: {
|
|
||||||
'stdout': params.stdout || 0,
|
|
||||||
'stderr': params.stderr || 0,
|
|
||||||
'timestamps': params.timestamps || 0,
|
|
||||||
'tail': params.tail || 'all'
|
|
||||||
}
|
|
||||||
}).success(callback).error(function (data, status, headers, config) {
|
|
||||||
console.log(error, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('ContainerTop', ['$http', 'Settings', function ($http, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#list-processes-running-inside-a-container
|
|
||||||
return {
|
|
||||||
get: function (id, params, callback, errorCallback) {
|
|
||||||
$http({
|
|
||||||
method: 'GET',
|
|
||||||
url: Settings.url + '/containers/' + id + '/top',
|
|
||||||
params: {
|
|
||||||
ps_args: params.ps_args
|
|
||||||
}
|
|
||||||
}).success(callback);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('Image', ['$resource', 'Settings', function ImageFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-2-images
|
|
||||||
return $resource(Settings.url + '/images/:id/:action', {}, {
|
|
||||||
query: {method: 'GET', params: {all: 0, action: 'json'}, isArray: true},
|
|
||||||
get: {method: 'GET', params: {action: 'json'}},
|
|
||||||
search: {method: 'GET', params: {action: 'search'}},
|
|
||||||
history: {method: 'GET', params: {action: 'history'}, isArray: true},
|
|
||||||
insert: {method: 'POST', params: {id: '@id', action: 'insert'}},
|
|
||||||
tag: {method: 'POST', params: {id: '@id', action: 'tag', force: 0, repo: '@repo', tag: '@tag'}},
|
|
||||||
inspect: {method: 'GET', params: {id: '@id', action: 'json'}},
|
|
||||||
push: {
|
|
||||||
method: 'POST', params: {action: 'push', id: '@tag'},
|
|
||||||
isArray: true, transformResponse: jsonObjectsToArrayHandler
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
method: 'POST', params: {action: 'create', fromImage: '@fromImage', tag: '@tag'},
|
|
||||||
isArray: true, transformResponse: jsonObjectsToArrayHandler
|
|
||||||
},
|
|
||||||
remove: {
|
|
||||||
method: 'DELETE', params: {id: '@id'},
|
|
||||||
isArray: true, transformResponse: deleteImageHandler
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Events', ['$resource', 'Settings', function EventFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#/monitor-docker-s-events
|
|
||||||
return $resource(Settings.url + '/events', {}, {
|
|
||||||
query: {
|
|
||||||
method: 'GET', params: {since: '@since', until: '@until'},
|
|
||||||
isArray: true, transformResponse: jsonObjectsToArrayHandler
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Version', ['$resource', 'Settings', function VersionFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#show-the-docker-version-information
|
|
||||||
return $resource(Settings.url + '/version', {}, {
|
|
||||||
get: {method: 'GET'}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Node', ['$resource', 'Settings', function NodeFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// https://docs.docker.com/engine/reference/api/docker_remote_api_<%= remoteApiVersion %>/#/3-7-nodes
|
|
||||||
return $resource(Settings.url + '/nodes/:id/:action', {}, {
|
|
||||||
query: {method: 'GET', isArray: true},
|
|
||||||
get: {method: 'GET', params: {id: '@id'}},
|
|
||||||
update: { method: 'POST', params: {id: '@id', action: 'update', version: '@version'} },
|
|
||||||
remove: { method: 'DELETE', params: {id: '@id'} }
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Swarm', ['$resource', 'Settings', function SwarmFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// https://docs.docker.com/engine/reference/api/docker_remote_api_<%= remoteApiVersion %>/#/3-8-swarm
|
|
||||||
return $resource(Settings.url + '/swarm', {}, {
|
|
||||||
get: {method: 'GET'}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Info', ['$resource', 'Settings', function InfoFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#display-system-wide-information
|
|
||||||
return $resource(Settings.url + '/info', {}, {
|
|
||||||
get: {method: 'GET'}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Network', ['$resource', 'Settings', function NetworkFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-5-networks
|
|
||||||
return $resource(Settings.url + '/networks/:id/:action', {id: '@id'}, {
|
|
||||||
query: {method: 'GET', isArray: true},
|
|
||||||
get: {method: 'GET'},
|
|
||||||
create: {method: 'POST', params: {action: 'create'}, transformResponse: genericHandler},
|
|
||||||
remove: { method: 'DELETE', transformResponse: genericHandler },
|
|
||||||
connect: {method: 'POST', params: {action: 'connect'}},
|
|
||||||
disconnect: {method: 'POST', params: {action: 'disconnect'}}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Volume', ['$resource', 'Settings', function VolumeFactory($resource, Settings) {
|
|
||||||
'use strict';
|
|
||||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-5-networks
|
|
||||||
return $resource(Settings.url + '/volumes/:name/:action', {name: '@name'}, {
|
|
||||||
query: {method: 'GET'},
|
|
||||||
get: {method: 'GET'},
|
|
||||||
create: {method: 'POST', params: {action: 'create'}, transformResponse: genericHandler},
|
|
||||||
remove: {
|
|
||||||
method: 'DELETE', transformResponse: genericHandler
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Config', ['$resource', 'CONFIG_ENDPOINT', function ConfigFactory($resource, CONFIG_ENDPOINT) {
|
|
||||||
return $resource(CONFIG_ENDPOINT).get();
|
|
||||||
}])
|
|
||||||
.factory('Templates', ['$resource', 'TEMPLATES_ENDPOINT', function TemplatesFactory($resource, TEMPLATES_ENDPOINT) {
|
|
||||||
return $resource(TEMPLATES_ENDPOINT, {}, {
|
|
||||||
get: {method: 'GET', isArray: true}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Settings', ['DOCKER_ENDPOINT', 'DOCKER_PORT', 'UI_VERSION', 'PAGINATION_MAX_ITEMS', function SettingsFactory(DOCKER_ENDPOINT, DOCKER_PORT, UI_VERSION, PAGINATION_MAX_ITEMS) {
|
|
||||||
'use strict';
|
|
||||||
var url = DOCKER_ENDPOINT;
|
|
||||||
if (DOCKER_PORT) {
|
|
||||||
url = url + DOCKER_PORT + '\\' + DOCKER_PORT;
|
|
||||||
}
|
|
||||||
var firstLoad = (localStorage.getItem('firstLoad') || 'true') === 'true';
|
|
||||||
return {
|
|
||||||
displayAll: true,
|
|
||||||
endpoint: DOCKER_ENDPOINT,
|
|
||||||
uiVersion: UI_VERSION,
|
|
||||||
url: url,
|
|
||||||
firstLoad: firstLoad,
|
|
||||||
pagination_count: PAGINATION_MAX_ITEMS
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('Auth', ['$resource', 'AUTH_ENDPOINT', function AuthFactory($resource, AUTH_ENDPOINT) {
|
|
||||||
'use strict';
|
|
||||||
return $resource(AUTH_ENDPOINT, {}, {
|
|
||||||
login: {
|
|
||||||
method: 'POST'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Users', ['$resource', 'USERS_ENDPOINT', function UsersFactory($resource, USERS_ENDPOINT) {
|
|
||||||
'use strict';
|
|
||||||
return $resource(USERS_ENDPOINT + '/:username/:action', {}, {
|
|
||||||
create: { method: 'POST' },
|
|
||||||
get: { method: 'GET', params: { username: '@username' } },
|
|
||||||
update: { method: 'PUT', params: { username: '@username' } },
|
|
||||||
checkPassword: { method: 'POST', params: { username: '@username', action: 'passwd' } },
|
|
||||||
checkAdminUser: { method: 'GET', params: { username: 'admin', action: 'check' } },
|
|
||||||
initAdminUser: { method: 'POST', params: { username: 'admin', action: 'init' } }
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Authentication', ['$q', '$rootScope', 'Auth', 'jwtHelper', 'LocalStorage', 'StateManager', function AuthenticationFactory($q, $rootScope, Auth, jwtHelper, LocalStorage, StateManager) {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
init: function() {
|
|
||||||
var jwt = LocalStorage.getJWT();
|
|
||||||
if (jwt) {
|
|
||||||
var tokenPayload = jwtHelper.decodeToken(jwt);
|
|
||||||
$rootScope.username = tokenPayload.username;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
login: function(username, password) {
|
|
||||||
return $q(function (resolve, reject) {
|
|
||||||
Auth.login({username: username, password: password}).$promise
|
|
||||||
.then(function(data) {
|
|
||||||
LocalStorage.storeJWT(data.jwt);
|
|
||||||
$rootScope.username = username;
|
|
||||||
resolve();
|
|
||||||
}, function() {
|
|
||||||
reject();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
logout: function() {
|
|
||||||
StateManager.clean();
|
|
||||||
LocalStorage.clean();
|
|
||||||
},
|
|
||||||
isAuthenticated: function() {
|
|
||||||
var jwt = LocalStorage.getJWT();
|
|
||||||
return jwt && !jwtHelper.isTokenExpired(jwt);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('FileUploadService', ['$q', 'Upload', function FileUploadFactory($q, Upload) {
|
|
||||||
'use strict';
|
|
||||||
function uploadFile(url, file) {
|
|
||||||
var deferred = $q.defer();
|
|
||||||
Upload.upload({
|
|
||||||
url: url,
|
|
||||||
data: { file: file }
|
|
||||||
}).then(function success(data) {
|
|
||||||
deferred.resolve(data);
|
|
||||||
}, function error(e) {
|
|
||||||
deferred.reject(e);
|
|
||||||
}, function progress(evt) {
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
uploadTLSFilesForEndpoint: function(endpointID, TLSCAFile, TLSCertFile, TLSKeyFile) {
|
|
||||||
var deferred = $q.defer();
|
|
||||||
var queue = [];
|
|
||||||
|
|
||||||
if (TLSCAFile !== null) {
|
|
||||||
var uploadTLSCA = uploadFile('api/upload/tls/' + endpointID + '/ca', TLSCAFile);
|
|
||||||
queue.push(uploadTLSCA);
|
|
||||||
}
|
|
||||||
if (TLSCertFile !== null) {
|
|
||||||
var uploadTLSCert = uploadFile('api/upload/tls/' + endpointID + '/cert', TLSCertFile);
|
|
||||||
queue.push(uploadTLSCert);
|
|
||||||
}
|
|
||||||
if (TLSKeyFile !== null) {
|
|
||||||
var uploadTLSKey = uploadFile('api/upload/tls/' + endpointID + '/key', TLSKeyFile);
|
|
||||||
queue.push(uploadTLSKey);
|
|
||||||
}
|
|
||||||
$q.all(queue).then(function (data) {
|
|
||||||
deferred.resolve(data);
|
|
||||||
}, function (err) {
|
|
||||||
deferred.reject(err);
|
|
||||||
}, function update(evt) {
|
|
||||||
deferred.notify(evt);
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('Endpoints', ['$resource', 'ENDPOINTS_ENDPOINT', function EndpointsFactory($resource, ENDPOINTS_ENDPOINT) {
|
|
||||||
'use strict';
|
|
||||||
return $resource(ENDPOINTS_ENDPOINT + '/:id/:action', {}, {
|
|
||||||
create: { method: 'POST' },
|
|
||||||
query: { method: 'GET', isArray: true },
|
|
||||||
get: { method: 'GET', params: { id: '@id' } },
|
|
||||||
update: { method: 'PUT', params: { id: '@id' } },
|
|
||||||
remove: { method: 'DELETE', params: { id: '@id'} },
|
|
||||||
getActiveEndpoint: { method: 'GET', params: { id: '0' } },
|
|
||||||
setActiveEndpoint: { method: 'POST', params: { id: '@id', action: 'active' } }
|
|
||||||
});
|
|
||||||
}])
|
|
||||||
.factory('Pagination', ['LocalStorage', 'Settings', function PaginationFactory(LocalStorage, Settings) {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
getPaginationCount: function(key) {
|
|
||||||
var storedCount = LocalStorage.getPaginationCount(key);
|
|
||||||
var paginationCount = Settings.pagination_count;
|
|
||||||
if (storedCount !== null) {
|
|
||||||
paginationCount = storedCount;
|
|
||||||
}
|
|
||||||
return '' + paginationCount;
|
|
||||||
},
|
|
||||||
setPaginationCount: function(key, count) {
|
|
||||||
LocalStorage.storePaginationCount(key, count);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('LocalStorage', ['localStorageService', function LocalStorageFactory(localStorageService) {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
storeEndpointState: function(state) {
|
|
||||||
localStorageService.set('ENDPOINT_STATE', state);
|
|
||||||
},
|
|
||||||
getEndpointState: function() {
|
|
||||||
return localStorageService.get('ENDPOINT_STATE');
|
|
||||||
},
|
|
||||||
storeJWT: function(jwt) {
|
|
||||||
localStorageService.set('JWT', jwt);
|
|
||||||
},
|
|
||||||
getJWT: function() {
|
|
||||||
return localStorageService.get('JWT');
|
|
||||||
},
|
|
||||||
deleteJWT: function() {
|
|
||||||
localStorageService.remove('JWT');
|
|
||||||
},
|
|
||||||
storePaginationCount: function(key, count) {
|
|
||||||
localStorageService.cookie.set('pagination_' + key, count);
|
|
||||||
},
|
|
||||||
getPaginationCount: function(key) {
|
|
||||||
return localStorageService.cookie.get('pagination_' + key);
|
|
||||||
},
|
|
||||||
clean: function() {
|
|
||||||
localStorageService.clearAll();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('StateManager', ['$q', 'Info', 'InfoHelper', 'Version', 'LocalStorage', function StateManagerFactory($q, Info, InfoHelper, Version, LocalStorage) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var state = {
|
|
||||||
loading: true,
|
|
||||||
application: {},
|
|
||||||
endpoint: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
init: function() {
|
|
||||||
var endpointState = LocalStorage.getEndpointState();
|
|
||||||
if (endpointState) {
|
|
||||||
state.endpoint = endpointState;
|
|
||||||
}
|
|
||||||
state.loading = false;
|
|
||||||
},
|
|
||||||
clean: function() {
|
|
||||||
state.endpoint = {};
|
|
||||||
},
|
|
||||||
updateEndpointState: function(loading) {
|
|
||||||
var deferred = $q.defer();
|
|
||||||
if (loading) {
|
|
||||||
state.loading = true;
|
|
||||||
}
|
|
||||||
$q.all([Info.get({}).$promise, Version.get({}).$promise])
|
|
||||||
.then(function success(data) {
|
|
||||||
var endpointMode = InfoHelper.determineEndpointMode(data[0]);
|
|
||||||
var endpointAPIVersion = parseFloat(data[1].ApiVersion);
|
|
||||||
state.endpoint.mode = endpointMode;
|
|
||||||
state.endpoint.apiVersion = endpointAPIVersion;
|
|
||||||
LocalStorage.storeEndpointState(state.endpoint);
|
|
||||||
state.loading = false;
|
|
||||||
deferred.resolve();
|
|
||||||
}, function error(err) {
|
|
||||||
state.loading = false;
|
|
||||||
deferred.reject({msg: 'Unable to connect to the Docker endpoint', err: err});
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
},
|
|
||||||
getState: function() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('EndpointService', ['$q', 'Endpoints', 'FileUploadService', function EndpointServiceFactory($q, Endpoints, FileUploadService) {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
getActive: function() {
|
|
||||||
return Endpoints.getActiveEndpoint().$promise;
|
|
||||||
},
|
|
||||||
setActive: function(endpointID) {
|
|
||||||
return Endpoints.setActiveEndpoint({id: endpointID}).$promise;
|
|
||||||
},
|
|
||||||
endpoint: function(endpointID) {
|
|
||||||
return Endpoints.get({id: endpointID}).$promise;
|
|
||||||
},
|
|
||||||
endpoints: function() {
|
|
||||||
return Endpoints.query({}).$promise;
|
|
||||||
},
|
|
||||||
updateEndpoint: function(ID, name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, type) {
|
|
||||||
var endpoint = {
|
|
||||||
id: ID,
|
|
||||||
Name: name,
|
|
||||||
URL: type === 'local' ? ("unix://" + URL) : ("tcp://" + URL),
|
|
||||||
TLS: TLS
|
|
||||||
};
|
|
||||||
var deferred = $q.defer();
|
|
||||||
Endpoints.update({}, endpoint, function success(data) {
|
|
||||||
FileUploadService.uploadTLSFilesForEndpoint(ID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
|
|
||||||
deferred.notify({upload: false});
|
|
||||||
deferred.resolve(data);
|
|
||||||
}, function error(err) {
|
|
||||||
deferred.notify({upload: false});
|
|
||||||
deferred.reject({msg: 'Unable to upload TLS certs', err: err});
|
|
||||||
});
|
|
||||||
}, function error(err) {
|
|
||||||
deferred.reject({msg: 'Unable to update endpoint', err: err});
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
},
|
|
||||||
deleteEndpoint: function(endpointID) {
|
|
||||||
return Endpoints.remove({id: endpointID}).$promise;
|
|
||||||
},
|
|
||||||
createLocalEndpoint: function(name, URL, TLS, active) {
|
|
||||||
var endpoint = {
|
|
||||||
Name: "local",
|
|
||||||
URL: "unix:///var/run/docker.sock",
|
|
||||||
TLS: false
|
|
||||||
};
|
|
||||||
return Endpoints.create({active: active}, endpoint).$promise;
|
|
||||||
},
|
|
||||||
createRemoteEndpoint: function(name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, active) {
|
|
||||||
var endpoint = {
|
|
||||||
Name: name,
|
|
||||||
URL: 'tcp://' + URL,
|
|
||||||
TLS: TLS
|
|
||||||
};
|
|
||||||
var deferred = $q.defer();
|
|
||||||
Endpoints.create({active: active}, endpoint, function success(data) {
|
|
||||||
var endpointID = data.Id;
|
|
||||||
if (TLS) {
|
|
||||||
deferred.notify({upload: true});
|
|
||||||
FileUploadService.uploadTLSFilesForEndpoint(endpointID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
|
|
||||||
deferred.notify({upload: false});
|
|
||||||
if (active) {
|
|
||||||
Endpoints.setActiveEndpoint({}, {id: endpointID}, function success(data) {
|
|
||||||
deferred.resolve(data);
|
|
||||||
}, function error(err) {
|
|
||||||
deferred.reject({msg: 'Unable to create endpoint', err: err});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
deferred.resolve(data);
|
|
||||||
}
|
|
||||||
}, function error(err) {
|
|
||||||
deferred.notify({upload: false});
|
|
||||||
deferred.reject({msg: 'Unable to upload TLS certs', err: err});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
deferred.resolve(data);
|
|
||||||
}
|
|
||||||
}, function error(err) {
|
|
||||||
deferred.reject({msg: 'Unable to create endpoint', err: err});
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('Messages', ['$rootScope', '$sanitize', function MessagesFactory($rootScope, $sanitize) {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
send: function (title, text) {
|
|
||||||
$.gritter.add({
|
|
||||||
title: $sanitize(title),
|
|
||||||
text: $sanitize(text),
|
|
||||||
time: 2000,
|
|
||||||
before_open: function () {
|
|
||||||
if ($('.gritter-item-wrapper').length === 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
error: function (title, e, fallbackText) {
|
|
||||||
var msg = fallbackText;
|
|
||||||
if (e.data && e.data.message) {
|
|
||||||
msg = e.data.message;
|
|
||||||
} else if (e.message) {
|
|
||||||
msg = e.message;
|
|
||||||
} else if (e.data && e.data.length > 0 && e.data[0].message) {
|
|
||||||
msg = e.data[0].message;
|
|
||||||
}
|
|
||||||
$.gritter.add({
|
|
||||||
title: $sanitize(title),
|
|
||||||
text: $sanitize(msg),
|
|
||||||
time: 10000,
|
|
||||||
before_open: function () {
|
|
||||||
if ($('.gritter-item-wrapper').length === 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('LineChart', ['Settings', function LineChartFactory(Settings) {
|
|
||||||
'use strict';
|
|
||||||
return {
|
|
||||||
build: function (id, data, getkey) {
|
|
||||||
var chart = new Chart($(id).get(0).getContext("2d"));
|
|
||||||
var map = {};
|
|
||||||
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
|
||||||
var c = data[i];
|
|
||||||
var key = getkey(c);
|
|
||||||
|
|
||||||
var count = map[key];
|
|
||||||
if (count === undefined) {
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
count += 1;
|
|
||||||
map[key] = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
var labels = [];
|
|
||||||
data = [];
|
|
||||||
var keys = Object.keys(map);
|
|
||||||
var max = 1;
|
|
||||||
|
|
||||||
for (i = keys.length - 1; i > -1; i--) {
|
|
||||||
var k = keys[i];
|
|
||||||
labels.push(k);
|
|
||||||
data.push(map[k]);
|
|
||||||
if (map[k] > max) {
|
|
||||||
max = map[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var steps = Math.min(max, 10);
|
|
||||||
var dataset = {
|
|
||||||
fillColor: "rgba(151,187,205,0.5)",
|
|
||||||
strokeColor: "rgba(151,187,205,1)",
|
|
||||||
pointColor: "rgba(151,187,205,1)",
|
|
||||||
pointStrokeColor: "#fff",
|
|
||||||
data: data
|
|
||||||
};
|
|
||||||
chart.Line({
|
|
||||||
labels: labels,
|
|
||||||
datasets: [dataset]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scaleStepWidth: Math.ceil(max / steps),
|
|
||||||
pointDotRadius: 1,
|
|
||||||
scaleIntegersOnly: true,
|
|
||||||
scaleOverride: true,
|
|
||||||
scaleSteps: steps
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
|
@ -1,240 +0,0 @@
|
||||||
function ImageViewModel(data) {
|
|
||||||
this.Id = data.Id;
|
|
||||||
this.Tag = data.Tag;
|
|
||||||
this.Repository = data.Repository;
|
|
||||||
this.Created = data.Created;
|
|
||||||
this.Checked = false;
|
|
||||||
this.RepoTags = data.RepoTags;
|
|
||||||
this.VirtualSize = data.VirtualSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
function TaskViewModel(data, node_data) {
|
|
||||||
this.Id = data.ID;
|
|
||||||
this.Created = data.CreatedAt;
|
|
||||||
this.Updated = data.UpdatedAt;
|
|
||||||
this.Slot = data.Slot;
|
|
||||||
this.Status = data.Status.State;
|
|
||||||
this.Image = data.Spec.ContainerSpec ? data.Spec.ContainerSpec.Image : '';
|
|
||||||
if (node_data) {
|
|
||||||
for (var i = 0; i < node_data.length; ++i) {
|
|
||||||
if (data.NodeID === node_data[i].ID) {
|
|
||||||
this.Node = node_data[i].Description.Hostname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ServiceViewModel(data) {
|
|
||||||
this.Model = data;
|
|
||||||
this.Id = data.ID;
|
|
||||||
this.Name = data.Spec.Name;
|
|
||||||
this.Image = data.Spec.TaskTemplate.ContainerSpec.Image;
|
|
||||||
this.Version = data.Version.Index;
|
|
||||||
if (data.Spec.Mode.Replicated) {
|
|
||||||
this.Mode = 'replicated' ;
|
|
||||||
this.Replicas = data.Spec.Mode.Replicated.Replicas;
|
|
||||||
} else {
|
|
||||||
this.Mode = 'global';
|
|
||||||
}
|
|
||||||
this.Labels = data.Spec.Labels;
|
|
||||||
if (data.Spec.TaskTemplate.ContainerSpec) {
|
|
||||||
this.ContainerLabels = data.Spec.TaskTemplate.ContainerSpec.Labels;
|
|
||||||
}
|
|
||||||
if (data.Spec.TaskTemplate.ContainerSpec.Env) {
|
|
||||||
this.Env = data.Spec.TaskTemplate.ContainerSpec.Env;
|
|
||||||
}
|
|
||||||
if (data.Endpoint.Ports) {
|
|
||||||
this.Ports = data.Endpoint.Ports;
|
|
||||||
}
|
|
||||||
if (data.Spec.UpdateConfig) {
|
|
||||||
this.UpdateParallelism = (typeof data.Spec.UpdateConfig.Parallelism !== undefined) ? data.Spec.UpdateConfig.Parallelism || 0 : 1;
|
|
||||||
this.UpdateDelay = data.Spec.UpdateConfig.Delay || 0;
|
|
||||||
this.UpdateFailureAction = data.Spec.UpdateConfig.FailureAction || 'pause';
|
|
||||||
} else {
|
|
||||||
this.UpdateParallelism = 1;
|
|
||||||
this.UpdateDelay = 0;
|
|
||||||
this.UpdateFailureAction = 'pause';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Checked = false;
|
|
||||||
this.Scale = false;
|
|
||||||
this.EditName = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function NodeViewModel(data) {
|
|
||||||
this.Model = data;
|
|
||||||
this.Id = data.ID;
|
|
||||||
this.Version = data.Version.Index;
|
|
||||||
this.Name = data.Spec.Name;
|
|
||||||
this.Role = data.Spec.Role;
|
|
||||||
this.CreatedAt = data.CreatedAt;
|
|
||||||
this.UpdatedAt = data.UpdatedAt;
|
|
||||||
this.Availability = data.Spec.Availability;
|
|
||||||
|
|
||||||
var labels = data.Spec.Labels;
|
|
||||||
if (labels) {
|
|
||||||
this.Labels = Object.keys(labels).map(function(key) {
|
|
||||||
return { key: key, value: labels[key], originalKey: key, originalValue: labels[key], added: true };
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.Labels = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Hostname = data.Description.Hostname;
|
|
||||||
this.PlatformArchitecture = data.Description.Platform.Architecture;
|
|
||||||
this.PlatformOS = data.Description.Platform.OS;
|
|
||||||
this.CPUs = data.Description.Resources.NanoCPUs;
|
|
||||||
this.Memory = data.Description.Resources.MemoryBytes;
|
|
||||||
this.EngineVersion = data.Description.Engine.EngineVersion;
|
|
||||||
this.EngineLabels = data.Description.Engine.Labels;
|
|
||||||
this.Plugins = data.Description.Engine.Plugins;
|
|
||||||
this.Status = data.Status.State;
|
|
||||||
|
|
||||||
if (data.ManagerStatus) {
|
|
||||||
this.Leader = data.ManagerStatus.Leader;
|
|
||||||
this.Reachability = data.ManagerStatus.Reachability;
|
|
||||||
this.ManagerAddr = data.ManagerStatus.Addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ContainerViewModel(data) {
|
|
||||||
this.Id = data.Id;
|
|
||||||
this.Status = data.Status;
|
|
||||||
this.State = data.State;
|
|
||||||
this.Names = data.Names;
|
|
||||||
// Unavailable in Docker < 1.10
|
|
||||||
if (data.NetworkSettings && !_.isEmpty(data.NetworkSettings.Networks)) {
|
|
||||||
this.IP = data.NetworkSettings.Networks[Object.keys(data.NetworkSettings.Networks)[0]].IPAddress;
|
|
||||||
}
|
|
||||||
this.Image = data.Image;
|
|
||||||
this.Command = data.Command;
|
|
||||||
this.Checked = false;
|
|
||||||
this.Ports = [];
|
|
||||||
for (var i = 0; i < data.Ports.length; ++i) {
|
|
||||||
var p = data.Ports[i];
|
|
||||||
if (p.PublicPort) {
|
|
||||||
this.Ports.push({ host: p.IP, private: p.PrivatePort, public: p.PublicPort });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createEventDetails(event) {
|
|
||||||
var eventAttr = event.Actor.Attributes;
|
|
||||||
var details = '';
|
|
||||||
switch (event.Type) {
|
|
||||||
case 'container':
|
|
||||||
switch (event.Action) {
|
|
||||||
case 'stop':
|
|
||||||
details = 'Container ' + eventAttr.name + ' stopped';
|
|
||||||
break;
|
|
||||||
case 'destroy':
|
|
||||||
details = 'Container ' + eventAttr.name + ' deleted';
|
|
||||||
break;
|
|
||||||
case 'create':
|
|
||||||
details = 'Container ' + eventAttr.name + ' created';
|
|
||||||
break;
|
|
||||||
case 'start':
|
|
||||||
details = 'Container ' + eventAttr.name + ' started';
|
|
||||||
break;
|
|
||||||
case 'kill':
|
|
||||||
details = 'Container ' + eventAttr.name + ' killed';
|
|
||||||
break;
|
|
||||||
case 'die':
|
|
||||||
details = 'Container ' + eventAttr.name + ' exited with status code ' + eventAttr.exitCode;
|
|
||||||
break;
|
|
||||||
case 'commit':
|
|
||||||
details = 'Container ' + eventAttr.name + ' committed';
|
|
||||||
break;
|
|
||||||
case 'restart':
|
|
||||||
details = 'Container ' + eventAttr.name + ' restarted';
|
|
||||||
break;
|
|
||||||
case 'pause':
|
|
||||||
details = 'Container ' + eventAttr.name + ' paused';
|
|
||||||
break;
|
|
||||||
case 'unpause':
|
|
||||||
details = 'Container ' + eventAttr.name + ' unpaused';
|
|
||||||
break;
|
|
||||||
case 'attach':
|
|
||||||
details = 'Container ' + eventAttr.name + ' attached';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (event.Action.indexOf('exec_create') === 0) {
|
|
||||||
details = 'Exec instance created';
|
|
||||||
} else if (event.Action.indexOf('exec_start') === 0) {
|
|
||||||
details = 'Exec instance started';
|
|
||||||
} else {
|
|
||||||
details = 'Unsupported event';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'image':
|
|
||||||
switch (event.Action) {
|
|
||||||
case 'delete':
|
|
||||||
details = 'Image deleted';
|
|
||||||
break;
|
|
||||||
case 'tag':
|
|
||||||
details = 'New tag created for ' + eventAttr.name;
|
|
||||||
break;
|
|
||||||
case 'untag':
|
|
||||||
details = 'Image untagged';
|
|
||||||
break;
|
|
||||||
case 'pull':
|
|
||||||
details = 'Image ' + event.Actor.ID + ' pulled';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
details = 'Unsupported event';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'network':
|
|
||||||
switch (event.Action) {
|
|
||||||
case 'create':
|
|
||||||
details = 'Network ' + eventAttr.name + ' created';
|
|
||||||
break;
|
|
||||||
case 'destroy':
|
|
||||||
details = 'Network ' + eventAttr.name + ' deleted';
|
|
||||||
break;
|
|
||||||
case 'connect':
|
|
||||||
details = 'Container connected to ' + eventAttr.name + ' network';
|
|
||||||
break;
|
|
||||||
case 'disconnect':
|
|
||||||
details = 'Container disconnected from ' + eventAttr.name + ' network';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
details = 'Unsupported event';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'volume':
|
|
||||||
switch (event.Action) {
|
|
||||||
case 'create':
|
|
||||||
details = 'Volume ' + event.Actor.ID + ' created';
|
|
||||||
break;
|
|
||||||
case 'destroy':
|
|
||||||
details = 'Volume ' + event.Actor.ID + ' deleted';
|
|
||||||
break;
|
|
||||||
case 'mount':
|
|
||||||
details = 'Volume ' + event.Actor.ID + ' mounted';
|
|
||||||
break;
|
|
||||||
case 'unmount':
|
|
||||||
details = 'Volume ' + event.Actor.ID + ' unmounted';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
details = 'Unsupported event';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
details = 'Unsupported event';
|
|
||||||
}
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
function EventViewModel(data) {
|
|
||||||
// Type, Action, Actor unavailable in Docker < 1.10
|
|
||||||
this.Time = data.time;
|
|
||||||
if (data.Type) {
|
|
||||||
this.Type = data.Type;
|
|
||||||
this.Details = createEventDetails(data);
|
|
||||||
} else {
|
|
||||||
this.Type = data.status;
|
|
||||||
this.Details = data.from;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue