diff --git a/.gitignore b/.gitignore index 43b170ab0..d9c64e8bc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ dist portainer-checksum.txt api/cmd/portainer/portainer* .tmp -.vscode \ No newline at end of file +.vscode +.eslintcache \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..3217d14ee --- /dev/null +++ b/.prettierrc @@ -0,0 +1,13 @@ +{ + "printWidth": 180, + "singleQuote": true, + "htmlWhitespaceSensitivity": "strict", + "overrides": [ + { + "files": ["*.html"], + "options": { + "parser": "angular" + } + } + ] +} diff --git a/app/__module.js b/app/__module.js index 881453c9a..e5db84c05 100644 --- a/app/__module.js +++ b/app/__module.js @@ -32,12 +32,12 @@ angular.module('portainer', [ 'portainer.extensions', 'portainer.integrations', 'rzModule', - 'moment-picker' + 'moment-picker', ]); if (require) { var req = require.context('./', true, /^(.*\.(js$))[^.]*$/im); - req.keys().forEach(function(key) { + req.keys().forEach(function (key) { req(key); }); } diff --git a/app/agent/components/file-uploader/file-uploader-controller.js b/app/agent/components/file-uploader/file-uploader-controller.js index e6516c67c..d0c5ad798 100644 --- a/app/agent/components/file-uploader/file-uploader-controller.js +++ b/app/agent/components/file-uploader/file-uploader-controller.js @@ -4,7 +4,7 @@ angular.module('portainer.agent').controller('FileUploaderController', [ var ctrl = this; ctrl.state = { - uploadInProgress: false + uploadInProgress: false, }; ctrl.onFileSelected = onFileSelected; @@ -19,5 +19,5 @@ angular.module('portainer.agent').controller('FileUploaderController', [ ctrl.state.uploadInProgress = false; }); } - } + }, ]); diff --git a/app/agent/components/file-uploader/file-uploader.html b/app/agent/components/file-uploader/file-uploader.html index e092ce5d6..5354b5c2f 100644 --- a/app/agent/components/file-uploader/file-uploader.html +++ b/app/agent/components/file-uploader/file-uploader.html @@ -1,6 +1,3 @@ - diff --git a/app/agent/components/file-uploader/file-uploader.js b/app/agent/components/file-uploader/file-uploader.js index 6427bae4a..6232c7f8d 100644 --- a/app/agent/components/file-uploader/file-uploader.js +++ b/app/agent/components/file-uploader/file-uploader.js @@ -2,6 +2,6 @@ angular.module('portainer.agent').component('fileUploader', { templateUrl: './file-uploader.html', controller: 'FileUploaderController', bindings: { - uploadFile: ' - - - + +
@@ -43,36 +49,33 @@ - - + + - - + + @@ -28,4 +28,4 @@ - \ No newline at end of file + diff --git a/app/docker/components/host-view-panels/devices-panel/devices-panel.js b/app/docker/components/host-view-panels/devices-panel/devices-panel.js index 8049add85..a7d19bcae 100644 --- a/app/docker/components/host-view-panels/devices-panel/devices-panel.js +++ b/app/docker/components/host-view-panels/devices-panel/devices-panel.js @@ -1,6 +1,6 @@ angular.module('portainer.docker').component('devicesPanel', { templateUrl: './devices-panel.html', bindings: { - devices: '<' - } + devices: '<', + }, }); diff --git a/app/docker/components/host-view-panels/disks-panel/disks-panel.html b/app/docker/components/host-view-panels/disks-panel/disks-panel.html index 632f07151..f2f59ec2c 100644 --- a/app/docker/components/host-view-panels/disks-panel/disks-panel.html +++ b/app/docker/components/host-view-panels/disks-panel/disks-panel.html @@ -12,8 +12,8 @@ - - + + @@ -28,4 +28,4 @@ - \ No newline at end of file + diff --git a/app/docker/components/host-view-panels/disks-panel/disks-panel.js b/app/docker/components/host-view-panels/disks-panel/disks-panel.js index 3997a89b3..4b755a607 100644 --- a/app/docker/components/host-view-panels/disks-panel/disks-panel.js +++ b/app/docker/components/host-view-panels/disks-panel/disks-panel.js @@ -1,6 +1,6 @@ angular.module('portainer.docker').component('disksPanel', { templateUrl: './disks-panel.html', bindings: { - disks: '<' - } + disks: '<', + }, }); diff --git a/app/docker/components/host-view-panels/engine-details-panel/engine-details-panel.html b/app/docker/components/host-view-panels/engine-details-panel/engine-details-panel.html index 036e4d7b7..5b25d0ea2 100644 --- a/app/docker/components/host-view-panels/engine-details-panel/engine-details-panel.html +++ b/app/docker/components/host-view-panels/engine-details-panel/engine-details-panel.html @@ -7,7 +7,9 @@ - + @@ -31,11 +33,11 @@ - +
- Go - to parent + Go to parent
- + - + - {{ item.Name }} - - - {{ - item.Name }} + {{ item.Name }} + {{ item.Name }} {{ item.Size | humansize }} {{ item.ModTime | getisodatefromtimestamp }} - + Download @@ -94,4 +97,4 @@ - \ No newline at end of file + diff --git a/app/agent/components/files-datatable/files-datatable.js b/app/agent/components/files-datatable/files-datatable.js index d1735cf48..d75d0f970 100644 --- a/app/agent/components/files-datatable/files-datatable.js +++ b/app/agent/components/files-datatable/files-datatable.js @@ -15,8 +15,8 @@ angular.module('portainer.agent').component('filesDatatable', { rename: '&', download: '&', delete: '&', - + isUploadAllowed: '<', - onFileSelectedForUpload: '<' - } + onFileSelectedForUpload: '<', + }, }); diff --git a/app/agent/components/host-browser/host-browser-controller.js b/app/agent/components/host-browser/host-browser-controller.js index 797f5c6ac..c9c1e5e0f 100644 --- a/app/agent/components/host-browser/host-browser-controller.js +++ b/app/agent/components/host-browser/host-browser-controller.js @@ -1,12 +1,15 @@ import _ from 'lodash-es'; angular.module('portainer.agent').controller('HostBrowserController', [ - 'HostBrowserService', 'Notifications', 'FileSaver', 'ModalService', + 'HostBrowserService', + 'Notifications', + 'FileSaver', + 'ModalService', function HostBrowserController(HostBrowserService, Notifications, FileSaver, ModalService) { var ctrl = this; var ROOT_PATH = '/host'; ctrl.state = { - path: ROOT_PATH + path: ROOT_PATH, }; ctrl.goToParent = goToParent; @@ -21,7 +24,7 @@ angular.module('portainer.agent').controller('HostBrowserController', [ function getRelativePath(path) { path = path || ctrl.state.path; - var rootPathRegex = new RegExp('^' + ROOT_PATH + '\/?'); + var rootPathRegex = new RegExp('^' + ROOT_PATH + '/?'); var relativePath = path.replace(rootPathRegex, '/'); return relativePath; } @@ -71,7 +74,7 @@ angular.module('portainer.agent').controller('HostBrowserController', [ HostBrowserService.get(filePath) .then(function onFileReceived(data) { var downloadData = new Blob([data.file], { - type: 'text/plain;charset=utf-8' + type: 'text/plain;charset=utf-8', }); FileSaver.saveAs(downloadData, file); }) @@ -83,15 +86,12 @@ angular.module('portainer.agent').controller('HostBrowserController', [ function confirmDeleteFile(name) { var filePath = buildPath(ctrl.state.path, name); - ModalService.confirmDeletion( - 'Are you sure that you want to delete ' + getRelativePath(filePath) + ' ?', - function onConfirm(confirmed) { - if (!confirmed) { - return; - } - return deleteFile(filePath); + ModalService.confirmDeletion('Are you sure that you want to delete ' + getRelativePath(filePath) + ' ?', function onConfirm(confirmed) { + if (!confirmed) { + return; } - ); + return deleteFile(filePath); + }); } function deleteFile(path) { @@ -145,5 +145,5 @@ angular.module('portainer.agent').controller('HostBrowserController', [ function refreshList() { getFilesForPath(ctrl.state.path); } - } + }, ]); diff --git a/app/agent/components/host-browser/host-browser.html b/app/agent/components/host-browser/host-browser.html index cf7b59306..b81ecc744 100644 --- a/app/agent/components/host-browser/host-browser.html +++ b/app/agent/components/host-browser/host-browser.html @@ -1,6 +1,8 @@ - diff --git a/app/agent/components/host-browser/host-browser.js b/app/agent/components/host-browser/host-browser.js index d702255eb..9b16b5a01 100644 --- a/app/agent/components/host-browser/host-browser.js +++ b/app/agent/components/host-browser/host-browser.js @@ -1,5 +1,5 @@ angular.module('portainer.agent').component('hostBrowser', { controller: 'HostBrowserController', templateUrl: './host-browser.html', - bindings: {} + bindings: {}, }); diff --git a/app/agent/components/node-selector/node-selector.js b/app/agent/components/node-selector/node-selector.js index 0d9c93ed3..2f7e14e82 100644 --- a/app/agent/components/node-selector/node-selector.js +++ b/app/agent/components/node-selector/node-selector.js @@ -2,6 +2,6 @@ angular.module('portainer.agent').component('nodeSelector', { templateUrl: './nodeSelector.html', controller: 'NodeSelectorController', bindings: { - model: '=' - } + model: '=', + }, }); diff --git a/app/agent/components/node-selector/nodeSelector.html b/app/agent/components/node-selector/nodeSelector.html index 1a910396c..4ab9e75bb 100644 --- a/app/agent/components/node-selector/nodeSelector.html +++ b/app/agent/components/node-selector/nodeSelector.html @@ -1,8 +1,6 @@
- +
diff --git a/app/agent/components/node-selector/nodeSelectorController.js b/app/agent/components/node-selector/nodeSelectorController.js index be2f6ce92..ce44f8568 100644 --- a/app/agent/components/node-selector/nodeSelectorController.js +++ b/app/agent/components/node-selector/nodeSelectorController.js @@ -1,18 +1,20 @@ -angular.module('portainer.agent') -.controller('NodeSelectorController', ['AgentService', 'Notifications', function (AgentService, Notifications) { - var ctrl = this; +angular.module('portainer.agent').controller('NodeSelectorController', [ + 'AgentService', + 'Notifications', + function (AgentService, Notifications) { + var ctrl = this; - this.$onInit = function() { - AgentService.agents() - .then(function success(data) { - ctrl.agents = data; - if (!ctrl.model) { - ctrl.model = data[0].NodeName; - } - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to load agents'); - }); - }; - -}]); + this.$onInit = function () { + AgentService.agents() + .then(function success(data) { + ctrl.agents = data; + if (!ctrl.model) { + ctrl.model = data[0].NodeName; + } + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to load agents'); + }); + }; + }, +]); diff --git a/app/agent/components/volume-browser/volume-browser.js b/app/agent/components/volume-browser/volume-browser.js index bea11e61a..5c2b2b78d 100644 --- a/app/agent/components/volume-browser/volume-browser.js +++ b/app/agent/components/volume-browser/volume-browser.js @@ -4,6 +4,6 @@ angular.module('portainer.agent').component('volumeBrowser', { bindings: { volumeId: '<', nodeName: '<', - isUploadEnabled: '<' - } + isUploadEnabled: '<', + }, }); diff --git a/app/agent/components/volume-browser/volumeBrowser.html b/app/agent/components/volume-browser/volumeBrowser.html index 97c8a4da6..5b85cfd94 100644 --- a/app/agent/components/volume-browser/volumeBrowser.html +++ b/app/agent/components/volume-browser/volumeBrowser.html @@ -1,6 +1,8 @@ diff --git a/app/agent/components/volume-browser/volumeBrowserController.js b/app/agent/components/volume-browser/volumeBrowserController.js index 0f8e99d86..fccde7753 100644 --- a/app/agent/components/volume-browser/volumeBrowserController.js +++ b/app/agent/components/volume-browser/volumeBrowserController.js @@ -1,137 +1,137 @@ import _ from 'lodash-es'; -angular.module('portainer.agent') -.controller('VolumeBrowserController', ['HttpRequestHelper', 'VolumeBrowserService', 'FileSaver', 'Blob', 'ModalService', 'Notifications', -function (HttpRequestHelper, VolumeBrowserService, FileSaver, Blob, ModalService, Notifications) { - var ctrl = this; +angular.module('portainer.agent').controller('VolumeBrowserController', [ + 'HttpRequestHelper', + 'VolumeBrowserService', + 'FileSaver', + 'Blob', + 'ModalService', + 'Notifications', + function (HttpRequestHelper, VolumeBrowserService, FileSaver, Blob, ModalService, Notifications) { + var ctrl = this; - this.state = { - path: '/' - }; + this.state = { + path: '/', + }; - this.rename = function(file, newName) { - var filePath = this.state.path === '/' ? file : this.state.path + '/' + file; - var newFilePath = this.state.path === '/' ? newName : this.state.path + '/' + newName; + this.rename = function (file, newName) { + var filePath = this.state.path === '/' ? file : this.state.path + '/' + file; + var newFilePath = this.state.path === '/' ? newName : this.state.path + '/' + newName; - VolumeBrowserService.rename(this.volumeId, filePath, newFilePath) - .then(function success() { - Notifications.success('File successfully renamed', newFilePath); - return VolumeBrowserService.ls(ctrl.volumeId, ctrl.state.path); - }) - .then(function success(data) { - ctrl.files = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to rename file'); - }); - }; + VolumeBrowserService.rename(this.volumeId, filePath, newFilePath) + .then(function success() { + Notifications.success('File successfully renamed', newFilePath); + return VolumeBrowserService.ls(ctrl.volumeId, ctrl.state.path); + }) + .then(function success(data) { + ctrl.files = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to rename file'); + }); + }; - this.delete = function(file) { - var filePath = this.state.path === '/' ? file : this.state.path + '/' + file; + this.delete = function (file) { + var filePath = this.state.path === '/' ? file : this.state.path + '/' + file; - ModalService.confirmDeletion( - 'Are you sure that you want to delete ' + filePath + ' ?', - function onConfirm(confirmed) { - if(!confirmed) { return; } + ModalService.confirmDeletion('Are you sure that you want to delete ' + filePath + ' ?', function onConfirm(confirmed) { + if (!confirmed) { + return; + } deleteFile(filePath); - } - ); - }; - - this.download = function(file) { - var filePath = this.state.path === '/' ? file : this.state.path + '/' + file; - VolumeBrowserService.get(this.volumeId, filePath) - .then(function success(data) { - var downloadData = new Blob([data.file]); - FileSaver.saveAs(downloadData, file); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to download file'); - }); - }; - - this.up = function() { - var parentFolder = parentPath(this.state.path); - browse(parentFolder); - }; - - this.browse = function(folder) { - var path = buildPath(this.state.path, folder); - browse(path); - }; - - function deleteFile(file) { - VolumeBrowserService.delete(ctrl.volumeId, file) - .then(function success() { - Notifications.success('File successfully deleted', file); - return VolumeBrowserService.ls(ctrl.volumeId, ctrl.state.path); - }) - .then(function success(data) { - ctrl.files = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to delete file'); - }); - } - - - function browse(path) { - VolumeBrowserService.ls(ctrl.volumeId, path) - .then(function success(data) { - ctrl.state.path = path; - ctrl.files = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to browse volume'); - }); - } - - this.onFileSelectedForUpload = function onFileSelectedForUpload(file) { - VolumeBrowserService.upload(ctrl.state.path, file, ctrl.volumeId) - .then(function onFileUpload() { - onFileUploaded(); - }) - .catch(function onFileUpload(err) { - Notifications.error('Failure', err, 'Unable to upload file'); }); - }; + }; - function parentPath(path) { - if (path.lastIndexOf('/') === 0) { - return '/'; + this.download = function (file) { + var filePath = this.state.path === '/' ? file : this.state.path + '/' + file; + VolumeBrowserService.get(this.volumeId, filePath) + .then(function success(data) { + var downloadData = new Blob([data.file]); + FileSaver.saveAs(downloadData, file); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to download file'); + }); + }; + + this.up = function () { + var parentFolder = parentPath(this.state.path); + browse(parentFolder); + }; + + this.browse = function (folder) { + var path = buildPath(this.state.path, folder); + browse(path); + }; + + function deleteFile(file) { + VolumeBrowserService.delete(ctrl.volumeId, file) + .then(function success() { + Notifications.success('File successfully deleted', file); + return VolumeBrowserService.ls(ctrl.volumeId, ctrl.state.path); + }) + .then(function success(data) { + ctrl.files = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to delete file'); + }); } - var split = _.split(path, '/'); - return _.join(_.slice(split, 0, split.length - 1), '/'); - } - - function buildPath(parent, file) { - if (parent === '/') { - return parent + file; + function browse(path) { + VolumeBrowserService.ls(ctrl.volumeId, path) + .then(function success(data) { + ctrl.state.path = path; + ctrl.files = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to browse volume'); + }); } - return parent + '/' + file; - } + this.onFileSelectedForUpload = function onFileSelectedForUpload(file) { + VolumeBrowserService.upload(ctrl.state.path, file, ctrl.volumeId) + .then(function onFileUpload() { + onFileUploaded(); + }) + .catch(function onFileUpload(err) { + Notifications.error('Failure', err, 'Unable to upload file'); + }); + }; - this.$onInit = function() { - HttpRequestHelper.setPortainerAgentTargetHeader(this.nodeName); - VolumeBrowserService.ls(this.volumeId, this.state.path) - .then(function success(data) { - ctrl.files = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to browse volume'); - }); - }; + function parentPath(path) { + if (path.lastIndexOf('/') === 0) { + return '/'; + } - function onFileUploaded() { - refreshList(); - } + var split = _.split(path, '/'); + return _.join(_.slice(split, 0, split.length - 1), '/'); + } - function refreshList() { - browse(ctrl.state.path); - } + function buildPath(parent, file) { + if (parent === '/') { + return parent + file; + } + return parent + '/' + file; + } - + this.$onInit = function () { + HttpRequestHelper.setPortainerAgentTargetHeader(this.nodeName); + VolumeBrowserService.ls(this.volumeId, this.state.path) + .then(function success(data) { + ctrl.files = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to browse volume'); + }); + }; -}]); + function onFileUploaded() { + refreshList(); + } + + function refreshList() { + browse(ctrl.state.path); + } + }, +]); diff --git a/app/agent/models/agent.js b/app/agent/models/agent.js index 3e171ff07..54866ef90 100644 --- a/app/agent/models/agent.js +++ b/app/agent/models/agent.js @@ -1,5 +1,5 @@ export function AgentViewModel(data) { this.IPAddress = data.IPAddress; - this.NodeName = data.NodeName; - this.NodeRole = data.NodeRole; + this.NodeName = data.NodeName; + this.NodeRole = data.NodeRole; } diff --git a/app/agent/rest/agent.js b/app/agent/rest/agent.js index 522296c3a..d7d0c6a2f 100644 --- a/app/agent/rest/agent.js +++ b/app/agent/rest/agent.js @@ -1,12 +1,19 @@ -angular.module('portainer.agent') -.factory('Agent', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'StateManager', +angular.module('portainer.agent').factory('Agent', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'StateManager', function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/v:version/agents', { - endpointId: EndpointProvider.endpointID, - version: StateManager.getAgentApiVersion + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/v:version/agents', + { + endpointId: EndpointProvider.endpointID, + version: StateManager.getAgentApiVersion, + }, + { + query: { method: 'GET', isArray: true }, + } + ); }, - { - query: { method: 'GET', isArray: true } - }); -}]); +]); diff --git a/app/agent/rest/browse.js b/app/agent/rest/browse.js index 82e5d4b21..852ee0535 100644 --- a/app/agent/rest/browse.js +++ b/app/agent/rest/browse.js @@ -1,27 +1,39 @@ import { browseGetResponse } from './response/browse'; -angular.module('portainer.agent') -.factory('Browse', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'StateManager', +angular.module('portainer.agent').factory('Browse', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'StateManager', function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/v:version/browse/:action', { - endpointId: EndpointProvider.endpointID, - version: StateManager.getAgentApiVersion + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/v:version/browse/:action', + { + endpointId: EndpointProvider.endpointID, + version: StateManager.getAgentApiVersion, + }, + { + ls: { + method: 'GET', + isArray: true, + params: { action: 'ls' }, + }, + get: { + method: 'GET', + params: { action: 'get' }, + transformResponse: browseGetResponse, + responseType: 'arraybuffer', + }, + delete: { + method: 'DELETE', + params: { action: 'delete' }, + }, + rename: { + method: 'PUT', + params: { action: 'rename' }, + }, + } + ); }, - { - ls: { - method: 'GET', isArray: true, params: { action: 'ls' } - }, - get: { - method: 'GET', params: { action: 'get' }, - transformResponse: browseGetResponse, - responseType: 'arraybuffer' - }, - delete: { - method: 'DELETE', params: { action: 'delete' } - }, - rename: { - method: 'PUT', params: { action: 'rename' } - } - }); -}]); +]); diff --git a/app/agent/rest/host.js b/app/agent/rest/host.js index f184d2544..a5fb198ae 100644 --- a/app/agent/rest/host.js +++ b/app/agent/rest/host.js @@ -1,16 +1,19 @@ angular.module('portainer.agent').factory('Host', [ - '$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'StateManager', + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'StateManager', function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { 'use strict'; return $resource( API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/v:version/host/:action', { endpointId: EndpointProvider.endpointID, - version: StateManager.getAgentApiVersion + version: StateManager.getAgentApiVersion, }, { - info: { method: 'GET', params: { action: 'info' } } + info: { method: 'GET', params: { action: 'info' } }, } ); - } + }, ]); diff --git a/app/agent/rest/ping.js b/app/agent/rest/ping.js index 7eeb93f2e..b6527dfb4 100644 --- a/app/agent/rest/ping.js +++ b/app/agent/rest/ping.js @@ -1,11 +1,14 @@ angular.module('portainer.agent').factory('AgentPing', [ - '$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', '$q', + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + '$q', function AgentPingFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, $q) { 'use strict'; return $resource( API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/ping', - { - endpointId: EndpointProvider.endpointID + { + endpointId: EndpointProvider.endpointID, }, { ping: { @@ -13,8 +16,7 @@ angular.module('portainer.agent').factory('AgentPing', [ interceptor: { response: function versionInterceptor(response) { var instance = response.resource; - var version = - response.headers('Portainer-Agent-Api-Version') || 1; + var version = response.headers('Portainer-Agent-Api-Version') || 1; instance.version = Number(version); return instance; }, @@ -24,10 +26,10 @@ angular.module('portainer.agent').factory('AgentPing', [ return { version: 1 }; } return $q.reject(error); - } - } - } + }, + }, + }, } ); - } + }, ]); diff --git a/app/agent/rest/v1/agent.js b/app/agent/rest/v1/agent.js index a78755b35..3d9e8d606 100644 --- a/app/agent/rest/v1/agent.js +++ b/app/agent/rest/v1/agent.js @@ -1,10 +1,17 @@ -angular.module('portainer.agent') -.factory('AgentVersion1', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/agents', { - endpointId: EndpointProvider.endpointID +angular.module('portainer.agent').factory('AgentVersion1', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/agents', + { + endpointId: EndpointProvider.endpointID, + }, + { + query: { method: 'GET', isArray: true }, + } + ); }, - { - query: { method: 'GET', isArray: true } - }); -}]); +]); diff --git a/app/agent/rest/v1/browse.js b/app/agent/rest/v1/browse.js index 62a198743..89c18b384 100644 --- a/app/agent/rest/v1/browse.js +++ b/app/agent/rest/v1/browse.js @@ -1,25 +1,37 @@ import { browseGetResponse } from '../response/browse'; -angular.module('portainer.agent') -.factory('BrowseVersion1', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/browse/:volumeID/:action', { - endpointId: EndpointProvider.endpointID +angular.module('portainer.agent').factory('BrowseVersion1', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/browse/:volumeID/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + ls: { + method: 'GET', + isArray: true, + params: { action: 'ls' }, + }, + get: { + method: 'GET', + params: { action: 'get' }, + transformResponse: browseGetResponse, + responseType: 'arraybuffer', + }, + delete: { + method: 'DELETE', + params: { action: 'delete' }, + }, + rename: { + method: 'PUT', + params: { action: 'rename' }, + }, + } + ); }, - { - ls: { - method: 'GET', isArray: true, params: { action: 'ls' } - }, - get: { - method: 'GET', params: { action: 'get' }, - transformResponse: browseGetResponse, - responseType: 'arraybuffer' - }, - delete: { - method: 'DELETE', params: { action: 'delete' } - }, - rename: { - method: 'PUT', params: { action: 'rename' } - } - }); -}]); +]); diff --git a/app/agent/services/agentService.js b/app/agent/services/agentService.js index af471da09..b9d938d94 100644 --- a/app/agent/services/agentService.js +++ b/app/agent/services/agentService.js @@ -1,7 +1,12 @@ import { AgentViewModel } from '../models/agent'; angular.module('portainer.agent').factory('AgentService', [ - '$q', 'Agent', 'AgentVersion1', 'HttpRequestHelper', 'Host', 'StateManager', + '$q', + 'Agent', + 'AgentVersion1', + 'HttpRequestHelper', + 'Host', + 'StateManager', function AgentServiceFactory($q, Agent, AgentVersion1, HttpRequestHelper, Host, StateManager) { 'use strict'; var service = {}; @@ -24,10 +29,11 @@ angular.module('portainer.agent').factory('AgentService', [ var agentVersion = getAgentApiVersion(); var service = agentVersion > 1 ? Agent : AgentVersion1; - - service.query({ version: agentVersion }) + + service + .query({ version: agentVersion }) .$promise.then(function success(data) { - var agents = data.map(function(item) { + var agents = data.map(function (item) { return new AgentViewModel(item); }); deferred.resolve(agents); @@ -40,5 +46,5 @@ angular.module('portainer.agent').factory('AgentService', [ } return service; - } + }, ]); diff --git a/app/agent/services/hostBrowserService.js b/app/agent/services/hostBrowserService.js index 6f292c36a..8de01f815 100644 --- a/app/agent/services/hostBrowserService.js +++ b/app/agent/services/hostBrowserService.js @@ -1,5 +1,10 @@ angular.module('portainer.agent').factory('HostBrowserService', [ - 'Browse', 'Upload', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', '$q', 'StateManager', + 'Browse', + 'Upload', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + '$q', + 'StateManager', function HostBrowserServiceFactory(Browse, Upload, API_ENDPOINT_ENDPOINTS, EndpointProvider, $q, StateManager) { var service = {}; @@ -24,7 +29,7 @@ angular.module('portainer.agent').factory('HostBrowserService', [ function rename(path, newPath) { var payload = { CurrentFilePath: path, - NewFilePath: newPath + NewFilePath: newPath, }; return Browse.rename({}, payload).$promise; } @@ -32,21 +37,15 @@ angular.module('portainer.agent').factory('HostBrowserService', [ function upload(path, file, onProgress) { var deferred = $q.defer(); var agentVersion = StateManager.getAgentApiVersion(); - var url = - API_ENDPOINT_ENDPOINTS + - '/' + - EndpointProvider.endpointID() + - '/docker' + - (agentVersion > 1 ? '/v' + agentVersion : '') + - '/browse/put'; + var url = API_ENDPOINT_ENDPOINTS + '/' + EndpointProvider.endpointID() + '/docker' + (agentVersion > 1 ? '/v' + agentVersion : '') + '/browse/put'; Upload.upload({ url: url, - data: { file: file, Path: path } + data: { file: file, Path: path }, }).then(deferred.resolve, deferred.reject, onProgress); return deferred.promise; } return service; - } + }, ]); diff --git a/app/agent/services/pingService.js b/app/agent/services/pingService.js index 765d47a5f..cc3133f22 100644 --- a/app/agent/services/pingService.js +++ b/app/agent/services/pingService.js @@ -10,5 +10,5 @@ angular.module('portainer.agent').service('AgentPingService', [ } return service; - } + }, ]); diff --git a/app/agent/services/volumeBrowserService.js b/app/agent/services/volumeBrowserService.js index a4ffdbf9d..002edb08b 100644 --- a/app/agent/services/volumeBrowserService.js +++ b/app/agent/services/volumeBrowserService.js @@ -1,5 +1,11 @@ angular.module('portainer.agent').factory('VolumeBrowserService', [ - 'StateManager', 'Browse', 'BrowseVersion1', '$q', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'Upload', + 'StateManager', + 'Browse', + 'BrowseVersion1', + '$q', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'Upload', function VolumeBrowserServiceFactory(StateManager, Browse, BrowseVersion1, $q, API_ENDPOINT_ENDPOINTS, EndpointProvider, Upload) { 'use strict'; var service = {}; @@ -14,22 +20,22 @@ angular.module('portainer.agent').factory('VolumeBrowserService', [ return agentVersion > 1 ? Browse : BrowseVersion1; } - service.ls = function(volumeId, path) { + service.ls = function (volumeId, path) { return getBrowseService().ls({ volumeID: volumeId, path: path, version: getAgentApiVersion() }).$promise; }; - service.get = function(volumeId, path) { + service.get = function (volumeId, path) { return getBrowseService().get({ volumeID: volumeId, path: path, version: getAgentApiVersion() }).$promise; }; - service.delete = function(volumeId, path) { + service.delete = function (volumeId, path) { return getBrowseService().delete({ volumeID: volumeId, path: path, version: getAgentApiVersion() }).$promise; }; - service.rename = function(volumeId, path, newPath) { + service.rename = function (volumeId, path, newPath) { var payload = { - CurrentFilePath: path, - NewFilePath: newPath + CurrentFilePath: path, + NewFilePath: newPath, }; return getBrowseService().rename({ volumeID: volumeId, version: getAgentApiVersion() }, payload).$promise; }; @@ -37,26 +43,19 @@ angular.module('portainer.agent').factory('VolumeBrowserService', [ service.upload = function upload(path, file, volumeId, onProgress) { var deferred = $q.defer(); var agentVersion = StateManager.getAgentApiVersion(); - if (agentVersion <2) { + if (agentVersion < 2) { deferred.reject('upload is not supported on this agent version'); return; } - var url = - API_ENDPOINT_ENDPOINTS + - '/' + - EndpointProvider.endpointID() + - '/docker' + - '/v' + agentVersion + - '/browse/put?volumeID=' + - volumeId; + var url = API_ENDPOINT_ENDPOINTS + '/' + EndpointProvider.endpointID() + '/docker' + '/v' + agentVersion + '/browse/put?volumeID=' + volumeId; Upload.upload({ url: url, - data: { file: file, Path: path } + data: { file: file, Path: path }, }).then(deferred.resolve, deferred.reject, onProgress); return deferred.promise; }; return service; - } + }, ]); diff --git a/app/app.js b/app/app.js index 95cf796bf..6cec23d30 100644 --- a/app/app.js +++ b/app/app.js @@ -1,46 +1,55 @@ import $ from 'jquery'; -import '@babel/polyfill' +import '@babel/polyfill'; -angular.module('portainer') -.run(['$rootScope', '$state', '$interval', 'LocalStorage', 'EndpointProvider', 'SystemService', 'cfpLoadingBar', '$transitions', 'HttpRequestHelper', -function ($rootScope, $state, $interval, LocalStorage, EndpointProvider, SystemService, cfpLoadingBar, $transitions, HttpRequestHelper) { - 'use strict'; +angular.module('portainer').run([ + '$rootScope', + '$state', + '$interval', + 'LocalStorage', + 'EndpointProvider', + 'SystemService', + 'cfpLoadingBar', + '$transitions', + 'HttpRequestHelper', + function ($rootScope, $state, $interval, LocalStorage, EndpointProvider, SystemService, cfpLoadingBar, $transitions, HttpRequestHelper) { + 'use strict'; - EndpointProvider.initialize(); + EndpointProvider.initialize(); - $rootScope.$state = $state; + $rootScope.$state = $state; - // Workaround to prevent the loading bar from going backward - // https://github.com/chieffancypants/angular-loading-bar/issues/273 - var originalSet = cfpLoadingBar.set; - cfpLoadingBar.set = function overrideSet(n) { - if (n > cfpLoadingBar.status()) { - originalSet.apply(cfpLoadingBar, arguments); - } - }; + // Workaround to prevent the loading bar from going backward + // https://github.com/chieffancypants/angular-loading-bar/issues/273 + var originalSet = cfpLoadingBar.set; + cfpLoadingBar.set = function overrideSet(n) { + if (n > cfpLoadingBar.status()) { + originalSet.apply(cfpLoadingBar, arguments); + } + }; - $transitions.onBefore({}, function() { - HttpRequestHelper.resetAgentHeaders(); - }); + $transitions.onBefore({}, function () { + HttpRequestHelper.resetAgentHeaders(); + }); - $state.defaultErrorHandler(function() { - // Do not log transitionTo errors - }); + $state.defaultErrorHandler(function () { + // Do not log transitionTo errors + }); - // Keep-alive Edge endpoints by sending a ping request every minute - $interval(function() { - ping(EndpointProvider, SystemService); - }, 60 * 1000) + // Keep-alive Edge endpoints by sending a ping request every minute + $interval(function () { + ping(EndpointProvider, SystemService); + }, 60 * 1000); - $(document).ajaxSend(function (event, jqXhr, jqOpts) { - const type = jqOpts.type === 'POST' || jqOpts.type === 'PUT' || jqOpts.type === 'PATCH'; - const hasNoContentType = jqOpts.contentType !== 'application/json' && jqOpts.headers && !jqOpts.headers['Content-Type']; - if (type && hasNoContentType) { - jqXhr.setRequestHeader('Content-Type', 'application/json'); - } - jqXhr.setRequestHeader('Authorization', 'Bearer ' + LocalStorage.getJWT()); - }); -}]); + $(document).ajaxSend(function (event, jqXhr, jqOpts) { + const type = jqOpts.type === 'POST' || jqOpts.type === 'PUT' || jqOpts.type === 'PATCH'; + const hasNoContentType = jqOpts.contentType !== 'application/json' && jqOpts.headers && !jqOpts.headers['Content-Type']; + if (type && hasNoContentType) { + jqXhr.setRequestHeader('Content-Type', 'application/json'); + } + jqXhr.setRequestHeader('Authorization', 'Bearer ' + LocalStorage.getJWT()); + }); + }, +]); function ping(EndpointProvider, SystemService) { let endpoint = EndpointProvider.currentEndpoint(); diff --git a/app/azure/_module.js b/app/azure/_module.js index 663f2c511..a11a5aa5e 100644 --- a/app/azure/_module.js +++ b/app/azure/_module.js @@ -1,49 +1,51 @@ -angular.module('portainer.azure', ['portainer.app']) -.config(['$stateRegistryProvider', function ($stateRegistryProvider) { - 'use strict'; +angular.module('portainer.azure', ['portainer.app']).config([ + '$stateRegistryProvider', + function ($stateRegistryProvider) { + 'use strict'; - var azure = { - name: 'azure', - url: '/azure', - parent: 'root', - abstract: true - }; + var azure = { + name: 'azure', + url: '/azure', + parent: 'root', + abstract: true, + }; - var containerInstances = { - name: 'azure.containerinstances', - url: '/containerinstances', - views: { - 'content@': { - templateUrl: './views/containerinstances/containerinstances.html', - controller: 'AzureContainerInstancesController' - } - } - }; + var containerInstances = { + name: 'azure.containerinstances', + url: '/containerinstances', + views: { + 'content@': { + templateUrl: './views/containerinstances/containerinstances.html', + controller: 'AzureContainerInstancesController', + }, + }, + }; - var containerInstanceCreation = { - name: 'azure.containerinstances.new', - url: '/new/', - views: { - 'content@': { - templateUrl: './views/containerinstances/create/createcontainerinstance.html', - controller: 'AzureCreateContainerInstanceController' - } - } - }; + var containerInstanceCreation = { + name: 'azure.containerinstances.new', + url: '/new/', + views: { + 'content@': { + templateUrl: './views/containerinstances/create/createcontainerinstance.html', + controller: 'AzureCreateContainerInstanceController', + }, + }, + }; - var dashboard = { - name: 'azure.dashboard', - url: '/dashboard', - views: { - 'content@': { - templateUrl: './views/dashboard/dashboard.html', - controller: 'AzureDashboardController' - } - } - }; + var dashboard = { + name: 'azure.dashboard', + url: '/dashboard', + views: { + 'content@': { + templateUrl: './views/dashboard/dashboard.html', + controller: 'AzureDashboardController', + }, + }, + }; - $stateRegistryProvider.register(azure); - $stateRegistryProvider.register(containerInstances); - $stateRegistryProvider.register(containerInstanceCreation); - $stateRegistryProvider.register(dashboard); -}]); + $stateRegistryProvider.register(azure); + $stateRegistryProvider.register(containerInstances); + $stateRegistryProvider.register(containerInstanceCreation); + $stateRegistryProvider.register(dashboard); + }, +]); diff --git a/app/azure/components/azure-endpoint-config/azure-endpoint-config.js b/app/azure/components/azure-endpoint-config/azure-endpoint-config.js index 2909d3853..ff09f0908 100644 --- a/app/azure/components/azure-endpoint-config/azure-endpoint-config.js +++ b/app/azure/components/azure-endpoint-config/azure-endpoint-config.js @@ -2,7 +2,7 @@ angular.module('portainer.azure').component('azureEndpointConfig', { bindings: { applicationId: '=', tenantId: '=', - authenticationKey: '=' + authenticationKey: '=', }, - templateUrl: './azureEndpointConfig.html' + templateUrl: './azureEndpointConfig.html', }); diff --git a/app/azure/components/azure-endpoint-config/azureEndpointConfig.html b/app/azure/components/azure-endpoint-config/azureEndpointConfig.html index c0d839102..efc8bd79f 100644 --- a/app/azure/components/azure-endpoint-config/azureEndpointConfig.html +++ b/app/azure/components/azure-endpoint-config/azureEndpointConfig.html @@ -6,7 +6,7 @@
- +
@@ -14,7 +14,7 @@
- +
@@ -22,7 +22,14 @@
- +
diff --git a/app/azure/components/azure-sidebar-content/azure-sidebar-content.js b/app/azure/components/azure-sidebar-content/azure-sidebar-content.js index 68401cc1e..daec3ef12 100644 --- a/app/azure/components/azure-sidebar-content/azure-sidebar-content.js +++ b/app/azure/components/azure-sidebar-content/azure-sidebar-content.js @@ -1,3 +1,3 @@ angular.module('portainer.azure').component('azureSidebarContent', { - templateUrl: './azureSidebarContent.html' + templateUrl: './azureSidebarContent.html', }); diff --git a/app/azure/components/datatables/containergroups-datatable/containerGroupsDatatable.html b/app/azure/components/datatables/containergroups-datatable/containerGroupsDatatable.html index 54361570c..f9936d78b 100644 --- a/app/azure/components/datatables/containergroups-datatable/containerGroupsDatatable.html +++ b/app/azure/components/datatables/containergroups-datatable/containerGroupsDatatable.html @@ -2,13 +2,10 @@
-
- {{ $ctrl.titleText }} -
+
{{ $ctrl.titleText }}
-
@@ -47,20 +52,23 @@ - + @@ -73,9 +81,7 @@
- + - {{ item.Name | truncate:50 }} + {{ item.Name | truncate: 50 }} {{ item.Location }} :{{ p.port }} - - + -
- -
-
+
+
- \ No newline at end of file + diff --git a/app/docker/components/container-quick-actions/containerQuickActions.html b/app/docker/components/container-quick-actions/containerQuickActions.html index 65ee13949..d4bbc55d1 100644 --- a/app/docker/components/container-quick-actions/containerQuickActions.html +++ b/app/docker/components/container-quick-actions/containerQuickActions.html @@ -1,10 +1,11 @@ - diff --git a/app/docker/components/container-quick-actions/containerQuickActions.js b/app/docker/components/container-quick-actions/containerQuickActions.js index 619cf7efa..6f8631df7 100644 --- a/app/docker/components/container-quick-actions/containerQuickActions.js +++ b/app/docker/components/container-quick-actions/containerQuickActions.js @@ -5,6 +5,6 @@ angular.module('portainer.docker').component('containerQuickActions', { nodeName: '<', status: '<', state: '<', - taskId: '<' - } + taskId: '<', + }, }); diff --git a/app/docker/components/container-restart-policy/container-restart-policy-controller.js b/app/docker/components/container-restart-policy/container-restart-policy-controller.js index 64a8604fc..159b8a2f5 100644 --- a/app/docker/components/container-restart-policy/container-restart-policy-controller.js +++ b/app/docker/components/container-restart-policy/container-restart-policy-controller.js @@ -1,26 +1,25 @@ -angular -.module('portainer.docker') -.controller('ContainerRestartPolicyController', [function ContainerRestartPolicyController() { - var ctrl = this; +angular.module('portainer.docker').controller('ContainerRestartPolicyController', [ + function ContainerRestartPolicyController() { + var ctrl = this; - this.state = { - editModel : {} - }; - - ctrl.save = save; - - function save() { - if (ctrl.state.editModel.name === ctrl.name && ctrl.state.editModel.maximumRetryCount === ctrl.maximumRetryCount) { - return; - } - ctrl.updateRestartPolicy(ctrl.state.editModel); - } - - this.$onInit = function() { - ctrl.state.editModel = { - name: ctrl.name ? ctrl.name : 'no', - maximumRetryCount: ctrl.maximumRetryCount + this.state = { + editModel: {}, }; - }; -} + + ctrl.save = save; + + function save() { + if (ctrl.state.editModel.name === ctrl.name && ctrl.state.editModel.maximumRetryCount === ctrl.maximumRetryCount) { + return; + } + ctrl.updateRestartPolicy(ctrl.state.editModel); + } + + this.$onInit = function () { + ctrl.state.editModel = { + name: ctrl.name ? ctrl.name : 'no', + maximumRetryCount: ctrl.maximumRetryCount, + }; + }; + }, ]); diff --git a/app/docker/components/container-restart-policy/container-restart-policy.js b/app/docker/components/container-restart-policy/container-restart-policy.js index 60e4f0c4b..bc4d02709 100644 --- a/app/docker/components/container-restart-policy/container-restart-policy.js +++ b/app/docker/components/container-restart-policy/container-restart-policy.js @@ -1,10 +1,9 @@ -angular.module('portainer.docker') -.component('containerRestartPolicy', { +angular.module('portainer.docker').component('containerRestartPolicy', { templateUrl: './container-restart-policy.html', controller: 'ContainerRestartPolicyController', bindings: { - 'name': '<', - 'maximumRetryCount': '<', - 'updateRestartPolicy': '&' - } + name: '<', + maximumRetryCount: '<', + updateRestartPolicy: '&', + }, }); diff --git a/app/docker/components/dashboard-cluster-agent-info/dashboard-cluster-agent-info.js b/app/docker/components/dashboard-cluster-agent-info/dashboard-cluster-agent-info.js index 88aae5cec..6498c2edc 100644 --- a/app/docker/components/dashboard-cluster-agent-info/dashboard-cluster-agent-info.js +++ b/app/docker/components/dashboard-cluster-agent-info/dashboard-cluster-agent-info.js @@ -1,4 +1,4 @@ angular.module('portainer.docker').component('dashboardClusterAgentInfo', { templateUrl: './dashboardClusterAgentInfo.html', - controller: 'DashboardClusterAgentInfoController' + controller: 'DashboardClusterAgentInfoController', }); diff --git a/app/docker/components/dashboard-cluster-agent-info/dashboardClusterAgentInfoController.js b/app/docker/components/dashboard-cluster-agent-info/dashboardClusterAgentInfoController.js index 7ba6f7f08..2b421729b 100644 --- a/app/docker/components/dashboard-cluster-agent-info/dashboardClusterAgentInfoController.js +++ b/app/docker/components/dashboard-cluster-agent-info/dashboardClusterAgentInfoController.js @@ -1,16 +1,17 @@ -angular.module('portainer.docker') -.controller('DashboardClusterAgentInfoController', ['AgentService', 'Notifications', -function (AgentService, Notifications) { - var ctrl = this; +angular.module('portainer.docker').controller('DashboardClusterAgentInfoController', [ + 'AgentService', + 'Notifications', + function (AgentService, Notifications) { + var ctrl = this; - this.$onInit = function() { - AgentService.agents() - .then(function success(data) { - ctrl.agentCount = data.length; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve agent information'); - }); - }; - -}]); + this.$onInit = function () { + AgentService.agents() + .then(function success(data) { + ctrl.agentCount = data.length; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve agent information'); + }); + }; + }, +]); diff --git a/app/docker/components/datatables/configs-datatable/configsDatatable.html b/app/docker/components/datatables/configs-datatable/configsDatatable.html index d6a1e386d..a6b8aa6a7 100644 --- a/app/docker/components/datatables/configs-datatable/configsDatatable.html +++ b/app/docker/components/datatables/configs-datatable/configsDatatable.html @@ -2,9 +2,7 @@
-
- {{ $ctrl.titleText }} -
+
{{ $ctrl.titleText }}
Settings @@ -16,7 +14,7 @@
{{ key }}
{{ key }} {{ value.IPAddress || '-' }} {{ value.Gateway || '-' }} {{ value.MacAddress || '-' }} - diff --git a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.js b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.js index 7ac1b5580..501f86c46 100644 --- a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.js +++ b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.js @@ -12,6 +12,6 @@ angular.module('portainer.docker').component('containerNetworksDatatable', { joinNetworkActionInProgress: '<', leaveNetworkActionInProgress: '<', leaveNetworkAction: '<', - nodeName: '<' - } + nodeName: '<', + }, }); diff --git a/app/docker/components/datatables/container-processes-datatable/containerProcessesDatatable.html b/app/docker/components/datatables/container-processes-datatable/containerProcessesDatatable.html index 37f3152b5..326deef73 100644 --- a/app/docker/components/datatables/container-processes-datatable/containerProcessesDatatable.html +++ b/app/docker/components/datatables/container-processes-datatable/containerProcessesDatatable.html @@ -2,13 +2,11 @@
-
- {{ $ctrl.titleText }} -
+
{{ $ctrl.titleText }}
diff --git a/app/docker/components/datatables/container-processes-datatable/containerProcessesDatatable.js b/app/docker/components/datatables/container-processes-datatable/containerProcessesDatatable.js index 1a0abdc3a..b89a4d63b 100644 --- a/app/docker/components/datatables/container-processes-datatable/containerProcessesDatatable.js +++ b/app/docker/components/datatables/container-processes-datatable/containerProcessesDatatable.js @@ -8,6 +8,6 @@ angular.module('portainer.docker').component('containerProcessesDatatable', { headerset: '<', tableKey: '@', orderBy: '@', - reverseOrder: '<' - } + reverseOrder: '<', + }, }); diff --git a/app/docker/components/datatables/containers-datatable/actions/containersDatatableActions.html b/app/docker/components/datatables/containers-datatable/actions/containersDatatableActions.html index 873657caf..9d9f8d9f8 100644 --- a/app/docker/components/datatables/containers-datatable/actions/containersDatatableActions.html +++ b/app/docker/components/datatables/containers-datatable/actions/containersDatatableActions.html @@ -1,31 +1,69 @@ -
+
- - - - - - -
diff --git a/app/docker/components/datatables/containers-datatable/actions/containersDatatableActions.js b/app/docker/components/datatables/containers-datatable/actions/containersDatatableActions.js index 2f82916a1..b6f83f273 100644 --- a/app/docker/components/datatables/containers-datatable/actions/containersDatatableActions.js +++ b/app/docker/components/datatables/containers-datatable/actions/containersDatatableActions.js @@ -7,6 +7,6 @@ angular.module('portainer.docker').component('containersDatatableActions', { noStoppedItemsSelected: '=', noRunningItemsSelected: '=', noPausedItemsSelected: '=', - showAddAction: '<' - } + showAddAction: '<', + }, }); diff --git a/app/docker/components/datatables/containers-datatable/actions/containersDatatableActionsController.js b/app/docker/components/datatables/containers-datatable/actions/containersDatatableActionsController.js index efacb89e7..432df50f8 100644 --- a/app/docker/components/datatables/containers-datatable/actions/containersDatatableActionsController.js +++ b/app/docker/components/datatables/containers-datatable/actions/containersDatatableActionsController.js @@ -1,106 +1,112 @@ -angular.module('portainer.docker') -.controller('ContainersDatatableActionsController', ['$state', 'ContainerService', 'ModalService', 'Notifications', 'HttpRequestHelper', -function ($state, ContainerService, ModalService, Notifications, HttpRequestHelper) { - this.startAction = function(selectedItems) { - var successMessage = 'Container successfully started'; - var errorMessage = 'Unable to start container'; - executeActionOnContainerList(selectedItems, ContainerService.startContainer, successMessage, errorMessage); - }; +angular.module('portainer.docker').controller('ContainersDatatableActionsController', [ + '$state', + 'ContainerService', + 'ModalService', + 'Notifications', + 'HttpRequestHelper', + function ($state, ContainerService, ModalService, Notifications, HttpRequestHelper) { + this.startAction = function (selectedItems) { + var successMessage = 'Container successfully started'; + var errorMessage = 'Unable to start container'; + executeActionOnContainerList(selectedItems, ContainerService.startContainer, successMessage, errorMessage); + }; - this.stopAction = function(selectedItems) { - var successMessage = 'Container successfully stopped'; - var errorMessage = 'Unable to stop container'; - executeActionOnContainerList(selectedItems, ContainerService.stopContainer, successMessage, errorMessage); - }; + this.stopAction = function (selectedItems) { + var successMessage = 'Container successfully stopped'; + var errorMessage = 'Unable to stop container'; + executeActionOnContainerList(selectedItems, ContainerService.stopContainer, successMessage, errorMessage); + }; - this.restartAction = function(selectedItems) { - var successMessage = 'Container successfully restarted'; - var errorMessage = 'Unable to restart container'; - executeActionOnContainerList(selectedItems, ContainerService.restartContainer, successMessage, errorMessage); - }; + this.restartAction = function (selectedItems) { + var successMessage = 'Container successfully restarted'; + var errorMessage = 'Unable to restart container'; + executeActionOnContainerList(selectedItems, ContainerService.restartContainer, successMessage, errorMessage); + }; - this.killAction = function(selectedItems) { - var successMessage = 'Container successfully killed'; - var errorMessage = 'Unable to kill container'; - executeActionOnContainerList(selectedItems, ContainerService.killContainer, successMessage, errorMessage); - }; + this.killAction = function (selectedItems) { + var successMessage = 'Container successfully killed'; + var errorMessage = 'Unable to kill container'; + executeActionOnContainerList(selectedItems, ContainerService.killContainer, successMessage, errorMessage); + }; - this.pauseAction = function(selectedItems) { - var successMessage = 'Container successfully paused'; - var errorMessage = 'Unable to pause container'; - executeActionOnContainerList(selectedItems, ContainerService.pauseContainer, successMessage, errorMessage); - }; + this.pauseAction = function (selectedItems) { + var successMessage = 'Container successfully paused'; + var errorMessage = 'Unable to pause container'; + executeActionOnContainerList(selectedItems, ContainerService.pauseContainer, successMessage, errorMessage); + }; - this.resumeAction = function(selectedItems) { - var successMessage = 'Container successfully resumed'; - var errorMessage = 'Unable to resume container'; - executeActionOnContainerList(selectedItems, ContainerService.resumeContainer, successMessage, errorMessage); - }; + this.resumeAction = function (selectedItems) { + var successMessage = 'Container successfully resumed'; + var errorMessage = 'Unable to resume container'; + executeActionOnContainerList(selectedItems, ContainerService.resumeContainer, successMessage, errorMessage); + }; - this.removeAction = function(selectedItems) { - var isOneContainerRunning = false; - for (var i = 0; i < selectedItems.length; i++) { - var container = selectedItems[i]; - if (container.State === 'running') { - isOneContainerRunning = true; - break; + this.removeAction = function (selectedItems) { + var isOneContainerRunning = false; + for (var i = 0; i < selectedItems.length; i++) { + var container = selectedItems[i]; + if (container.State === 'running') { + isOneContainerRunning = true; + break; + } } - } - var title = 'You are about to remove one or more container.'; - if (isOneContainerRunning) { - title = 'You are about to remove one or more running container.'; - } + var title = 'You are about to remove one or more container.'; + if (isOneContainerRunning) { + title = 'You are about to remove one or more running container.'; + } - ModalService.confirmContainerDeletion(title, function (result) { - if(!result) { return; } + ModalService.confirmContainerDeletion(title, function (result) { + if (!result) { + return; + } var cleanVolumes = false; if (result[0]) { cleanVolumes = true; } removeSelectedContainers(selectedItems, cleanVolumes); - } - ); - }; - - function executeActionOnContainerList(containers, action, successMessage, errorMessage) { - var actionCount = containers.length; - angular.forEach(containers, function (container) { - HttpRequestHelper.setPortainerAgentTargetHeader(container.NodeName); - action(container.Id) - .then(function success() { - Notifications.success(successMessage, container.Names[0]); - }) - .catch(function error(err) { - errorMessage = errorMessage + ':' + container.Names[0]; - Notifications.error('Failure', err, errorMessage); - }) - .finally(function final() { - --actionCount; - if (actionCount === 0) { - $state.reload(); - } }); - }); - } + }; - function removeSelectedContainers(containers, cleanVolumes) { - var actionCount = containers.length; - angular.forEach(containers, function (container) { - HttpRequestHelper.setPortainerAgentTargetHeader(container.NodeName); - ContainerService.remove(container, cleanVolumes) - .then(function success() { - Notifications.success('Container successfully removed', container.Names[0]); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove container'); - }) - .finally(function final() { - --actionCount; - if (actionCount === 0) { - $state.reload(); - } + function executeActionOnContainerList(containers, action, successMessage, errorMessage) { + var actionCount = containers.length; + angular.forEach(containers, function (container) { + HttpRequestHelper.setPortainerAgentTargetHeader(container.NodeName); + action(container.Id) + .then(function success() { + Notifications.success(successMessage, container.Names[0]); + }) + .catch(function error(err) { + errorMessage = errorMessage + ':' + container.Names[0]; + Notifications.error('Failure', err, errorMessage); + }) + .finally(function final() { + --actionCount; + if (actionCount === 0) { + $state.reload(); + } + }); }); - }); - } -}]); + } + + function removeSelectedContainers(containers, cleanVolumes) { + var actionCount = containers.length; + angular.forEach(containers, function (container) { + HttpRequestHelper.setPortainerAgentTargetHeader(container.NodeName); + ContainerService.remove(container, cleanVolumes) + .then(function success() { + Notifications.success('Container successfully removed', container.Names[0]); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove container'); + }) + .finally(function final() { + --actionCount; + if (actionCount === 0) { + $state.reload(); + } + }); + }); + } + }, +]); diff --git a/app/docker/components/datatables/containers-datatable/containersDatatable.html b/app/docker/components/datatables/containers-datatable/containersDatatable.html index b8bdc3a4b..638b45e72 100644 --- a/app/docker/components/datatables/containers-datatable/containersDatatable.html +++ b/app/docker/components/datatables/containers-datatable/containersDatatable.html @@ -2,60 +2,65 @@
-
- {{ $ctrl.titleText }} -
+
{{ $ctrl.titleText }}
- - Columns -
- @@ -235,39 +263,69 @@ - + - - +
- + @@ -170,7 +188,7 @@ @@ -180,7 +198,17 @@ + Quick actions @@ -199,8 +227,8 @@ - - + + Created
- - + + - {{ item | containername | truncate: $ctrl.settings.containerNameTruncateSize }} + {{ + item | containername | truncate: $ctrl.settings.containerNameTruncateSize + }} {{ item | containername | truncate: $ctrl.settings.containerNameTruncateSize }} - {{ item.Status }} - {{ item.Status }} + {{ item.Status }} + {{ item.Status }} + - {{ item.StackName ? item.StackName : '-' }} {{ item.Image | trimshasum }} {{ item.Image | trimshasum }} - {{item.Created | getisodatefromtimestamp}} + {{ item.Created | getisodatefromtimestamp }} {{ item.IP ? item.IP : '-' }} {{ item.NodeName ? item.NodeName : '-' }} - + {{ p.public }}:{{ p.private }} - - + - @@ -286,9 +344,7 @@
{{device.Name}}{{device.Vendor}}{{ device.Name }}{{ device.Vendor }}
Loading...
{{disk.Vendor}}{{disk.Size | humansize}}{{ disk.Vendor }}{{ disk.Size | humansize }}
Loading...
Version{{ $ctrl.engine.releaseVersion }} (API: {{ $ctrl.engine.apiVersion }}){{ $ctrl.engine.releaseVersion }} (API: {{ $ctrl.engine.apiVersion }})
Root directory
Engine Labels{{ $ctrl.engine.engineLabels | labelsToStr:', ' }}{{ $ctrl.engine.engineLabels | labelsToStr: ', ' }}
- \ No newline at end of file + diff --git a/app/docker/components/host-view-panels/engine-details-panel/engine-details-panel.js b/app/docker/components/host-view-panels/engine-details-panel/engine-details-panel.js index 12bb2fb1e..543a5909e 100644 --- a/app/docker/components/host-view-panels/engine-details-panel/engine-details-panel.js +++ b/app/docker/components/host-view-panels/engine-details-panel/engine-details-panel.js @@ -1,6 +1,6 @@ angular.module('portainer.docker').component('engineDetailsPanel', { templateUrl: './engine-details-panel.html', bindings: { - engine: '<' - } + engine: '<', + }, }); diff --git a/app/docker/components/host-view-panels/host-details-panel/host-details-panel.html b/app/docker/components/host-view-panels/host-details-panel/host-details-panel.html index 9b5b006d7..24ba17e70 100644 --- a/app/docker/components/host-view-panels/host-details-panel/host-details-panel.html +++ b/app/docker/components/host-view-panels/host-details-panel/host-details-panel.html @@ -11,8 +11,7 @@ OS Information - {{ $ctrl.host.os.type }} {{$ctrl.host.os.arch}} - {{$ctrl.host.os.name}} + {{ $ctrl.host.os.type }} {{ $ctrl.host.os.arch }} {{ $ctrl.host.os.name }} Kernel Version @@ -28,10 +27,10 @@ - - diff --git a/app/docker/components/host-view-panels/host-details-panel/host-details-panel.js b/app/docker/components/host-view-panels/host-details-panel/host-details-panel.js index 5d25a626e..693a022b7 100644 --- a/app/docker/components/host-view-panels/host-details-panel/host-details-panel.js +++ b/app/docker/components/host-view-panels/host-details-panel/host-details-panel.js @@ -5,6 +5,6 @@ angular.module('portainer.docker').component('hostDetailsPanel', { isJobEnabled: '<', isBrowseEnabled: '<', browseUrl: '@', - jobUrl: '@' - } + jobUrl: '@', + }, }); diff --git a/app/docker/components/host-view-panels/node-availability-select/node-availability-select-controller.js b/app/docker/components/host-view-panels/node-availability-select/node-availability-select-controller.js index 52df40cd6..2ebd29ee6 100644 --- a/app/docker/components/host-view-panels/node-availability-select/node-availability-select-controller.js +++ b/app/docker/components/host-view-panels/node-availability-select/node-availability-select-controller.js @@ -1,11 +1,9 @@ -angular - .module('portainer.docker') - .controller('NodeAvailabilitySelectController', [ - function NodeAvailabilitySelectController() { - this.onChange = onChange; +angular.module('portainer.docker').controller('NodeAvailabilitySelectController', [ + function NodeAvailabilitySelectController() { + this.onChange = onChange; - function onChange() { - this.onSave({ availability: this.availability }); - } + function onChange() { + this.onSave({ availability: this.availability }); } - ]); + }, +]); diff --git a/app/docker/components/host-view-panels/node-availability-select/node-availability-select.html b/app/docker/components/host-view-panels/node-availability-select/node-availability-select.html index 94e086127..b37f7d9d6 100644 --- a/app/docker/components/host-view-panels/node-availability-select/node-availability-select.html +++ b/app/docker/components/host-view-panels/node-availability-select/node-availability-select.html @@ -1,8 +1,7 @@
- -
\ No newline at end of file + diff --git a/app/docker/components/host-view-panels/node-availability-select/node-availability-select.js b/app/docker/components/host-view-panels/node-availability-select/node-availability-select.js index b396d65f7..b9af163be 100644 --- a/app/docker/components/host-view-panels/node-availability-select/node-availability-select.js +++ b/app/docker/components/host-view-panels/node-availability-select/node-availability-select.js @@ -4,6 +4,6 @@ angular.module('portainer.docker').component('nodeAvailabilitySelect', { bindings: { availability: '<', originalValue: '<', - onSave: '&' - } + onSave: '&', + }, }); diff --git a/app/docker/components/host-view-panels/node-labels-table/node-labels-table-controller.js b/app/docker/components/host-view-panels/node-labels-table/node-labels-table-controller.js index a9ad8ab58..4296d4bc0 100644 --- a/app/docker/components/host-view-panels/node-labels-table/node-labels-table-controller.js +++ b/app/docker/components/host-view-panels/node-labels-table/node-labels-table-controller.js @@ -12,12 +12,9 @@ angular.module('portainer.docker').controller('NodeLabelsTableController', [ } function updateLabel(label) { - if ( - label.value !== label.originalValue || - label.key !== label.originalKey - ) { + if (label.value !== label.originalValue || label.key !== label.originalKey) { ctrl.onChangedLabels({ labels: ctrl.labels }); } } - } + }, ]); diff --git a/app/docker/components/host-view-panels/node-labels-table/node-labels-table.html b/app/docker/components/host-view-panels/node-labels-table/node-labels-table.html index 86eee9356..e26ec168c 100644 --- a/app/docker/components/host-view-panels/node-labels-table/node-labels-table.html +++ b/app/docker/components/host-view-panels/node-labels-table/node-labels-table.html @@ -14,15 +14,13 @@
Name - +
Value - + -
- \ No newline at end of file + diff --git a/app/docker/components/host-view-panels/swarm-node-details-panel/swarm-node-details-panel.js b/app/docker/components/host-view-panels/swarm-node-details-panel/swarm-node-details-panel.js index ad5bf7a7a..751e4aea4 100644 --- a/app/docker/components/host-view-panels/swarm-node-details-panel/swarm-node-details-panel.js +++ b/app/docker/components/host-view-panels/swarm-node-details-panel/swarm-node-details-panel.js @@ -3,6 +3,6 @@ angular.module('portainer.docker').component('swarmNodeDetailsPanel', { controller: 'SwarmNodeDetailsPanelController', bindings: { details: '<', - originalNode: '<' - } + originalNode: '<', + }, }); diff --git a/app/docker/components/imageRegistry/por-image-registry.js b/app/docker/components/imageRegistry/por-image-registry.js index 39d6a5919..4c2f7b4bd 100644 --- a/app/docker/components/imageRegistry/por-image-registry.js +++ b/app/docker/components/imageRegistry/por-image-registry.js @@ -2,13 +2,13 @@ angular.module('portainer.docker').component('porImageRegistry', { templateUrl: './porImageRegistry.html', controller: 'porImageRegistryController', bindings: { - 'model': '=', // must be of type PorImageRegistryModel - 'pullWarning': '<', - 'autoComplete': '<', - 'labelClass': '@', - 'inputClass': '@' + model: '=', // must be of type PorImageRegistryModel + pullWarning: '<', + autoComplete: '<', + labelClass: '@', + inputClass: '@', }, require: { - form: '^form' - } + form: '^form', + }, }); diff --git a/app/docker/components/imageRegistry/porImageRegistry.html b/app/docker/components/imageRegistry/porImageRegistry.html index 05bc7ea07..feee8ba1b 100644 --- a/app/docker/components/imageRegistry/porImageRegistry.html +++ b/app/docker/components/imageRegistry/porImageRegistry.html @@ -5,15 +5,28 @@ Registry
- +
- {{$ctrl.displayedRegistryURL()}} - + {{ $ctrl.displayedRegistryURL() }} +
@@ -22,11 +35,12 @@
-
@@ -35,7 +49,10 @@
-

Image name is required. Tag must be specified otherwise Portainer will pull all tags associated to the image.

+

Image name is required. + Tag must be specified otherwise Portainer will pull all tags associated to the image.

diff --git a/app/docker/components/imageRegistry/porImageRegistryController.js b/app/docker/components/imageRegistry/porImageRegistryController.js index 7f4e9cfbc..f16902c9d 100644 --- a/app/docker/components/imageRegistry/porImageRegistryController.js +++ b/app/docker/components/imageRegistry/porImageRegistryController.js @@ -38,7 +38,7 @@ class porImageRegistryController { if (this.isKnownRegistry(registry)) { const url = this.getRegistryURL(registry); const registryImages = _.filter(this.images, (image) => _.includes(image, url)); - images = _.map(registryImages, (image) => _.replace(image, new RegExp(url + '\/?'), '')); + images = _.map(registryImages, (image) => _.replace(image, new RegExp(url + '/?'), '')); } else { const registries = _.filter(this.availableRegistries, (reg) => this.isKnownRegistry(reg)); const registryImages = _.flatMap(registries, (registry) => _.filter(this.images, (image) => _.includes(image, registry.URL))); @@ -64,7 +64,7 @@ class porImageRegistryController { const [registries, dockerhub, images] = await Promise.all([ this.RegistryService.registries(), this.DockerHubService.dockerhub(), - this.autoComplete ? this.ImageService.images() : [] + this.autoComplete ? this.ImageService.images() : [], ]); this.images = this.ImageService.getUniqueTagListFromImages(images); this.availableRegistries = _.concat(dockerhub, registries); @@ -73,7 +73,7 @@ class porImageRegistryController { if (!id) { this.model.Registry = dockerhub; } else { - this.model.Registry = _.find(this.availableRegistries, { 'Id': id }); + this.model.Registry = _.find(this.availableRegistries, { Id: id }); } } catch (err) { this.Notifications.error('Failure', err, 'Unable to retrieve registries'); diff --git a/app/docker/components/log-viewer/log-viewer.js b/app/docker/components/log-viewer/log-viewer.js index 0be45bc3c..7521916ea 100644 --- a/app/docker/components/log-viewer/log-viewer.js +++ b/app/docker/components/log-viewer/log-viewer.js @@ -6,6 +6,6 @@ angular.module('portainer.docker').component('logViewer', { displayTimestamps: '=', logCollectionChange: '<', sinceTimestamp: '=', - lineCount: '=' - } + lineCount: '=', + }, }); diff --git a/app/docker/components/log-viewer/logViewer.html b/app/docker/components/log-viewer/logViewer.html index 44c1c5d7e..ac9095ebc 100644 --- a/app/docker/components/log-viewer/logViewer.html +++ b/app/docker/components/log-viewer/logViewer.html @@ -11,7 +11,11 @@ @@ -20,9 +24,7 @@ - +
@@ -30,9 +32,7 @@ - +
@@ -51,7 +51,7 @@ Search
- +
@@ -59,7 +59,7 @@ Lines
- +
@@ -67,9 +67,21 @@ Actions
- - - + + + @@ -81,9 +93,9 @@
-
-
-
+
+
+
       

{{ line }}

No log line matching the '{{ $ctrl.state.search }}' filter

No logs available

diff --git a/app/docker/components/log-viewer/logViewerController.js b/app/docker/components/log-viewer/logViewerController.js index 9fdc62663..d55fe555e 100644 --- a/app/docker/components/log-viewer/logViewerController.js +++ b/app/docker/components/log-viewer/logViewerController.js @@ -1,47 +1,47 @@ import moment from 'moment'; -angular.module('portainer.docker') -.controller('LogViewerController', ['clipboard', -function (clipboard) { +angular.module('portainer.docker').controller('LogViewerController', [ + 'clipboard', + function (clipboard) { + this.state = { + availableSinceDatetime: [ + { desc: 'Last day', value: moment().subtract(1, 'days').format() }, + { desc: 'Last 4 hours', value: moment().subtract(4, 'hours').format() }, + { desc: 'Last hour', value: moment().subtract(1, 'hours').format() }, + { desc: 'Last 10 minutes', value: moment().subtract(10, 'minutes').format() }, + ], + copySupported: clipboard.supported, + logCollection: true, + autoScroll: true, + wrapLines: true, + search: '', + filteredLogs: [], + selectedLines: [], + }; - this.state = { - availableSinceDatetime: [ - { desc: 'Last day', value: moment().subtract(1, 'days').format() }, - { desc: 'Last 4 hours', value: moment().subtract(4, 'hours').format() }, - { desc: 'Last hour', value: moment().subtract(1, 'hours').format() }, - { desc: 'Last 10 minutes', value: moment().subtract(10, 'minutes').format() } - ], - copySupported: clipboard.supported, - logCollection: true, - autoScroll: true, - wrapLines: true, - search: '', - filteredLogs: [], - selectedLines: [] - }; + this.copy = function () { + clipboard.copyText(this.state.filteredLogs); + $('#refreshRateChange').show(); + $('#refreshRateChange').fadeOut(2000); + }; - this.copy = function() { - clipboard.copyText(this.state.filteredLogs); - $('#refreshRateChange').show(); - $('#refreshRateChange').fadeOut(2000); - }; + this.copySelection = function () { + clipboard.copyText(this.state.selectedLines); + $('#refreshRateChange').show(); + $('#refreshRateChange').fadeOut(2000); + }; - this.copySelection = function() { - clipboard.copyText(this.state.selectedLines); - $('#refreshRateChange').show(); - $('#refreshRateChange').fadeOut(2000); - }; + this.clearSelection = function () { + this.state.selectedLines = []; + }; - this.clearSelection = function() { - this.state.selectedLines = []; - }; - - this.selectLine = function(line) { - var idx = this.state.selectedLines.indexOf(line); - if (idx === -1) { - this.state.selectedLines.push(line); - } else { - this.state.selectedLines.splice(idx, 1); - } - }; -}]); + this.selectLine = function (line) { + var idx = this.state.selectedLines.indexOf(line); + if (idx === -1) { + this.state.selectedLines.push(line); + } else { + this.state.selectedLines.splice(idx, 1); + } + }; + }, +]); diff --git a/app/docker/components/network-macvlan-form/network-macvlan-form.js b/app/docker/components/network-macvlan-form/network-macvlan-form.js index d9f07d4c8..3ae345cfb 100644 --- a/app/docker/components/network-macvlan-form/network-macvlan-form.js +++ b/app/docker/components/network-macvlan-form/network-macvlan-form.js @@ -3,6 +3,6 @@ angular.module('portainer.docker').component('networkMacvlanForm', { controller: 'NetworkMacvlanFormController', bindings: { data: '=', - applicationState: '<' - } -}); \ No newline at end of file + applicationState: '<', + }, +}); diff --git a/app/docker/components/network-macvlan-form/networkMacvlanForm.html b/app/docker/components/network-macvlan-form/networkMacvlanForm.html index b104bac9d..fca929aa5 100644 --- a/app/docker/components/network-macvlan-form/networkMacvlanForm.html +++ b/app/docker/components/network-macvlan-form/networkMacvlanForm.html @@ -10,10 +10,10 @@
-
+
- +
-
\ No newline at end of file +
diff --git a/app/docker/filters/filters.js b/app/docker/filters/filters.js index 46bdd65f0..a7ad2310c 100644 --- a/app/docker/filters/filters.js +++ b/app/docker/filters/filters.js @@ -1,7 +1,7 @@ import _ from 'lodash-es'; function includeString(text, values) { - return values.some(function(val){ + return values.some(function (val) { return text.indexOf(val) !== -1; }); } @@ -16,290 +16,293 @@ function strToHash(str) { function hashToHexColor(hash) { var color = '#'; - for (var i = 0; i < 3;) { - color += ('00' + ((hash >> i++ * 8) & 0xFF).toString(16)).slice(-2); + for (var i = 0; i < 3; ) { + color += ('00' + ((hash >> (i++ * 8)) & 0xff).toString(16)).slice(-2); } return color; } -angular.module('portainer.docker') -.filter('visualizerTask', function () { - 'use strict'; - return function (text) { - var status = _.toLower(text); - if (includeString(status, ['new', 'allocated', 'assigned', 'accepted', 'complete', 'preparing'])) { - return 'info'; - } else if (includeString(status, ['pending'])) { - return 'warning'; - } else if (includeString(status, ['shutdown', 'failed', 'rejected'])) { - return 'stopped'; - } - return 'running'; - }; -}) -.filter('visualizerTaskBorderColor', function () { - 'use strict'; - return function (str) { - var hash = strToHash(str); - var color = hashToHexColor(hash); - return color; - }; -}) -.filter('taskstatusbadge', function () { - 'use strict'; - return function (text) { - var status = _.toLower(text); - var labelStyle = 'default'; - if (includeString(status, ['new', 'allocated', 'assigned', 'accepted', 'preparing', 'ready', 'starting', 'remove'])) { - labelStyle = 'info'; - } else if (includeString(status, ['pending'])) { - labelStyle = 'warning'; - } else if (includeString(status, ['shutdown', 'failed', 'rejected', 'orphaned'])) { - labelStyle = 'danger'; - } else if (includeString(status, ['complete'])) { - labelStyle = 'primary'; - } else if (includeString(status, ['running'])) { - labelStyle = 'success'; - } - return labelStyle; - }; -}) -.filter('taskhaslogs', function () { - 'use strict'; - return function (state) { - var validState = ['running', 'complete', 'failed', 'shutdown']; - if (validState.indexOf(state) > -1) { - return true; - } - return false; - }; -}) -.filter('containerstatusbadge', function () { - 'use strict'; - return function (text) { - var status = _.toLower(text); - if (includeString(status, ['paused', 'starting', 'unhealthy'])) { - return 'warning'; - } else if (includeString(status, ['created'])) { - return 'info'; - } else if (includeString(status, ['stopped', 'dead', 'exited'])) { - return 'danger'; - } - return 'success'; - }; -}) -.filter('nodestatusbadge', function () { - 'use strict'; - return function (text) { - if (text === 'down' || text === 'Unhealthy') { - return 'danger'; - } - return 'success'; - }; -}) -.filter('dockerNodeAvailabilityBadge', function () { - 'use strict'; - return function (text) { - if (text === 'pause') { - return 'warning'; - } - else if (text === 'drain') { - return 'danger'; - } - return 'success'; - }; -}) -.filter('trimcontainername', function () { - 'use strict'; - return function (name) { - if (name) { - return (name.indexOf('/') === 0 ? name.replace('/','') : name); - } - return ''; - }; -}) -.filter('getstatetext', function () { - 'use strict'; - return function (state) { - if (state === undefined) { +angular + .module('portainer.docker') + .filter('visualizerTask', function () { + 'use strict'; + return function (text) { + var status = _.toLower(text); + if (includeString(status, ['new', 'allocated', 'assigned', 'accepted', 'complete', 'preparing'])) { + return 'info'; + } else if (includeString(status, ['pending'])) { + return 'warning'; + } else if (includeString(status, ['shutdown', 'failed', 'rejected'])) { + return 'stopped'; + } + return 'running'; + }; + }) + .filter('visualizerTaskBorderColor', function () { + 'use strict'; + return function (str) { + var hash = strToHash(str); + var color = hashToHexColor(hash); + return color; + }; + }) + .filter('taskstatusbadge', function () { + 'use strict'; + return function (text) { + var status = _.toLower(text); + var labelStyle = 'default'; + if (includeString(status, ['new', 'allocated', 'assigned', 'accepted', 'preparing', 'ready', 'starting', 'remove'])) { + labelStyle = 'info'; + } else if (includeString(status, ['pending'])) { + labelStyle = 'warning'; + } else if (includeString(status, ['shutdown', 'failed', 'rejected', 'orphaned'])) { + labelStyle = 'danger'; + } else if (includeString(status, ['complete'])) { + labelStyle = 'primary'; + } else if (includeString(status, ['running'])) { + labelStyle = 'success'; + } + return labelStyle; + }; + }) + .filter('taskhaslogs', function () { + 'use strict'; + return function (state) { + var validState = ['running', 'complete', 'failed', 'shutdown']; + if (validState.indexOf(state) > -1) { + return true; + } + return false; + }; + }) + .filter('containerstatusbadge', function () { + 'use strict'; + return function (text) { + var status = _.toLower(text); + if (includeString(status, ['paused', 'starting', 'unhealthy'])) { + return 'warning'; + } else if (includeString(status, ['created'])) { + return 'info'; + } else if (includeString(status, ['stopped', 'dead', 'exited'])) { + return 'danger'; + } + return 'success'; + }; + }) + .filter('nodestatusbadge', function () { + 'use strict'; + return function (text) { + if (text === 'down' || text === 'Unhealthy') { + return 'danger'; + } + return 'success'; + }; + }) + .filter('dockerNodeAvailabilityBadge', function () { + 'use strict'; + return function (text) { + if (text === 'pause') { + return 'warning'; + } else if (text === 'drain') { + return 'danger'; + } + return 'success'; + }; + }) + .filter('trimcontainername', function () { + 'use strict'; + return function (name) { + if (name) { + return name.indexOf('/') === 0 ? name.replace('/', '') : name; + } return ''; - } - if (state.Dead) { - return 'Dead'; - } - if (state.Ghost && state.Running) { - return 'Ghost'; - } - if (state.Running && state.Paused) { - return 'Running (Paused)'; - } - if (state.Running) { - return 'Running'; - } - if (state.Status === 'created') { - return 'Created'; - } - return 'Stopped'; - }; -}) -.filter('getstatelabel', function () { - 'use strict'; - return function (state) { - if (state === undefined) { + }; + }) + .filter('getstatetext', function () { + 'use strict'; + return function (state) { + if (state === undefined) { + return ''; + } + if (state.Dead) { + return 'Dead'; + } + if (state.Ghost && state.Running) { + return 'Ghost'; + } + if (state.Running && state.Paused) { + return 'Running (Paused)'; + } + if (state.Running) { + return 'Running'; + } + if (state.Status === 'created') { + return 'Created'; + } + return 'Stopped'; + }; + }) + .filter('getstatelabel', function () { + 'use strict'; + return function (state) { + if (state === undefined) { + return 'label-default'; + } + if (state.Ghost && state.Running) { + return 'label-important'; + } + if (state.Running) { + return 'label-success'; + } return 'label-default'; - } - if (state.Ghost && state.Running) { - return 'label-important'; - } - if (state.Running) { - return 'label-success'; - } - return 'label-default'; - }; -}) -.filter('containername', function () { - 'use strict'; - return function (container) { - var name = container.Names[0]; - return name.substring(1, name.length); - }; -}) -.filter('swarmversion', function () { - 'use strict'; - return function (text) { - return _.split(text, '/')[1]; - }; -}) -.filter('swarmhostname', function () { - 'use strict'; - return function (container) { - return _.split(container.Names[0], '/')[1]; - }; -}) -.filter('repotags', function () { - 'use strict'; - return function (image) { - if (image.RepoTags && image.RepoTags.length > 0) { - var tag = image.RepoTags[0]; - if (tag === ':') { - return []; + }; + }) + .filter('containername', function () { + 'use strict'; + return function (container) { + var name = container.Names[0]; + return name.substring(1, name.length); + }; + }) + .filter('swarmversion', function () { + 'use strict'; + return function (text) { + return _.split(text, '/')[1]; + }; + }) + .filter('swarmhostname', function () { + 'use strict'; + return function (container) { + return _.split(container.Names[0], '/')[1]; + }; + }) + .filter('repotags', function () { + 'use strict'; + return function (image) { + if (image.RepoTags && image.RepoTags.length > 0) { + var tag = image.RepoTags[0]; + if (tag === ':') { + return []; + } + return image.RepoTags; } - return image.RepoTags; - } - return []; - }; -}) -.filter('command', function () { - 'use strict'; - return function (command) { - if (command) { - return command.join(' '); - } - }; -}) -.filter('hideshasum', function () { - 'use strict'; - return function (imageName) { - if (imageName) { - return imageName.split('@sha')[0]; - } - return ''; - }; -}) -.filter('availablenodecount', ['ConstraintsHelper', function (ConstraintsHelper) { - 'use strict'; - return function (nodes, service) { - var availableNodes = 0; - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - if (node.Availability === 'active' && node.Status === 'ready' && ConstraintsHelper.matchesServiceConstraints(service, node)) { - availableNodes++; + return []; + }; + }) + .filter('command', function () { + 'use strict'; + return function (command) { + if (command) { + return command.join(' '); } - } - return availableNodes; - }; -}]) -.filter('runningtaskscount', function () { - 'use strict'; - return function (tasks) { - var runningTasks = 0; - for (var i = 0; i < tasks.length; i++) { - var task = tasks[i]; - if (task.Status.State === 'running' && task.DesiredState === 'running') { - runningTasks++; + }; + }) + .filter('hideshasum', function () { + 'use strict'; + return function (imageName) { + if (imageName) { + return imageName.split('@sha')[0]; } - } - return runningTasks; - }; -}) -.filter('runningcontainers', function () { - 'use strict'; - return function runningContainersFilter(containers) { - return containers.filter(function (container) { - return container.State === 'running'; - }).length; - }; -}) -.filter('stoppedcontainers', function () { - 'use strict'; - return function stoppedContainersFilter(containers) { - return containers.filter(function (container) { - return container.State === 'exited'; - }).length; - }; -}) -.filter('healthycontainers', function () { - 'use strict'; - return function healthyContainersFilter(containers) { - return containers.filter(function (container) { - return container.Status === 'healthy'; - }).length; - } -}) -.filter('unhealthycontainers', function () { - 'use strict'; - return function unhealthyContainersFilter(containers) { - return containers.filter(function (container) { - return container.Status === 'unhealthy'; - }).length; - } -}) -.filter('imagestotalsize', function () { - 'use strict'; - return function (images) { - var totalImageSize = 0; - for (var i = 0; i < images.length; i++) { - var item = images[i]; - totalImageSize += item.VirtualSize; - } - return totalImageSize; - }; -}) -.filter('tasknodename', function () { - 'use strict'; - return function (nodeId, nodes) { - var node = _.find(nodes, { Id: nodeId }); - if (node) { - return node.Hostname; - } - return ''; - }; -}) -.filter('imagelayercommand', function () { - 'use strict'; - return function (createdBy) { - return createdBy.replace('/bin/sh -c #(nop) ', '').replace('/bin/sh -c ', 'RUN '); - }; -}) -.filter('trimshasum', function () { - 'use strict'; - return function (imageName) { - if (!imageName) { - return; - } - if (imageName.indexOf('sha256:') === 0) { - return imageName.substring(7, 19); - } - return _.split(imageName, '@sha256')[0]; - }; -}); + return ''; + }; + }) + .filter('availablenodecount', [ + 'ConstraintsHelper', + function (ConstraintsHelper) { + 'use strict'; + return function (nodes, service) { + var availableNodes = 0; + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (node.Availability === 'active' && node.Status === 'ready' && ConstraintsHelper.matchesServiceConstraints(service, node)) { + availableNodes++; + } + } + return availableNodes; + }; + }, + ]) + .filter('runningtaskscount', function () { + 'use strict'; + return function (tasks) { + var runningTasks = 0; + for (var i = 0; i < tasks.length; i++) { + var task = tasks[i]; + if (task.Status.State === 'running' && task.DesiredState === 'running') { + runningTasks++; + } + } + return runningTasks; + }; + }) + .filter('runningcontainers', function () { + 'use strict'; + return function runningContainersFilter(containers) { + return containers.filter(function (container) { + return container.State === 'running'; + }).length; + }; + }) + .filter('stoppedcontainers', function () { + 'use strict'; + return function stoppedContainersFilter(containers) { + return containers.filter(function (container) { + return container.State === 'exited'; + }).length; + }; + }) + .filter('healthycontainers', function () { + 'use strict'; + return function healthyContainersFilter(containers) { + return containers.filter(function (container) { + return container.Status === 'healthy'; + }).length; + }; + }) + .filter('unhealthycontainers', function () { + 'use strict'; + return function unhealthyContainersFilter(containers) { + return containers.filter(function (container) { + return container.Status === 'unhealthy'; + }).length; + }; + }) + .filter('imagestotalsize', function () { + 'use strict'; + return function (images) { + var totalImageSize = 0; + for (var i = 0; i < images.length; i++) { + var item = images[i]; + totalImageSize += item.VirtualSize; + } + return totalImageSize; + }; + }) + .filter('tasknodename', function () { + 'use strict'; + return function (nodeId, nodes) { + var node = _.find(nodes, { Id: nodeId }); + if (node) { + return node.Hostname; + } + return ''; + }; + }) + .filter('imagelayercommand', function () { + 'use strict'; + return function (createdBy) { + return createdBy.replace('/bin/sh -c #(nop) ', '').replace('/bin/sh -c ', 'RUN '); + }; + }) + .filter('trimshasum', function () { + 'use strict'; + return function (imageName) { + if (!imageName) { + return; + } + if (imageName.indexOf('sha256:') === 0) { + return imageName.substring(7, 19); + } + return _.split(imageName, '@sha256')[0]; + }; + }); diff --git a/app/docker/helpers/configHelper.js b/app/docker/helpers/configHelper.js index 104377414..00c1dbcde 100644 --- a/app/docker/helpers/configHelper.js +++ b/app/docker/helpers/configHelper.js @@ -1,34 +1,35 @@ -angular.module('portainer.docker') -.factory('ConfigHelper', [function ConfigHelperFactory() { - 'use strict'; - return { - flattenConfig: function(config) { - if (config) { - return { - Id: config.ConfigID, - Name: config.ConfigName, - FileName: config.File.Name, - Uid: config.File.UID, - Gid: config.File.GID, - Mode: config.File.Mode - }; - } - return {}; - }, - configConfig: function(config) { - if (config) { - return { - ConfigID: config.Id, - ConfigName: config.Name, - File: { - Name: config.FileName || config.Name, - UID: config.Uid || '0', - GID: config.Gid || '0', - Mode: config.Mode || 292 - } - }; - } - return {}; - } - }; -}]); +angular.module('portainer.docker').factory('ConfigHelper', [ + function ConfigHelperFactory() { + 'use strict'; + return { + flattenConfig: function (config) { + if (config) { + return { + Id: config.ConfigID, + Name: config.ConfigName, + FileName: config.File.Name, + Uid: config.File.UID, + Gid: config.File.GID, + Mode: config.File.Mode, + }; + } + return {}; + }, + configConfig: function (config) { + if (config) { + return { + ConfigID: config.Id, + ConfigName: config.Name, + File: { + Name: config.FileName || config.Name, + UID: config.Uid || '0', + GID: config.Gid || '0', + Mode: config.Mode || 292, + }, + }; + } + return {}; + }, + }; + }, +]); diff --git a/app/docker/helpers/constraintsHelper.js b/app/docker/helpers/constraintsHelper.js index f006dcf09..c2288f71b 100644 --- a/app/docker/helpers/constraintsHelper.js +++ b/app/docker/helpers/constraintsHelper.js @@ -12,18 +12,16 @@ var patterns = { nodeHostname: 'node.hostname', nodeRole: 'node.role', nodeLabels: 'node.labels.', - engineLabels: 'engine.labels.' + engineLabels: 'engine.labels.', }, op: { eq: '==', - neq: '!=' - } + neq: '!=', + }, }; function matchesConstraint(value, constraint) { - if (!constraint || - (constraint.op === patterns.op.eq && value === constraint.value) || - (constraint.op === patterns.op.neq && value !== constraint.value)) { + if (!constraint || (constraint.op === patterns.op.eq && value === constraint.value) || (constraint.op === patterns.op.neq && value !== constraint.value)) { return true; } return false; @@ -47,8 +45,8 @@ function extractCustomLabelKey(constraint, op, baseLabelKey) { return constraint.split(op).shift().trim().replace(baseLabelKey, ''); } -angular.module('portainer.docker') - .factory('ConstraintsHelper', [function ConstraintsHelperFactory() { +angular.module('portainer.docker').factory('ConstraintsHelper', [ + function ConstraintsHelperFactory() { 'use strict'; return { transformConstraints: function (constraints) { @@ -94,7 +92,8 @@ angular.module('portainer.docker') return true; } var constraints = this.transformConstraints(angular.copy(service.Constraints)); - if (matchesConstraint(node.Id, constraints.nodeId) && + if ( + matchesConstraint(node.Id, constraints.nodeId) && matchesConstraint(node.Hostname, constraints.nodeHostname) && matchesConstraint(node.Role, constraints.nodeRole) && matchesLabel(node.Labels, constraints.nodeLabels) && @@ -103,6 +102,7 @@ angular.module('portainer.docker') return true; } return false; - } + }, }; - }]); \ No newline at end of file + }, +]); diff --git a/app/docker/helpers/containerHelper.js b/app/docker/helpers/containerHelper.js index ab169a4c5..e047676b7 100644 --- a/app/docker/helpers/containerHelper.js +++ b/app/docker/helpers/containerHelper.js @@ -1,5 +1,5 @@ import _ from 'lodash-es'; -import splitargs from 'splitargs/src/splitargs' +import splitargs from 'splitargs/src/splitargs'; const portPattern = /^([1-9]|[1-5]?[0-9]{2,4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/m; @@ -33,8 +33,7 @@ function isValidPortRange(portRange) { portRange = parsePortRange(); } - return Array.isArray(portRange) && portRange.length === 2 && - portRange[0] > 0 && portRange[1] >= portRange[0]; + return Array.isArray(portRange) && portRange.length === 2 && portRange[0] > 0 && portRange[1] >= portRange[0]; } function createPortRange(portRangeText, port) { @@ -49,7 +48,7 @@ function createPortRange(portRangeText, port) { portRangeText = portRangeText.substr(colonIndex + 1); } - port = (typeof port === 'number' ? port : parsePort(port)); + port = typeof port === 'number' ? port : parsePort(port); const portRange = parsePortRange(portRangeText); const startPort = Math.min(portRange[0], port); const endPort = Math.max(portRange[1], port); @@ -61,178 +60,181 @@ function createPortRange(portRangeText, port) { } } -angular.module('portainer.docker') -.factory('ContainerHelper', [function ContainerHelperFactory() { - 'use strict'; - var helper = {}; +angular.module('portainer.docker').factory('ContainerHelper', [ + function ContainerHelperFactory() { + 'use strict'; + var helper = {}; - helper.commandStringToArray = function(command) { - return splitargs(command); - }; - - helper.commandArrayToString = function(array) { - return array.map(function(elem) { - return '\'' + elem + '\''; - }).join(' '); - }; - - helper.configFromContainer = function(container) { - var config = container.Config; - // HostConfig - config.HostConfig = container.HostConfig; - // Name - config.name = container.Name.replace(/^\//g, ''); - // Network - var mode = config.HostConfig.NetworkMode; - config.NetworkingConfig = { - 'EndpointsConfig': {} + helper.commandStringToArray = function (command) { + return splitargs(command); }; - config.NetworkingConfig.EndpointsConfig = container.NetworkSettings.Networks; - if (mode.indexOf('container:') !== -1) { - delete config.Hostname; - delete config.ExposedPorts; - } - // Set volumes - var binds = []; - var volumes = {}; - for (var v in container.Mounts) { - if ({}.hasOwnProperty.call(container.Mounts, v)) { - var mount = container.Mounts[v]; - var name = mount.Name || mount.Source; - var containerPath = mount.Destination; - if (name && containerPath) { - var bind = name + ':' + containerPath; - volumes[containerPath] = {}; - if (mount.RW === false) { - bind += ':ro'; + + helper.commandArrayToString = function (array) { + return array + .map(function (elem) { + return "'" + elem + "'"; + }) + .join(' '); + }; + + helper.configFromContainer = function (container) { + var config = container.Config; + // HostConfig + config.HostConfig = container.HostConfig; + // Name + config.name = container.Name.replace(/^\//g, ''); + // Network + var mode = config.HostConfig.NetworkMode; + config.NetworkingConfig = { + EndpointsConfig: {}, + }; + config.NetworkingConfig.EndpointsConfig = container.NetworkSettings.Networks; + if (mode.indexOf('container:') !== -1) { + delete config.Hostname; + delete config.ExposedPorts; + } + // Set volumes + var binds = []; + var volumes = {}; + for (var v in container.Mounts) { + if ({}.hasOwnProperty.call(container.Mounts, v)) { + var mount = container.Mounts[v]; + var name = mount.Name || mount.Source; + var containerPath = mount.Destination; + if (name && containerPath) { + var bind = name + ':' + containerPath; + volumes[containerPath] = {}; + if (mount.RW === false) { + bind += ':ro'; + } + binds.push(bind); } - binds.push(bind); } } - } - config.HostConfig.Binds = binds; - config.Volumes = volumes; - return config; - }; + config.HostConfig.Binds = binds; + config.Volumes = volumes; + return config; + }; - helper.preparePortBindings = function(portBindings) { - const bindings = {}; - _.forEach(portBindings, (portBinding) => { - if (!portBinding.containerPort) { - return; - } - - let hostPort = portBinding.hostPort; - const containerPortRange = parsePortRange(portBinding.containerPort); - if (!isValidPortRange(containerPortRange)) { - throw new Error('Invalid port specification: ' + portBinding.containerPort); - } - - const startPort = containerPortRange[0]; - const endPort = containerPortRange[1]; - let hostIp = undefined; - let startHostPort = 0; - let endHostPort = 0; - if (hostPort) { - if (hostPort.indexOf(':') > -1) { - const hostAndPort = _.split(hostPort, ':'); - hostIp = hostAndPort[0]; - hostPort = hostAndPort[1]; + helper.preparePortBindings = function (portBindings) { + const bindings = {}; + _.forEach(portBindings, (portBinding) => { + if (!portBinding.containerPort) { + return; } - const hostPortRange = parsePortRange(hostPort); - if (!isValidPortRange(hostPortRange)) { - throw new Error('Invalid port specification: ' + hostPort); + let hostPort = portBinding.hostPort; + const containerPortRange = parsePortRange(portBinding.containerPort); + if (!isValidPortRange(containerPortRange)) { + throw new Error('Invalid port specification: ' + portBinding.containerPort); } - startHostPort = hostPortRange[0]; - endHostPort = hostPortRange[1]; - if (endPort !== startPort && (endPort - startPort) !== (endHostPort - startHostPort)) { - throw new Error('Invalid port specification: ' + hostPort); - } - } + const startPort = containerPortRange[0]; + const endPort = containerPortRange[1]; + let hostIp = undefined; + let startHostPort = 0; + let endHostPort = 0; + if (hostPort) { + if (hostPort.indexOf(':') > -1) { + const hostAndPort = _.split(hostPort, ':'); + hostIp = hostAndPort[0]; + hostPort = hostAndPort[1]; + } - for (let i = 0; i <= (endPort - startPort); i++) { - const containerPort = (startPort + i).toString(); - if (startHostPort > 0) { - hostPort = (startHostPort + i).toString(); - } - if (startPort === endPort && startHostPort !== endHostPort) { - hostPort += '-' + endHostPort.toString(); + const hostPortRange = parsePortRange(hostPort); + if (!isValidPortRange(hostPortRange)) { + throw new Error('Invalid port specification: ' + hostPort); + } + + startHostPort = hostPortRange[0]; + endHostPort = hostPortRange[1]; + if (endPort !== startPort && endPort - startPort !== endHostPort - startHostPort) { + throw new Error('Invalid port specification: ' + hostPort); + } } - const bindKey = containerPort + '/' + portBinding.protocol; - bindings[bindKey] = [{ HostIp: hostIp, HostPort: hostPort }]; - } - }); - return bindings; - }; + for (let i = 0; i <= endPort - startPort; i++) { + const containerPort = (startPort + i).toString(); + if (startHostPort > 0) { + hostPort = (startHostPort + i).toString(); + } + if (startPort === endPort && startHostPort !== endHostPort) { + hostPort += '-' + endHostPort.toString(); + } - helper.sortAndCombinePorts = function(portBindings) { - const bindings = []; - const portBindingKeys = _.keys(portBindings); + const bindKey = containerPort + '/' + portBinding.protocol; + bindings[bindKey] = [{ HostIp: hostIp, HostPort: hostPort }]; + } + }); + return bindings; + }; - // Group the port bindings by protocol - const portBindingKeysByProtocol = _.groupBy(portBindingKeys, (portKey) => { - return _.split(portKey, '/')[1]; - }); + helper.sortAndCombinePorts = function (portBindings) { + const bindings = []; + const portBindingKeys = _.keys(portBindings); - _.forEach(portBindingKeysByProtocol, (portBindingKeys, protocol) => { - // Group the port bindings by host IP - const portBindingKeysByHostIp = _.groupBy(portBindingKeys, (portKey) => { - const portBinding = portBindings[portKey][0]; - return portBinding.HostIp || ''; + // Group the port bindings by protocol + const portBindingKeysByProtocol = _.groupBy(portBindingKeys, (portKey) => { + return _.split(portKey, '/')[1]; }); - _.forEach(portBindingKeysByHostIp, (portBindingKeys) => { - // Sort by host port - const sortedPortBindingKeys = _.orderBy(portBindingKeys, (portKey) => { - return parseInt(_.split(portKey, '/')[0]); + _.forEach(portBindingKeysByProtocol, (portBindingKeys, protocol) => { + // Group the port bindings by host IP + const portBindingKeysByHostIp = _.groupBy(portBindingKeys, (portKey) => { + const portBinding = portBindings[portKey][0]; + return portBinding.HostIp || ''; }); - let previousHostPort = -1; - let previousContainerPort = -1; - _.forEach(sortedPortBindingKeys, (portKey) => { - const portKeySplit = _.split(portKey, '/'); - const containerPort = parseInt(portKeySplit[0]); - const portBinding = portBindings[portKey][0]; - const hostPort = parsePort(portBinding.HostPort); + _.forEach(portBindingKeysByHostIp, (portBindingKeys) => { + // Sort by host port + const sortedPortBindingKeys = _.orderBy(portBindingKeys, (portKey) => { + return parseInt(_.split(portKey, '/')[0]); + }); + + let previousHostPort = -1; + let previousContainerPort = -1; + _.forEach(sortedPortBindingKeys, (portKey) => { + const portKeySplit = _.split(portKey, '/'); + const containerPort = parseInt(portKeySplit[0]); + const portBinding = portBindings[portKey][0]; + const hostPort = parsePort(portBinding.HostPort); + + // We only combine single ports, and skip the host port ranges on one container port + if (hostPort > 0) { + // If we detect consecutive ports, we create a range of them + if (bindings.length > 0 && previousHostPort === hostPort - 1 && previousContainerPort === containerPort - 1) { + bindings[bindings.length - 1].hostPort = createPortRange(bindings[bindings.length - 1].hostPort, hostPort); + bindings[bindings.length - 1].containerPort = createPortRange(bindings[bindings.length - 1].containerPort, containerPort); + previousHostPort = hostPort; + previousContainerPort = containerPort; + return; + } - // We only combine single ports, and skip the host port ranges on one container port - if (hostPort > 0) { - // If we detect consecutive ports, we create a range of them - if (bindings.length > 0 && previousHostPort === (hostPort - 1) && previousContainerPort === (containerPort - 1)) { - bindings[bindings.length-1].hostPort = createPortRange(bindings[bindings.length-1].hostPort, hostPort); - bindings[bindings.length-1].containerPort = createPortRange(bindings[bindings.length-1].containerPort, containerPort); previousHostPort = hostPort; previousContainerPort = containerPort; - return; + } else { + previousHostPort = -1; + previousContainerPort = -1; } - previousHostPort = hostPort; - previousContainerPort = containerPort; - } else { - previousHostPort = -1; - previousContainerPort = -1; - } + let bindingHostPort = portBinding.HostPort.toString(); + if (portBinding.HostIp) { + bindingHostPort = portBinding.HostIp + ':' + bindingHostPort; + } - let bindingHostPort = portBinding.HostPort.toString(); - if (portBinding.HostIp) { - bindingHostPort = portBinding.HostIp + ':' + bindingHostPort; - } - - const binding = { - hostPort: bindingHostPort, - containerPort: containerPort, - protocol: protocol - }; - bindings.push(binding); + const binding = { + hostPort: bindingHostPort, + containerPort: containerPort, + protocol: protocol, + }; + bindings.push(binding); + }); }); }); - }); - return bindings; - }; + return bindings; + }; - return helper; -}]); + return helper; + }, +]); diff --git a/app/docker/helpers/imageHelper.js b/app/docker/helpers/imageHelper.js index b1bd8d78d..ea28976de 100644 --- a/app/docker/helpers/imageHelper.js +++ b/app/docker/helpers/imageHelper.js @@ -1,72 +1,73 @@ import _ from 'lodash-es'; import { RegistryTypes } from 'Extensions/registry-management/models/registryTypes'; -angular.module('portainer.docker') -.factory('ImageHelper', [function ImageHelperFactory() { - 'use strict'; +angular.module('portainer.docker').factory('ImageHelper', [ + function ImageHelperFactory() { + 'use strict'; - var helper = {}; + var helper = {}; - helper.isValidTag = isValidTag; - helper.createImageConfigForContainer = createImageConfigForContainer; - helper.getImagesNamesForDownload = getImagesNamesForDownload; - helper.removeDigestFromRepository = removeDigestFromRepository; - helper.imageContainsURL = imageContainsURL; + helper.isValidTag = isValidTag; + helper.createImageConfigForContainer = createImageConfigForContainer; + helper.getImagesNamesForDownload = getImagesNamesForDownload; + helper.removeDigestFromRepository = removeDigestFromRepository; + helper.imageContainsURL = imageContainsURL; - function isValidTag(tag) { - return tag.match(/^(?![\.\-])([a-zA-Z0-9\_\.\-])+$/g); - } + function isValidTag(tag) { + return tag.match(/^(?![\.\-])([a-zA-Z0-9\_\.\-])+$/g); + } - function getImagesNamesForDownload(images) { - var names = images.map(function(image) { - return image.RepoTags[0] !== ':' ? image.RepoTags[0] : image.Id; - }); - return { - names: names - }; - } + function getImagesNamesForDownload(images) { + var names = images.map(function (image) { + return image.RepoTags[0] !== ':' ? image.RepoTags[0] : image.Id; + }); + return { + names: names, + }; + } - /** - * - * @param {PorImageRegistryModel} registry - */ - function createImageConfigForContainer(registry) { - const data = { - fromImage: '' - }; - let fullImageName = ''; + /** + * + * @param {PorImageRegistryModel} registry + */ + function createImageConfigForContainer(registry) { + const data = { + fromImage: '', + }; + let fullImageName = ''; - if (registry.UseRegistry) { - if (registry.Registry.Type === RegistryTypes.GITLAB) { - const slash = _.startsWith(registry.Image, ':') ? '' : '/'; - fullImageName = registry.Registry.URL + '/' + registry.Registry.Gitlab.ProjectPath + slash + registry.Image; + if (registry.UseRegistry) { + if (registry.Registry.Type === RegistryTypes.GITLAB) { + const slash = _.startsWith(registry.Image, ':') ? '' : '/'; + fullImageName = registry.Registry.URL + '/' + registry.Registry.Gitlab.ProjectPath + slash + registry.Image; + } else { + const url = registry.Registry.URL ? registry.Registry.URL + '/' : ''; + fullImageName = url + registry.Image; + } + if (!_.includes(registry.Image, ':')) { + fullImageName += ':latest'; + } } else { - const url = registry.Registry.URL ? registry.Registry.URL + '/' : ''; - fullImageName = url + registry.Image; + fullImageName = registry.Image; } - if (!_.includes(registry.Image, ':')) { - fullImageName += ':latest'; - } - } else { - fullImageName = registry.Image; + + data.fromImage = fullImageName; + return data; } - data.fromImage = fullImageName; - return data; - } - - function imageContainsURL(image) { - const split = _.split(image, '/'); - const url = split[0]; - if (split.length > 1) { - return _.includes(url, '.') || _.includes(url, ':'); + function imageContainsURL(image) { + const split = _.split(image, '/'); + const url = split[0]; + if (split.length > 1) { + return _.includes(url, '.') || _.includes(url, ':'); + } + return false; } - return false; - } - function removeDigestFromRepository(repository) { - return repository.split('@sha')[0]; - } + function removeDigestFromRepository(repository) { + return repository.split('@sha')[0]; + } - return helper; -}]); + return helper; + }, +]); diff --git a/app/docker/helpers/infoHelper.js b/app/docker/helpers/infoHelper.js index 05f00012e..3ec824793 100644 --- a/app/docker/helpers/infoHelper.js +++ b/app/docker/helpers/infoHelper.js @@ -1,38 +1,39 @@ import _ from 'lodash-es'; -angular.module('portainer.docker') -.factory('InfoHelper', [function InfoHelperFactory() { - 'use strict'; +angular.module('portainer.docker').factory('InfoHelper', [ + function InfoHelperFactory() { + 'use strict'; - var helper = {}; + var helper = {}; - helper.determineEndpointMode = function(info, type) { - var mode = { - provider: '', - role: '', - agentProxy: false + helper.determineEndpointMode = function (info, type) { + var mode = { + provider: '', + role: '', + agentProxy: false, + }; + + if (type === 2 || type === 4) { + mode.agentProxy = true; + } + + if (!info.Swarm || _.isEmpty(info.Swarm.NodeID)) { + if (info.ID === 'vSphere Integrated Containers') { + mode.provider = 'VMWARE_VIC'; + } else { + mode.provider = 'DOCKER_STANDALONE'; + } + } else { + mode.provider = 'DOCKER_SWARM_MODE'; + if (info.Swarm.ControlAvailable) { + mode.role = 'MANAGER'; + } else { + mode.role = 'WORKER'; + } + } + return mode; }; - if (type === 2 || type === 4) { - mode.agentProxy = true; - } - - if (!info.Swarm || _.isEmpty(info.Swarm.NodeID)) { - if (info.ID === 'vSphere Integrated Containers') { - mode.provider = 'VMWARE_VIC'; - } else { - mode.provider = 'DOCKER_STANDALONE'; - } - } else { - mode.provider = 'DOCKER_SWARM_MODE'; - if (info.Swarm.ControlAvailable) { - mode.role = 'MANAGER'; - } else { - mode.role = 'WORKER'; - } - } - return mode; - }; - - return helper; -}]); + return helper; + }, +]); diff --git a/app/docker/helpers/labelHelper.js b/app/docker/helpers/labelHelper.js index 85de78ab1..b19c552cb 100644 --- a/app/docker/helpers/labelHelper.js +++ b/app/docker/helpers/labelHelper.js @@ -1,25 +1,26 @@ -angular.module('portainer.docker') -.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) { - if (label.key) { - labels[label.key] = label.value; - } - }); - } - return labels; - } - }; -}]); +angular.module('portainer.docker').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) { + if (label.key) { + labels[label.key] = label.value; + } + }); + } + return labels; + }, + }; + }, +]); diff --git a/app/docker/helpers/logHelper.js b/app/docker/helpers/logHelper.js index 47f903056..052a69843 100644 --- a/app/docker/helpers/logHelper.js +++ b/app/docker/helpers/logHelper.js @@ -1,22 +1,22 @@ -angular.module('portainer.docker') -.factory('LogHelper', [function LogHelperFactory() { - 'use strict'; - var helper = {}; +angular.module('portainer.docker').factory('LogHelper', [ + function LogHelperFactory() { + 'use strict'; + var helper = {}; - // Return an array with each line being an entry. - // It will also remove any ANSI code related character sequences. - // If the skipHeaders param is specified, it will strip the 8 first characters of each line. - helper.formatLogs = function(logs, skipHeaders) { - logs = logs.replace( - /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, ''); + // Return an array with each line being an entry. + // It will also remove any ANSI code related character sequences. + // If the skipHeaders param is specified, it will strip the 8 first characters of each line. + helper.formatLogs = function (logs, skipHeaders) { + logs = logs.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, ''); - if (skipHeaders) { - logs = logs.substring(8); - logs = logs.replace(/\n(.{8})/g, '\n\r'); - } + if (skipHeaders) { + logs = logs.substring(8); + logs = logs.replace(/\n(.{8})/g, '\n\r'); + } - return logs.split('\n'); - }; + return logs.split('\n'); + }; - return helper; -}]); + return helper; + }, +]); diff --git a/app/docker/helpers/nodeHelper.js b/app/docker/helpers/nodeHelper.js index ba02dfdd1..a97a7b81c 100644 --- a/app/docker/helpers/nodeHelper.js +++ b/app/docker/helpers/nodeHelper.js @@ -1,14 +1,15 @@ -angular.module('portainer.docker') -.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 - }; - } - }; -}]); +angular.module('portainer.docker').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, + }; + }, + }; + }, +]); diff --git a/app/docker/helpers/secretHelper.js b/app/docker/helpers/secretHelper.js index a96241474..9948f8481 100644 --- a/app/docker/helpers/secretHelper.js +++ b/app/docker/helpers/secretHelper.js @@ -1,34 +1,35 @@ -angular.module('portainer.docker') -.factory('SecretHelper', [function SecretHelperFactory() { - 'use strict'; - return { - flattenSecret: function(secret) { - if (secret) { - return { - Id: secret.SecretID, - Name: secret.SecretName, - FileName: secret.File.Name, - Uid: secret.File.UID, - Gid: secret.File.GID, - Mode: secret.File.Mode - }; - } - return {}; - }, - secretConfig: function(secret) { - if (secret) { - return { - SecretID: secret.Id, - SecretName: secret.Name, - File: { - Name: secret.FileName, - UID: secret.Uid || '0', - GID: secret.Gid || '0', - Mode: secret.Mode || 444 - } - }; - } - return {}; - } - }; -}]); +angular.module('portainer.docker').factory('SecretHelper', [ + function SecretHelperFactory() { + 'use strict'; + return { + flattenSecret: function (secret) { + if (secret) { + return { + Id: secret.SecretID, + Name: secret.SecretName, + FileName: secret.File.Name, + Uid: secret.File.UID, + Gid: secret.File.GID, + Mode: secret.File.Mode, + }; + } + return {}; + }, + secretConfig: function (secret) { + if (secret) { + return { + SecretID: secret.Id, + SecretName: secret.Name, + File: { + Name: secret.FileName, + UID: secret.Uid || '0', + GID: secret.Gid || '0', + Mode: secret.Mode || 444, + }, + }; + } + return {}; + }, + }; + }, +]); diff --git a/app/docker/helpers/serviceHelper.js b/app/docker/helpers/serviceHelper.js index f9d2fb689..8788c2c74 100644 --- a/app/docker/helpers/serviceHelper.js +++ b/app/docker/helpers/serviceHelper.js @@ -1,250 +1,251 @@ import moment from 'moment'; -angular.module('portainer.docker') -.factory('ServiceHelper', [function ServiceHelperFactory() { - 'use strict'; +angular.module('portainer.docker').factory('ServiceHelper', [ + function ServiceHelperFactory() { + 'use strict'; - var helper = {}; + var helper = {}; - helper.associateTasksToService = function(service, tasks) { - service.Tasks = []; - var otherServicesTasks = []; - for (var i = 0; i < tasks.length; i++) { - var task = tasks[i]; - if (task.ServiceId === service.Id) { - service.Tasks.push(task); - task.ServiceName = service.Name; - } else { - otherServicesTasks.push(task); + helper.associateTasksToService = function (service, tasks) { + service.Tasks = []; + var otherServicesTasks = []; + for (var i = 0; i < tasks.length; i++) { + var task = tasks[i]; + if (task.ServiceId === service.Id) { + service.Tasks.push(task); + task.ServiceName = service.Name; + } else { + otherServicesTasks.push(task); + } } - } - tasks = otherServicesTasks; - }; - - helper.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 + tasks = otherServicesTasks; }; - }; - helper.translateKeyValueToPlacementPreferences = function(keyValuePreferences) { - if (keyValuePreferences) { - var preferences = []; - keyValuePreferences.forEach(function(preference) { - if (preference.strategy && preference.strategy !== '' && preference.value && preference.value !== '') { - switch (preference.strategy.toLowerCase()) { - case 'spread': - preferences.push({ - 'Spread': { - 'SpreadDescriptor': preference.value - } - }); - break; + helper.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, + }; + }; + + helper.translateKeyValueToPlacementPreferences = function (keyValuePreferences) { + if (keyValuePreferences) { + var preferences = []; + keyValuePreferences.forEach(function (preference) { + if (preference.strategy && preference.strategy !== '' && preference.value && preference.value !== '') { + switch (preference.strategy.toLowerCase()) { + case 'spread': + preferences.push({ + Spread: { + SpreadDescriptor: preference.value, + }, + }); + break; + } } - } - }); - return preferences; - } - return []; - }; - - helper.translateKeyValueToPlacementConstraints = function(keyValueConstraints) { - if (keyValueConstraints) { - var constraints = []; - keyValueConstraints.forEach(function(constraint) { - if (constraint.key && constraint.key !== '' && constraint.value && constraint.value !== '') { - constraints.push(constraint.key + constraint.operator + constraint.value); - } - }); - return constraints; - } - return []; - }; - - helper.translateEnvironmentVariables = function(env) { - if (env) { - var variables = []; - env.forEach(function(variable) { - var idx = variable.indexOf('='); - var keyValue = [variable.slice(0, idx), variable.slice(idx + 1)]; - var originalValue = (keyValue.length > 1) ? keyValue[1] : ''; - variables.push({ - key: keyValue[0], - value: originalValue, - originalKey: keyValue[0], - originalValue: originalValue, - added: true }); - }); - return variables; - } - return []; - }; + return preferences; + } + return []; + }; - helper.translateEnvironmentVariablesToEnv = function(env) { - if (env) { - var variables = []; - env.forEach(function(variable) { - if (variable.key && variable.key !== '') { - variables.push(variable.key + '=' + variable.value); - } - }); - return variables; - } - return []; - }; + helper.translateKeyValueToPlacementConstraints = function (keyValueConstraints) { + if (keyValueConstraints) { + var constraints = []; + keyValueConstraints.forEach(function (constraint) { + if (constraint.key && constraint.key !== '' && constraint.value && constraint.value !== '') { + constraints.push(constraint.key + constraint.operator + constraint.value); + } + }); + return constraints; + } + return []; + }; - helper.translatePreferencesToKeyValue = function(preferences) { - if (preferences) { - var keyValuePreferences = []; - preferences.forEach(function(preference) { - if (preference.Spread) { - keyValuePreferences.push({ - strategy: 'Spread', - value: preference.Spread.SpreadDescriptor + helper.translateEnvironmentVariables = function (env) { + if (env) { + var variables = []; + env.forEach(function (variable) { + var idx = variable.indexOf('='); + var keyValue = [variable.slice(0, idx), variable.slice(idx + 1)]; + var originalValue = keyValue.length > 1 ? keyValue[1] : ''; + variables.push({ + key: keyValue[0], + value: originalValue, + originalKey: keyValue[0], + originalValue: originalValue, + added: true, }); - } - }); - return keyValuePreferences; - } - return []; - }; - - helper.translateConstraintsToKeyValue = function(constraints) { - function getOperator(constraint) { - var indexEquals = constraint.indexOf('=='); - if (indexEquals >= 0) { - return [indexEquals, '==']; - } - return [constraint.indexOf('!='), '!=']; - } - if (constraints) { - var keyValueConstraints = []; - constraints.forEach(function(constraint) { - var operatorIndices = getOperator(constraint); - - var key = constraint.slice(0, operatorIndices[0]); - var operator = operatorIndices[1]; - var value = constraint.slice(operatorIndices[0] + 2); - - keyValueConstraints.push({ - key: key, - value: value, - operator: operator, - originalKey: key, - originalValue: value }); - }); - return keyValueConstraints; - } - }; - - helper.translateHumanDurationToNanos = function(humanDuration) { - var nanos; - var regex = /^([0-9]+)(h|m|s|ms|us|ns)$/i; - var matches = humanDuration.match(regex); - - if (matches !== null && matches.length === 3) { - var duration = parseInt(matches[1], 10); - var unit = matches[2]; - // Moment.js cannot use micro or nanoseconds - switch (unit) { - case 'ns': - nanos = duration; - break; - case 'us': - nanos = duration * 1000; - break; - default: - nanos = moment.duration(duration, unit).asMilliseconds() * 1000000; + return variables; } - } - return nanos; - }; + return []; + }; - // Convert nanoseconds to the higher unit possible - // e.g 1840 nanoseconds = 1804ns - // e.g 300000000000 nanoseconds = 5m - // e.g 3510000000000 nanoseconds = 3510s - // e.g 3540000000000 nanoseconds = 59m - // e.g 3600000000000 nanoseconds = 1h - - helper.translateNanosToHumanDuration = function(nanos) { - var humanDuration = '0s'; - var conversionFromNano = {}; - conversionFromNano['ns'] = 1; - conversionFromNano['us'] = conversionFromNano['ns'] * 1000; - conversionFromNano['ms'] = conversionFromNano['us'] * 1000; - conversionFromNano['s'] = conversionFromNano['ms'] * 1000; - conversionFromNano['m'] = conversionFromNano['s'] * 60; - conversionFromNano['h'] = conversionFromNano['m'] * 60; - - Object.keys(conversionFromNano).forEach(function(unit) { - if ( nanos % conversionFromNano[unit] === 0 && (nanos / conversionFromNano[unit]) > 0) { - humanDuration = (nanos / conversionFromNano[unit]) + unit; - } - }); - return humanDuration; - }; - - helper.translateLogDriverOptsToKeyValue = function(logOptions) { - var options = []; - if (logOptions) { - Object.keys(logOptions).forEach(function(key) { - options.push({ - key: key, - value: logOptions[key], - originalKey: key, - originalValue: logOptions[key], - added: true + helper.translateEnvironmentVariablesToEnv = function (env) { + if (env) { + var variables = []; + env.forEach(function (variable) { + if (variable.key && variable.key !== '') { + variables.push(variable.key + '=' + variable.value); + } }); - }); - } - return options; - }; + return variables; + } + return []; + }; - helper.translateKeyValueToLogDriverOpts = function(keyValueLogDriverOpts) { - var options = {}; - if (keyValueLogDriverOpts) { - keyValueLogDriverOpts.forEach(function(option) { - if (option.key && option.key !== '' && option.value && option.value !== '') { - options[option.key] = option.value; + helper.translatePreferencesToKeyValue = function (preferences) { + if (preferences) { + var keyValuePreferences = []; + preferences.forEach(function (preference) { + if (preference.Spread) { + keyValuePreferences.push({ + strategy: 'Spread', + value: preference.Spread.SpreadDescriptor, + }); + } + }); + return keyValuePreferences; + } + return []; + }; + + helper.translateConstraintsToKeyValue = function (constraints) { + function getOperator(constraint) { + var indexEquals = constraint.indexOf('=='); + if (indexEquals >= 0) { + return [indexEquals, '==']; + } + return [constraint.indexOf('!='), '!=']; + } + if (constraints) { + var keyValueConstraints = []; + constraints.forEach(function (constraint) { + var operatorIndices = getOperator(constraint); + + var key = constraint.slice(0, operatorIndices[0]); + var operator = operatorIndices[1]; + var value = constraint.slice(operatorIndices[0] + 2); + + keyValueConstraints.push({ + key: key, + value: value, + operator: operator, + originalKey: key, + originalValue: value, + }); + }); + return keyValueConstraints; + } + }; + + helper.translateHumanDurationToNanos = function (humanDuration) { + var nanos; + var regex = /^([0-9]+)(h|m|s|ms|us|ns)$/i; + var matches = humanDuration.match(regex); + + if (matches !== null && matches.length === 3) { + var duration = parseInt(matches[1], 10); + var unit = matches[2]; + // Moment.js cannot use micro or nanoseconds + switch (unit) { + case 'ns': + nanos = duration; + break; + case 'us': + nanos = duration * 1000; + break; + default: + nanos = moment.duration(duration, unit).asMilliseconds() * 1000000; + } + } + return nanos; + }; + + // Convert nanoseconds to the higher unit possible + // e.g 1840 nanoseconds = 1804ns + // e.g 300000000000 nanoseconds = 5m + // e.g 3510000000000 nanoseconds = 3510s + // e.g 3540000000000 nanoseconds = 59m + // e.g 3600000000000 nanoseconds = 1h + + helper.translateNanosToHumanDuration = function (nanos) { + var humanDuration = '0s'; + var conversionFromNano = {}; + conversionFromNano['ns'] = 1; + conversionFromNano['us'] = conversionFromNano['ns'] * 1000; + conversionFromNano['ms'] = conversionFromNano['us'] * 1000; + conversionFromNano['s'] = conversionFromNano['ms'] * 1000; + conversionFromNano['m'] = conversionFromNano['s'] * 60; + conversionFromNano['h'] = conversionFromNano['m'] * 60; + + Object.keys(conversionFromNano).forEach(function (unit) { + if (nanos % conversionFromNano[unit] === 0 && nanos / conversionFromNano[unit] > 0) { + humanDuration = nanos / conversionFromNano[unit] + unit; } }); - } - return options; - }; + return humanDuration; + }; - helper.translateHostsEntriesToHostnameIP = function(entries) { - var ipHostEntries = []; - if (entries) { - entries.forEach(function(entry) { - if (entry.indexOf(' ') && entry.split(' ').length === 2) { - var keyValue = entry.split(' '); - ipHostEntries.push({ hostname: keyValue[1], ip: keyValue[0]}); - } - }); - } - return ipHostEntries; - }; + helper.translateLogDriverOptsToKeyValue = function (logOptions) { + var options = []; + if (logOptions) { + Object.keys(logOptions).forEach(function (key) { + options.push({ + key: key, + value: logOptions[key], + originalKey: key, + originalValue: logOptions[key], + added: true, + }); + }); + } + return options; + }; - helper.translateHostnameIPToHostsEntries = function(entries) { - var ipHostEntries = []; - if (entries) { - entries.forEach(function(entry) { - if (entry.ip && entry.hostname) { - ipHostEntries.push(entry.ip + ' ' + entry.hostname); - } - }); - } - return ipHostEntries; - }; + helper.translateKeyValueToLogDriverOpts = function (keyValueLogDriverOpts) { + var options = {}; + if (keyValueLogDriverOpts) { + keyValueLogDriverOpts.forEach(function (option) { + if (option.key && option.key !== '' && option.value && option.value !== '') { + options[option.key] = option.value; + } + }); + } + return options; + }; - return helper; -}]); + helper.translateHostsEntriesToHostnameIP = function (entries) { + var ipHostEntries = []; + if (entries) { + entries.forEach(function (entry) { + if (entry.indexOf(' ') && entry.split(' ').length === 2) { + var keyValue = entry.split(' '); + ipHostEntries.push({ hostname: keyValue[1], ip: keyValue[0] }); + } + }); + } + return ipHostEntries; + }; + + helper.translateHostnameIPToHostsEntries = function (entries) { + var ipHostEntries = []; + if (entries) { + entries.forEach(function (entry) { + if (entry.ip && entry.hostname) { + ipHostEntries.push(entry.ip + ' ' + entry.hostname); + } + }); + } + return ipHostEntries; + }; + + return helper; + }, +]); diff --git a/app/docker/helpers/taskHelper.js b/app/docker/helpers/taskHelper.js index 5526c3c32..2a134318b 100644 --- a/app/docker/helpers/taskHelper.js +++ b/app/docker/helpers/taskHelper.js @@ -1,18 +1,19 @@ -angular.module('portainer.docker') -.factory('TaskHelper', [function TaskHelperFactory() { - 'use strict'; +angular.module('portainer.docker').factory('TaskHelper', [ + function TaskHelperFactory() { + 'use strict'; - var helper = {}; + var helper = {}; - helper.associateContainerToTask = function(task, containers) { - for (var i = 0; i < containers.length; i++) { - var container = containers[i]; - if (task.ContainerId === container.Id) { - task.Container = container; - break; + helper.associateContainerToTask = function (task, containers) { + for (var i = 0; i < containers.length; i++) { + var container = containers[i]; + if (task.ContainerId === container.Id) { + task.Container = container; + break; + } } - } - }; + }; - return helper; -}]); + return helper; + }, +]); diff --git a/app/docker/helpers/volumeHelper.js b/app/docker/helpers/volumeHelper.js index 20cc66c2d..58f735397 100644 --- a/app/docker/helpers/volumeHelper.js +++ b/app/docker/helpers/volumeHelper.js @@ -1,30 +1,31 @@ -angular.module('portainer.docker') -.factory('VolumeHelper', [function VolumeHelperFactory() { - 'use strict'; - var helper = {}; +angular.module('portainer.docker').factory('VolumeHelper', [ + function VolumeHelperFactory() { + 'use strict'; + var helper = {}; - helper.createDriverOptions = function(optionArray) { - var options = {}; - optionArray.forEach(function (option) { - options[option.name] = option.value; - }); - return options; - }; + helper.createDriverOptions = function (optionArray) { + var options = {}; + optionArray.forEach(function (option) { + options[option.name] = option.value; + }); + return options; + }; - helper.isVolumeUsedByAService = function(volume, services) { - for (var i = 0; i < services.length; i++) { - var service = services[i]; - var mounts = service.Mounts; - for (var j = 0; j < mounts.length; j++) { - var mount = mounts[j]; - if (mount.Source === volume.Id) { - return true; + helper.isVolumeUsedByAService = function (volume, services) { + for (var i = 0; i < services.length; i++) { + var service = services[i]; + var mounts = service.Mounts; + for (var j = 0; j < mounts.length; j++) { + var mount = mounts[j]; + if (mount.Source === volume.Id) { + return true; + } } } - } - return false; - }; + return false; + }; - return helper; -}]); + return helper; + }, +]); diff --git a/app/docker/interceptors/containersInterceptor.js b/app/docker/interceptors/containersInterceptor.js index 066ffe4fe..b6a9b340d 100644 --- a/app/docker/interceptors/containersInterceptor.js +++ b/app/docker/interceptors/containersInterceptor.js @@ -1,5 +1,7 @@ -angular.module('portainer.app') - .factory('ContainersInterceptor', ['$q', 'EndpointProvider', function ($q, EndpointProvider) { +angular.module('portainer.app').factory('ContainersInterceptor', [ + '$q', + 'EndpointProvider', + function ($q, EndpointProvider) { 'use strict'; var interceptor = {}; @@ -18,4 +20,5 @@ angular.module('portainer.app') return $q.reject(rejection); } return interceptor; - }]); \ No newline at end of file + }, +]); diff --git a/app/docker/interceptors/imagesInterceptor.js b/app/docker/interceptors/imagesInterceptor.js index 9d79fbc86..5294d0b38 100644 --- a/app/docker/interceptors/imagesInterceptor.js +++ b/app/docker/interceptors/imagesInterceptor.js @@ -1,5 +1,7 @@ -angular.module('portainer.app') - .factory('ImagesInterceptor', ['$q', 'EndpointProvider', function ($q, EndpointProvider) { +angular.module('portainer.app').factory('ImagesInterceptor', [ + '$q', + 'EndpointProvider', + function ($q, EndpointProvider) { 'use strict'; var interceptor = {}; @@ -18,4 +20,5 @@ angular.module('portainer.app') return $q.reject(rejection); } return interceptor; - }]); \ No newline at end of file + }, +]); diff --git a/app/docker/interceptors/infoInterceptor.js b/app/docker/interceptors/infoInterceptor.js index 17f310641..d7b6e97de 100644 --- a/app/docker/interceptors/infoInterceptor.js +++ b/app/docker/interceptors/infoInterceptor.js @@ -1,5 +1,7 @@ -angular.module('portainer.app') - .factory('InfoInterceptor', ['$q', 'EndpointProvider', function ($q, EndpointProvider) { +angular.module('portainer.app').factory('InfoInterceptor', [ + '$q', + 'EndpointProvider', + function ($q, EndpointProvider) { 'use strict'; var interceptor = {}; @@ -18,4 +20,5 @@ angular.module('portainer.app') return $q.reject(rejection); } return interceptor; - }]); \ No newline at end of file + }, +]); diff --git a/app/docker/interceptors/networksInterceptor.js b/app/docker/interceptors/networksInterceptor.js index b5068534c..b3cfdce19 100644 --- a/app/docker/interceptors/networksInterceptor.js +++ b/app/docker/interceptors/networksInterceptor.js @@ -1,5 +1,7 @@ -angular.module('portainer.app') - .factory('NetworksInterceptor', ['$q', 'EndpointProvider', function ($q, EndpointProvider) { +angular.module('portainer.app').factory('NetworksInterceptor', [ + '$q', + 'EndpointProvider', + function ($q, EndpointProvider) { 'use strict'; var interceptor = {}; @@ -18,4 +20,5 @@ angular.module('portainer.app') return $q.reject(rejection); } return interceptor; - }]); \ No newline at end of file + }, +]); diff --git a/app/docker/interceptors/versionInterceptor.js b/app/docker/interceptors/versionInterceptor.js index 95a5d56c4..019a34c52 100644 --- a/app/docker/interceptors/versionInterceptor.js +++ b/app/docker/interceptors/versionInterceptor.js @@ -1,5 +1,7 @@ -angular.module('portainer.app') - .factory('VersionInterceptor', ['$q', 'EndpointProvider', function ($q, EndpointProvider) { +angular.module('portainer.app').factory('VersionInterceptor', [ + '$q', + 'EndpointProvider', + function ($q, EndpointProvider) { 'use strict'; var interceptor = {}; @@ -18,4 +20,5 @@ angular.module('portainer.app') return $q.reject(rejection); } return interceptor; - }]); + }, +]); diff --git a/app/docker/interceptors/volumesInterceptor.js b/app/docker/interceptors/volumesInterceptor.js index a42addd2c..bbb1dae35 100644 --- a/app/docker/interceptors/volumesInterceptor.js +++ b/app/docker/interceptors/volumesInterceptor.js @@ -1,5 +1,7 @@ -angular.module('portainer.app') - .factory('VolumesInterceptor', ['$q', 'EndpointProvider', function ($q, EndpointProvider) { +angular.module('portainer.app').factory('VolumesInterceptor', [ + '$q', + 'EndpointProvider', + function ($q, EndpointProvider) { 'use strict'; var interceptor = {}; @@ -18,4 +20,5 @@ angular.module('portainer.app') return $q.reject(rejection); } return interceptor; - }]); \ No newline at end of file + }, +]); diff --git a/app/docker/models/config.js b/app/docker/models/config.js index e9b2db69f..0939c692b 100644 --- a/app/docker/models/config.js +++ b/app/docker/models/config.js @@ -1,9 +1,14 @@ import { ResourceControlViewModel } from 'Portainer/models/resourceControl/resourceControl'; function b64DecodeUnicode(str) { - return decodeURIComponent(atob(str).split('').map(function(c) { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }).join('')); + return decodeURIComponent( + atob(str) + .split('') + .map(function (c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }) + .join('') + ); } export function ConfigViewModel(data) { diff --git a/app/docker/models/container.js b/app/docker/models/container.js index c09ad7748..58cc51a20 100644 --- a/app/docker/models/container.js +++ b/app/docker/models/container.js @@ -68,12 +68,14 @@ export function ContainerViewModel(data) { export function ContainerStatsViewModel(data) { this.read = data.read; this.preread = data.preread; - if(data.memory_stats.privateworkingset !== undefined) { // Windows + if (data.memory_stats.privateworkingset !== undefined) { + // Windows this.MemoryUsage = data.memory_stats.privateworkingset; this.MemoryCache = 0; this.NumProcs = data.num_procs; this.isWindows = true; - } else { // Linux + } else { + // Linux if (data.memory_stats.stats === undefined || data.memory_stats.usage === undefined) { this.MemoryUsage = this.MemoryCache = 0; } else { diff --git a/app/docker/models/containerCapabilities.js b/app/docker/models/containerCapabilities.js index 61706cc51..dadf14eac 100644 --- a/app/docker/models/containerCapabilities.js +++ b/app/docker/models/containerCapabilities.js @@ -1,90 +1,90 @@ var capDesc = { - 'SETPCAP': 'Modify process capabilities.', - 'MKNOD': 'Create special files using mknod(2).', - 'AUDIT_WRITE': 'Write records to kernel auditing log.', - 'CHOWN': 'Make arbitrary changes to file UIDs and GIDs (see chown(2)).', - 'NET_RAW': 'Use RAW and PACKET sockets.', - 'DAC_OVERRIDE': 'Bypass file read, write, and execute permission checks.', - 'FOWNER': 'Bypass permission checks on operations that normally require the file system UID of the process to match the UID of the file.', - 'FSETID': 'Don’t clear set-user-ID and set-group-ID permission bits when a file is modified.', - 'KILL': 'Bypass permission checks for sending signals.', - 'SETGID': 'Make arbitrary manipulations of process GIDs and supplementary GID list.', - 'SETUID': 'Make arbitrary manipulations of process UIDs.', - 'NET_BIND_SERVICE': 'Bind a socket to internet domain privileged ports (port numbers less than 1024).', - 'SYS_CHROOT': 'Use chroot(2), change root directory.', - 'SETFCAP': 'Set file capabilities.', - 'SYS_MODULE': 'Load and unload kernel modules.', - 'SYS_RAWIO': 'Perform I/O port operations (iopl(2) and ioperm(2)).', - 'SYS_PACCT': 'Use acct(2), switch process accounting on or off.', - 'SYS_ADMIN': 'Perform a range of system administration operations.', - 'SYS_NICE': 'Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes.', - 'SYS_RESOURCE': 'Override resource Limits.', - 'SYS_TIME': 'Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock.', - 'SYS_TTY_CONFIG': 'Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals.', - 'AUDIT_CONTROL': 'Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules.', - 'MAC_ADMIN': 'Allow MAC configuration or state changes. Implemented for the Smack LSM.', - 'MAC_OVERRIDE': 'Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM).', - 'NET_ADMIN': 'Perform various network-related operations.', - 'SYSLOG': 'Perform privileged syslog(2) operations.', - 'DAC_READ_SEARCH': 'Bypass file read permission checks and directory read and execute permission checks.', - 'LINUX_IMMUTABLE': 'Set the FS_APPEND_FL and FS_IMMUTABLE_FL i-node flags.', - 'NET_BROADCAST': 'Make socket broadcasts, and listen to multicasts.', - 'IPC_LOCK': 'Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2)).', - 'IPC_OWNER': 'Bypass permission checks for operations on System V IPC objects.', - 'SYS_PTRACE': 'Trace arbitrary processes using ptrace(2).', - 'SYS_BOOT': 'Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution.', - 'LEASE': 'Establish leases on arbitrary files (see fcntl(2)).', - 'WAKE_ALARM': 'Trigger something that will wake up the system.', - 'BLOCK_SUSPEND': 'Employ features that can block system suspend.' + SETPCAP: 'Modify process capabilities.', + MKNOD: 'Create special files using mknod(2).', + AUDIT_WRITE: 'Write records to kernel auditing log.', + CHOWN: 'Make arbitrary changes to file UIDs and GIDs (see chown(2)).', + NET_RAW: 'Use RAW and PACKET sockets.', + DAC_OVERRIDE: 'Bypass file read, write, and execute permission checks.', + FOWNER: 'Bypass permission checks on operations that normally require the file system UID of the process to match the UID of the file.', + FSETID: 'Don’t clear set-user-ID and set-group-ID permission bits when a file is modified.', + KILL: 'Bypass permission checks for sending signals.', + SETGID: 'Make arbitrary manipulations of process GIDs and supplementary GID list.', + SETUID: 'Make arbitrary manipulations of process UIDs.', + NET_BIND_SERVICE: 'Bind a socket to internet domain privileged ports (port numbers less than 1024).', + SYS_CHROOT: 'Use chroot(2), change root directory.', + SETFCAP: 'Set file capabilities.', + SYS_MODULE: 'Load and unload kernel modules.', + SYS_RAWIO: 'Perform I/O port operations (iopl(2) and ioperm(2)).', + SYS_PACCT: 'Use acct(2), switch process accounting on or off.', + SYS_ADMIN: 'Perform a range of system administration operations.', + SYS_NICE: 'Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes.', + SYS_RESOURCE: 'Override resource Limits.', + SYS_TIME: 'Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock.', + SYS_TTY_CONFIG: 'Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals.', + AUDIT_CONTROL: 'Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules.', + MAC_ADMIN: 'Allow MAC configuration or state changes. Implemented for the Smack LSM.', + MAC_OVERRIDE: 'Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM).', + NET_ADMIN: 'Perform various network-related operations.', + SYSLOG: 'Perform privileged syslog(2) operations.', + DAC_READ_SEARCH: 'Bypass file read permission checks and directory read and execute permission checks.', + LINUX_IMMUTABLE: 'Set the FS_APPEND_FL and FS_IMMUTABLE_FL i-node flags.', + NET_BROADCAST: 'Make socket broadcasts, and listen to multicasts.', + IPC_LOCK: 'Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2)).', + IPC_OWNER: 'Bypass permission checks for operations on System V IPC objects.', + SYS_PTRACE: 'Trace arbitrary processes using ptrace(2).', + SYS_BOOT: 'Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution.', + LEASE: 'Establish leases on arbitrary files (see fcntl(2)).', + WAKE_ALARM: 'Trigger something that will wake up the system.', + BLOCK_SUSPEND: 'Employ features that can block system suspend.', }; export function ContainerCapabilities() { - // all capabilities can be found at https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities - return [ - new ContainerCapability('SETPCAP', true), - new ContainerCapability('MKNOD', true), - new ContainerCapability('AUDIT_WRITE', true), - new ContainerCapability('CHOWN', true), - new ContainerCapability('NET_RAW', true), - new ContainerCapability('DAC_OVERRIDE', true), - new ContainerCapability('FOWNER', true), - new ContainerCapability('FSETID', true), - new ContainerCapability('KILL', true), - new ContainerCapability('SETGID', true), - new ContainerCapability('SETUID', true), - new ContainerCapability('NET_BIND_SERVICE', true), - new ContainerCapability('SYS_CHROOT', true), - new ContainerCapability('SETFCAP', true), - new ContainerCapability('SYS_MODULE', false), - new ContainerCapability('SYS_RAWIO', false), - new ContainerCapability('SYS_PACCT', false), - new ContainerCapability('SYS_ADMIN', false), - new ContainerCapability('SYS_NICE', false), - new ContainerCapability('SYS_RESOURCE', false), - new ContainerCapability('SYS_TIME', false), - new ContainerCapability('SYS_TTY_CONFIG', false), - new ContainerCapability('AUDIT_CONTROL', false), - new ContainerCapability('MAC_ADMIN', false), - new ContainerCapability('MAC_OVERRIDE', false), - new ContainerCapability('NET_ADMIN', false), - new ContainerCapability('SYSLOG', false), - new ContainerCapability('DAC_READ_SEARCH', false), - new ContainerCapability('LINUX_IMMUTABLE', false), - new ContainerCapability('NET_BROADCAST', false), - new ContainerCapability('IPC_LOCK', false), - new ContainerCapability('IPC_OWNER', false), - new ContainerCapability('SYS_PTRACE', false), - new ContainerCapability('SYS_BOOT', false), - new ContainerCapability('LEASE', false), - new ContainerCapability('WAKE_ALARM', false), - new ContainerCapability('BLOCK_SUSPEND', false) - ].sort(function (a, b) { - return a.capability < b.capability ? -1 : 1; - }); + // all capabilities can be found at https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities + return [ + new ContainerCapability('SETPCAP', true), + new ContainerCapability('MKNOD', true), + new ContainerCapability('AUDIT_WRITE', true), + new ContainerCapability('CHOWN', true), + new ContainerCapability('NET_RAW', true), + new ContainerCapability('DAC_OVERRIDE', true), + new ContainerCapability('FOWNER', true), + new ContainerCapability('FSETID', true), + new ContainerCapability('KILL', true), + new ContainerCapability('SETGID', true), + new ContainerCapability('SETUID', true), + new ContainerCapability('NET_BIND_SERVICE', true), + new ContainerCapability('SYS_CHROOT', true), + new ContainerCapability('SETFCAP', true), + new ContainerCapability('SYS_MODULE', false), + new ContainerCapability('SYS_RAWIO', false), + new ContainerCapability('SYS_PACCT', false), + new ContainerCapability('SYS_ADMIN', false), + new ContainerCapability('SYS_NICE', false), + new ContainerCapability('SYS_RESOURCE', false), + new ContainerCapability('SYS_TIME', false), + new ContainerCapability('SYS_TTY_CONFIG', false), + new ContainerCapability('AUDIT_CONTROL', false), + new ContainerCapability('MAC_ADMIN', false), + new ContainerCapability('MAC_OVERRIDE', false), + new ContainerCapability('NET_ADMIN', false), + new ContainerCapability('SYSLOG', false), + new ContainerCapability('DAC_READ_SEARCH', false), + new ContainerCapability('LINUX_IMMUTABLE', false), + new ContainerCapability('NET_BROADCAST', false), + new ContainerCapability('IPC_LOCK', false), + new ContainerCapability('IPC_OWNER', false), + new ContainerCapability('SYS_PTRACE', false), + new ContainerCapability('SYS_BOOT', false), + new ContainerCapability('LEASE', false), + new ContainerCapability('WAKE_ALARM', false), + new ContainerCapability('BLOCK_SUSPEND', false), + ].sort(function (a, b) { + return a.capability < b.capability ? -1 : 1; + }); } export function ContainerCapability(cap, allowed) { - this.capability = cap; - this.allowed = allowed; - this.description = capDesc[cap]; -} \ No newline at end of file + this.capability = cap; + this.allowed = allowed; + this.description = capDesc[cap]; +} diff --git a/app/docker/models/event.js b/app/docker/models/event.js index 46f9f8c10..914740a04 100644 --- a/app/docker/models/event.js +++ b/app/docker/models/event.js @@ -3,148 +3,148 @@ function createEventDetails(event) { 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; - case 'detach': - details = 'Container ' + eventAttr.name + ' detached'; - break; - case 'copy': - details = 'Container ' + eventAttr.name + ' copied'; - break; - case 'export': - details = 'Container ' + eventAttr.name + ' exported'; - break; - case 'health_status': - details = 'Container ' + eventAttr.name + ' executed health status'; - break; - case 'oom': - details = 'Container ' + eventAttr.name + ' goes in out of memory'; - break; - case 'rename': - details = 'Container ' + eventAttr.name + ' renamed'; - break; - case 'resize': - details = 'Container ' + eventAttr.name + ' resized'; - break; - case 'top': - details = 'Showed running processes for container ' + eventAttr.name; - break; - case 'update': - details = 'Container ' + eventAttr.name + ' updated'; - 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'; + 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; + case 'detach': + details = 'Container ' + eventAttr.name + ' detached'; + break; + case 'copy': + details = 'Container ' + eventAttr.name + ' copied'; + break; + case 'export': + details = 'Container ' + eventAttr.name + ' exported'; + break; + case 'health_status': + details = 'Container ' + eventAttr.name + ' executed health status'; + break; + case 'oom': + details = 'Container ' + eventAttr.name + ' goes in out of memory'; + break; + case 'rename': + details = 'Container ' + eventAttr.name + ' renamed'; + break; + case 'resize': + details = 'Container ' + eventAttr.name + ' resized'; + break; + case 'top': + details = 'Showed running processes for container ' + eventAttr.name; + break; + case 'update': + details = 'Container ' + eventAttr.name + ' updated'; + 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; + break; case 'image': - switch (event.Action) { - case 'delete': - details = 'Image deleted'; + switch (event.Action) { + case 'delete': + details = 'Image deleted'; + break; + case 'import': + details = 'Image ' + event.Actor.ID + ' imported'; + break; + case 'load': + details = 'Image ' + event.Actor.ID + ' loaded'; + break; + case 'tag': + details = 'New tag created for ' + eventAttr.name; + break; + case 'untag': + details = 'Image untagged'; + break; + case 'save': + details = 'Image ' + event.Actor.ID + ' saved'; + break; + case 'pull': + details = 'Image ' + event.Actor.ID + ' pulled'; + break; + case 'push': + details = 'Image ' + event.Actor.ID + ' pushed'; + break; + default: + details = 'Unsupported event'; + } break; - case 'import': - details = 'Image ' + event.Actor.ID + ' imported'; - break; - case 'load': - details = 'Image ' + event.Actor.ID + ' loaded'; - break; - case 'tag': - details = 'New tag created for ' + eventAttr.name; - break; - case 'untag': - details = 'Image untagged'; - break; - case 'save': - details = 'Image ' + event.Actor.ID + ' saved'; - break; - case 'pull': - details = 'Image ' + event.Actor.ID + ' pulled'; - break; - case 'push': - details = 'Image ' + event.Actor.ID + ' pushed'; - break; - default: - details = 'Unsupported event'; - } - break; case 'network': - switch (event.Action) { - case 'create': - details = 'Network ' + eventAttr.name + ' created'; + switch (event.Action) { + case 'create': + details = 'Network ' + eventAttr.name + ' created'; + break; + case 'destroy': + details = 'Network ' + eventAttr.name + ' deleted'; + break; + case 'remove': + details = 'Network ' + eventAttr.name + ' removed'; + 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 'destroy': - details = 'Network ' + eventAttr.name + ' deleted'; - break; - case 'remove': - details = 'Network ' + eventAttr.name + ' removed'; - 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'; + 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; - 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'; + details = 'Unsupported event'; } return details; } diff --git a/app/docker/models/network.js b/app/docker/models/network.js index a629eb0d3..e3beb5e1f 100644 --- a/app/docker/models/network.js +++ b/app/docker/models/network.js @@ -29,4 +29,4 @@ export function NetworkViewModel(data) { this.ConfigFrom = data.ConfigFrom; this.ConfigOnly = data.ConfigOnly; -} \ No newline at end of file +} diff --git a/app/docker/models/node.js b/app/docker/models/node.js index 4057141f4..9386bf984 100644 --- a/app/docker/models/node.js +++ b/app/docker/models/node.js @@ -10,7 +10,7 @@ export function NodeViewModel(data) { var labels = data.Spec.Labels; if (labels) { - this.Labels = Object.keys(labels).map(function(key) { + this.Labels = Object.keys(labels).map(function (key) { return { key: key, value: labels[key], originalKey: key, originalValue: labels[key], added: true }; }); } else { @@ -19,7 +19,7 @@ export function NodeViewModel(data) { var engineLabels = data.Description.Engine.Labels; if (engineLabels) { - this.EngineLabels = Object.keys(engineLabels).map(function(key) { + this.EngineLabels = Object.keys(engineLabels).map(function (key) { return { key: key, value: engineLabels[key] }; }); } else { diff --git a/app/docker/models/porImageRegistry.js b/app/docker/models/porImageRegistry.js index 38ea4ad94..c34c318ab 100644 --- a/app/docker/models/porImageRegistry.js +++ b/app/docker/models/porImageRegistry.js @@ -1,11 +1,11 @@ /** * This model should be used with por-image-registry component * And bound to the 'model' attribute - * + * * // viewController.js - * + * * this.imageModel = new PorImageRegistryModel(); - * + * * // view.html * */ @@ -13,4 +13,4 @@ export function PorImageRegistryModel() { this.UseRegistry = true; this.Registry = {}; this.Image = ''; -} \ No newline at end of file +} diff --git a/app/docker/models/service.js b/app/docker/models/service.js index 84f58eed0..df72a282f 100644 --- a/app/docker/models/service.js +++ b/app/docker/models/service.js @@ -10,7 +10,7 @@ export function ServiceViewModel(data, runningTasks, allTasks) { this.Image = data.Spec.TaskTemplate.ContainerSpec.Image; this.Version = data.Version.Index; if (data.Spec.Mode.Replicated) { - this.Mode = 'replicated' ; + this.Mode = 'replicated'; this.Replicas = data.Spec.Mode.Replicated.Replicas; } else { this.Mode = 'global'; @@ -23,12 +23,12 @@ export function ServiceViewModel(data, runningTasks, allTasks) { } if (data.Spec.TaskTemplate.Resources) { if (data.Spec.TaskTemplate.Resources.Limits) { - this.LimitNanoCPUs = data.Spec.TaskTemplate.Resources.Limits.NanoCPUs; - this.LimitMemoryBytes = data.Spec.TaskTemplate.Resources.Limits.MemoryBytes; + this.LimitNanoCPUs = data.Spec.TaskTemplate.Resources.Limits.NanoCPUs; + this.LimitMemoryBytes = data.Spec.TaskTemplate.Resources.Limits.MemoryBytes; } if (data.Spec.TaskTemplate.Resources.Reservations) { - this.ReservationNanoCPUs = data.Spec.TaskTemplate.Resources.Reservations.NanoCPUs; - this.ReservationMemoryBytes = data.Spec.TaskTemplate.Resources.Reservations.MemoryBytes; + this.ReservationNanoCPUs = data.Spec.TaskTemplate.Resources.Reservations.NanoCPUs; + this.ReservationMemoryBytes = data.Spec.TaskTemplate.Resources.Reservations.MemoryBytes; } } @@ -92,7 +92,7 @@ export function ServiceViewModel(data, runningTasks, allTasks) { this.VirtualIPs = data.Endpoint ? data.Endpoint.VirtualIPs : []; if (data.Spec.UpdateConfig) { - this.UpdateParallelism = (typeof data.Spec.UpdateConfig.Parallelism !== undefined) ? data.Spec.UpdateConfig.Parallelism || 0 : 1; + 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'; this.UpdateOrder = data.Spec.UpdateConfig.Order || 'stop-first'; diff --git a/app/docker/rest/build.js b/app/docker/rest/build.js index e48d12d51..b0ba607ad 100644 --- a/app/docker/rest/build.js +++ b/app/docker/rest/build.js @@ -1,20 +1,31 @@ import { jsonObjectsToArrayHandler } from './response/handlers'; -angular.module('portainer.docker') -.factory('Build', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function BuildFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/build', { - endpointId: EndpointProvider.endpointID +angular.module('portainer.docker').factory('Build', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function BuildFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/build', + { + endpointId: EndpointProvider.endpointID, + }, + { + buildImage: { + method: 'POST', + ignoreLoadingBar: true, + transformResponse: jsonObjectsToArrayHandler, + isArray: true, + headers: { 'Content-Type': 'application/x-tar' }, + }, + buildImageOverride: { + method: 'POST', + ignoreLoadingBar: true, + transformResponse: jsonObjectsToArrayHandler, + isArray: true, + }, + } + ); }, - { - buildImage: { - method: 'POST', ignoreLoadingBar: true, - transformResponse: jsonObjectsToArrayHandler, isArray: true, - headers: { 'Content-Type': 'application/x-tar' } - }, - buildImageOverride: { - method: 'POST', ignoreLoadingBar: true, - transformResponse: jsonObjectsToArrayHandler, isArray: true - } - }); -}]); +]); diff --git a/app/docker/rest/commit.js b/app/docker/rest/commit.js index 364610297..5d768a119 100644 --- a/app/docker/rest/commit.js +++ b/app/docker/rest/commit.js @@ -1,10 +1,17 @@ -angular.module('portainer.docker') -.factory('Commit', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function CommitFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/commit', { - endpointId: EndpointProvider.endpointID +angular.module('portainer.docker').factory('Commit', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function CommitFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/commit', + { + endpointId: EndpointProvider.endpointID, + }, + { + commitContainer: { method: 'POST', params: { container: '@id', repo: '@repo' }, ignoreLoadingBar: true }, + } + ); }, - { - commitContainer: {method: 'POST', params: {container: '@id', repo: '@repo'}, ignoreLoadingBar: true} - }); -}]); +]); diff --git a/app/docker/rest/config.js b/app/docker/rest/config.js index 2b21ee2d0..af3bcecc7 100644 --- a/app/docker/rest/config.js +++ b/app/docker/rest/config.js @@ -1,12 +1,20 @@ -angular.module('portainer.docker') -.factory('Config', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function ConfigFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/configs/:id/:action', { - endpointId: EndpointProvider.endpointID - }, { - get: { method: 'GET', params: { id: '@id' } }, - query: { method: 'GET', isArray: true }, - create: { method: 'POST', params: { action: 'create' }, ignoreLoadingBar: true }, - remove: { method: 'DELETE', params: { id: '@id' } } - }); -}]); +angular.module('portainer.docker').factory('Config', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function ConfigFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/configs/:id/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + get: { method: 'GET', params: { id: '@id' } }, + query: { method: 'GET', isArray: true }, + create: { method: 'POST', params: { action: 'create' }, ignoreLoadingBar: true }, + remove: { method: 'DELETE', params: { id: '@id' } }, + } + ); + }, +]); diff --git a/app/docker/rest/container.js b/app/docker/rest/container.js index 1aeb38e26..aae286f11 100644 --- a/app/docker/rest/container.js +++ b/app/docker/rest/container.js @@ -1,82 +1,115 @@ -import {genericHandler, logsHandler} from './response/handlers'; +import { genericHandler, logsHandler } from './response/handlers'; -angular.module('portainer.docker') -.factory('Container', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'ContainersInterceptor', -function ContainerFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, ContainersInterceptor) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/containers/:id/:action', { - name: '@name', - endpointId: EndpointProvider.endpointID +angular.module('portainer.docker').factory('Container', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'ContainersInterceptor', + function ContainerFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, ContainersInterceptor) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/containers/:id/:action', + { + name: '@name', + endpointId: EndpointProvider.endpointID, + }, + { + query: { + method: 'GET', + params: { all: 0, action: 'json', filters: '@filters' }, + isArray: true, + interceptor: ContainersInterceptor, + timeout: 15000, + }, + get: { + method: 'GET', + params: { action: 'json' }, + }, + stop: { + method: 'POST', + params: { id: '@id', action: 'stop' }, + }, + restart: { + method: 'POST', + params: { id: '@id', 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' }, + }, + logs: { + method: 'GET', + params: { id: '@id', action: 'logs' }, + timeout: 4500, + ignoreLoadingBar: true, + transformResponse: logsHandler, + }, + stats: { + method: 'GET', + params: { id: '@id', stream: false, action: 'stats' }, + timeout: 4500, + ignoreLoadingBar: true, + }, + top: { + method: 'GET', + params: { id: '@id', action: 'top' }, + timeout: 4500, + ignoreLoadingBar: true, + }, + start: { + method: 'POST', + params: { id: '@id', action: 'start' }, + transformResponse: genericHandler, + }, + create: { + method: 'POST', + params: { action: 'create' }, + transformResponse: genericHandler, + ignoreLoadingBar: true, + }, + remove: { + method: 'DELETE', + params: { id: '@id', v: '@v', force: '@force' }, + transformResponse: genericHandler, + }, + rename: { + method: 'POST', + params: { id: '@id', action: 'rename', name: '@name' }, + transformResponse: genericHandler, + }, + exec: { + method: 'POST', + params: { id: '@id', action: 'exec' }, + transformResponse: genericHandler, + ignoreLoadingBar: true, + }, + inspect: { + method: 'GET', + params: { id: '@id', action: 'json' }, + }, + update: { + method: 'POST', + params: { id: '@id', action: 'update' }, + }, + prune: { + method: 'POST', + params: { action: 'prune', filters: '@filters' }, + }, + resize: { + method: 'POST', + params: { id: '@id', action: 'resize', h: '@height', w: '@width' }, + transformResponse: genericHandler, + ignoreLoadingBar: true, + }, + } + ); }, - { - query: { - method: 'GET', params: { all: 0, action: 'json', filters: '@filters' }, - isArray: true, interceptor: ContainersInterceptor, timeout: 15000 - }, - get: { - method: 'GET', params: { action: 'json' } - }, - stop: { - method: 'POST', params: { id: '@id', action: 'stop' } - }, - restart: { - method: 'POST', params: { id: '@id', 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' } - }, - logs: { - method: 'GET', params: { id: '@id', action: 'logs' }, - timeout: 4500, ignoreLoadingBar: true, - transformResponse: logsHandler - }, - stats: { - method: 'GET', params: { id: '@id', stream: false, action: 'stats' }, - timeout: 4500, ignoreLoadingBar: true - }, - top: { - method: 'GET', params: { id: '@id', action: 'top' }, - timeout: 4500, ignoreLoadingBar: true - }, - start: { - method: 'POST', params: {id: '@id', action: 'start'}, - transformResponse: genericHandler - }, - create: { - method: 'POST', params: {action: 'create'}, - transformResponse: genericHandler, - ignoreLoadingBar: true - }, - remove: { - method: 'DELETE', params: {id: '@id', v: '@v', force: '@force'}, - transformResponse: genericHandler - }, - rename: { - method: 'POST', params: { id: '@id', action: 'rename', name: '@name' }, - transformResponse: genericHandler - }, - exec: { - method: 'POST', params: {id: '@id', action: 'exec'}, - transformResponse: genericHandler, ignoreLoadingBar: true - }, - inspect: { - method: 'GET', params: { id: '@id', action: 'json' } - }, - update: { - method: 'POST', params: { id: '@id', action: 'update'} - }, - prune: { - method: 'POST', params: { action: 'prune', filters: '@filters' } - }, - resize: { - method: 'POST', params: {id: '@id', action: 'resize', h: '@height', w: '@width'}, - transformResponse: genericHandler, ignoreLoadingBar: true - } - }); -}]); +]); diff --git a/app/docker/rest/exec.js b/app/docker/rest/exec.js index 6ad7b4f35..20c5035e4 100644 --- a/app/docker/rest/exec.js +++ b/app/docker/rest/exec.js @@ -1,16 +1,24 @@ import { genericHandler } from './response/handlers'; -angular.module('portainer.docker') -.factory('Exec', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', -function ExecFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/exec/:id/:action', { - endpointId: EndpointProvider.endpointID +angular.module('portainer.docker').factory('Exec', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function ExecFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/exec/:id/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + resize: { + method: 'POST', + params: { id: '@id', action: 'resize', h: '@height', w: '@width' }, + transformResponse: genericHandler, + ignoreLoadingBar: true, + }, + } + ); }, - { - resize: { - method: 'POST', params: {id: '@id', action: 'resize', h: '@height', w: '@width'}, - transformResponse: genericHandler, ignoreLoadingBar: true - } - }); -}]); +]); diff --git a/app/docker/rest/image.js b/app/docker/rest/image.js index a0cfd0cfc..aa0d8a6a9 100644 --- a/app/docker/rest/image.js +++ b/app/docker/rest/image.js @@ -1,43 +1,58 @@ -import {deleteImageHandler, jsonObjectsToArrayHandler} from './response/handlers'; -import {imageGetResponse} from './response/image'; +import { deleteImageHandler, jsonObjectsToArrayHandler } from './response/handlers'; +import { imageGetResponse } from './response/image'; -angular.module('portainer.docker') -.factory('Image', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'HttpRequestHelper', 'ImagesInterceptor', -function ImageFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, HttpRequestHelper, ImagesInterceptor) { - 'use strict'; +angular.module('portainer.docker').factory('Image', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'HttpRequestHelper', + 'ImagesInterceptor', + function ImageFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, HttpRequestHelper, ImagesInterceptor) { + 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/images/:id/:action', { - endpointId: EndpointProvider.endpointID + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/images/:id/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + query: { method: 'GET', params: { all: 0, action: 'json' }, isArray: true, interceptor: ImagesInterceptor, timeout: 15000 }, + 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' }, ignoreLoadingBar: true }, + inspect: { method: 'GET', params: { id: '@id', action: 'json' } }, + push: { + method: 'POST', + params: { action: 'push', id: '@imageName' }, + isArray: true, + transformResponse: jsonObjectsToArrayHandler, + headers: { 'X-Registry-Auth': HttpRequestHelper.registryAuthenticationHeader }, + ignoreLoadingBar: true, + }, + create: { + method: 'POST', + params: { action: 'create', fromImage: '@fromImage' }, + isArray: true, + transformResponse: jsonObjectsToArrayHandler, + headers: { 'X-Registry-Auth': HttpRequestHelper.registryAuthenticationHeader }, + ignoreLoadingBar: true, + }, + download: { + method: 'GET', + params: { action: 'get', names: '@names' }, + transformResponse: imageGetResponse, + responseType: 'blob', + ignoreLoadingBar: true, + }, + remove: { + method: 'DELETE', + params: { id: '@id', force: '@force' }, + isArray: true, + transformResponse: deleteImageHandler, + }, + } + ); }, - { - query: {method: 'GET', params: {all: 0, action: 'json'}, isArray: true, interceptor: ImagesInterceptor, timeout: 15000}, - 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'}, ignoreLoadingBar: true}, - inspect: {method: 'GET', params: {id: '@id', action: 'json'}}, - push: { - method: 'POST', params: {action: 'push', id: '@imageName'}, - isArray: true, transformResponse: jsonObjectsToArrayHandler, - headers: { 'X-Registry-Auth': HttpRequestHelper.registryAuthenticationHeader }, - ignoreLoadingBar: true - }, - create: { - method: 'POST', params: {action: 'create', fromImage: '@fromImage'}, - isArray: true, transformResponse: jsonObjectsToArrayHandler, - headers: { 'X-Registry-Auth': HttpRequestHelper.registryAuthenticationHeader }, - ignoreLoadingBar: true - }, - download: { - method: 'GET', params: {action:'get', names: '@names'}, - transformResponse: imageGetResponse, - responseType: 'blob', - ignoreLoadingBar: true - }, - remove: { - method: 'DELETE', params: {id: '@id', force: '@force'}, - isArray: true, transformResponse: deleteImageHandler - } - }); -}]); +]); diff --git a/app/docker/rest/network.js b/app/docker/rest/network.js index 5830483ef..8c8480158 100644 --- a/app/docker/rest/network.js +++ b/app/docker/rest/network.js @@ -1,32 +1,47 @@ -import {genericHandler} from './response/handlers'; +import { genericHandler } from './response/handlers'; -angular.module('portainer.docker') -.factory('Network', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'NetworksInterceptor', -function NetworkFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, NetworksInterceptor) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/networks/:id/:action', { - id: '@id', - endpointId: EndpointProvider.endpointID +angular.module('portainer.docker').factory('Network', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'NetworksInterceptor', + function NetworkFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, NetworksInterceptor) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/networks/:id/:action', + { + id: '@id', + endpointId: EndpointProvider.endpointID, + }, + { + query: { + method: 'GET', + isArray: true, + interceptor: NetworksInterceptor, + timeout: 15000, + }, + get: { + method: 'GET', + }, + create: { + method: 'POST', + params: { action: 'create' }, + transformResponse: genericHandler, + ignoreLoadingBar: true, + }, + remove: { + method: 'DELETE', + transformResponse: genericHandler, + }, + connect: { + method: 'POST', + params: { action: 'connect' }, + }, + disconnect: { + method: 'POST', + params: { action: 'disconnect' }, + }, + } + ); }, - { - query: { - method: 'GET', isArray: true, interceptor: NetworksInterceptor, timeout: 15000 - }, - get: { - method: 'GET' - }, - create: { - method: 'POST', params: {action: 'create'}, - transformResponse: genericHandler, ignoreLoadingBar: true - }, - remove: { - method: 'DELETE', transformResponse: genericHandler - }, - connect: { - method: 'POST', params: { action: 'connect' } - }, - disconnect: { - method: 'POST', params: { action: 'disconnect' } - } - }); -}]); +]); diff --git a/app/docker/rest/node.js b/app/docker/rest/node.js index 821e40328..aa35d1a13 100644 --- a/app/docker/rest/node.js +++ b/app/docker/rest/node.js @@ -1,13 +1,20 @@ -angular.module('portainer.docker') -.factory('Node', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function NodeFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/nodes/:id/:action', { - endpointId: EndpointProvider.endpointID +angular.module('portainer.docker').factory('Node', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function NodeFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/nodes/:id/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + 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' } }, + } + ); }, - { - 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'} } - }); -}]); +]); diff --git a/app/docker/rest/plugin.js b/app/docker/rest/plugin.js index c73817fd4..ed2e5784b 100644 --- a/app/docker/rest/plugin.js +++ b/app/docker/rest/plugin.js @@ -1,9 +1,17 @@ -angular.module('portainer.docker') -.factory('Plugin', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function PluginFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/plugins/:id/:action', { - endpointId: EndpointProvider.endpointID - }, { - query: { method: 'GET', isArray: true } - }); -}]); +angular.module('portainer.docker').factory('Plugin', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function PluginFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/plugins/:id/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + query: { method: 'GET', isArray: true }, + } + ); + }, +]); diff --git a/app/docker/rest/response/handlers.js b/app/docker/rest/response/handlers.js index 1a3854c34..7e14da023 100644 --- a/app/docker/rest/response/handlers.js +++ b/app/docker/rest/response/handlers.js @@ -1,15 +1,14 @@ function isJSONArray(jsonString) { - return Object.prototype.toString.call(jsonString) === '[object Array]'; + return Object.prototype.toString.call(jsonString) === '[object Array]'; } function isJSON(jsonString) { try { var o = JSON.parse(jsonString); if (o && typeof o === 'object') { - return o; + return o; } - } - catch (e) { + } catch (e) { //empty } return false; @@ -50,7 +49,7 @@ export function genericHandler(data) { // This handler wraps the data in a JSON object under the "logs" property. export function logsHandler(data) { return { - logs: data + logs: data, }; } @@ -63,7 +62,7 @@ export function deleteImageHandler(data) { // A string is returned on failure (Docker < 1.12) var response = []; if (!isJSON(data)) { - response.push({message: data}); + response.push({ message: data }); } // A JSON object is returned on failure (Docker = 1.12) else if (!isJSONArray(data)) { diff --git a/app/docker/rest/response/image.js b/app/docker/rest/response/image.js index c2e63cd82..7d61e5943 100644 --- a/app/docker/rest/response/image.js +++ b/app/docker/rest/response/image.js @@ -3,8 +3,7 @@ // This functions simply creates a response object and assign // the data to a field. export function imageGetResponse(data) { - var response = {}; - response.file = data; - return response; - } - \ No newline at end of file + var response = {}; + response.file = data; + return response; +} diff --git a/app/docker/rest/secret.js b/app/docker/rest/secret.js index 1f5f8ab95..9969a18d2 100644 --- a/app/docker/rest/secret.js +++ b/app/docker/rest/secret.js @@ -1,12 +1,20 @@ -angular.module('portainer.docker') -.factory('Secret', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function SecretFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/secrets/:id/:action', { - endpointId: EndpointProvider.endpointID - }, { - get: { method: 'GET', params: {id: '@id'} }, - query: { method: 'GET', isArray: true }, - create: { method: 'POST', params: {action: 'create'}, ignoreLoadingBar: true }, - remove: { method: 'DELETE', params: {id: '@id'} } - }); -}]); +angular.module('portainer.docker').factory('Secret', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function SecretFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/secrets/:id/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + get: { method: 'GET', params: { id: '@id' } }, + query: { method: 'GET', isArray: true }, + create: { method: 'POST', params: { action: 'create' }, ignoreLoadingBar: true }, + remove: { method: 'DELETE', params: { id: '@id' } }, + } + ); + }, +]); diff --git a/app/docker/rest/service.js b/app/docker/rest/service.js index 81a8eca7e..aecd4acbe 100644 --- a/app/docker/rest/service.js +++ b/app/docker/rest/service.js @@ -1,34 +1,45 @@ import { logsHandler } from './response/handlers'; -angular.module('portainer.docker') -.factory('Service', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'HttpRequestHelper', -function ServiceFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, HttpRequestHelper) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/services/:id/:action', { - endpointId: EndpointProvider.endpointID - }, - { - get: { method: 'GET', params: {id: '@id'} }, - query: { method: 'GET', isArray: true, params: {filters: '@filters'} }, - create: { - method: 'POST', params: {action: 'create'}, - headers: { - 'X-Registry-Auth': HttpRequestHelper.registryAuthenticationHeader, - 'version': '1.29' +angular.module('portainer.docker').factory('Service', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'HttpRequestHelper', + function ServiceFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, HttpRequestHelper) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/services/:id/:action', + { + endpointId: EndpointProvider.endpointID, }, - ignoreLoadingBar: true - }, - update: { - method: 'POST', params: { id: '@id', action: 'update', version: '@version', rollback: '@rollback' }, - headers: { - 'version': '1.29' + { + get: { method: 'GET', params: { id: '@id' } }, + query: { method: 'GET', isArray: true, params: { filters: '@filters' } }, + create: { + method: 'POST', + params: { action: 'create' }, + headers: { + 'X-Registry-Auth': HttpRequestHelper.registryAuthenticationHeader, + version: '1.29', + }, + ignoreLoadingBar: true, + }, + update: { + method: 'POST', + params: { id: '@id', action: 'update', version: '@version', rollback: '@rollback' }, + headers: { + version: '1.29', + }, + }, + remove: { method: 'DELETE', params: { id: '@id' } }, + logs: { + method: 'GET', + params: { id: '@id', action: 'logs' }, + timeout: 4500, + ignoreLoadingBar: true, + transformResponse: logsHandler, + }, } - }, - remove: { method: 'DELETE', params: {id: '@id'} }, - logs: { - method: 'GET', params: { id: '@id', action: 'logs' }, - timeout: 4500, ignoreLoadingBar: true, - transformResponse: logsHandler - } - }); -}]); + ); + }, +]); diff --git a/app/docker/rest/swarm.js b/app/docker/rest/swarm.js index de4cc85a4..0cdc1fd9a 100644 --- a/app/docker/rest/swarm.js +++ b/app/docker/rest/swarm.js @@ -1,10 +1,17 @@ -angular.module('portainer.docker') -.factory('Swarm', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function SwarmFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/swarm', { - endpointId: EndpointProvider.endpointID +angular.module('portainer.docker').factory('Swarm', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function SwarmFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/swarm', + { + endpointId: EndpointProvider.endpointID, + }, + { + get: { method: 'GET' }, + } + ); }, - { - get: { method: 'GET' } - }); -}]); +]); diff --git a/app/docker/rest/system.js b/app/docker/rest/system.js index 844ae046f..fa69df952 100644 --- a/app/docker/rest/system.js +++ b/app/docker/rest/system.js @@ -1,23 +1,36 @@ -import {jsonObjectsToArrayHandler} from './response/handlers'; +import { jsonObjectsToArrayHandler } from './response/handlers'; -angular.module('portainer.docker') -.factory('System', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'InfoInterceptor', 'VersionInterceptor', +angular.module('portainer.docker').factory('System', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'InfoInterceptor', + 'VersionInterceptor', function SystemFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, InfoInterceptor, VersionInterceptor) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/:action/:subAction', { - name: '@name', - endpointId: EndpointProvider.endpointID + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/:action/:subAction', + { + name: '@name', + endpointId: EndpointProvider.endpointID, + }, + { + info: { + method: 'GET', + params: { action: 'info' }, + timeout: 15000, + interceptor: InfoInterceptor, + }, + version: { method: 'GET', params: { action: 'version' }, timeout: 4500, interceptor: VersionInterceptor }, + events: { + method: 'GET', + params: { action: 'events', since: '@since', until: '@until' }, + isArray: true, + transformResponse: jsonObjectsToArrayHandler, + }, + auth: { method: 'POST', params: { action: 'auth' } }, + dataUsage: { method: 'GET', params: { action: 'system', subAction: 'df' } }, + } + ); }, - { - info: { - method: 'GET', params: { action: 'info' }, timeout: 15000, interceptor: InfoInterceptor - }, - version: { method: 'GET', params: { action: 'version' }, timeout: 4500, interceptor: VersionInterceptor }, - events: { - method: 'GET', params: { action: 'events', since: '@since', until: '@until' }, - isArray: true, transformResponse: jsonObjectsToArrayHandler - }, - auth: { method: 'POST', params: { action: 'auth' } }, - dataUsage: { method: 'GET', params: { action: 'system', subAction: 'df' } } - }); -}]); +]); diff --git a/app/docker/rest/systemEndpoint.js b/app/docker/rest/systemEndpoint.js index c54b8bda1..2bdad3df3 100644 --- a/app/docker/rest/systemEndpoint.js +++ b/app/docker/rest/systemEndpoint.js @@ -1,13 +1,19 @@ -angular.module('portainer.docker') -.factory('SystemEndpoint', ['$resource', 'API_ENDPOINT_ENDPOINTS', +angular.module('portainer.docker').factory('SystemEndpoint', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', function SystemEndpointFactory($resource, API_ENDPOINT_ENDPOINTS) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/:action/:subAction', { - name: '@name' + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/:action/:subAction', + { + name: '@name', + }, + { + ping: { + method: 'GET', + params: { action: '_ping', endpointId: '@endpointId' }, + }, + } + ); }, - { - ping: { - method: 'GET', params: { action: '_ping', endpointId: '@endpointId' } - } - }); -}]); +]); diff --git a/app/docker/rest/task.js b/app/docker/rest/task.js index b4860784f..e2fa19603 100644 --- a/app/docker/rest/task.js +++ b/app/docker/rest/task.js @@ -1,18 +1,27 @@ import { logsHandler } from './response/handlers'; -angular.module('portainer.docker') -.factory('Task', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function TaskFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/tasks/:id/:action', { - endpointId: EndpointProvider.endpointID +angular.module('portainer.docker').factory('Task', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + function TaskFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/tasks/:id/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + get: { method: 'GET', params: { id: '@id' } }, + query: { method: 'GET', isArray: true, params: { filters: '@filters' } }, + logs: { + method: 'GET', + params: { id: '@id', action: 'logs' }, + timeout: 4500, + ignoreLoadingBar: true, + transformResponse: logsHandler, + }, + } + ); }, - { - get: { method: 'GET', params: {id: '@id'} }, - query: { method: 'GET', isArray: true, params: {filters: '@filters'} }, - logs: { - method: 'GET', params: { id: '@id', action: 'logs' }, - timeout: 4500, ignoreLoadingBar: true, - transformResponse: logsHandler - } - }); -}]); +]); diff --git a/app/docker/rest/volume.js b/app/docker/rest/volume.js index 1a85ceef6..2a6f44165 100644 --- a/app/docker/rest/volume.js +++ b/app/docker/rest/volume.js @@ -1,19 +1,27 @@ -import {genericHandler} from './response/handlers'; +import { genericHandler } from './response/handlers'; -angular.module('portainer.docker') -.factory('Volume', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'VolumesInterceptor', +angular.module('portainer.docker').factory('Volume', [ + '$resource', + 'API_ENDPOINT_ENDPOINTS', + 'EndpointProvider', + 'VolumesInterceptor', function VolumeFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, VolumesInterceptor) { - 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/volumes/:id/:action', - { - endpointId: EndpointProvider.endpointID + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/volumes/:id/:action', + { + endpointId: EndpointProvider.endpointID, + }, + { + query: { method: 'GET', interceptor: VolumesInterceptor, timeout: 15000 }, + get: { method: 'GET', params: { id: '@id' } }, + create: { method: 'POST', params: { action: 'create' }, transformResponse: genericHandler, ignoreLoadingBar: true }, + remove: { + method: 'DELETE', + transformResponse: genericHandler, + params: { id: '@id' }, + }, + } + ); }, - { - query: { method: 'GET', interceptor: VolumesInterceptor, timeout: 15000}, - get: { method: 'GET', params: {id: '@id'} }, - create: {method: 'POST', params: {action: 'create'}, transformResponse: genericHandler, ignoreLoadingBar: true}, - remove: { - method: 'DELETE', transformResponse: genericHandler, params: {id: '@id'} - } - }); -}]); +]); diff --git a/app/docker/services/buildService.js b/app/docker/services/buildService.js index 53f50688e..e9e5fc433 100644 --- a/app/docker/services/buildService.js +++ b/app/docker/services/buildService.js @@ -1,67 +1,71 @@ -import { ImageBuildModel } from "../models/image"; +import { ImageBuildModel } from '../models/image'; -angular.module('portainer.docker') -.factory('BuildService', ['$q', 'Build', 'FileUploadService', function BuildServiceFactory($q, Build, FileUploadService) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('BuildService', [ + '$q', + 'Build', + 'FileUploadService', + function BuildServiceFactory($q, Build, FileUploadService) { + 'use strict'; + var service = {}; - service.buildImageFromUpload = function(names, file, path) { - var deferred = $q.defer(); + service.buildImageFromUpload = function (names, file, path) { + var deferred = $q.defer(); - FileUploadService.buildImage(names, file, path) - .then(function success(response) { - var model = new ImageBuildModel(response.data); - deferred.resolve(model); - }) - .catch(function error(err) { - deferred.reject(err); - }); + FileUploadService.buildImage(names, file, path) + .then(function success(response) { + var model = new ImageBuildModel(response.data); + deferred.resolve(model); + }) + .catch(function error(err) { + deferred.reject(err); + }); - return deferred.promise; - }; - - service.buildImageFromURL = function(names, url, path) { - var params = { - t: names, - remote: url, - dockerfile: path + return deferred.promise; }; - var deferred = $q.defer(); + service.buildImageFromURL = function (names, url, path) { + var params = { + t: names, + remote: url, + dockerfile: path, + }; - Build.buildImage(params, {}).$promise - .then(function success(data) { - var model = new ImageBuildModel(data); - deferred.resolve(model); - }) - .catch(function error(err) { - deferred.reject(err); - }); + var deferred = $q.defer(); - return deferred.promise; - }; + Build.buildImage(params, {}) + .$promise.then(function success(data) { + var model = new ImageBuildModel(data); + deferred.resolve(model); + }) + .catch(function error(err) { + deferred.reject(err); + }); - service.buildImageFromDockerfileContent = function(names, content) { - var params = { - t: names - }; - var payload = { - content: content + return deferred.promise; }; - var deferred = $q.defer(); + service.buildImageFromDockerfileContent = function (names, content) { + var params = { + t: names, + }; + var payload = { + content: content, + }; - Build.buildImageOverride(params, payload).$promise - .then(function success(data) { - var model = new ImageBuildModel(data); - deferred.resolve(model); - }) - .catch(function error(err) { - deferred.reject(err); - }); + var deferred = $q.defer(); - return deferred.promise; - }; + Build.buildImageOverride(params, payload) + .$promise.then(function success(data) { + var model = new ImageBuildModel(data); + deferred.resolve(model); + }) + .catch(function error(err) { + deferred.reject(err); + }); - return service; -}]); + return deferred.promise; + }; + + return service; + }, +]); diff --git a/app/docker/services/configService.js b/app/docker/services/configService.js index 520e190a6..1d773eeaf 100644 --- a/app/docker/services/configService.js +++ b/app/docker/services/configService.js @@ -1,63 +1,66 @@ import { ConfigViewModel } from '../models/config'; -angular.module('portainer.docker') -.factory('ConfigService', ['$q', 'Config', function ConfigServiceFactory($q, Config) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('ConfigService', [ + '$q', + 'Config', + function ConfigServiceFactory($q, Config) { + 'use strict'; + var service = {}; - service.config = function(configId) { - var deferred = $q.defer(); + service.config = function (configId) { + var deferred = $q.defer(); - Config.get({id: configId}).$promise - .then(function success(data) { - var config = new ConfigViewModel(data); - deferred.resolve(config); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve config details', err: err }); - }); + Config.get({ id: configId }) + .$promise.then(function success(data) { + var config = new ConfigViewModel(data); + deferred.resolve(config); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve config details', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.configs = function() { - var deferred = $q.defer(); + service.configs = function () { + var deferred = $q.defer(); - Config.query({}).$promise - .then(function success(data) { - var configs = data.map(function (item) { - return new ConfigViewModel(item); - }); - deferred.resolve(configs); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve configs', err: err }); - }); + Config.query({}) + .$promise.then(function success(data) { + var configs = data.map(function (item) { + return new ConfigViewModel(item); + }); + deferred.resolve(configs); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve configs', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.remove = function(configId) { - var deferred = $q.defer(); + service.remove = function (configId) { + var deferred = $q.defer(); - Config.remove({ id: configId }).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message }); - } else { - deferred.resolve(); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to remove config', err: err }); - }); + Config.remove({ id: configId }) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message }); + } else { + deferred.resolve(); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to remove config', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.create = function(config) { - return Config.create(config).$promise; - }; + service.create = function (config) { + return Config.create(config).$promise; + }; - return service; -}]); + return service; + }, +]); diff --git a/app/docker/services/containerService.js b/app/docker/services/containerService.js index 300a09f91..65a90ba72 100644 --- a/app/docker/services/containerService.js +++ b/app/docker/services/containerService.js @@ -1,213 +1,217 @@ import { ContainerDetailsViewModel, ContainerViewModel, ContainerStatsViewModel } from '../models/container'; -angular.module('portainer.docker') -.factory('ContainerService', ['$q', 'Container', 'ResourceControlService', 'LogHelper', '$timeout', -function ContainerServiceFactory($q, Container, ResourceControlService, LogHelper, $timeout) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('ContainerService', [ + '$q', + 'Container', + 'ResourceControlService', + 'LogHelper', + '$timeout', + function ContainerServiceFactory($q, Container, ResourceControlService, LogHelper, $timeout) { + 'use strict'; + var service = {}; - service.container = function(id) { - var deferred = $q.defer(); + service.container = function (id) { + var deferred = $q.defer(); - Container.get({ id: id }).$promise - .then(function success(data) { - var container = new ContainerDetailsViewModel(data); - deferred.resolve(container); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve container information', err: err }); - }); + Container.get({ id: id }) + .$promise.then(function success(data) { + var container = new ContainerDetailsViewModel(data); + deferred.resolve(container); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve container information', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.containers = function(all, filters) { - var deferred = $q.defer(); - Container.query({ all : all, filters: filters }).$promise - .then(function success(data) { - var containers = data.map(function (item) { - return new ContainerViewModel(item); - }); - deferred.resolve(containers); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve containers', err: err }); - }); + service.containers = function (all, filters) { + var deferred = $q.defer(); + Container.query({ all: all, filters: filters }) + .$promise.then(function success(data) { + var containers = data.map(function (item) { + return new ContainerViewModel(item); + }); + deferred.resolve(containers); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve containers', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.resizeTTY = function (id, width, height, timeout) { - var deferred = $q.defer(); + service.resizeTTY = function (id, width, height, timeout) { + var deferred = $q.defer(); - $timeout(function() { - Container.resize({}, {id: id, height: height, width: width}).$promise - .then(function success(data) { + $timeout(function () { + Container.resize({}, { id: id, height: height, width: width }) + .$promise.then(function success(data) { if (data.message) { - deferred.reject({msg: 'Unable to resize tty of container ' + id, err: data.message}); + deferred.reject({ msg: 'Unable to resize tty of container ' + id, err: data.message }); } else { deferred.resolve(data); } }) .catch(function error(err) { - deferred.reject({msg: 'Unable to resize tty of container ' + id, err: err}); + deferred.reject({ msg: 'Unable to resize tty of container ' + id, err: err }); }); - }, timeout); + }, timeout); - return deferred.promise; - }; - - service.startContainer = function(id) { - return Container.start({ id: id }, {}).$promise; - }; - - service.stopContainer = function(id) { - return Container.stop({ id: id }, {}).$promise; - }; - - service.restartContainer = function(id) { - return Container.restart({ id: id }, {}).$promise; - }; - - service.killContainer = function(id) { - return Container.kill({ id: id }, {}).$promise; - }; - - service.pauseContainer = function(id) { - return Container.pause({ id: id }, {}).$promise; - }; - - service.resumeContainer = function(id) { - return Container.unpause({ id: id }, {}).$promise; - }; - - service.renameContainer = function(id, newContainerName) { - return Container.rename({id: id, name: newContainerName }, {}).$promise; - }; - - service.updateRestartPolicy = updateRestartPolicy; - - function updateRestartPolicy(id, restartPolicy, maximumRetryCounts) { - return Container.update({ id: id }, - { RestartPolicy: { Name: restartPolicy, MaximumRetryCount: maximumRetryCounts } } - ).$promise; - } - - service.createContainer = function(configuration) { - var deferred = $q.defer(); - Container.create(configuration).$promise - .then(function success(data) { - deferred.resolve(data); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to create container', err: err }); - }); - return deferred.promise; - }; - - service.createAndStartContainer = function(configuration) { - var deferred = $q.defer(); - var container; - service.createContainer(configuration) - .then(function success(data) { - container = data; - return service.startContainer(container.Id); - }) - .then(function success() { - deferred.resolve(container); - }) - .catch(function error(err) { - deferred.reject(err); - }); - return deferred.promise; - }; - - service.remove = function(container, removeVolumes) { - var deferred = $q.defer(); - - Container.remove({ id: container.Id, v: (removeVolumes) ? 1 : 0, force: true }).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message, err: data.message }); - } else { - deferred.resolve(); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to remove container', err: err }); - }); - - return deferred.promise; - }; - - service.createExec = function(execConfig) { - var deferred = $q.defer(); - - Container.exec({}, execConfig).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message, err: data.message }); - } else { - deferred.resolve(data); - } - }) - .catch(function error(err) { - deferred.reject(err); - }); - - return deferred.promise; - }; - - service.logs = function(id, stdout, stderr, timestamps, since, tail, stripHeaders) { - var deferred = $q.defer(); - - var parameters = { - id: id, - stdout: stdout || 0, - stderr: stderr || 0, - timestamps: timestamps || 0, - since: since || 0, - tail: tail || 'all' + return deferred.promise; }; - Container.logs(parameters).$promise - .then(function success(data) { - var logs = LogHelper.formatLogs(data.logs, stripHeaders); - deferred.resolve(logs); - }) - .catch(function error(err) { - deferred.reject(err); - }); + service.startContainer = function (id) { + return Container.start({ id: id }, {}).$promise; + }; - return deferred.promise; - }; + service.stopContainer = function (id) { + return Container.stop({ id: id }, {}).$promise; + }; - service.containerStats = function(id) { - var deferred = $q.defer(); + service.restartContainer = function (id) { + return Container.restart({ id: id }, {}).$promise; + }; - Container.stats({ id: id }).$promise - .then(function success(data) { - var containerStats = new ContainerStatsViewModel(data); - deferred.resolve(containerStats); - }) - .catch(function error(err) { - deferred.reject(err); - }); + service.killContainer = function (id) { + return Container.kill({ id: id }, {}).$promise; + }; - return deferred.promise; - }; + service.pauseContainer = function (id) { + return Container.pause({ id: id }, {}).$promise; + }; - service.containerTop = function(id) { - return Container.top({ id: id }).$promise; - }; + service.resumeContainer = function (id) { + return Container.unpause({ id: id }, {}).$promise; + }; - service.inspect = function(id) { - return Container.inspect({ id: id }).$promise; - }; + service.renameContainer = function (id, newContainerName) { + return Container.rename({ id: id, name: newContainerName }, {}).$promise; + }; - service.prune = function(filters) { - return Container.prune({ filters: filters }).$promise; - }; + service.updateRestartPolicy = updateRestartPolicy; - return service; -}]); + function updateRestartPolicy(id, restartPolicy, maximumRetryCounts) { + return Container.update({ id: id }, { RestartPolicy: { Name: restartPolicy, MaximumRetryCount: maximumRetryCounts } }).$promise; + } + + service.createContainer = function (configuration) { + var deferred = $q.defer(); + Container.create(configuration) + .$promise.then(function success(data) { + deferred.resolve(data); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to create container', err: err }); + }); + return deferred.promise; + }; + + service.createAndStartContainer = function (configuration) { + var deferred = $q.defer(); + var container; + service + .createContainer(configuration) + .then(function success(data) { + container = data; + return service.startContainer(container.Id); + }) + .then(function success() { + deferred.resolve(container); + }) + .catch(function error(err) { + deferred.reject(err); + }); + return deferred.promise; + }; + + service.remove = function (container, removeVolumes) { + var deferred = $q.defer(); + + Container.remove({ id: container.Id, v: removeVolumes ? 1 : 0, force: true }) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message, err: data.message }); + } else { + deferred.resolve(); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to remove container', err: err }); + }); + + return deferred.promise; + }; + + service.createExec = function (execConfig) { + var deferred = $q.defer(); + + Container.exec({}, execConfig) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message, err: data.message }); + } else { + deferred.resolve(data); + } + }) + .catch(function error(err) { + deferred.reject(err); + }); + + return deferred.promise; + }; + + service.logs = function (id, stdout, stderr, timestamps, since, tail, stripHeaders) { + var deferred = $q.defer(); + + var parameters = { + id: id, + stdout: stdout || 0, + stderr: stderr || 0, + timestamps: timestamps || 0, + since: since || 0, + tail: tail || 'all', + }; + + Container.logs(parameters) + .$promise.then(function success(data) { + var logs = LogHelper.formatLogs(data.logs, stripHeaders); + deferred.resolve(logs); + }) + .catch(function error(err) { + deferred.reject(err); + }); + + return deferred.promise; + }; + + service.containerStats = function (id) { + var deferred = $q.defer(); + + Container.stats({ id: id }) + .$promise.then(function success(data) { + var containerStats = new ContainerStatsViewModel(data); + deferred.resolve(containerStats); + }) + .catch(function error(err) { + deferred.reject(err); + }); + + return deferred.promise; + }; + + service.containerTop = function (id) { + return Container.top({ id: id }).$promise; + }; + + service.inspect = function (id) { + return Container.inspect({ id: id }).$promise; + }; + + service.prune = function (filters) { + return Container.prune({ filters: filters }).$promise; + }; + + return service; + }, +]); diff --git a/app/docker/services/execService.js b/app/docker/services/execService.js index bcb09b77c..a6a29490f 100644 --- a/app/docker/services/execService.js +++ b/app/docker/services/execService.js @@ -1,27 +1,31 @@ -angular.module('portainer.docker') - .factory('ExecService', ['$q', '$timeout', 'Exec', function ExecServiceFactory($q, $timeout, Exec) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('ExecService', [ + '$q', + '$timeout', + 'Exec', + function ExecServiceFactory($q, $timeout, Exec) { + 'use strict'; + var service = {}; - service.resizeTTY = function (execId, width, height, timeout) { - var deferred = $q.defer(); + service.resizeTTY = function (execId, width, height, timeout) { + var deferred = $q.defer(); - $timeout(function() { - Exec.resize({}, {id: execId, height: height, width: width}).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({msg: "Unable to resize tty of exec", err: data.message}); - } else { - deferred.resolve(data); - } - }) - .catch(function error(err) { - deferred.reject({msg: "Unable to resize tty of exec", err: err}); - }); - }, timeout); + $timeout(function () { + Exec.resize({}, { id: execId, height: height, width: width }) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: 'Unable to resize tty of exec', err: data.message }); + } else { + deferred.resolve(data); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to resize tty of exec', err: err }); + }); + }, timeout); - return deferred.promise; - }; + return deferred.promise; + }; - return service; - }]); + return service; + }, +]); diff --git a/app/docker/services/imageService.js b/app/docker/services/imageService.js index afd70aff3..56a13983e 100644 --- a/app/docker/services/imageService.js +++ b/app/docker/services/imageService.js @@ -1,205 +1,212 @@ import _ from 'lodash-es'; import { ImageViewModel } from '../models/image'; -import { ImageDetailsViewModel } from "../models/imageDetails"; -import { ImageLayerViewModel } from "../models/imageLayer"; +import { ImageDetailsViewModel } from '../models/imageDetails'; +import { ImageLayerViewModel } from '../models/imageLayer'; -angular.module('portainer.docker') -.factory('ImageService', ['$q', 'Image', 'ImageHelper', 'RegistryService', 'HttpRequestHelper', 'ContainerService', 'FileUploadService', +angular.module('portainer.docker').factory('ImageService', [ + '$q', + 'Image', + 'ImageHelper', + 'RegistryService', + 'HttpRequestHelper', + 'ContainerService', + 'FileUploadService', function ImageServiceFactory($q, Image, ImageHelper, RegistryService, HttpRequestHelper, ContainerService, FileUploadService) { - 'use strict'; - var service = {}; + 'use strict'; + var service = {}; - service.image = function(imageId) { - var deferred = $q.defer(); - Image.get({id: imageId}).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message }); - } else { - var image = new ImageDetailsViewModel(data); - deferred.resolve(image); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve image details', err: err }); - }); - return deferred.promise; - }; - - service.images = function(withUsage) { - var deferred = $q.defer(); - - $q.all({ - containers: withUsage ? ContainerService.containers(1) : [], - images: Image.query({}).$promise - }) - .then(function success(data) { - var containers = data.containers; - - var images = data.images.map(function(item) { - item.ContainerCount = 0; - for (var i = 0; i < containers.length; i++) { - var container = containers[i]; - if (container.ImageID === item.Id) { - item.ContainerCount++; + service.image = function (imageId) { + var deferred = $q.defer(); + Image.get({ id: imageId }) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message }); + } else { + var image = new ImageDetailsViewModel(data); + deferred.resolve(image); } - } - return new ImageViewModel(item); - }); - - deferred.resolve(images); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve images', err: err }); - }); - return deferred.promise; - }; - - service.history = function(imageId) { - var deferred = $q.defer(); - Image.history({id: imageId}).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message }); - } else { - var layers = []; - var order = data.length; - angular.forEach(data, function(imageLayer) { - layers.push(new ImageLayerViewModel(order, imageLayer)); - order--; + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve image details', err: err }); }); - deferred.resolve(layers); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve image details', err: err }); - }); - return deferred.promise; - }; + return deferred.promise; + }; - service.pushImage = pushImage; - /** - * - * @param {PorImageRegistryModel} registryModel - */ - function pushImage(registryModel) { - var deferred = $q.defer(); + service.images = function (withUsage) { + var deferred = $q.defer(); - var authenticationDetails = registryModel.Registry.Authentication ? RegistryService.encodedCredentials(registryModel.Registry) : ''; - HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails); + $q.all({ + containers: withUsage ? ContainerService.containers(1) : [], + images: Image.query({}).$promise, + }) + .then(function success(data) { + var containers = data.containers; - const imageConfiguration = ImageHelper.createImageConfigForContainer(registryModel); + var images = data.images.map(function (item) { + item.ContainerCount = 0; + for (var i = 0; i < containers.length; i++) { + var container = containers[i]; + if (container.ImageID === item.Id) { + item.ContainerCount++; + } + } + return new ImageViewModel(item); + }); - Image.push({imageName: imageConfiguration.fromImage}).$promise - .then(function success(data) { - if (data[data.length - 1].error) { - deferred.reject({ msg: data[data.length - 1].error }); - } else { - deferred.resolve(); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to push image tag', err: err }); - }); - return deferred.promise; - } + deferred.resolve(images); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve images', err: err }); + }); + return deferred.promise; + }; - /** - * PULL IMAGE - */ + service.history = function (imageId) { + var deferred = $q.defer(); + Image.history({ id: imageId }) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message }); + } else { + var layers = []; + var order = data.length; + angular.forEach(data, function (imageLayer) { + layers.push(new ImageLayerViewModel(order, imageLayer)); + order--; + }); + deferred.resolve(layers); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve image details', err: err }); + }); + return deferred.promise; + }; - function pullImageAndIgnoreErrors(imageConfiguration) { - var deferred = $q.defer(); + service.pushImage = pushImage; + /** + * + * @param {PorImageRegistryModel} registryModel + */ + function pushImage(registryModel) { + var deferred = $q.defer(); - Image.create({}, imageConfiguration).$promise - .finally(function final() { - deferred.resolve(); - }); + var authenticationDetails = registryModel.Registry.Authentication ? RegistryService.encodedCredentials(registryModel.Registry) : ''; + HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails); - return deferred.promise; - } + const imageConfiguration = ImageHelper.createImageConfigForContainer(registryModel); - function pullImageAndAcknowledgeErrors(imageConfiguration) { - var deferred = $q.defer(); - - Image.create({}, imageConfiguration).$promise - .then(function success(data) { - var err = data.length > 0 && data[data.length - 1].hasOwnProperty('message'); - if (err) { - var detail = data[data.length - 1]; - deferred.reject({ msg: detail.message }); - } else { - deferred.resolve(data); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to pull image', err: err }); - }); - - return deferred.promise; - } - - service.pullImage = pullImage; - - /** - * - * @param {PorImageRegistryModel} registry - * @param {bool} ignoreErrors - */ - function pullImage(registry, ignoreErrors) { - var authenticationDetails = registry.Registry.Authentication ? RegistryService.encodedCredentials(registry.Registry) : ''; - HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails); - - var imageConfiguration = ImageHelper.createImageConfigForContainer(registry); - - if (ignoreErrors) { - return pullImageAndIgnoreErrors(imageConfiguration); + Image.push({ imageName: imageConfiguration.fromImage }) + .$promise.then(function success(data) { + if (data[data.length - 1].error) { + deferred.reject({ msg: data[data.length - 1].error }); + } else { + deferred.resolve(); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to push image tag', err: err }); + }); + return deferred.promise; } - return pullImageAndAcknowledgeErrors(imageConfiguration); - } - /** - * ! PULL IMAGE - */ + /** + * PULL IMAGE + */ - service.tagImage = function(id, image) { - return Image.tag({id: id, repo: image}).$promise; - }; + function pullImageAndIgnoreErrors(imageConfiguration) { + var deferred = $q.defer(); - service.downloadImages = function(images) { - var names = ImageHelper.getImagesNamesForDownload(images); - return Image.download(names).$promise; - }; - - service.uploadImage = function(file) { - return FileUploadService.loadImages(file); - }; - - service.deleteImage = function(id, forceRemoval) { - var deferred = $q.defer(); - Image.remove({id: id, force: forceRemoval}).$promise - .then(function success(data) { - if (data[0].message) { - deferred.reject({ msg: data[0].message }); - } else { + Image.create({}, imageConfiguration).$promise.finally(function final() { deferred.resolve(); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to remove image', err: err }); - }); - return deferred.promise; - }; - - service.getUniqueTagListFromImages = function (availableImages) { - - return _.uniq(_.flatMap(availableImages, function (image) { - _.remove(image.RepoTags, function (item) { - return item.indexOf('') !== -1; }); - return image.RepoTags ? _.uniqWith(image.RepoTags, _.isEqual) : []; - })); - }; - return service; -}]); + return deferred.promise; + } + + function pullImageAndAcknowledgeErrors(imageConfiguration) { + var deferred = $q.defer(); + + Image.create({}, imageConfiguration) + .$promise.then(function success(data) { + var err = data.length > 0 && data[data.length - 1].hasOwnProperty('message'); + if (err) { + var detail = data[data.length - 1]; + deferred.reject({ msg: detail.message }); + } else { + deferred.resolve(data); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to pull image', err: err }); + }); + + return deferred.promise; + } + + service.pullImage = pullImage; + + /** + * + * @param {PorImageRegistryModel} registry + * @param {bool} ignoreErrors + */ + function pullImage(registry, ignoreErrors) { + var authenticationDetails = registry.Registry.Authentication ? RegistryService.encodedCredentials(registry.Registry) : ''; + HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails); + + var imageConfiguration = ImageHelper.createImageConfigForContainer(registry); + + if (ignoreErrors) { + return pullImageAndIgnoreErrors(imageConfiguration); + } + return pullImageAndAcknowledgeErrors(imageConfiguration); + } + + /** + * ! PULL IMAGE + */ + + service.tagImage = function (id, image) { + return Image.tag({ id: id, repo: image }).$promise; + }; + + service.downloadImages = function (images) { + var names = ImageHelper.getImagesNamesForDownload(images); + return Image.download(names).$promise; + }; + + service.uploadImage = function (file) { + return FileUploadService.loadImages(file); + }; + + service.deleteImage = function (id, forceRemoval) { + var deferred = $q.defer(); + Image.remove({ id: id, force: forceRemoval }) + .$promise.then(function success(data) { + if (data[0].message) { + deferred.reject({ msg: data[0].message }); + } else { + deferred.resolve(); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to remove image', err: err }); + }); + return deferred.promise; + }; + + service.getUniqueTagListFromImages = function (availableImages) { + return _.uniq( + _.flatMap(availableImages, function (image) { + _.remove(image.RepoTags, function (item) { + return item.indexOf('') !== -1; + }); + return image.RepoTags ? _.uniqWith(image.RepoTags, _.isEqual) : []; + }) + ); + }; + + return service; + }, +]); diff --git a/app/docker/services/networkService.js b/app/docker/services/networkService.js index f8400b693..3804aaeed 100644 --- a/app/docker/services/networkService.js +++ b/app/docker/services/networkService.js @@ -1,87 +1,92 @@ import { NetworkViewModel } from '../models/network'; -angular.module('portainer.docker') -.factory('NetworkService', ['$q', 'Network', function NetworkServiceFactory($q, Network) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('NetworkService', [ + '$q', + 'Network', + function NetworkServiceFactory($q, Network) { + 'use strict'; + var service = {}; - service.create = function(networkConfiguration) { - var deferred = $q.defer(); + service.create = function (networkConfiguration) { + var deferred = $q.defer(); - Network.create(networkConfiguration).$promise - .then(function success(data) { - deferred.resolve(data); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to create network', err: err }); - }); - return deferred.promise; - }; - - service.network = function(id) { - var deferred = $q.defer(); - - Network.get({ id: id }).$promise - .then(function success(data) { - var network = new NetworkViewModel(data); - deferred.resolve(network); - }) - .catch(function error(err) { - deferred.reject({msg: 'Unable to retrieve network details', err: err}); - }); - - return deferred.promise; - }; - - service.networks = function(localNetworks, swarmNetworks, swarmAttachableNetworks, filters) { - var deferred = $q.defer(); - - Network.query({ filters: filters }).$promise - .then(function success(data) { - var networks = data; - - var filteredNetworks = networks.filter(function(network) { - if (localNetworks && network.Scope === 'local') { - return network; - } - if (swarmNetworks && network.Scope === 'swarm') { - return network; - } - if (swarmAttachableNetworks && network.Scope === 'swarm' && network.Attachable === true) { - return network; - } - }).map(function (item) { - return new NetworkViewModel(item); - }); - - deferred.resolve(filteredNetworks); - }) - .catch(function error(err) { - deferred.reject({msg: 'Unable to retrieve networks', err: err}); - }); - - return deferred.promise; - }; - - service.remove = function(id) { - return Network.remove({ id: id }).$promise; - }; - - service.disconnectContainer = function(networkId, containerId, force) { - return Network.disconnect({ id: networkId }, { Container: containerId, Force: force }).$promise; - }; - - service.connectContainer = function(networkId, containerId, aliases) { - var payload = { - Container: containerId, + Network.create(networkConfiguration) + .$promise.then(function success(data) { + deferred.resolve(data); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to create network', err: err }); + }); + return deferred.promise; }; - if (aliases) { - payload.EndpointConfig = { - Aliases: aliases, - } - } - return Network.connect({ id: networkId }, payload).$promise; - }; - return service; -}]); + service.network = function (id) { + var deferred = $q.defer(); + + Network.get({ id: id }) + .$promise.then(function success(data) { + var network = new NetworkViewModel(data); + deferred.resolve(network); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve network details', err: err }); + }); + + return deferred.promise; + }; + + service.networks = function (localNetworks, swarmNetworks, swarmAttachableNetworks, filters) { + var deferred = $q.defer(); + + Network.query({ filters: filters }) + .$promise.then(function success(data) { + var networks = data; + + var filteredNetworks = networks + .filter(function (network) { + if (localNetworks && network.Scope === 'local') { + return network; + } + if (swarmNetworks && network.Scope === 'swarm') { + return network; + } + if (swarmAttachableNetworks && network.Scope === 'swarm' && network.Attachable === true) { + return network; + } + }) + .map(function (item) { + return new NetworkViewModel(item); + }); + + deferred.resolve(filteredNetworks); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve networks', err: err }); + }); + + return deferred.promise; + }; + + service.remove = function (id) { + return Network.remove({ id: id }).$promise; + }; + + service.disconnectContainer = function (networkId, containerId, force) { + return Network.disconnect({ id: networkId }, { Container: containerId, Force: force }).$promise; + }; + + service.connectContainer = function (networkId, containerId, aliases) { + var payload = { + Container: containerId, + }; + if (aliases) { + payload.EndpointConfig = { + Aliases: aliases, + }; + } + return Network.connect({ id: networkId }, payload).$promise; + }; + + return service; + }, +]); diff --git a/app/docker/services/nodeService.js b/app/docker/services/nodeService.js index 943f4201d..42ddf7ed8 100644 --- a/app/docker/services/nodeService.js +++ b/app/docker/services/nodeService.js @@ -1,7 +1,8 @@ import { NodeViewModel } from '../models/node'; angular.module('portainer.docker').factory('NodeService', [ - '$q', 'Node', + '$q', + 'Node', function NodeServiceFactory($q, Node) { 'use strict'; var service = {}; @@ -30,7 +31,7 @@ angular.module('portainer.docker').factory('NodeService', [ Node.query({}) .$promise.then(function success(data) { - var nodes = data.map(function(item) { + var nodes = data.map(function (item) { return new NodeViewModel(item); }); deferred.resolve(nodes); @@ -49,7 +50,8 @@ angular.module('portainer.docker').factory('NodeService', [ function getActiveManager() { var deferred = $q.defer(); - service.nodes() + service + .nodes() .then(function success(data) { for (var i = 0; i < data.length; ++i) { var node = data[i]; @@ -67,5 +69,5 @@ angular.module('portainer.docker').factory('NodeService', [ } return service; - } + }, ]); diff --git a/app/docker/services/pluginService.js b/app/docker/services/pluginService.js index 49c6d2afb..cdf22b90a 100644 --- a/app/docker/services/pluginService.js +++ b/app/docker/services/pluginService.js @@ -1,72 +1,76 @@ import _ from 'lodash-es'; -import { PluginViewModel } from "../models/plugin"; +import { PluginViewModel } from '../models/plugin'; -angular.module('portainer.docker') -.factory('PluginService', ['$q', 'Plugin', 'SystemService', function PluginServiceFactory($q, Plugin, SystemService) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('PluginService', [ + '$q', + 'Plugin', + 'SystemService', + function PluginServiceFactory($q, Plugin, SystemService) { + 'use strict'; + var service = {}; - service.plugins = function() { - var deferred = $q.defer(); - var plugins = []; + service.plugins = function () { + var deferred = $q.defer(); + var plugins = []; - Plugin.query({}).$promise - .then(function success(data) { - for (var i = 0; i < data.length; i++) { - var plugin = new PluginViewModel(data[i]); - plugins.push(plugin); - } - }) - .finally(function final() { - deferred.resolve(plugins); - }); + Plugin.query({}) + .$promise.then(function success(data) { + for (var i = 0; i < data.length; i++) { + var plugin = new PluginViewModel(data[i]); + plugins.push(plugin); + } + }) + .finally(function final() { + deferred.resolve(plugins); + }); - return deferred.promise; - }; + return deferred.promise; + }; - function servicePlugins(systemOnly, pluginType, pluginVersion) { - var deferred = $q.defer(); + function servicePlugins(systemOnly, pluginType, pluginVersion) { + var deferred = $q.defer(); - $q.all({ - system: SystemService.plugins(), - plugins: systemOnly ? [] : service.plugins() - }) - .then(function success(data) { - var aggregatedPlugins = []; - var systemPlugins = data.system; - var plugins = data.plugins; + $q.all({ + system: SystemService.plugins(), + plugins: systemOnly ? [] : service.plugins(), + }) + .then(function success(data) { + var aggregatedPlugins = []; + var systemPlugins = data.system; + var plugins = data.plugins; - if (systemPlugins[pluginType]) { - aggregatedPlugins = aggregatedPlugins.concat(systemPlugins[pluginType]); - } + if (systemPlugins[pluginType]) { + aggregatedPlugins = aggregatedPlugins.concat(systemPlugins[pluginType]); + } - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; - if (plugin.Enabled && _.includes(plugin.Config.Interface.Types, pluginVersion)) { - aggregatedPlugins.push(plugin.Name); - } - } + for (var i = 0; i < plugins.length; i++) { + var plugin = plugins[i]; + if (plugin.Enabled && _.includes(plugin.Config.Interface.Types, pluginVersion)) { + aggregatedPlugins.push(plugin.Name); + } + } - deferred.resolve(aggregatedPlugins); - }) - .catch(function error(err) { - deferred.reject({ msg: err.msg, err: err }); - }); + deferred.resolve(aggregatedPlugins); + }) + .catch(function error(err) { + deferred.reject({ msg: err.msg, err: err }); + }); - return deferred.promise; - } + return deferred.promise; + } - service.volumePlugins = function(systemOnly) { - return servicePlugins(systemOnly, 'Volume', 'docker.volumedriver/1.0'); - }; + service.volumePlugins = function (systemOnly) { + return servicePlugins(systemOnly, 'Volume', 'docker.volumedriver/1.0'); + }; - service.networkPlugins = function(systemOnly) { - return servicePlugins(systemOnly, 'Network', 'docker.networkdriver/1.0'); - }; + service.networkPlugins = function (systemOnly) { + return servicePlugins(systemOnly, 'Network', 'docker.networkdriver/1.0'); + }; - service.loggingPlugins = function(systemOnly) { - return servicePlugins(systemOnly, 'Log', 'docker.logdriver/1.0'); - }; + service.loggingPlugins = function (systemOnly) { + return servicePlugins(systemOnly, 'Log', 'docker.logdriver/1.0'); + }; - return service; -}]); + return service; + }, +]); diff --git a/app/docker/services/secretService.js b/app/docker/services/secretService.js index f12494929..40268c3fb 100644 --- a/app/docker/services/secretService.js +++ b/app/docker/services/secretService.js @@ -1,63 +1,66 @@ import { SecretViewModel } from '../models/secret'; -angular.module('portainer.docker') -.factory('SecretService', ['$q', 'Secret', function SecretServiceFactory($q, Secret) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('SecretService', [ + '$q', + 'Secret', + function SecretServiceFactory($q, Secret) { + 'use strict'; + var service = {}; - service.secret = function(secretId) { - var deferred = $q.defer(); + service.secret = function (secretId) { + var deferred = $q.defer(); - Secret.get({id: secretId}).$promise - .then(function success(data) { - var secret = new SecretViewModel(data); - deferred.resolve(secret); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve secret details', err: err }); - }); + Secret.get({ id: secretId }) + .$promise.then(function success(data) { + var secret = new SecretViewModel(data); + deferred.resolve(secret); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve secret details', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.secrets = function() { - var deferred = $q.defer(); + service.secrets = function () { + var deferred = $q.defer(); - Secret.query({}).$promise - .then(function success(data) { - var secrets = data.map(function (item) { - return new SecretViewModel(item); - }); - deferred.resolve(secrets); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve secrets', err: err }); - }); + Secret.query({}) + .$promise.then(function success(data) { + var secrets = data.map(function (item) { + return new SecretViewModel(item); + }); + deferred.resolve(secrets); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve secrets', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.remove = function(secretId) { - var deferred = $q.defer(); + service.remove = function (secretId) { + var deferred = $q.defer(); - Secret.remove({ id: secretId }).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message }); - } else { - deferred.resolve(); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to remove secret', err: err }); - }); + Secret.remove({ id: secretId }) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message }); + } else { + deferred.resolve(); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to remove secret', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.create = function(secretConfig) { - return Secret.create(secretConfig).$promise; - }; + service.create = function (secretConfig) { + return Secret.create(secretConfig).$promise; + }; - return service; -}]); + return service; + }, +]); diff --git a/app/docker/services/serviceService.js b/app/docker/services/serviceService.js index 95f16d214..d2caa7e69 100644 --- a/app/docker/services/serviceService.js +++ b/app/docker/services/serviceService.js @@ -1,98 +1,103 @@ import { ServiceViewModel } from '../models/service'; +angular.module('portainer.docker').factory('ServiceService', [ + '$q', + 'Service', + 'ServiceHelper', + 'TaskService', + 'ResourceControlService', + 'LogHelper', + function ServiceServiceFactory($q, Service, ServiceHelper, TaskService, ResourceControlService, LogHelper) { + 'use strict'; + var service = {}; -angular.module('portainer.docker') -.factory('ServiceService', ['$q', 'Service', 'ServiceHelper', 'TaskService', 'ResourceControlService', 'LogHelper', -function ServiceServiceFactory($q, Service, ServiceHelper, TaskService, ResourceControlService, LogHelper) { - 'use strict'; - var service = {}; + service.services = function (filters) { + var deferred = $q.defer(); - service.services = function(filters) { - var deferred = $q.defer(); + Service.query({ filters: filters ? filters : {} }) + .$promise.then(function success(data) { + var services = data.map(function (item) { + return new ServiceViewModel(item); + }); + deferred.resolve(services); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve services', err: err }); + }); - Service.query({ filters: filters ? filters : {} }).$promise - .then(function success(data) { - var services = data.map(function (item) { - return new ServiceViewModel(item); - }); - deferred.resolve(services); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve services', err: err }); - }); - - return deferred.promise; - }; - - service.service = function(id) { - var deferred = $q.defer(); - - Service.get({ id: id }).$promise - .then(function success(data) { - var service = new ServiceViewModel(data); - deferred.resolve(service); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve service details', err: err }); - }); - - return deferred.promise; - }; - - service.remove = function(service) { - var deferred = $q.defer(); - - Service.remove({id: service.Id}).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message, err: data.message }); - } else { - deferred.resolve(); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to remove service', err: err }); - }); - - return deferred.promise; - }; - - service.update = function(serv, config, rollback) { - return service.service(serv.Id).then((data) => { - const params = { - id: serv.Id, - version: data.Version - }; - if (rollback) { - params.rollback = rollback - } - return Service.update(params, config).$promise; - }); - }; - - service.logs = function(id, stdout, stderr, timestamps, since, tail) { - var deferred = $q.defer(); - - var parameters = { - id: id, - stdout: stdout || 0, - stderr: stderr || 0, - timestamps: timestamps || 0, - since: since || 0, - tail: tail || 'all' + return deferred.promise; }; - Service.logs(parameters).$promise - .then(function success(data) { - var logs = LogHelper.formatLogs(data.logs, true); - deferred.resolve(logs); - }) - .catch(function error(err) { - deferred.reject(err); - }); + service.service = function (id) { + var deferred = $q.defer(); - return deferred.promise; - }; + Service.get({ id: id }) + .$promise.then(function success(data) { + var service = new ServiceViewModel(data); + deferred.resolve(service); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve service details', err: err }); + }); - return service; -}]); + return deferred.promise; + }; + + service.remove = function (service) { + var deferred = $q.defer(); + + Service.remove({ id: service.Id }) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message, err: data.message }); + } else { + deferred.resolve(); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to remove service', err: err }); + }); + + return deferred.promise; + }; + + service.update = function (serv, config, rollback) { + return service.service(serv.Id).then((data) => { + const params = { + id: serv.Id, + version: data.Version, + }; + if (rollback) { + params.rollback = rollback; + } + return Service.update(params, config).$promise; + }); + }; + + service.logs = function (id, stdout, stderr, timestamps, since, tail) { + var deferred = $q.defer(); + + var parameters = { + id: id, + stdout: stdout || 0, + stderr: stderr || 0, + timestamps: timestamps || 0, + since: since || 0, + tail: tail || 'all', + }; + + Service.logs(parameters) + .$promise.then(function success(data) { + var logs = LogHelper.formatLogs(data.logs, true); + deferred.resolve(logs); + }) + .catch(function error(err) { + deferred.reject(err); + }); + + return deferred.promise; + }; + + return service; + }, +]); diff --git a/app/docker/services/swarmService.js b/app/docker/services/swarmService.js index 308163ef5..9ad18d212 100644 --- a/app/docker/services/swarmService.js +++ b/app/docker/services/swarmService.js @@ -1,24 +1,27 @@ import { SwarmViewModel } from '../models/swarm'; -angular.module('portainer.docker') -.factory('SwarmService', ['$q', 'Swarm', function SwarmServiceFactory($q, Swarm) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('SwarmService', [ + '$q', + 'Swarm', + function SwarmServiceFactory($q, Swarm) { + 'use strict'; + var service = {}; - service.swarm = function() { - var deferred = $q.defer(); + service.swarm = function () { + var deferred = $q.defer(); - Swarm.get().$promise - .then(function success(data) { - var swarm = new SwarmViewModel(data); - deferred.resolve(swarm); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve Swarm details', err: err }); - }); + Swarm.get() + .$promise.then(function success(data) { + var swarm = new SwarmViewModel(data); + deferred.resolve(swarm); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve Swarm details', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - return service; -}]); + return service; + }, +]); diff --git a/app/docker/services/systemService.js b/app/docker/services/systemService.js index 9e89300ce..90ac1168e 100644 --- a/app/docker/services/systemService.js +++ b/app/docker/services/systemService.js @@ -1,55 +1,59 @@ -import {EventViewModel} from '../models/event'; +import { EventViewModel } from '../models/event'; -angular.module('portainer.docker') -.factory('SystemService', ['$q', 'System', 'SystemEndpoint', function SystemServiceFactory($q, System, SystemEndpoint) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('SystemService', [ + '$q', + 'System', + 'SystemEndpoint', + function SystemServiceFactory($q, System, SystemEndpoint) { + 'use strict'; + var service = {}; - service.plugins = function() { - var deferred = $q.defer(); - System.info({}).$promise - .then(function success(data) { - var plugins = data.Plugins; - deferred.resolve(plugins); - }) - .catch(function error(err) { - deferred.reject({msg: 'Unable to retrieve plugins information from system', err: err}); - }); - return deferred.promise; - }; + service.plugins = function () { + var deferred = $q.defer(); + System.info({}) + .$promise.then(function success(data) { + var plugins = data.Plugins; + deferred.resolve(plugins); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve plugins information from system', err: err }); + }); + return deferred.promise; + }; - service.info = function() { - return System.info({}).$promise; - }; + service.info = function () { + return System.info({}).$promise; + }; - service.ping = function(endpointId) { - return SystemEndpoint.ping({endpointId: endpointId}).$promise; - }; + service.ping = function (endpointId) { + return SystemEndpoint.ping({ endpointId: endpointId }).$promise; + }; - service.version = function() { - return System.version({}).$promise; - }; + service.version = function () { + return System.version({}).$promise; + }; - service.events = function(from, to) { - var deferred = $q.defer(); + service.events = function (from, to) { + var deferred = $q.defer(); - System.events({since: from, until: to}).$promise - .then(function success(data) { - var events = data.map(function (item) { - return new EventViewModel(item); - }); - deferred.resolve(events); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve engine events', err: err }); - }); + System.events({ since: from, until: to }) + .$promise.then(function success(data) { + var events = data.map(function (item) { + return new EventViewModel(item); + }); + deferred.resolve(events); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve engine events', err: err }); + }); - return deferred.promise; - }; + return deferred.promise; + }; - service.dataUsage = function () { - return System.dataUsage().$promise; - }; + service.dataUsage = function () { + return System.dataUsage().$promise; + }; - return service; -}]); + return service; + }, +]); diff --git a/app/docker/services/taskService.js b/app/docker/services/taskService.js index 472ca051c..e5e6d4708 100644 --- a/app/docker/services/taskService.js +++ b/app/docker/services/taskService.js @@ -1,66 +1,69 @@ import { TaskViewModel } from '../models/task'; -angular.module('portainer.docker') -.factory('TaskService', ['$q', 'Task', 'LogHelper', -function TaskServiceFactory($q, Task, LogHelper) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('TaskService', [ + '$q', + 'Task', + 'LogHelper', + function TaskServiceFactory($q, Task, LogHelper) { + 'use strict'; + var service = {}; - service.task = function(id) { - var deferred = $q.defer(); + service.task = function (id) { + var deferred = $q.defer(); - Task.get({ id: id }).$promise - .then(function success(data) { - var task = new TaskViewModel(data); - deferred.resolve(task); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve task details', err: err }); - }); + Task.get({ id: id }) + .$promise.then(function success(data) { + var task = new TaskViewModel(data); + deferred.resolve(task); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve task details', err: err }); + }); - return deferred.promise; - }; - - service.tasks = function(filters) { - var deferred = $q.defer(); - - Task.query({ filters: filters ? filters : {} }).$promise - .then(function success(data) { - var tasks = data.map(function (item) { - return new TaskViewModel(item); - }); - deferred.resolve(tasks); - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to retrieve tasks', err: err }); - }); - - return deferred.promise; - }; - - service.logs = function(id, stdout, stderr, timestamps, since, tail) { - var deferred = $q.defer(); - - var parameters = { - id: id, - stdout: stdout || 0, - stderr: stderr || 0, - timestamps: timestamps || 0, - since: since || 0, - tail: tail || 'all' + return deferred.promise; }; - Task.logs(parameters).$promise - .then(function success(data) { - var logs = LogHelper.formatLogs(data.logs, true); - deferred.resolve(logs); - }) - .catch(function error(err) { - deferred.reject(err); - }); + service.tasks = function (filters) { + var deferred = $q.defer(); - return deferred.promise; - }; + Task.query({ filters: filters ? filters : {} }) + .$promise.then(function success(data) { + var tasks = data.map(function (item) { + return new TaskViewModel(item); + }); + deferred.resolve(tasks); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve tasks', err: err }); + }); - return service; -}]); + return deferred.promise; + }; + + service.logs = function (id, stdout, stderr, timestamps, since, tail) { + var deferred = $q.defer(); + + var parameters = { + id: id, + stdout: stdout || 0, + stderr: stderr || 0, + timestamps: timestamps || 0, + since: since || 0, + tail: tail || 'all', + }; + + Task.logs(parameters) + .$promise.then(function success(data) { + var logs = LogHelper.formatLogs(data.logs, true); + deferred.resolve(logs); + }) + .catch(function error(err) { + deferred.reject(err); + }); + + return deferred.promise; + }; + + return service; + }, +]); diff --git a/app/docker/services/volumeService.js b/app/docker/services/volumeService.js index 1ad5cbb9c..a812a86cb 100644 --- a/app/docker/services/volumeService.js +++ b/app/docker/services/volumeService.js @@ -1,101 +1,105 @@ import { VolumeViewModel } from '../models/volume'; -angular.module('portainer.docker') -.factory('VolumeService', ['$q', 'Volume', 'VolumeHelper', function VolumeServiceFactory($q, Volume, VolumeHelper) { - 'use strict'; - var service = {}; +angular.module('portainer.docker').factory('VolumeService', [ + '$q', + 'Volume', + 'VolumeHelper', + function VolumeServiceFactory($q, Volume, VolumeHelper) { + 'use strict'; + var service = {}; - service.volumes = function(params) { - var deferred = $q.defer(); - Volume.query(params).$promise - .then(function success(data) { - var volumes = data.Volumes || []; - volumes = volumes.map(function (item) { - return new VolumeViewModel(item); - }); - deferred.resolve(volumes); - }) - .catch(function error(err) { - deferred.reject({msg: 'Unable to retrieve volumes', err: err}); - }); - return deferred.promise; - }; - - service.volume = function(id) { - var deferred = $q.defer(); - Volume.get({id: id}).$promise - .then(function success(data) { - var volume = new VolumeViewModel(data); - deferred.resolve(volume); - }) - .catch(function error(err) { - deferred.reject({msg: 'Unable to retrieve volume details', err: err}); - }); - return deferred.promise; - }; - - service.getVolumes = function() { - return Volume.query({}).$promise; - }; - - service.remove = function(volume) { - var deferred = $q.defer(); - - Volume.remove({id: volume.Id}).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message, err: data.message }); - } else { - deferred.resolve(); - } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to remove volume', err: err }); - }); - - return deferred.promise; - }; - - service.createVolumeConfiguration = function(name, driver, driverOptions) { - var volumeConfiguration = { - Name: name, - Driver: driver, - DriverOpts: VolumeHelper.createDriverOptions(driverOptions) + service.volumes = function (params) { + var deferred = $q.defer(); + Volume.query(params) + .$promise.then(function success(data) { + var volumes = data.Volumes || []; + volumes = volumes.map(function (item) { + return new VolumeViewModel(item); + }); + deferred.resolve(volumes); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve volumes', err: err }); + }); + return deferred.promise; }; - return volumeConfiguration; - }; - service.createVolume = function(volumeConfiguration) { - var deferred = $q.defer(); - Volume.create(volumeConfiguration).$promise - .then(function success(data) { - if (data.message) { - deferred.reject({ msg: data.message }); - } else { - var volume = new VolumeViewModel(data); - deferred.resolve(volume); + service.volume = function (id) { + var deferred = $q.defer(); + Volume.get({ id: id }) + .$promise.then(function success(data) { + var volume = new VolumeViewModel(data); + deferred.resolve(volume); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve volume details', err: err }); + }); + return deferred.promise; + }; + + service.getVolumes = function () { + return Volume.query({}).$promise; + }; + + service.remove = function (volume) { + var deferred = $q.defer(); + + Volume.remove({ id: volume.Id }) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message, err: data.message }); + } else { + deferred.resolve(); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to remove volume', err: err }); + }); + + return deferred.promise; + }; + + service.createVolumeConfiguration = function (name, driver, driverOptions) { + var volumeConfiguration = { + Name: name, + Driver: driver, + DriverOpts: VolumeHelper.createDriverOptions(driverOptions), + }; + return volumeConfiguration; + }; + + service.createVolume = function (volumeConfiguration) { + var deferred = $q.defer(); + Volume.create(volumeConfiguration) + .$promise.then(function success(data) { + if (data.message) { + deferred.reject({ msg: data.message }); + } else { + var volume = new VolumeViewModel(data); + deferred.resolve(volume); + } + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to create volume', err: err }); + }); + return deferred.promise; + }; + + service.createVolumes = function (volumeConfigurations) { + var createVolumeQueries = volumeConfigurations.map(function (volumeConfiguration) { + return service.createVolume(volumeConfiguration); + }); + return $q.all(createVolumeQueries); + }; + + service.createXAutoGeneratedLocalVolumes = function (x) { + var createVolumeQueries = []; + for (var i = 0; i < x; i++) { + createVolumeQueries.push(service.createVolume({ Driver: 'local' })); } - }) - .catch(function error(err) { - deferred.reject({ msg: 'Unable to create volume', err: err }); - }); - return deferred.promise; - }; + return $q.all(createVolumeQueries); + }; - service.createVolumes = function(volumeConfigurations) { - var createVolumeQueries = volumeConfigurations.map(function(volumeConfiguration) { - return service.createVolume(volumeConfiguration); - }); - return $q.all(createVolumeQueries); - }; - - service.createXAutoGeneratedLocalVolumes = function (x) { - var createVolumeQueries = []; - for (var i = 0; i < x; i++) { - createVolumeQueries.push(service.createVolume({ Driver: 'local' })); - } - return $q.all(createVolumeQueries); - }; - - return service; -}]); + return service; + }, +]); diff --git a/app/docker/views/configs/configs.html b/app/docker/views/configs/configs.html index d124e86c7..0145c737e 100644 --- a/app/docker/views/configs/configs.html +++ b/app/docker/views/configs/configs.html @@ -10,12 +10,14 @@
diff --git a/app/docker/views/configs/configsController.js b/app/docker/views/configs/configsController.js index 41cd2e313..013dbf9f7 100644 --- a/app/docker/views/configs/configsController.js +++ b/app/docker/views/configs/configsController.js @@ -1,7 +1,6 @@ import angular from 'angular'; class ConfigsController { - /* @ngInject */ constructor($state, ConfigService, Notifications, $async) { this.$state = $state; diff --git a/app/docker/views/configs/create/createConfigController.js b/app/docker/views/configs/create/createConfigController.js index 316250c47..5d1e686f9 100644 --- a/app/docker/views/configs/create/createConfigController.js +++ b/app/docker/views/configs/create/createConfigController.js @@ -1,7 +1,7 @@ -import _ from "lodash-es"; -import { AccessControlFormData } from "Portainer/components/accessControlForm/porAccessControlFormModel"; +import _ from 'lodash-es'; +import { AccessControlFormData } from 'Portainer/components/accessControlForm/porAccessControlFormModel'; -import angular from "angular"; +import angular from 'angular'; class CreateConfigController { /* @ngInject */ @@ -16,14 +16,14 @@ class CreateConfigController { this.$async = $async; this.formValues = { - Name: "", + Name: '', Labels: [], AccessControlData: new AccessControlFormData(), - ConfigContent: "" + ConfigContent: '', }; this.state = { - formValidationError: "" + formValidationError: '', }; this.editorUpdate = this.editorUpdate.bind(this); @@ -38,7 +38,7 @@ class CreateConfigController { try { let data = await this.ConfigService.config(this.$transition$.params().id); - this.formValues.Name = data.Name + "_copy"; + this.formValues.Name = data.Name + '_copy'; this.formValues.Data = data.Data; let labels = _.keys(data.Labels); for (let i = 0; i < labels.length; i++) { @@ -49,12 +49,12 @@ class CreateConfigController { this.formValues.displayCodeEditor = true; } catch (err) { this.formValues.displayCodeEditor = true; - this.Notifications.error("Failure", err, "Unable to clone config"); + this.Notifications.error('Failure', err, 'Unable to clone config'); } } addLabel() { - this.formValues.Labels.push({ name: "", value: "" }); + this.formValues.Labels.push({ name: '', value: '' }); } removeLabel(index) { @@ -63,7 +63,7 @@ class CreateConfigController { prepareLabelsConfig(config) { let labels = {}; - this.formValues.Labels.forEach(function(label) { + this.formValues.Labels.forEach(function (label) { if (label.name && label.value) { labels[label.name] = label.value; } @@ -85,12 +85,9 @@ class CreateConfigController { } validateForm(accessControlData, isAdmin) { - this.state.formValidationError = ""; - let error = ""; - error = this.FormValidator.validateAccessControl( - accessControlData, - isAdmin - ); + this.state.formValidationError = ''; + let error = ''; + error = this.FormValidator.validateAccessControl(accessControlData, isAdmin); if (error) { this.state.formValidationError = error; @@ -108,8 +105,8 @@ class CreateConfigController { const userDetails = this.Authentication.getUserDetails(); const isAdmin = this.Authentication.isAdmin(); - if (this.formValues.ConfigContent === "") { - this.state.formValidationError = "Config content must not be empty"; + if (this.formValues.ConfigContent === '') { + this.state.formValidationError = 'Config content must not be empty'; return; } @@ -124,10 +121,10 @@ class CreateConfigController { const resourceControl = data.Portainer.ResourceControl; const userId = userDetails.ID; await this.ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); - this.Notifications.success("Config successfully created"); - this.$state.go("docker.configs", {}, { reload: true }); + this.Notifications.success('Config successfully created'); + this.$state.go('docker.configs', {}, { reload: true }); } catch (err) { - this.Notifications.error("Failure", err, "Unable to create config"); + this.Notifications.error('Failure', err, 'Unable to create config'); } } @@ -137,6 +134,4 @@ class CreateConfigController { } export default CreateConfigController; -angular - .module("portainer.docker") - .controller("CreateConfigController", CreateConfigController); +angular.module('portainer.docker').controller('CreateConfigController', CreateConfigController); diff --git a/app/docker/views/configs/create/createconfig.html b/app/docker/views/configs/create/createconfig.html index dbbfeda36..e92186639 100644 --- a/app/docker/views/configs/create/createconfig.html +++ b/app/docker/views/configs/create/createconfig.html @@ -1,8 +1,6 @@ - - Configs > Add config - + Configs > Add config
@@ -14,7 +12,7 @@
- +
@@ -25,7 +23,7 @@ identifier="config-creation-editor" placeholder="Define or paste the content of your config here" yml="false" - on-change="ctrl.editorUpdate" + on-change="(ctrl.editorUpdate)" value="ctrl.formValues.Data" >
@@ -44,11 +42,11 @@
name - +
value - +
- + + @@ -55,11 +59,7 @@
- + @@ -71,12 +71,7 @@
- +
diff --git a/app/docker/views/configs/edit/configController.js b/app/docker/views/configs/edit/configController.js index 2457c9609..516d65b69 100644 --- a/app/docker/views/configs/edit/configController.js +++ b/app/docker/views/configs/edit/configController.js @@ -1,27 +1,31 @@ -angular.module('portainer.docker') -.controller('ConfigController', ['$scope', '$transition$', '$state', 'ConfigService', 'Notifications', -function ($scope, $transition$, $state, ConfigService, Notifications) { +angular.module('portainer.docker').controller('ConfigController', [ + '$scope', + '$transition$', + '$state', + 'ConfigService', + 'Notifications', + function ($scope, $transition$, $state, ConfigService, Notifications) { + $scope.removeConfig = function removeConfig(configId) { + ConfigService.remove(configId) + .then(function success() { + Notifications.success('Config successfully removed'); + $state.go('docker.configs', {}); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove config'); + }); + }; - $scope.removeConfig = function removeConfig(configId) { - ConfigService.remove(configId) - .then(function success() { - Notifications.success('Config successfully removed'); - $state.go('docker.configs', {}); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove config'); - }); - }; + function initView() { + ConfigService.config($transition$.params().id) + .then(function success(data) { + $scope.config = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve config details'); + }); + } - function initView() { - ConfigService.config($transition$.params().id) - .then(function success(data) { - $scope.config = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve config details'); - }); - } - - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/containers/console/attach.html b/app/docker/views/containers/console/attach.html index 98e618848..703b57cb5 100644 --- a/app/docker/views/containers/console/attach.html +++ b/app/docker/views/containers/console/attach.html @@ -1,7 +1,7 @@ - Containers > {{ container.Name|trimcontainername }} > Console + Containers > {{ container.Name | trimcontainername }} > Console @@ -10,7 +10,6 @@ -

@@ -32,12 +31,16 @@

- -
diff --git a/app/docker/views/containers/console/containerConsoleController.js b/app/docker/views/containers/console/containerConsoleController.js index 2fa3c3e46..27bee1fa6 100644 --- a/app/docker/views/containers/console/containerConsoleController.js +++ b/app/docker/views/containers/console/containerConsoleController.js @@ -1,41 +1,63 @@ -import {Terminal} from 'xterm'; +import { Terminal } from 'xterm'; -angular.module('portainer.docker') - .controller('ContainerConsoleController', ['$scope', '$transition$', 'ContainerService', 'ImageService', 'EndpointProvider', 'Notifications', 'ContainerHelper', 'ExecService', 'HttpRequestHelper', 'LocalStorage', 'CONSOLE_COMMANDS_LABEL_PREFIX', - function ($scope, $transition$, ContainerService, ImageService, EndpointProvider, Notifications, ContainerHelper, ExecService, HttpRequestHelper, LocalStorage, CONSOLE_COMMANDS_LABEL_PREFIX) { - var socket, term; +angular.module('portainer.docker').controller('ContainerConsoleController', [ + '$scope', + '$transition$', + 'ContainerService', + 'ImageService', + 'EndpointProvider', + 'Notifications', + 'ContainerHelper', + 'ExecService', + 'HttpRequestHelper', + 'LocalStorage', + 'CONSOLE_COMMANDS_LABEL_PREFIX', + function ( + $scope, + $transition$, + ContainerService, + ImageService, + EndpointProvider, + Notifications, + ContainerHelper, + ExecService, + HttpRequestHelper, + LocalStorage, + CONSOLE_COMMANDS_LABEL_PREFIX + ) { + var socket, term; - let states = Object.freeze({ - disconnected: 0, - connecting: 1, - connected: 2, - }); + let states = Object.freeze({ + disconnected: 0, + connecting: 1, + connected: 2, + }); - $scope.loaded = false; - $scope.states = states; - $scope.state = states.disconnected; + $scope.loaded = false; + $scope.states = states; + $scope.state = states.disconnected; - $scope.formValues = {}; - $scope.containerCommands = []; + $scope.formValues = {}; + $scope.containerCommands = []; - // Ensure the socket is closed before leaving the view - $scope.$on('$stateChangeStart', function () { - $scope.disconnect(); - }); + // Ensure the socket is closed before leaving the view + $scope.$on('$stateChangeStart', function () { + $scope.disconnect(); + }); - $scope.connectAttach = function() { - if ($scope.state > states.disconnected) { - return; - } + $scope.connectAttach = function () { + if ($scope.state > states.disconnected) { + return; + } - $scope.state = states.connecting; + $scope.state = states.connecting; - let attachId = $transition$.params().id; - - ContainerService.container(attachId).then((details) => { + let attachId = $transition$.params().id; + ContainerService.container(attachId) + .then((details) => { if (!details.State.Running) { - Notifications.error("Failure", details, "Container " + attachId + " is not running!"); + Notifications.error('Failure', details, 'Container ' + attachId + ' is not running!'); $scope.disconnect(); return; } @@ -43,173 +65,177 @@ angular.module('portainer.docker') const params = { token: LocalStorage.getJWT(), endpointId: EndpointProvider.endpointID(), - id: attachId + id: attachId, }; - var url = window.location.href.split('#')[0] + 'api/websocket/attach?' + (Object.keys(params).map((k) => k + "=" + params[k]).join("&")); + var url = + window.location.href.split('#')[0] + + 'api/websocket/attach?' + + Object.keys(params) + .map((k) => k + '=' + params[k]) + .join('&'); initTerm(url, ContainerService.resizeTTY.bind(this, attachId)); }) - .catch(function error(err) { - Notifications.error('Error', err, 'Unable to retrieve container details'); - $scope.disconnect(); - }); - }; - - $scope.connectExec = function () { - if ($scope.state > states.disconnected) { - return; - } - - $scope.state = states.connecting; - var command = $scope.formValues.isCustomCommand ? - $scope.formValues.customCommand : $scope.formValues.command; - var execConfig = { - id: $transition$.params().id, - AttachStdin: true, - AttachStdout: true, - AttachStderr: true, - Tty: true, - User: $scope.formValues.user, - Cmd: ContainerHelper.commandStringToArray(command) - }; - - ContainerService.createExec(execConfig) - .then(function success(data) { - - const params = { - token: LocalStorage.getJWT(), - endpointId: EndpointProvider.endpointID(), - id: data.Id - }; - - var url = window.location.href.split('#')[0] + 'api/websocket/exec?' + (Object.keys(params).map((k) => k + "=" + params[k]).join("&")); - - initTerm(url, ExecService.resizeTTY.bind(this, params.id)); - - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to exec into container'); - $scope.disconnect(); - }); - }; - - $scope.disconnect = function () { - if (socket) { - socket.close(); - } - if ($scope.state > states.disconnected) { - $scope.state = states.disconnected; - if (term) { - term.write("\n\r(connection closed)"); - term.dispose(); - } - } - }; - - $scope.autoconnectAttachView = function () { - return $scope.initView().then(function success() { - if ($scope.container.State.Running) { - $scope.connectAttach(); - } + .catch(function error(err) { + Notifications.error('Error', err, 'Unable to retrieve container details'); + $scope.disconnect(); }); - }; + }; - function resize(restcall, add) { - add = add || 0; - - term.fit(); - var termWidth = term.cols; - var termHeight = 30; - term.resize(termWidth, termHeight); - - - restcall(termWidth + add, termHeight + add, 1); + $scope.connectExec = function () { + if ($scope.state > states.disconnected) { + return; } - function initTerm(url, resizeRestCall) { + $scope.state = states.connecting; + var command = $scope.formValues.isCustomCommand ? $scope.formValues.customCommand : $scope.formValues.command; + var execConfig = { + id: $transition$.params().id, + AttachStdin: true, + AttachStdout: true, + AttachStderr: true, + Tty: true, + User: $scope.formValues.user, + Cmd: ContainerHelper.commandStringToArray(command), + }; - let resizefun = resize.bind(this, resizeRestCall); + ContainerService.createExec(execConfig) + .then(function success(data) { + const params = { + token: LocalStorage.getJWT(), + endpointId: EndpointProvider.endpointID(), + id: data.Id, + }; - if ($transition$.params().nodeName) { - url += '&nodeName=' + $transition$.params().nodeName; + var url = + window.location.href.split('#')[0] + + 'api/websocket/exec?' + + Object.keys(params) + .map((k) => k + '=' + params[k]) + .join('&'); + + initTerm(url, ExecService.resizeTTY.bind(this, params.id)); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to exec into container'); + $scope.disconnect(); + }); + }; + + $scope.disconnect = function () { + if (socket) { + socket.close(); + } + if ($scope.state > states.disconnected) { + $scope.state = states.disconnected; + if (term) { + term.write('\n\r(connection closed)'); + term.dispose(); } - if (url.indexOf('https') > -1) { - url = url.replace('https://', 'wss://'); - } else { - url = url.replace('http://', 'ws://'); + } + }; + + $scope.autoconnectAttachView = function () { + return $scope.initView().then(function success() { + if ($scope.container.State.Running) { + $scope.connectAttach(); } + }); + }; - socket = new WebSocket(url); + function resize(restcall, add) { + add = add || 0; + term.fit(); + var termWidth = term.cols; + var termHeight = 30; + term.resize(termWidth, termHeight); - socket.onopen = function () { - $scope.state = states.connected; - term = new Terminal(); + restcall(termWidth + add, termHeight + add, 1); + } + function initTerm(url, resizeRestCall) { + let resizefun = resize.bind(this, resizeRestCall); - term.on('data', function (data) { - socket.send(data); - }); - var terminal_container = document.getElementById('terminal-container'); - term.open(terminal_container); - term.focus(); - term.setOption('cursorBlink', true); + if ($transition$.params().nodeName) { + url += '&nodeName=' + $transition$.params().nodeName; + } + if (url.indexOf('https') > -1) { + url = url.replace('https://', 'wss://'); + } else { + url = url.replace('http://', 'ws://'); + } - window.onresize = function () { - resizefun(); - $scope.$apply(); - }; + socket = new WebSocket(url); - $scope.$watch('toggle', function () { - setTimeout(resizefun, 400); - }); + socket.onopen = function () { + $scope.state = states.connected; + term = new Terminal(); - socket.onmessage = function (e) { - term.write(e.data); - }; - socket.onerror = function (err) { - $scope.disconnect(); - $scope.$apply(); - Notifications.error("Failure", err, "Connection error"); - }; - socket.onclose = function () { - $scope.disconnect(); - $scope.$apply(); - }; + term.on('data', function (data) { + socket.send(data); + }); + var terminal_container = document.getElementById('terminal-container'); + term.open(terminal_container); + term.focus(); + term.setOption('cursorBlink', true); - resizefun(1); + window.onresize = function () { + resizefun(); $scope.$apply(); }; - } - $scope.initView = function () { - HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); - return ContainerService.container($transition$.params().id) - .then(function success(data) { - var container = data; - $scope.container = container; - return ImageService.image(container.Image); - }) - .then(function success(data) { - var image = data; - var containerLabels = $scope.container.Config.Labels; - $scope.imageOS = image.Os; - $scope.formValues.command = image.Os === 'windows' ? 'powershell' : 'bash'; - $scope.containerCommands = Object.keys(containerLabels) - .filter(function (label) { - return label.indexOf(CONSOLE_COMMANDS_LABEL_PREFIX) === 0; - }) - .map(function (label) { - return { - title: label.replace(CONSOLE_COMMANDS_LABEL_PREFIX, ''), - command: containerLabels[label] - }; - }); - $scope.loaded = true; - }) - .catch(function error(err) { - Notifications.error('Error', err, 'Unable to retrieve container details'); - }); - } - }]); + $scope.$watch('toggle', function () { + setTimeout(resizefun, 400); + }); + + socket.onmessage = function (e) { + term.write(e.data); + }; + socket.onerror = function (err) { + $scope.disconnect(); + $scope.$apply(); + Notifications.error('Failure', err, 'Connection error'); + }; + socket.onclose = function () { + $scope.disconnect(); + $scope.$apply(); + }; + + resizefun(1); + $scope.$apply(); + }; + } + + $scope.initView = function () { + HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); + return ContainerService.container($transition$.params().id) + .then(function success(data) { + var container = data; + $scope.container = container; + return ImageService.image(container.Image); + }) + .then(function success(data) { + var image = data; + var containerLabels = $scope.container.Config.Labels; + $scope.imageOS = image.Os; + $scope.formValues.command = image.Os === 'windows' ? 'powershell' : 'bash'; + $scope.containerCommands = Object.keys(containerLabels) + .filter(function (label) { + return label.indexOf(CONSOLE_COMMANDS_LABEL_PREFIX) === 0; + }) + .map(function (label) { + return { + title: label.replace(CONSOLE_COMMANDS_LABEL_PREFIX, ''), + command: containerLabels[label], + }; + }); + $scope.loaded = true; + }) + .catch(function error(err) { + Notifications.error('Error', err, 'Unable to retrieve container details'); + }); + }; + }, +]); diff --git a/app/docker/views/containers/console/exec.html b/app/docker/views/containers/console/exec.html index 31594f1c6..13ddfb32c 100644 --- a/app/docker/views/containers/console/exec.html +++ b/app/docker/views/containers/console/exec.html @@ -1,7 +1,7 @@ - Containers > {{ container.Name|trimcontainername }} > Console + Containers > {{ container.Name | trimcontainername }} > Console @@ -13,32 +13,30 @@
-
- -
-
- - - - - -
- +
+ +
+
+ + + + +
+
+
- +
- +
@@ -62,7 +60,10 @@
- + @@ -182,7 +196,7 @@
- +
@@ -190,7 +204,7 @@
- +
@@ -198,11 +212,11 @@
- +
- +
@@ -212,13 +226,13 @@
@@ -226,13 +240,13 @@
@@ -255,7 +269,8 @@

- Logging driver that will override the default docker daemon driver. Select Default logging driver if you don't want to override it. Supported logging drivers can be found in the Docker documentation. + Logging driver that will override the default docker daemon driver. Select Default logging driver if you don't want to override it. Supported logging drivers + can be found in the Docker documentation.

@@ -265,9 +280,16 @@
- + add logging driver option
@@ -276,11 +298,11 @@
option - +
value - +
- -
@@ -314,7 +334,7 @@
container - +
@@ -338,14 +358,14 @@ volume
host - +
@@ -399,7 +419,7 @@
- +
@@ -407,7 +427,7 @@
- +
@@ -415,7 +435,7 @@
- +
@@ -423,7 +443,7 @@
- +
@@ -431,7 +451,7 @@
- +
@@ -439,7 +459,7 @@
- +
@@ -447,7 +467,7 @@
- +
@@ -464,7 +484,7 @@
value - +
@@ -592,8 +610,7 @@
-
@@ -609,16 +626,16 @@ add device
- +
host - +
container - +
- +

@@ -658,7 +675,7 @@

- +

@@ -687,7 +704,7 @@

- +
diff --git a/app/docker/views/containers/edit/container.html b/app/docker/views/containers/edit/container.html index 11a927aaa..2d7e9fadb 100644 --- a/app/docker/views/containers/edit/container.html +++ b/app/docker/views/containers/edit/container.html @@ -1,277 +1,326 @@ - - + - Containers > {{ container.Name|trimcontainername }} + Containers > {{ container.Name | trimcontainername }} -
-
- - - -
- - - - - - - +
+
+ + + +
+ + + + + + + +
+
+ + Duplicate/Edit +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID{{ container.Id }}
Name + {{ container.Name | trimcontainername }} + + +
+ + + +
+
IP address{{ container.NetworkSettings.IPAddress }}
Status + + + {{ container.State | getstatetext }} for {{ activityTime + }} with exit code {{ container.State.ExitCode }} +
Created{{ container.Created | getisodate }}
Start time{{ container.State.StartedAt | getisodate }}
Finished{{ container.State.FinishedAt | getisodate }}
+ +
+
+
+
+
+ + + + + + +
+
+ + + + + + + + + + + + + + + + + + +
Status + + {{ container.State.Health.Status }} +
Failure count{{ container.State.Health.FailingStreak }}
Last output{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}
+
+
+
+
+ +
+
+ + + +
+ +
+
+ + You can create an image from this container, this allows you to backup important data or save helpful configurations. You'll be able to spin up another container + based on this image afterward. + +
-
- - Duplicate/Edit + + + + + +
+
+ Note: if you don't specify the tag in the image name, latest will be used. +
- - -
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ID{{ container.Id }}
Name - {{ container.Name|trimcontainername }} - - - - - - - -
IP address{{ container.NetworkSettings.IPAddress }}
Status - - - {{ container.State|getstatetext }} for {{ activityTime }} with exit code {{ container.State.ExitCode }} -
Created{{ container.Created|getisodate }}
Start time{{ container.State.StartedAt|getisodate }}
Finished{{ container.State.FinishedAt|getisodate }}
- -
-
-
-
-
- - - - - - -
-
- - - - - - - - - - - - - - - - - - -
Status - - {{ container.State.Health.Status }} -
Failure count{{ container.State.Health.FailingStreak }}
Last output{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}
-
-
-
-
- -
-
- - - -
- -
-
- - You can create an image from this container, this allows you to backup important data or save - helpful configurations. You'll be able to spin up another container based on this image afterward. - -
+ +
+
+
- - - - - -
-
- Note: if you don't specify the tag in the image name, latest will be used. -
-
- -
-
- -
-
- - - -
+
+ +
+
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Image{{ container.Config.Image}}@{{container.Image}}
Port configuration -
- {{ portMapping.host }} {{ portMapping.container }} -
-
CMD{{ container.Config.Cmd|command }}
ENTRYPOINT{{ container.Config.Entrypoint ? (container.Config.Entrypoint|command) : "null" }}
ENV - - - - - -
{{ var|key: '=' }}{{ var|value: '=' }}
-
Labels - - - - - -
{{ k }}{{ v }}
-
Restart policies - -
-
-
-
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Image{{ container.Config.Image }}@{{ container.Image }}
Port configuration +
{{ portMapping.host }} {{ portMapping.container }}
+
CMD{{ container.Config.Cmd | command }}
ENTRYPOINT{{ container.Config.Entrypoint ? (container.Config.Entrypoint | command) : 'null' }}
ENV + + + + + +
{{ var|key: '=' }}{{ var|value: '=' }}
+
Labels + + + + + +
{{ k }}{{ v }}
+
Restart policies + + +
+
+
+
-
-
- - - - - - - - - - - - - - - - - -
Host/volumePath in container
{{ vol.Source }}{{ vol.Name }}{{ vol.Destination }}
-
-
-
+
+
+ + + + + + + + + + + + + + + + + +
Host/volumePath in container
{{ vol.Source }}{{ vol.Name }}{{ vol.Destination }}
+
+
+
-
-
- +
+ -
+ >
+
diff --git a/app/docker/views/containers/edit/containerController.js b/app/docker/views/containers/edit/containerController.js index f775fbc1e..6528669f1 100644 --- a/app/docker/views/containers/edit/containerController.js +++ b/app/docker/views/containers/edit/containerController.js @@ -1,356 +1,383 @@ import moment from 'moment'; import { PorImageRegistryModel } from 'Docker/models/porImageRegistry'; -angular.module('portainer.docker') -.controller('ContainerController', ['$q', '$scope', '$state','$transition$', '$filter', '$async', 'ExtensionService', 'Commit', 'ContainerHelper', 'ContainerService', 'ImageHelper', 'NetworkService', 'Notifications', 'ModalService', 'ResourceControlService', 'RegistryService', 'ImageService', 'HttpRequestHelper', 'Authentication', -function ($q, $scope, $state, $transition$, $filter, $async, ExtensionService, Commit, ContainerHelper, ContainerService, ImageHelper, NetworkService, Notifications, ModalService, ResourceControlService, RegistryService, ImageService, HttpRequestHelper, Authentication) { - $scope.activityTime = 0; - $scope.portBindings = []; - $scope.displayRecreateButton = false; +angular.module('portainer.docker').controller('ContainerController', [ + '$q', + '$scope', + '$state', + '$transition$', + '$filter', + '$async', + 'ExtensionService', + 'Commit', + 'ContainerHelper', + 'ContainerService', + 'ImageHelper', + 'NetworkService', + 'Notifications', + 'ModalService', + 'ResourceControlService', + 'RegistryService', + 'ImageService', + 'HttpRequestHelper', + 'Authentication', + function ( + $q, + $scope, + $state, + $transition$, + $filter, + $async, + ExtensionService, + Commit, + ContainerHelper, + ContainerService, + ImageHelper, + NetworkService, + Notifications, + ModalService, + ResourceControlService, + RegistryService, + ImageService, + HttpRequestHelper, + Authentication + ) { + $scope.activityTime = 0; + $scope.portBindings = []; + $scope.displayRecreateButton = false; - $scope.config = { - RegistryModel: new PorImageRegistryModel(), - commitInProgress: false - }; + $scope.config = { + RegistryModel: new PorImageRegistryModel(), + commitInProgress: false, + }; - $scope.state = { - recreateContainerInProgress: false, - joinNetworkInProgress: false, - leaveNetworkInProgress: false - }; + $scope.state = { + recreateContainerInProgress: false, + joinNetworkInProgress: false, + leaveNetworkInProgress: false, + }; - $scope.updateRestartPolicy = updateRestartPolicy; + $scope.updateRestartPolicy = updateRestartPolicy; - var update = function () { - var nodeName = $transition$.params().nodeName; - HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); - $scope.nodeName = nodeName; + var update = function () { + var nodeName = $transition$.params().nodeName; + HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); + $scope.nodeName = nodeName; - ContainerService.container($transition$.params().id) - .then(function success(data) { - var container = data; - $scope.container = container; - $scope.container.edit = false; - $scope.container.newContainerName = $filter('trimcontainername')(container.Name); + ContainerService.container($transition$.params().id) + .then(function success(data) { + var container = data; + $scope.container = container; + $scope.container.edit = false; + $scope.container.newContainerName = $filter('trimcontainername')(container.Name); - if (container.State.Running) { - $scope.activityTime = moment.duration(moment(container.State.StartedAt).utc().diff(moment().utc())).humanize(); - } else if (container.State.Status === 'created') { - $scope.activityTime = moment.duration(moment(container.Created).utc().diff(moment().utc())).humanize(); - } else { - $scope.activityTime = moment.duration(moment().utc().diff(moment(container.State.FinishedAt).utc())).humanize(); - } - - $scope.portBindings = []; - if (container.NetworkSettings.Ports) { - angular.forEach(Object.keys(container.NetworkSettings.Ports), function(portMapping) { - if (container.NetworkSettings.Ports[portMapping]) { - var mapping = {}; - mapping.container = portMapping; - mapping.host = container.NetworkSettings.Ports[portMapping][0].HostIp + ':' + container.NetworkSettings.Ports[portMapping][0].HostPort; - $scope.portBindings.push(mapping); + if (container.State.Running) { + $scope.activityTime = moment.duration(moment(container.State.StartedAt).utc().diff(moment().utc())).humanize(); + } else if (container.State.Status === 'created') { + $scope.activityTime = moment.duration(moment(container.Created).utc().diff(moment().utc())).humanize(); + } else { + $scope.activityTime = moment.duration(moment().utc().diff(moment(container.State.FinishedAt).utc())).humanize(); } + + $scope.portBindings = []; + if (container.NetworkSettings.Ports) { + angular.forEach(Object.keys(container.NetworkSettings.Ports), function (portMapping) { + if (container.NetworkSettings.Ports[portMapping]) { + var mapping = {}; + mapping.container = portMapping; + mapping.host = container.NetworkSettings.Ports[portMapping][0].HostIp + ':' + container.NetworkSettings.Ports[portMapping][0].HostPort; + $scope.portBindings.push(mapping); + } + }); + } + + const inSwarm = $scope.container.Config.Labels['com.docker.swarm.service.id']; + const autoRemove = $scope.container.HostConfig.AutoRemove; + const admin = Authentication.isAdmin(); + + ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC).then((rbacEnabled) => { + $scope.displayRecreateButton = !inSwarm && !autoRemove && (rbacEnabled ? admin : true); + }); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve container info'); }); + }; + + function executeContainerAction(id, action, successMessage, errorMessage) { + action(id) + .then(function success() { + Notifications.success(successMessage, id); + update(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, errorMessage); + }); + } + + $scope.start = function () { + var successMessage = 'Container successfully started'; + var errorMessage = 'Unable to start container'; + executeContainerAction($transition$.params().id, ContainerService.startContainer, successMessage, errorMessage); + }; + + $scope.stop = function () { + var successMessage = 'Container successfully stopped'; + var errorMessage = 'Unable to stop container'; + executeContainerAction($transition$.params().id, ContainerService.stopContainer, successMessage, errorMessage); + }; + + $scope.kill = function () { + var successMessage = 'Container successfully killed'; + var errorMessage = 'Unable to kill container'; + executeContainerAction($transition$.params().id, ContainerService.killContainer, successMessage, errorMessage); + }; + + $scope.pause = function () { + var successMessage = 'Container successfully paused'; + var errorMessage = 'Unable to pause container'; + executeContainerAction($transition$.params().id, ContainerService.pauseContainer, successMessage, errorMessage); + }; + + $scope.unpause = function () { + var successMessage = 'Container successfully resumed'; + var errorMessage = 'Unable to resume container'; + executeContainerAction($transition$.params().id, ContainerService.resumeContainer, successMessage, errorMessage); + }; + + $scope.restart = function () { + var successMessage = 'Container successfully restarted'; + var errorMessage = 'Unable to restart container'; + executeContainerAction($transition$.params().id, ContainerService.restartContainer, successMessage, errorMessage); + }; + + $scope.renameContainer = function () { + var container = $scope.container; + ContainerService.renameContainer($transition$.params().id, container.newContainerName) + .then(function success() { + container.Name = container.newContainerName; + Notifications.success('Container successfully renamed', container.Name); + }) + .catch(function error(err) { + container.newContainerName = container.Name; + Notifications.error('Failure', err, 'Unable to rename container'); + }) + .finally(function final() { + $scope.container.edit = false; + }); + }; + + $scope.containerLeaveNetwork = function containerLeaveNetwork(container, networkId) { + $scope.state.leaveNetworkInProgress = true; + NetworkService.disconnectContainer(networkId, container.Id, false) + .then(function success() { + Notifications.success('Container left network', container.Id); + $state.reload(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to disconnect container from network'); + }) + .finally(function final() { + $scope.state.leaveNetworkInProgress = false; + }); + }; + + $scope.containerJoinNetwork = function containerJoinNetwork(container, networkId) { + $scope.state.joinNetworkInProgress = true; + NetworkService.connectContainer(networkId, container.Id) + .then(function success() { + Notifications.success('Container joined network', container.Id); + $state.reload(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to connect container to network'); + }) + .finally(function final() { + $scope.state.joinNetworkInProgress = false; + }); + }; + + async function commitContainerAsync() { + $scope.config.commitInProgress = true; + const registryModel = $scope.config.RegistryModel; + const imageConfig = ImageHelper.createImageConfigForContainer(registryModel); + try { + await Commit.commitContainer({ id: $transition$.params().id, repo: imageConfig.fromImage }).$promise; + Notifications.success('Image created', $transition$.params().id); + $state.reload(); + } catch (err) { + Notifications.error('Failure', err, 'Unable to create image'); + $scope.config.commitInProgress = false; } - - const inSwarm = $scope.container.Config.Labels['com.docker.swarm.service.id']; - const autoRemove = $scope.container.HostConfig.AutoRemove; - const admin = Authentication.isAdmin(); - - ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC).then((rbacEnabled) => { - $scope.displayRecreateButton = !inSwarm && !autoRemove && (rbacEnabled ? admin : true) - }); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve container info'); - }); - }; - - function executeContainerAction(id, action, successMessage, errorMessage) { - action(id) - .then(function success() { - Notifications.success(successMessage, id); - update(); - }) - .catch(function error(err) { - Notifications.error('Failure', err, errorMessage); - }); - } - - $scope.start = function () { - var successMessage = 'Container successfully started'; - var errorMessage = 'Unable to start container'; - executeContainerAction($transition$.params().id, ContainerService.startContainer, successMessage, errorMessage); - }; - - $scope.stop = function () { - var successMessage = 'Container successfully stopped'; - var errorMessage = 'Unable to stop container'; - executeContainerAction($transition$.params().id, ContainerService.stopContainer, successMessage, errorMessage); - }; - - $scope.kill = function () { - var successMessage = 'Container successfully killed'; - var errorMessage = 'Unable to kill container'; - executeContainerAction($transition$.params().id, ContainerService.killContainer, successMessage, errorMessage); - }; - - $scope.pause = function() { - var successMessage = 'Container successfully paused'; - var errorMessage = 'Unable to pause container'; - executeContainerAction($transition$.params().id, ContainerService.pauseContainer, successMessage, errorMessage); - }; - - $scope.unpause = function() { - var successMessage = 'Container successfully resumed'; - var errorMessage = 'Unable to resume container'; - executeContainerAction($transition$.params().id, ContainerService.resumeContainer, successMessage, errorMessage); - }; - - $scope.restart = function () { - var successMessage = 'Container successfully restarted'; - var errorMessage = 'Unable to restart container'; - executeContainerAction($transition$.params().id, ContainerService.restartContainer, successMessage, errorMessage); - }; - - $scope.renameContainer = function () { - var container = $scope.container; - ContainerService.renameContainer($transition$.params().id, container.newContainerName) - .then(function success() { - container.Name = container.newContainerName; - Notifications.success('Container successfully renamed', container.Name); - }) - .catch(function error(err) { - container.newContainerName = container.Name; - Notifications.error('Failure', err, 'Unable to rename container'); - }) - .finally(function final() { - $scope.container.edit = false; - }); - }; - - $scope.containerLeaveNetwork = function containerLeaveNetwork(container, networkId) { - $scope.state.leaveNetworkInProgress = true; - NetworkService.disconnectContainer(networkId, container.Id, false) - .then(function success() { - Notifications.success('Container left network', container.Id); - $state.reload(); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to disconnect container from network'); - }) - .finally(function final() { - $scope.state.leaveNetworkInProgress = false; - }); - }; - - $scope.containerJoinNetwork = function containerJoinNetwork(container, networkId) { - $scope.state.joinNetworkInProgress = true; - NetworkService.connectContainer(networkId, container.Id) - .then(function success() { - Notifications.success('Container joined network', container.Id); - $state.reload(); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to connect container to network'); - }) - .finally(function final() { - $scope.state.joinNetworkInProgress = false; - }); - }; - - async function commitContainerAsync() { - $scope.config.commitInProgress = true; - const registryModel = $scope.config.RegistryModel; - const imageConfig = ImageHelper.createImageConfigForContainer(registryModel); - try { - await Commit.commitContainer({id: $transition$.params().id, repo: imageConfig.fromImage}).$promise; - Notifications.success('Image created', $transition$.params().id); - $state.reload(); - } catch (err) { - Notifications.error('Failure', err, 'Unable to create image'); - $scope.config.commitInProgress = false; } - } - $scope.commit = function () { - return $async(commitContainerAsync); - }; + $scope.commit = function () { + return $async(commitContainerAsync); + }; - $scope.confirmRemove = function () { - var title = 'You are about to remove a container.'; - if ($scope.container.State.Running) { - title = 'You are about to remove a running container.'; - } - ModalService.confirmContainerDeletion( - title, - function (result) { - if(!result) { return; } + $scope.confirmRemove = function () { + var title = 'You are about to remove a container.'; + if ($scope.container.State.Running) { + title = 'You are about to remove a running container.'; + } + ModalService.confirmContainerDeletion(title, function (result) { + if (!result) { + return; + } var cleanAssociatedVolumes = false; if (result[0]) { cleanAssociatedVolumes = true; } removeContainer(cleanAssociatedVolumes); - } - ); - }; - - function removeContainer(cleanAssociatedVolumes) { - ContainerService.remove($scope.container, cleanAssociatedVolumes) - .then(function success() { - Notifications.success('Container successfully removed'); - $state.go('docker.containers', {}, {reload: true}); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove container'); - }); - } - - function recreateContainer(pullImage) { - var container = $scope.container; - var config = ContainerHelper.configFromContainer(container.Model); - $scope.state.recreateContainerInProgress = true; - var isRunning = container.State.Running; - - return pullImageIfNeeded() - .then(stopContainerIfNeeded) - .then(renameContainer) - .then(setMainNetworkAndCreateContainer) - .then(connectContainerToOtherNetworks) - .then(startContainerIfNeeded) - .then(createResourceControl) - .then(deleteOldContainer) - .then(notifyAndChangeView) - .catch(notifyOnError); - - function stopContainerIfNeeded() { - if (!isRunning) { - return $q.when(); - } - return ContainerService.stopContainer(container.Id); - } - - function renameContainer() { - return ContainerService.renameContainer(container.Id, container.Name + '-old'); - } - - function pullImageIfNeeded() { - if (!pullImage) { - return $q.when(); - } - return RegistryService.retrievePorRegistryModelFromRepository(container.Config.Image) - .then(function pullImage(registryModel) { - return ImageService.pullImage(registryModel, true); }); - } + }; - function setMainNetworkAndCreateContainer() { - var networks = config.NetworkingConfig.EndpointsConfig; - var networksNames = Object.keys(networks); - if (networksNames.length > 1) { - config.NetworkingConfig.EndpointsConfig = {}; - config.NetworkingConfig.EndpointsConfig[networksNames[0]] = networks[0]; - } - return $q.all([ContainerService.createContainer(config), networks]); - } - - function connectContainerToOtherNetworks(createContainerData) { - var newContainer = createContainerData[0]; - var networks = createContainerData[1]; - var networksNames = Object.keys(networks); - var connectionPromises = networksNames.map(function connectToNetwork(name) { - NetworkService.connectContainer(name, newContainer.Id); - }); - return $q.all(connectionPromises) - .then(function onConnectToNetworkSuccess() { - return newContainer; + function removeContainer(cleanAssociatedVolumes) { + ContainerService.remove($scope.container, cleanAssociatedVolumes) + .then(function success() { + Notifications.success('Container successfully removed'); + $state.go('docker.containers', {}, { reload: true }); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove container'); }); } - function deleteOldContainer(newContainer) { - return ContainerService.remove(container, true).then( - function onRemoveSuccess() { - return newContainer; + function recreateContainer(pullImage) { + var container = $scope.container; + var config = ContainerHelper.configFromContainer(container.Model); + $scope.state.recreateContainerInProgress = true; + var isRunning = container.State.Running; + + return pullImageIfNeeded() + .then(stopContainerIfNeeded) + .then(renameContainer) + .then(setMainNetworkAndCreateContainer) + .then(connectContainerToOtherNetworks) + .then(startContainerIfNeeded) + .then(createResourceControl) + .then(deleteOldContainer) + .then(notifyAndChangeView) + .catch(notifyOnError); + + function stopContainerIfNeeded() { + if (!isRunning) { + return $q.when(); } - ); - } - - function startContainerIfNeeded(newContainer) { - if (!isRunning) { - return $q.when(newContainer); + return ContainerService.stopContainer(container.Id); } - return ContainerService.startContainer(newContainer.Id).then( - function onStartSuccess() { - return newContainer; + + function renameContainer() { + return ContainerService.renameContainer(container.Id, container.Name + '-old'); + } + + function pullImageIfNeeded() { + if (!pullImage) { + return $q.when(); } - ); - } - - function createResourceControl(newContainer) { - const userId = Authentication.getUserDetails().ID; - const oldResourceControl = container.ResourceControl; - const newResourceControl = newContainer.Portainer.ResourceControl; - return ResourceControlService.duplicateResourceControl(userId, oldResourceControl, newResourceControl); - } - - function notifyAndChangeView() { - Notifications.success('Container successfully re-created'); - $state.go('docker.containers', {}, { reload: true }); - } - - function notifyOnError(err) { - Notifications.error('Failure', err, 'Unable to re-create container'); - $scope.state.recreateContainerInProgress = false; - } - } - - $scope.recreate = function() { - ModalService.confirmContainerRecreation(function (result) { - if(!result) { return; } - var pullImage = false; - if (result[0]) { - pullImage = true; + return RegistryService.retrievePorRegistryModelFromRepository(container.Config.Image).then(function pullImage(registryModel) { + return ImageService.pullImage(registryModel, true); + }); } - recreateContainer(pullImage); - }); - }; - function updateRestartPolicy(restartPolicy, maximumRetryCount) { - maximumRetryCount = restartPolicy === 'on-failure' ? maximumRetryCount : undefined; + function setMainNetworkAndCreateContainer() { + var networks = config.NetworkingConfig.EndpointsConfig; + var networksNames = Object.keys(networks); + if (networksNames.length > 1) { + config.NetworkingConfig.EndpointsConfig = {}; + config.NetworkingConfig.EndpointsConfig[networksNames[0]] = networks[0]; + } + return $q.all([ContainerService.createContainer(config), networks]); + } - return ContainerService - .updateRestartPolicy($scope.container.Id, restartPolicy, maximumRetryCount) - .then(onUpdateSuccess) - .catch(notifyOnError); + function connectContainerToOtherNetworks(createContainerData) { + var newContainer = createContainerData[0]; + var networks = createContainerData[1]; + var networksNames = Object.keys(networks); + var connectionPromises = networksNames.map(function connectToNetwork(name) { + NetworkService.connectContainer(name, newContainer.Id); + }); + return $q.all(connectionPromises).then(function onConnectToNetworkSuccess() { + return newContainer; + }); + } - function onUpdateSuccess() { - $scope.container.HostConfig.RestartPolicy = { - Name: restartPolicy, - MaximumRetryCount: maximumRetryCount - }; - Notifications.success('Restart policy updated'); + function deleteOldContainer(newContainer) { + return ContainerService.remove(container, true).then(function onRemoveSuccess() { + return newContainer; + }); + } + + function startContainerIfNeeded(newContainer) { + if (!isRunning) { + return $q.when(newContainer); + } + return ContainerService.startContainer(newContainer.Id).then(function onStartSuccess() { + return newContainer; + }); + } + + function createResourceControl(newContainer) { + const userId = Authentication.getUserDetails().ID; + const oldResourceControl = container.ResourceControl; + const newResourceControl = newContainer.Portainer.ResourceControl; + return ResourceControlService.duplicateResourceControl(userId, oldResourceControl, newResourceControl); + } + + function notifyAndChangeView() { + Notifications.success('Container successfully re-created'); + $state.go('docker.containers', {}, { reload: true }); + } + + function notifyOnError(err) { + Notifications.error('Failure', err, 'Unable to re-create container'); + $scope.state.recreateContainerInProgress = false; + } } - function notifyOnError(err) { - Notifications.error('Failure', err, 'Unable to update restart policy'); - return $q.reject(err); + $scope.recreate = function () { + ModalService.confirmContainerRecreation(function (result) { + if (!result) { + return; + } + var pullImage = false; + if (result[0]) { + pullImage = true; + } + recreateContainer(pullImage); + }); + }; + + function updateRestartPolicy(restartPolicy, maximumRetryCount) { + maximumRetryCount = restartPolicy === 'on-failure' ? maximumRetryCount : undefined; + + return ContainerService.updateRestartPolicy($scope.container.Id, restartPolicy, maximumRetryCount).then(onUpdateSuccess).catch(notifyOnError); + + function onUpdateSuccess() { + $scope.container.HostConfig.RestartPolicy = { + Name: restartPolicy, + MaximumRetryCount: maximumRetryCount, + }; + Notifications.success('Restart policy updated'); + } + + function notifyOnError(err) { + Notifications.error('Failure', err, 'Unable to update restart policy'); + return $q.reject(err); + } } - } - var provider = $scope.applicationState.endpoint.mode.provider; - var apiVersion = $scope.applicationState.endpoint.apiVersion; - NetworkService.networks( - provider === 'DOCKER_STANDALONE' || provider === 'DOCKER_SWARM_MODE', - false, - provider === 'DOCKER_SWARM_MODE' && apiVersion >= 1.25 - ) - .then(function success(data) { - var networks = data; - $scope.availableNetworks = networks; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve networks'); - }); + var provider = $scope.applicationState.endpoint.mode.provider; + var apiVersion = $scope.applicationState.endpoint.apiVersion; + NetworkService.networks(provider === 'DOCKER_STANDALONE' || provider === 'DOCKER_SWARM_MODE', false, provider === 'DOCKER_SWARM_MODE' && apiVersion >= 1.25) + .then(function success(data) { + var networks = data; + $scope.availableNetworks = networks; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve networks'); + }); - update(); -}]); + update(); + }, +]); diff --git a/app/docker/views/containers/inspect/containerInspectController.js b/app/docker/views/containers/inspect/containerInspectController.js index 458a0e6a4..823f9d2b6 100644 --- a/app/docker/views/containers/inspect/containerInspectController.js +++ b/app/docker/views/containers/inspect/containerInspectController.js @@ -1,22 +1,26 @@ -angular.module('portainer.docker') -.controller('ContainerInspectController', ['$scope', '$transition$', 'Notifications', 'ContainerService', 'HttpRequestHelper', -function ($scope, $transition$, Notifications, ContainerService, HttpRequestHelper) { +angular.module('portainer.docker').controller('ContainerInspectController', [ + '$scope', + '$transition$', + 'Notifications', + 'ContainerService', + 'HttpRequestHelper', + function ($scope, $transition$, Notifications, ContainerService, HttpRequestHelper) { + $scope.state = { + DisplayTextView: false, + }; + $scope.containerInfo = {}; - $scope.state = { - DisplayTextView: false - }; - $scope.containerInfo = {}; + function initView() { + HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); + ContainerService.inspect($transition$.params().id) + .then(function success(d) { + $scope.containerInfo = d; + }) + .catch(function error(e) { + Notifications.error('Failure', e, 'Unable to inspect container'); + }); + } - function initView() { - HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); - ContainerService.inspect($transition$.params().id) - .then(function success(d) { - $scope.containerInfo = d; - }) - .catch(function error(e) { - Notifications.error('Failure', e, 'Unable to inspect container'); - }); - } - - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/containers/inspect/containerinspect.html b/app/docker/views/containers/inspect/containerinspect.html index b381ed2bb..def4954d5 100644 --- a/app/docker/views/containers/inspect/containerinspect.html +++ b/app/docker/views/containers/inspect/containerinspect.html @@ -1,8 +1,8 @@ - - + - Containers > {{ containerInfo.Name|trimcontainername }} > Inspect + Containers > {{ containerInfo.Name | trimcontainername }} > + Inspect @@ -16,7 +16,7 @@ -
{{ containerInfo|json:4 }}
+
{{ containerInfo | json: 4 }}
diff --git a/app/docker/views/containers/logs/containerLogsController.js b/app/docker/views/containers/logs/containerLogsController.js index 695bfd339..d6799a451 100644 --- a/app/docker/views/containers/logs/containerLogsController.js +++ b/app/docker/views/containers/logs/containerLogsController.js @@ -1,73 +1,87 @@ import moment from 'moment'; -angular.module('portainer.docker') -.controller('ContainerLogsController', ['$scope', '$transition$', '$interval', 'ContainerService', 'Notifications', 'HttpRequestHelper', -function ($scope, $transition$, $interval, ContainerService, Notifications, HttpRequestHelper) { - $scope.state = { - refreshRate: 3, - lineCount: 100, - sinceTimestamp: '', - displayTimestamps: false - }; +angular.module('portainer.docker').controller('ContainerLogsController', [ + '$scope', + '$transition$', + '$interval', + 'ContainerService', + 'Notifications', + 'HttpRequestHelper', + function ($scope, $transition$, $interval, ContainerService, Notifications, HttpRequestHelper) { + $scope.state = { + refreshRate: 3, + lineCount: 100, + sinceTimestamp: '', + displayTimestamps: false, + }; - $scope.changeLogCollection = function(logCollectionStatus) { - if (!logCollectionStatus) { - stopRepeater(); - } else { - setUpdateRepeater(!$scope.container.Config.Tty); - } - }; - - $scope.$on('$destroy', function() { - stopRepeater(); - }); - - function stopRepeater() { - var repeater = $scope.repeater; - if (angular.isDefined(repeater)) { - $interval.cancel(repeater); - repeater = null; - } - } - - function setUpdateRepeater(skipHeaders) { - var refreshRate = $scope.state.refreshRate; - $scope.repeater = $interval(function() { - ContainerService.logs($transition$.params().id, 1, 1, $scope.state.displayTimestamps ? 1 : 0, moment($scope.state.sinceTimestamp).unix(), $scope.state.lineCount, skipHeaders) - .then(function success(data) { - $scope.logs = data; - }) - .catch(function error(err) { + $scope.changeLogCollection = function (logCollectionStatus) { + if (!logCollectionStatus) { stopRepeater(); - Notifications.error('Failure', err, 'Unable to retrieve container logs'); - }); - }, refreshRate * 1000); - } + } else { + setUpdateRepeater(!$scope.container.Config.Tty); + } + }; - function startLogPolling(skipHeaders) { - ContainerService.logs($transition$.params().id, 1, 1, $scope.state.displayTimestamps ? 1 : 0, moment($scope.state.sinceTimestamp).unix(), $scope.state.lineCount, skipHeaders) - .then(function success(data) { - $scope.logs = data; - setUpdateRepeater(skipHeaders); - }) - .catch(function error(err) { + $scope.$on('$destroy', function () { stopRepeater(); - Notifications.error('Failure', err, 'Unable to retrieve container logs'); }); - } - function initView() { - HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); - ContainerService.container($transition$.params().id) - .then(function success(data) { - var container = data; - $scope.container = container; - startLogPolling(!container.Config.Tty); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve container information'); - }); - } + function stopRepeater() { + var repeater = $scope.repeater; + if (angular.isDefined(repeater)) { + $interval.cancel(repeater); + repeater = null; + } + } - initView(); -}]); + function setUpdateRepeater(skipHeaders) { + var refreshRate = $scope.state.refreshRate; + $scope.repeater = $interval(function () { + ContainerService.logs( + $transition$.params().id, + 1, + 1, + $scope.state.displayTimestamps ? 1 : 0, + moment($scope.state.sinceTimestamp).unix(), + $scope.state.lineCount, + skipHeaders + ) + .then(function success(data) { + $scope.logs = data; + }) + .catch(function error(err) { + stopRepeater(); + Notifications.error('Failure', err, 'Unable to retrieve container logs'); + }); + }, refreshRate * 1000); + } + + function startLogPolling(skipHeaders) { + ContainerService.logs($transition$.params().id, 1, 1, $scope.state.displayTimestamps ? 1 : 0, moment($scope.state.sinceTimestamp).unix(), $scope.state.lineCount, skipHeaders) + .then(function success(data) { + $scope.logs = data; + setUpdateRepeater(skipHeaders); + }) + .catch(function error(err) { + stopRepeater(); + Notifications.error('Failure', err, 'Unable to retrieve container logs'); + }); + } + + function initView() { + HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); + ContainerService.container($transition$.params().id) + .then(function success(data) { + var container = data; + $scope.container = container; + startLogPolling(!container.Config.Tty); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve container information'); + }); + } + + initView(); + }, +]); diff --git a/app/docker/views/containers/logs/containerlogs.html b/app/docker/views/containers/logs/containerlogs.html index 133e354c2..0cba93e8a 100644 --- a/app/docker/views/containers/logs/containerlogs.html +++ b/app/docker/views/containers/logs/containerlogs.html @@ -1,10 +1,15 @@ - Containers > {{ container.Name|trimcontainername }} > Logs + Containers > {{ container.Name | trimcontainername }} > Logs diff --git a/app/docker/views/containers/stats/containerStatsController.js b/app/docker/views/containers/stats/containerStatsController.js index a1c57c10c..9fef44e41 100644 --- a/app/docker/views/containers/stats/containerStatsController.js +++ b/app/docker/views/containers/stats/containerStatsController.js @@ -1,156 +1,163 @@ import moment from 'moment'; -angular.module('portainer.docker') -.controller('ContainerStatsController', ['$q', '$scope', '$transition$', '$document', '$interval', 'ContainerService', 'ChartService', 'Notifications', 'HttpRequestHelper', -function ($q, $scope, $transition$, $document, $interval, ContainerService, ChartService, Notifications, HttpRequestHelper) { +angular.module('portainer.docker').controller('ContainerStatsController', [ + '$q', + '$scope', + '$transition$', + '$document', + '$interval', + 'ContainerService', + 'ChartService', + 'Notifications', + 'HttpRequestHelper', + function ($q, $scope, $transition$, $document, $interval, ContainerService, ChartService, Notifications, HttpRequestHelper) { + $scope.state = { + refreshRate: '5', + networkStatsUnavailable: false, + }; - $scope.state = { - refreshRate: '5', - networkStatsUnavailable: false - }; + $scope.$on('$destroy', function () { + stopRepeater(); + }); - $scope.$on('$destroy', function() { - stopRepeater(); - }); - - function stopRepeater() { - var repeater = $scope.repeater; - if (angular.isDefined(repeater)) { - $interval.cancel(repeater); - repeater = null; + function stopRepeater() { + var repeater = $scope.repeater; + if (angular.isDefined(repeater)) { + $interval.cancel(repeater); + repeater = null; + } } - } - function updateNetworkChart(stats, chart) { - if (stats.Networks.length > 0) { - var rx = stats.Networks[0].rx_bytes; - var tx = stats.Networks[0].tx_bytes; + function updateNetworkChart(stats, chart) { + if (stats.Networks.length > 0) { + var rx = stats.Networks[0].rx_bytes; + var tx = stats.Networks[0].tx_bytes; + var label = moment(stats.read).format('HH:mm:ss'); + + ChartService.UpdateNetworkChart(label, rx, tx, chart); + } + } + + function updateMemoryChart(stats, chart) { var label = moment(stats.read).format('HH:mm:ss'); - ChartService.UpdateNetworkChart(label, rx, tx, chart); - } - } - - function updateMemoryChart(stats, chart) { - var label = moment(stats.read).format('HH:mm:ss'); - - ChartService.UpdateMemoryChart(label, stats.MemoryUsage, stats.MemoryCache, chart); - } - - function updateCPUChart(stats, chart) { - var label = moment(stats.read).format('HH:mm:ss'); - var value = stats.isWindows ? calculateCPUPercentWindows(stats) : calculateCPUPercentUnix(stats); - - ChartService.UpdateCPUChart(label, value, chart); - } - - function calculateCPUPercentUnix(stats) { - var cpuPercent = 0.0; - var cpuDelta = stats.CurrentCPUTotalUsage - stats.PreviousCPUTotalUsage; - var systemDelta = stats.CurrentCPUSystemUsage - stats.PreviousCPUSystemUsage; - - if (systemDelta > 0.0 && cpuDelta > 0.0) { - cpuPercent = (cpuDelta / systemDelta) * stats.CPUCores * 100.0; + ChartService.UpdateMemoryChart(label, stats.MemoryUsage, stats.MemoryCache, chart); } - return cpuPercent; - } + function updateCPUChart(stats, chart) { + var label = moment(stats.read).format('HH:mm:ss'); + var value = stats.isWindows ? calculateCPUPercentWindows(stats) : calculateCPUPercentUnix(stats); - function calculateCPUPercentWindows(stats) { - var possIntervals = stats.NumProcs * parseFloat( - moment(stats.read, 'YYYY-MM-DDTHH:mm:ss.SSSSSSSSSZ').valueOf() - moment(stats.preread, 'YYYY-MM-DDTHH:mm:ss.SSSSSSSSSZ').valueOf()); - var windowsCpuUsage = 0.0; - if(possIntervals > 0) { - windowsCpuUsage = parseFloat(stats.CurrentCPUTotalUsage - stats.PreviousCPUTotalUsage) / parseFloat(possIntervals * 100); + ChartService.UpdateCPUChart(label, value, chart); } - return windowsCpuUsage; - } + function calculateCPUPercentUnix(stats) { + var cpuPercent = 0.0; + var cpuDelta = stats.CurrentCPUTotalUsage - stats.PreviousCPUTotalUsage; + var systemDelta = stats.CurrentCPUSystemUsage - stats.PreviousCPUSystemUsage; - $scope.changeUpdateRepeater = function() { - var networkChart = $scope.networkChart; - var cpuChart = $scope.cpuChart; - var memoryChart = $scope.memoryChart; - - stopRepeater(); - setUpdateRepeater(networkChart, cpuChart, memoryChart); - $('#refreshRateChange').show(); - $('#refreshRateChange').fadeOut(1500); - }; - - function startChartUpdate(networkChart, cpuChart, memoryChart) { - $q.all({ - stats: ContainerService.containerStats($transition$.params().id), - top: ContainerService.containerTop($transition$.params().id) - }) - .then(function success(data) { - var stats = data.stats; - $scope.processInfo = data.top; - if (stats.Networks.length === 0) { - $scope.state.networkStatsUnavailable = true; + if (systemDelta > 0.0 && cpuDelta > 0.0) { + cpuPercent = (cpuDelta / systemDelta) * stats.CPUCores * 100.0; } - updateNetworkChart(stats, networkChart); - updateMemoryChart(stats, memoryChart); - updateCPUChart(stats, cpuChart); - setUpdateRepeater(networkChart, cpuChart, memoryChart); - }) - .catch(function error(err) { - stopRepeater(); - Notifications.error('Failure', err, 'Unable to retrieve container statistics'); - }); - } - function setUpdateRepeater(networkChart, cpuChart, memoryChart) { - var refreshRate = $scope.state.refreshRate; - $scope.repeater = $interval(function() { + return cpuPercent; + } + + function calculateCPUPercentWindows(stats) { + var possIntervals = + stats.NumProcs * parseFloat(moment(stats.read, 'YYYY-MM-DDTHH:mm:ss.SSSSSSSSSZ').valueOf() - moment(stats.preread, 'YYYY-MM-DDTHH:mm:ss.SSSSSSSSSZ').valueOf()); + var windowsCpuUsage = 0.0; + if (possIntervals > 0) { + windowsCpuUsage = parseFloat(stats.CurrentCPUTotalUsage - stats.PreviousCPUTotalUsage) / parseFloat(possIntervals * 100); + } + return windowsCpuUsage; + } + + $scope.changeUpdateRepeater = function () { + var networkChart = $scope.networkChart; + var cpuChart = $scope.cpuChart; + var memoryChart = $scope.memoryChart; + + stopRepeater(); + setUpdateRepeater(networkChart, cpuChart, memoryChart); + $('#refreshRateChange').show(); + $('#refreshRateChange').fadeOut(1500); + }; + + function startChartUpdate(networkChart, cpuChart, memoryChart) { $q.all({ stats: ContainerService.containerStats($transition$.params().id), - top: ContainerService.containerTop($transition$.params().id) + top: ContainerService.containerTop($transition$.params().id), }) - .then(function success(data) { - var stats = data.stats; - $scope.processInfo = data.top; - updateNetworkChart(stats, networkChart); - updateMemoryChart(stats, memoryChart); - updateCPUChart(stats, cpuChart); - }) - .catch(function error(err) { - stopRepeater(); - Notifications.error('Failure', err, 'Unable to retrieve container statistics'); + .then(function success(data) { + var stats = data.stats; + $scope.processInfo = data.top; + if (stats.Networks.length === 0) { + $scope.state.networkStatsUnavailable = true; + } + updateNetworkChart(stats, networkChart); + updateMemoryChart(stats, memoryChart); + updateCPUChart(stats, cpuChart); + setUpdateRepeater(networkChart, cpuChart, memoryChart); + }) + .catch(function error(err) { + stopRepeater(); + Notifications.error('Failure', err, 'Unable to retrieve container statistics'); + }); + } + + function setUpdateRepeater(networkChart, cpuChart, memoryChart) { + var refreshRate = $scope.state.refreshRate; + $scope.repeater = $interval(function () { + $q.all({ + stats: ContainerService.containerStats($transition$.params().id), + top: ContainerService.containerTop($transition$.params().id), + }) + .then(function success(data) { + var stats = data.stats; + $scope.processInfo = data.top; + updateNetworkChart(stats, networkChart); + updateMemoryChart(stats, memoryChart); + updateCPUChart(stats, cpuChart); + }) + .catch(function error(err) { + stopRepeater(); + Notifications.error('Failure', err, 'Unable to retrieve container statistics'); + }); + }, refreshRate * 1000); + } + + function initCharts() { + var networkChartCtx = $('#networkChart'); + var networkChart = ChartService.CreateNetworkChart(networkChartCtx); + $scope.networkChart = networkChart; + + var cpuChartCtx = $('#cpuChart'); + var cpuChart = ChartService.CreateCPUChart(cpuChartCtx); + $scope.cpuChart = cpuChart; + + var memoryChartCtx = $('#memoryChart'); + var memoryChart = ChartService.CreateMemoryChart(memoryChartCtx); + $scope.memoryChart = memoryChart; + + startChartUpdate(networkChart, cpuChart, memoryChart); + } + + function initView() { + HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); + ContainerService.container($transition$.params().id) + .then(function success(data) { + $scope.container = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve container information'); + }); + + $document.ready(function () { + initCharts(); }); - }, refreshRate * 1000); - } + } - function initCharts() { - var networkChartCtx = $('#networkChart'); - var networkChart = ChartService.CreateNetworkChart(networkChartCtx); - $scope.networkChart = networkChart; - - var cpuChartCtx = $('#cpuChart'); - var cpuChart = ChartService.CreateCPUChart(cpuChartCtx); - $scope.cpuChart = cpuChart; - - var memoryChartCtx = $('#memoryChart'); - var memoryChart = ChartService.CreateMemoryChart(memoryChartCtx); - $scope.memoryChart = memoryChart; - - startChartUpdate(networkChart, cpuChart, memoryChart); - } - - function initView() { - HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); - ContainerService.container($transition$.params().id) - .then(function success(data) { - $scope.container = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve container information'); - }); - - $document.ready(function() { - initCharts(); - }); - } - - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/containers/stats/containerstats.html b/app/docker/views/containers/stats/containerstats.html index a14def6e2..c4d800b9a 100644 --- a/app/docker/views/containers/stats/containerstats.html +++ b/app/docker/views/containers/stats/containerstats.html @@ -1,22 +1,21 @@ - Containers > {{ container.Name|trimcontainername }} > Stats + Containers > {{ container.Name | trimcontainername }} > Stats
- - +
- This view displays real-time statistics about the container {{ container.Name|trimcontainername }} as well as a list of the running processes - inside this container. + This view displays real-time statistics about the container {{ container.Name | trimcontainername }} as well as a list of the running processes inside this + container.
@@ -40,9 +39,7 @@
- - Network stats are unavailable for this container. - + Network stats are unavailable for this container.
@@ -52,7 +49,7 @@
-
+
@@ -62,7 +59,7 @@
-
+
@@ -85,9 +82,11 @@
diff --git a/app/docker/views/dashboard/dashboard.html b/app/docker/views/dashboard/dashboard.html index b40e9bc62..59c6e44d2 100644 --- a/app/docker/views/dashboard/dashboard.html +++ b/app/docker/views/dashboard/dashboard.html @@ -10,14 +10,19 @@
+ dismiss-action="dismissInformationPanel('docker-dashboard-info-01')" +>

- Portainer is connected to a node that is part of a Swarm cluster. Some resources located on other nodes in the cluster might not be available for management, have a look - at our agent setup for more details. + Portainer is connected to a node that is part of a Swarm cluster. Some resources located on other nodes in the cluster might not be available for management, have a look at + our agent setup for more details.

@@ -38,10 +43,12 @@ {{ endpoint.Name }} - {{ endpoint.Snapshots[0].TotalCPU }} - {{ endpoint.Snapshots[0].TotalMemory | humansize }} + {{ endpoint.Snapshots[0].TotalCPU }} {{ endpoint.Snapshots[0].TotalMemory | humansize }} - - {{ info.Swarm && info.Swarm.NodeID !== '' ? 'Swarm' : 'Standalone' }} {{ info.ServerVersion }} + Agent + + - {{ info.Swarm && info.Swarm.NodeID !== '' ? 'Swarm' : 'Standalone' }} {{ info.ServerVersion }} + + Agent @@ -55,9 +62,7 @@ - - - {{ tag }}{{ $last? '' : ', ' }} - + {{ tag }}{{ $last ? '' : ', ' }} @@ -109,7 +114,7 @@

-
+
{{ containers | runningcontainers }} running
{{ containers | stoppedcontainers }} stopped
diff --git a/app/docker/views/dashboard/dashboardController.js b/app/docker/views/dashboard/dashboardController.js index 5f1efa332..9a83cdf4e 100644 --- a/app/docker/views/dashboard/dashboardController.js +++ b/app/docker/views/dashboard/dashboardController.js @@ -1,42 +1,68 @@ -angular.module('portainer.docker') -.controller('DashboardController', ['$scope', '$q', 'ContainerService', 'ImageService', 'NetworkService', 'VolumeService', 'SystemService', 'ServiceService', 'StackService', 'EndpointService', 'Notifications', 'EndpointProvider', 'StateManager', -function ($scope, $q, ContainerService, ImageService, NetworkService, VolumeService, SystemService, ServiceService, StackService, EndpointService, Notifications, EndpointProvider, StateManager) { +angular.module('portainer.docker').controller('DashboardController', [ + '$scope', + '$q', + 'ContainerService', + 'ImageService', + 'NetworkService', + 'VolumeService', + 'SystemService', + 'ServiceService', + 'StackService', + 'EndpointService', + 'Notifications', + 'EndpointProvider', + 'StateManager', + function ( + $scope, + $q, + ContainerService, + ImageService, + NetworkService, + VolumeService, + SystemService, + ServiceService, + StackService, + EndpointService, + Notifications, + EndpointProvider, + StateManager + ) { + $scope.dismissInformationPanel = function (id) { + StateManager.dismissInformationPanel(id); + }; - $scope.dismissInformationPanel = function(id) { - StateManager.dismissInformationPanel(id); - }; + $scope.offlineMode = false; - $scope.offlineMode = false; + function initView() { + var endpointMode = $scope.applicationState.endpoint.mode; + var endpointId = EndpointProvider.endpointID(); - function initView() { - var endpointMode = $scope.applicationState.endpoint.mode; - var endpointId = EndpointProvider.endpointID(); + $q.all({ + containers: ContainerService.containers(1), + images: ImageService.images(false), + volumes: VolumeService.volumes(), + networks: NetworkService.networks(true, true, true), + services: endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER' ? ServiceService.services() : [], + stacks: StackService.stacks(true, endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER', endpointId), + info: SystemService.info(), + endpoint: EndpointService.endpoint(endpointId), + }) + .then(function success(data) { + $scope.containers = data.containers; + $scope.images = data.images; + $scope.volumeCount = data.volumes.length; + $scope.networkCount = data.networks.length; + $scope.serviceCount = data.services.length; + $scope.stackCount = data.stacks.length; + $scope.info = data.info; + $scope.endpoint = data.endpoint; + $scope.offlineMode = EndpointProvider.offlineMode(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to load dashboard data'); + }); + } - $q.all({ - containers: ContainerService.containers(1), - images: ImageService.images(false), - volumes: VolumeService.volumes(), - networks: NetworkService.networks(true, true, true), - services: endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER' ? ServiceService.services() : [], - stacks: StackService.stacks(true, endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER', endpointId), - info: SystemService.info(), - endpoint: EndpointService.endpoint(endpointId) - }) - .then(function success(data) { - $scope.containers = data.containers; - $scope.images = data.images; - $scope.volumeCount = data.volumes.length; - $scope.networkCount = data.networks.length; - $scope.serviceCount = data.services.length; - $scope.stackCount = data.stacks.length; - $scope.info = data.info; - $scope.endpoint = data.endpoint; - $scope.offlineMode = EndpointProvider.offlineMode(); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to load dashboard data'); - }); - } - - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/events/events.html b/app/docker/views/events/events.html index d67e3fc44..98caa58da 100644 --- a/app/docker/views/events/events.html +++ b/app/docker/views/events/events.html @@ -9,11 +9,6 @@
- +
diff --git a/app/docker/views/events/eventsController.js b/app/docker/views/events/eventsController.js index f0d0ef68f..8affeaf84 100644 --- a/app/docker/views/events/eventsController.js +++ b/app/docker/views/events/eventsController.js @@ -1,21 +1,23 @@ import moment from 'moment'; -angular.module('portainer.docker') -.controller('EventsController', ['$scope', 'Notifications', 'SystemService', -function ($scope, Notifications, SystemService) { +angular.module('portainer.docker').controller('EventsController', [ + '$scope', + 'Notifications', + 'SystemService', + function ($scope, Notifications, SystemService) { + function initView() { + var from = moment().subtract(24, 'hour').unix(); + var to = moment().unix(); - function initView() { - var from = moment().subtract(24, 'hour').unix(); - var to = moment().unix(); + SystemService.events(from, to) + .then(function success(data) { + $scope.events = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to load events'); + }); + } - SystemService.events(from, to) - .then(function success(data) { - $scope.events = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to load events'); - }); - } - - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/host/host-browser-view/host-browser-view-controller.js b/app/docker/views/host/host-browser-view/host-browser-view-controller.js index 3f45fcc48..4024fd152 100644 --- a/app/docker/views/host/host-browser-view/host-browser-view-controller.js +++ b/app/docker/views/host/host-browser-view/host-browser-view-controller.js @@ -1,17 +1,18 @@ angular.module('portainer.docker').controller('HostBrowserViewController', [ - 'SystemService', 'Notifications', + 'SystemService', + 'Notifications', function HostBrowserViewController(SystemService, Notifications) { var ctrl = this; ctrl.$onInit = $onInit; function $onInit() { SystemService.info() - .then(function onInfoLoaded(host) { - ctrl.host = host; - }) - .catch(function onError(err) { - Notifications.error('Unable to retrieve host information', err); - }); + .then(function onInfoLoaded(host) { + ctrl.host = host; + }) + .catch(function onError(err) { + Notifications.error('Unable to retrieve host information', err); + }); } - } + }, ]); diff --git a/app/docker/views/host/host-browser-view/host-browser-view.html b/app/docker/views/host/host-browser-view/host-browser-view.html index 2d87e4b2e..b8836c773 100644 --- a/app/docker/views/host/host-browser-view/host-browser-view.html +++ b/app/docker/views/host/host-browser-view/host-browser-view.html @@ -1,14 +1,12 @@ - Host > {{ $ctrl.host.Name }} > browse + Host > {{ $ctrl.host.Name }} > browse
- +
diff --git a/app/docker/views/host/host-browser-view/host-browser-view.js b/app/docker/views/host/host-browser-view/host-browser-view.js index 8d2bd1a20..4887dece2 100644 --- a/app/docker/views/host/host-browser-view/host-browser-view.js +++ b/app/docker/views/host/host-browser-view/host-browser-view.js @@ -1,4 +1,4 @@ angular.module('portainer.docker').component('hostBrowserView', { templateUrl: './host-browser-view.html', - controller: 'HostBrowserViewController' + controller: 'HostBrowserViewController', }); diff --git a/app/docker/views/host/host-job/host-job-controller.js b/app/docker/views/host/host-job/host-job-controller.js index 811509f7b..9e34700c4 100644 --- a/app/docker/views/host/host-job/host-job-controller.js +++ b/app/docker/views/host/host-job/host-job-controller.js @@ -1,17 +1,18 @@ angular.module('portainer.docker').controller('HostJobController', [ - 'SystemService', 'Notifications', + 'SystemService', + 'Notifications', function HostJobController(SystemService, Notifications) { var ctrl = this; ctrl.$onInit = $onInit; function $onInit() { SystemService.info() - .then(function onInfoLoaded(host) { - ctrl.host = host; - }) - .catch(function onError(err) { - Notifications.error('Unable to retrieve host information', err); - }); + .then(function onInfoLoaded(host) { + ctrl.host = host; + }) + .catch(function onError(err) { + Notifications.error('Unable to retrieve host information', err); + }); } - } + }, ]); diff --git a/app/docker/views/host/host-job/host-job.js b/app/docker/views/host/host-job/host-job.js index 2436075ec..c7959a63c 100644 --- a/app/docker/views/host/host-job/host-job.js +++ b/app/docker/views/host/host-job/host-job.js @@ -1,4 +1,4 @@ angular.module('portainer.docker').component('hostJobView', { templateUrl: './host-job.html', - controller: 'HostJobController' + controller: 'HostJobController', }); diff --git a/app/docker/views/host/host-view-controller.js b/app/docker/views/host/host-view-controller.js index 2bc6421b2..ebb5a6975 100644 --- a/app/docker/views/host/host-view-controller.js +++ b/app/docker/views/host/host-view-controller.js @@ -1,5 +1,12 @@ angular.module('portainer.docker').controller('HostViewController', [ - '$q', 'SystemService', 'Notifications', 'StateManager', 'AgentService', 'ContainerService', 'Authentication', 'EndpointProvider', + '$q', + 'SystemService', + 'Notifications', + 'StateManager', + 'AgentService', + 'ContainerService', + 'Authentication', + 'EndpointProvider', function HostViewController($q, SystemService, Notifications, StateManager, AgentService, ContainerService, Authentication, EndpointProvider) { var ctrl = this; @@ -7,8 +14,8 @@ angular.module('portainer.docker').controller('HostViewController', [ ctrl.state = { isAgent: false, - isAdmin : false, - offlineMode: false + isAdmin: false, + offlineMode: false, }; this.engineDetails = {}; @@ -27,28 +34,24 @@ angular.module('portainer.docker').controller('HostViewController', [ $q.all({ version: SystemService.version(), info: SystemService.info(), - jobs: ctrl.state.isAdmin ? ContainerService.containers(true, { label: ['io.portainer.job.endpoint'] }) : [] + jobs: ctrl.state.isAdmin ? ContainerService.containers(true, { label: ['io.portainer.job.endpoint'] }) : [], }) - .then(function success(data) { - ctrl.engineDetails = buildEngineDetails(data); - ctrl.hostDetails = buildHostDetails(data.info); - ctrl.state.offlineMode = EndpointProvider.offlineMode(); - ctrl.jobs = data.jobs; + .then(function success(data) { + ctrl.engineDetails = buildEngineDetails(data); + ctrl.hostDetails = buildHostDetails(data.info); + ctrl.state.offlineMode = EndpointProvider.offlineMode(); + ctrl.jobs = data.jobs; - if (ctrl.state.isAgent && agentApiVersion > 1) { - return AgentService.hostInfo(data.info.Hostname).then(function onHostInfoLoad(agentHostInfo) { - ctrl.devices = agentHostInfo.PCIDevices; - ctrl.disks = agentHostInfo.PhysicalDisks; - }); - } - }) - .catch(function error(err) { - Notifications.error( - 'Failure', - err, - 'Unable to retrieve engine details' - ); - }); + if (ctrl.state.isAgent && agentApiVersion > 1) { + return AgentService.hostInfo(data.info.Hostname).then(function onHostInfoLoad(agentHostInfo) { + ctrl.devices = agentHostInfo.PCIDevices; + ctrl.disks = agentHostInfo.PhysicalDisks; + }); + } + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve engine details'); + }); } function buildEngineDetails(data) { @@ -61,7 +64,7 @@ angular.module('portainer.docker').controller('HostViewController', [ storageDriver: info.Driver, loggingDriver: info.LoggingDriver, volumePlugins: info.Plugins.Volume, - networkPlugins: info.Plugins.Network + networkPlugins: info.Plugins.Network, }; } @@ -70,13 +73,13 @@ angular.module('portainer.docker').controller('HostViewController', [ os: { arch: info.Architecture, type: info.OSType, - name: info.OperatingSystem + name: info.OperatingSystem, }, name: info.Name, kernelVersion: info.KernelVersion, totalCPU: info.NCPU, - totalMemory: info.MemTotal + totalMemory: info.MemTotal, }; } - } + }, ]); diff --git a/app/docker/views/host/host-view.js b/app/docker/views/host/host-view.js index d6171c666..eec3d03e5 100644 --- a/app/docker/views/host/host-view.js +++ b/app/docker/views/host/host-view.js @@ -1,4 +1,4 @@ angular.module('portainer.docker').component('hostView', { templateUrl: './host-view.html', - controller: 'HostViewController' + controller: 'HostViewController', }); diff --git a/app/docker/views/images/build/buildImageController.js b/app/docker/views/images/build/buildImageController.js index 5f4aec623..0503642ff 100644 --- a/app/docker/views/images/build/buildImageController.js +++ b/app/docker/views/images/build/buildImageController.js @@ -1,94 +1,98 @@ -angular.module('portainer.docker') -.controller('BuildImageController', ['$scope', '$state', 'BuildService', 'Notifications', 'HttpRequestHelper', -function ($scope, $state, BuildService, Notifications, HttpRequestHelper) { +angular.module('portainer.docker').controller('BuildImageController', [ + '$scope', + '$state', + 'BuildService', + 'Notifications', + 'HttpRequestHelper', + function ($scope, $state, BuildService, Notifications, HttpRequestHelper) { + $scope.state = { + BuildType: 'editor', + actionInProgress: false, + activeTab: 0, + }; - $scope.state = { - BuildType: 'editor', - actionInProgress: false, - activeTab: 0 - }; + $scope.formValues = { + ImageNames: [{ Name: '' }], + UploadFile: null, + DockerFileContent: '', + URL: '', + Path: 'Dockerfile', + NodeName: null, + }; - $scope.formValues = { - ImageNames: [{ Name: '' }], - UploadFile: null, - DockerFileContent: '', - URL: '', - Path: 'Dockerfile', - NodeName: null - }; + $scope.addImageName = function () { + $scope.formValues.ImageNames.push({ Name: '' }); + }; - $scope.addImageName = function() { - $scope.formValues.ImageNames.push({ Name: '' }); - }; + $scope.removeImageName = function (index) { + $scope.formValues.ImageNames.splice(index, 1); + }; - $scope.removeImageName = function(index) { - $scope.formValues.ImageNames.splice(index, 1); - }; + function buildImageBasedOnBuildType(method, names) { + var buildType = $scope.state.BuildType; + var dockerfilePath = $scope.formValues.Path; - function buildImageBasedOnBuildType(method, names) { - var buildType = $scope.state.BuildType; - var dockerfilePath = $scope.formValues.Path; + if (buildType === 'upload') { + var file = $scope.formValues.UploadFile; + return BuildService.buildImageFromUpload(names, file, dockerfilePath); + } else if (buildType === 'url') { + var URL = $scope.formValues.URL; + return BuildService.buildImageFromURL(names, URL, dockerfilePath); + } else { + var dockerfileContent = $scope.formValues.DockerFileContent; + return BuildService.buildImageFromDockerfileContent(names, dockerfileContent); + } + } - if (buildType === 'upload') { - var file = $scope.formValues.UploadFile; - return BuildService.buildImageFromUpload(names, file, dockerfilePath); - } else if (buildType === 'url') { - var URL = $scope.formValues.URL; - return BuildService.buildImageFromURL(names, URL, dockerfilePath); - } else { - var dockerfileContent = $scope.formValues.DockerFileContent; - return BuildService.buildImageFromDockerfileContent(names, dockerfileContent); - } - } + $scope.buildImage = function () { + var buildType = $scope.state.BuildType; - $scope.buildImage = function() { - var buildType = $scope.state.BuildType; + if (buildType === 'editor' && $scope.formValues.DockerFileContent === '') { + $scope.state.formValidationError = 'Dockerfile content must not be empty'; + return; + } - if (buildType === 'editor' && $scope.formValues.DockerFileContent === '') { - $scope.state.formValidationError = 'Dockerfile content must not be empty'; - return; - } + $scope.state.actionInProgress = true; - $scope.state.actionInProgress = true; + var imageNames = $scope.formValues.ImageNames.filter(function filterNull(x) { + return x.Name; + }).map(function getNames(x) { + return x.Name; + }); - var imageNames = $scope.formValues.ImageNames.filter(function filterNull(x) { - return x.Name; - }).map(function getNames(x) { - return x.Name; - }); + var nodeName = $scope.formValues.NodeName; + HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); - var nodeName = $scope.formValues.NodeName; - HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); + buildImageBasedOnBuildType(buildType, imageNames) + .then(function success(data) { + $scope.buildLogs = data.buildLogs; + $scope.state.activeTab = 1; + if (data.hasError) { + Notifications.error('An error occured during build', { msg: 'Please check build logs output' }); + } else { + Notifications.success('Image successfully built'); + } + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to build image'); + }) + .finally(function final() { + $scope.state.actionInProgress = false; + }); + }; - buildImageBasedOnBuildType(buildType, imageNames) - .then(function success(data) { - $scope.buildLogs = data.buildLogs; - $scope.state.activeTab = 1; - if (data.hasError) { - Notifications.error('An error occured during build', { msg: 'Please check build logs output' }); - } else { - Notifications.success('Image successfully built'); - } - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to build image'); - }) - .finally(function final() { - $scope.state.actionInProgress = false; - }); - }; + $scope.validImageNames = function () { + for (var i = 0; i < $scope.formValues.ImageNames.length; i++) { + var item = $scope.formValues.ImageNames[i]; + if (item.Name !== '') { + return true; + } + } + return false; + }; - $scope.validImageNames = function() { - for (var i = 0; i < $scope.formValues.ImageNames.length; i++) { - var item = $scope.formValues.ImageNames[i]; - if (item.Name !== '') { - return true; - } - } - return false; - }; - - $scope.editorUpdate = function(cm) { - $scope.formValues.DockerFileContent = cm.getValue(); - }; -}]); + $scope.editorUpdate = function (cm) { + $scope.formValues.DockerFileContent = cm.getValue(); + }; + }, +]); diff --git a/app/docker/views/images/build/buildimage.html b/app/docker/views/images/build/buildimage.html index 7820c4b9b..2bde8f32a 100644 --- a/app/docker/views/images/build/buildimage.html +++ b/app/docker/views/images/build/buildimage.html @@ -1,8 +1,6 @@ - - Images > Build image - + Images > Build image
@@ -11,9 +9,7 @@ - - Builder - + Builder
Naming @@ -42,18 +38,21 @@
- A name must be specified in one of the following formats: name:tag, repository/name:tag or registryfqdn:port/repository/name:tag format. If you omit the tag the default latest value is assumed. + A name must be specified in one of the following formats: name:tag, repository/name:tag or + registryfqdn:port/repository/name:tag format. If you omit the tag the default latest value is assumed.
-
+
name - - + +
@@ -74,10 +73,10 @@ Build method
-
+
- +
- Specify the URL to a Dockerfile, a tarball or a public Git repository (suffixed by .git). When using a tarball or a Git repository URL, the root folder will be used as the build context. + Specify the URL to a Dockerfile, a tarball or a public Git repository (suffixed by .git). When using a tarball or a Git repository URL, the root folder + will be used as the build context.
- +
@@ -189,7 +191,7 @@
- +
@@ -199,9 +201,7 @@ Deployment
- - +
@@ -210,12 +210,16 @@
- @@ -226,9 +230,7 @@ - - Output - + Output
               

{{ line }}

No build output available.

diff --git a/app/docker/views/images/edit/image.html b/app/docker/views/images/edit/image.html index 5dcc3ba26..ba3de195a 100644 --- a/app/docker/views/images/edit/image.html +++ b/app/docker/views/images/edit/image.html @@ -1,4 +1,4 @@ - + Images > {{ image.Id }} @@ -13,8 +13,8 @@
-
-
+
+
{{ tag }} @@ -34,9 +34,9 @@
- Note: you can click on the upload icon to push an image - or on the download icon to pull an image - or on the trash icon to delete a tag. + Note: you can click on the upload icon to push an image or on the download icon + to pull an image or on the trash icon to delete a + tag.
@@ -63,10 +63,7 @@ - +
@@ -97,29 +94,39 @@ ID {{ image.Id }} - - + Parent - {{ image.Parent }} + {{ image.Parent }} Size - {{ image.VirtualSize|humansize }} + {{ image.VirtualSize | humansize }} Created - {{ image.Created|getisodate }} + {{ image.Created | getisodate }} Build - Docker {{ image.DockerVersion }} on {{ image.Os}}, {{ image.Architecture }} + Docker {{ image.DockerVersion }} on {{ image.Os }}, {{ image.Architecture }} Author @@ -141,11 +148,15 @@ CMD - {{ image.Command|command }} + {{ image.Command | command }} ENTRYPOINT - {{ image.Entrypoint|command }} + {{ image.Entrypoint | command }} EXPOSE @@ -179,7 +190,6 @@
-
@@ -188,7 +198,7 @@ - - - @@ -56,7 +58,8 @@ resource-id="network.Id" resource-control="network.ResourceControl" resource-type="'network'" - disable-ownership-change="isSystemNetwork()"> + disable-ownership-change="isSystemNetwork()" +> @@ -78,7 +81,6 @@ -
@@ -94,12 +96,16 @@
- + diff --git a/app/docker/views/networks/edit/networkController.js b/app/docker/views/networks/edit/networkController.js index 294c76c5e..06431ad1a 100644 --- a/app/docker/views/networks/edit/networkController.js +++ b/app/docker/views/networks/edit/networkController.js @@ -1,96 +1,112 @@ -angular.module('portainer.docker') -.controller('NetworkController', ['$scope', '$state', '$transition$', '$filter', 'NetworkService', 'Container', 'Notifications', 'HttpRequestHelper', 'NetworkHelper', -function ($scope, $state, $transition$, $filter, NetworkService, Container, Notifications, HttpRequestHelper, NetworkHelper) { +angular.module('portainer.docker').controller('NetworkController', [ + '$scope', + '$state', + '$transition$', + '$filter', + 'NetworkService', + 'Container', + 'Notifications', + 'HttpRequestHelper', + 'NetworkHelper', + function ($scope, $state, $transition$, $filter, NetworkService, Container, Notifications, HttpRequestHelper, NetworkHelper) { + $scope.removeNetwork = function removeNetwork() { + NetworkService.remove($transition$.params().id, $transition$.params().id) + .then(function success() { + Notifications.success('Network removed', $transition$.params().id); + $state.go('docker.networks', {}); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove network'); + }); + }; - $scope.removeNetwork = function removeNetwork() { - NetworkService.remove($transition$.params().id, $transition$.params().id) - .then(function success() { - Notifications.success('Network removed', $transition$.params().id); - $state.go('docker.networks', {}); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove network'); - }); - }; + $scope.containerLeaveNetwork = function containerLeaveNetwork(network, container) { + HttpRequestHelper.setPortainerAgentTargetHeader(container.NodeName); + NetworkService.disconnectContainer($transition$.params().id, container.Id, false) + .then(function success() { + Notifications.success('Container left network', $transition$.params().id); + $state.go('docker.networks.network', { id: network.Id }, { reload: true }); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to disconnect container from network'); + }); + }; - $scope.containerLeaveNetwork = function containerLeaveNetwork(network, container) { - HttpRequestHelper.setPortainerAgentTargetHeader(container.NodeName); - NetworkService.disconnectContainer($transition$.params().id, container.Id, false) - .then(function success() { - Notifications.success('Container left network', $transition$.params().id); - $state.go('docker.networks.network', { id: network.Id }, { reload: true }); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to disconnect container from network'); - }); - }; + $scope.isSystemNetwork = function () { + return $scope.network && NetworkHelper.isSystemNetwork($scope.network); + }; - $scope.isSystemNetwork = function() { - return $scope.network && NetworkHelper.isSystemNetwork($scope.network); - } + $scope.allowRemove = function () { + return !$scope.isSystemNetwork(); + }; - $scope.allowRemove = function() { - return !$scope.isSystemNetwork(); - }; - - function filterContainersInNetwork(network, containers) { - var containersInNetwork = []; - containers.forEach(function(container) { - var containerInNetwork = network.Containers[container.Id]; - if (containerInNetwork) { - containerInNetwork.Id = container.Id; - // Name is not available in Docker 1.9 - if (!containerInNetwork.Name) { - containerInNetwork.Name = $filter('trimcontainername')(container.Names[0]); + function filterContainersInNetwork(network, containers) { + var containersInNetwork = []; + containers.forEach(function (container) { + var containerInNetwork = network.Containers[container.Id]; + if (containerInNetwork) { + containerInNetwork.Id = container.Id; + // Name is not available in Docker 1.9 + if (!containerInNetwork.Name) { + containerInNetwork.Name = $filter('trimcontainername')(container.Names[0]); + } + containersInNetwork.push(containerInNetwork); } - containersInNetwork.push(containerInNetwork); - } - }); - $scope.containersInNetwork = containersInNetwork; - } + }); + $scope.containersInNetwork = containersInNetwork; + } - function getContainersInNetwork(network) { - var apiVersion = $scope.applicationState.endpoint.apiVersion; - if (network.Containers) { - if (apiVersion < 1.24) { - Container.query({}, function success(data) { - var containersInNetwork = data.filter(function filter(container) { - if (container.HostConfig.NetworkMode === network.Name) { - return container; + function getContainersInNetwork(network) { + var apiVersion = $scope.applicationState.endpoint.apiVersion; + if (network.Containers) { + if (apiVersion < 1.24) { + Container.query( + {}, + function success(data) { + var containersInNetwork = data.filter(function filter(container) { + if (container.HostConfig.NetworkMode === network.Name) { + return container; + } + }); + filterContainersInNetwork(network, containersInNetwork); + }, + function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve containers in network'); } - }); - filterContainersInNetwork(network, containersInNetwork); - }, function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve containers in network'); - }); - } else { - Container.query({ - filters: { network: [$transition$.params().id] } - }, function success(data) { - filterContainersInNetwork(network, data); - }, function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve containers in network'); - }); + ); + } else { + Container.query( + { + filters: { network: [$transition$.params().id] }, + }, + function success(data) { + filterContainersInNetwork(network, data); + }, + function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve containers in network'); + } + ); + } } } - } - function initView() { - var nodeName = $transition$.params().nodeName; - HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); - $scope.nodeName = nodeName; - NetworkService.network($transition$.params().id) - .then(function success(data) { - $scope.network = data; - var endpointProvider = $scope.applicationState.endpoint.mode.provider; - if (endpointProvider !== 'VMWARE_VIC') { - getContainersInNetwork(data); - } - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve network info'); - }); - } + function initView() { + var nodeName = $transition$.params().nodeName; + HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); + $scope.nodeName = nodeName; + NetworkService.network($transition$.params().id) + .then(function success(data) { + $scope.network = data; + var endpointProvider = $scope.applicationState.endpoint.mode.provider; + if (endpointProvider !== 'VMWARE_VIC') { + getContainersInNetwork(data); + } + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve network info'); + }); + } - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/networks/networks.html b/app/docker/views/networks/networks.html index 497d95cde..737063089 100644 --- a/app/docker/views/networks/networks.html +++ b/app/docker/views/networks/networks.html @@ -10,14 +10,16 @@
diff --git a/app/docker/views/networks/networksController.js b/app/docker/views/networks/networksController.js index 6beb8da73..be66b64b9 100644 --- a/app/docker/views/networks/networksController.js +++ b/app/docker/views/networks/networksController.js @@ -1,80 +1,87 @@ import _ from 'lodash-es'; -angular.module('portainer.docker') -.controller('NetworksController', ['$q', '$scope', '$state', 'NetworkService', 'Notifications', 'HttpRequestHelper', 'EndpointProvider', 'AgentService', -function ($q, $scope, $state, NetworkService, Notifications, HttpRequestHelper, EndpointProvider, AgentService) { - - $scope.removeAction = function (selectedItems) { - var actionCount = selectedItems.length; - angular.forEach(selectedItems, function (network) { - HttpRequestHelper.setPortainerAgentTargetHeader(network.NodeName); - NetworkService.remove(network.Id) - .then(function success() { - Notifications.success('Network successfully removed', network.Name); - var index = $scope.networks.indexOf(network); - $scope.networks.splice(index, 1); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove network'); - }) - .finally(function final() { - --actionCount; - if (actionCount === 0) { - $state.reload(); - } +angular.module('portainer.docker').controller('NetworksController', [ + '$q', + '$scope', + '$state', + 'NetworkService', + 'Notifications', + 'HttpRequestHelper', + 'EndpointProvider', + 'AgentService', + function ($q, $scope, $state, NetworkService, Notifications, HttpRequestHelper, EndpointProvider, AgentService) { + $scope.removeAction = function (selectedItems) { + var actionCount = selectedItems.length; + angular.forEach(selectedItems, function (network) { + HttpRequestHelper.setPortainerAgentTargetHeader(network.NodeName); + NetworkService.remove(network.Id) + .then(function success() { + Notifications.success('Network successfully removed', network.Name); + var index = $scope.networks.indexOf(network); + $scope.networks.splice(index, 1); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove network'); + }) + .finally(function final() { + --actionCount; + if (actionCount === 0) { + $state.reload(); + } + }); }); - }); - }; - - $scope.offlineMode = false; - - $scope.getNetworks = getNetworks; - - function groupSwarmNetworksManagerNodesFirst(networks, agents) { - const getRole = (item) => _.find(agents, (agent) => agent.NodeName === item.NodeName).NodeRole; - - const nonSwarmNetworks = _.remove(networks, (item) => item.Scope !== 'swarm') - const grouped = _.toArray(_.groupBy(networks, (item) => item.Id)); - const sorted = _.map(grouped, (arr) => _.sortBy(arr, (item) => getRole(item))); - const arr = _.map(sorted, (a) => { - const item = a[0]; - for (let i = 1; i < a.length; i++) { - item.Subs.push(a[i]); - } - return item; - }); - const res = _.concat(arr, ...nonSwarmNetworks); - return res; - } - - function getNetworks() { - const req = { - networks: NetworkService.networks(true, true, true) }; - if ($scope.applicationState.endpoint.mode.agentProxy && $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') { - req.agents = AgentService.agents(); + $scope.offlineMode = false; + + $scope.getNetworks = getNetworks; + + function groupSwarmNetworksManagerNodesFirst(networks, agents) { + const getRole = (item) => _.find(agents, (agent) => agent.NodeName === item.NodeName).NodeRole; + + const nonSwarmNetworks = _.remove(networks, (item) => item.Scope !== 'swarm'); + const grouped = _.toArray(_.groupBy(networks, (item) => item.Id)); + const sorted = _.map(grouped, (arr) => _.sortBy(arr, (item) => getRole(item))); + const arr = _.map(sorted, (a) => { + const item = a[0]; + for (let i = 1; i < a.length; i++) { + item.Subs.push(a[i]); + } + return item; + }); + const res = _.concat(arr, ...nonSwarmNetworks); + return res; } - $q.all(req) - .then((data) => { - $scope.offlineMode = EndpointProvider.offlineMode(); - const networks = _.forEach(data.networks, (item) => item.Subs = []); + function getNetworks() { + const req = { + networks: NetworkService.networks(true, true, true), + }; + if ($scope.applicationState.endpoint.mode.agentProxy && $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') { - $scope.networks = groupSwarmNetworksManagerNodesFirst(data.networks, data.agents); - } else { - $scope.networks = networks; + req.agents = AgentService.agents(); } - }) - .catch((err) => { - $scope.networks = []; - Notifications.error('Failure', err, 'Unable to retrieve networks'); - }); - } - function initView() { - getNetworks(); - } + $q.all(req) + .then((data) => { + $scope.offlineMode = EndpointProvider.offlineMode(); + const networks = _.forEach(data.networks, (item) => (item.Subs = [])); + if ($scope.applicationState.endpoint.mode.agentProxy && $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') { + $scope.networks = groupSwarmNetworksManagerNodesFirst(data.networks, data.agents); + } else { + $scope.networks = networks; + } + }) + .catch((err) => { + $scope.networks = []; + Notifications.error('Failure', err, 'Unable to retrieve networks'); + }); + } - initView(); -}]); + function initView() { + getNetworks(); + } + + initView(); + }, +]); diff --git a/app/docker/views/nodes/node-browser/node-browser-controller.js b/app/docker/views/nodes/node-browser/node-browser-controller.js index 5c55c3e1b..e34fcef5a 100644 --- a/app/docker/views/nodes/node-browser/node-browser-controller.js +++ b/app/docker/views/nodes/node-browser/node-browser-controller.js @@ -1,5 +1,8 @@ angular.module('portainer.docker').controller('NodeBrowserController', [ - '$stateParams', 'NodeService', 'HttpRequestHelper', 'Notifications', + '$stateParams', + 'NodeService', + 'HttpRequestHelper', + 'Notifications', function NodeBrowserController($stateParams, NodeService, HttpRequestHelper, Notifications) { var ctrl = this; ctrl.$onInit = $onInit; @@ -8,13 +11,13 @@ angular.module('portainer.docker').controller('NodeBrowserController', [ ctrl.nodeId = $stateParams.id; NodeService.node(ctrl.nodeId) - .then(function onNodeLoaded(node) { - HttpRequestHelper.setPortainerAgentTargetHeader(node.Hostname); - ctrl.node = node; - }) - .catch(function onError(err) { - Notifications.error('Unable to retrieve host information', err); - }); + .then(function onNodeLoaded(node) { + HttpRequestHelper.setPortainerAgentTargetHeader(node.Hostname); + ctrl.node = node; + }) + .catch(function onError(err) { + Notifications.error('Unable to retrieve host information', err); + }); } - } + }, ]); diff --git a/app/docker/views/nodes/node-browser/node-browser.html b/app/docker/views/nodes/node-browser/node-browser.html index 2edeae199..7e9dfe3ce 100644 --- a/app/docker/views/nodes/node-browser/node-browser.html +++ b/app/docker/views/nodes/node-browser/node-browser.html @@ -1,14 +1,12 @@ - Swarm > {{ $ctrl.node.Hostname }} > browse + Swarm > {{ $ctrl.node.Hostname }} > browse
- +
diff --git a/app/docker/views/nodes/node-browser/node-browser.js b/app/docker/views/nodes/node-browser/node-browser.js index a43fa97fe..b073a2a40 100644 --- a/app/docker/views/nodes/node-browser/node-browser.js +++ b/app/docker/views/nodes/node-browser/node-browser.js @@ -1,4 +1,4 @@ angular.module('portainer.docker').component('nodeBrowserView', { templateUrl: './node-browser.html', - controller: 'NodeBrowserController' + controller: 'NodeBrowserController', }); diff --git a/app/docker/views/nodes/node-details/node-details-view-controller.js b/app/docker/views/nodes/node-details/node-details-view-controller.js index 3cc0a6e90..020c3b586 100644 --- a/app/docker/views/nodes/node-details/node-details-view-controller.js +++ b/app/docker/views/nodes/node-details/node-details-view-controller.js @@ -1,5 +1,11 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [ - '$q', '$stateParams', 'NodeService', 'StateManager', 'AgentService', 'ContainerService', 'Authentication', + '$q', + '$stateParams', + 'NodeService', + 'StateManager', + 'AgentService', + 'ContainerService', + 'Authentication', function NodeDetailsViewController($q, $stateParams, NodeService, StateManager, AgentService, ContainerService, Authentication) { var ctrl = this; @@ -7,7 +13,7 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [ ctrl.state = { isAgent: false, - isAdmin: false + isAdmin: false, }; function initView() { @@ -21,9 +27,8 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [ var nodeId = $stateParams.id; $q.all({ node: NodeService.node(nodeId), - jobs: fetchJobs ? ContainerService.containers(true, { label: ['io.portainer.job.endpoint'] }) : [] - }) - .then(function (data) { + jobs: fetchJobs ? ContainerService.containers(true, { label: ['io.portainer.job.endpoint'] }) : [], + }).then(function (data) { var node = data.node; ctrl.originalNode = node; ctrl.hostDetails = buildHostDetails(node); @@ -37,8 +42,7 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [ return; } - AgentService.hostInfo(node.Hostname) - .then(function onHostInfoLoad(agentHostInfo) { + AgentService.hostInfo(node.Hostname).then(function onHostInfoLoad(agentHostInfo) { ctrl.devices = agentHostInfo.PCIDevices; ctrl.disks = agentHostInfo.PhysicalDisks; }); @@ -50,11 +54,11 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [ return { os: { arch: node.PlatformArchitecture, - type: node.PlatformOS + type: node.PlatformOS, }, name: node.Hostname, totalCPU: node.CPUs / 1e9, - totalMemory: node.Memory + totalMemory: node.Memory, }; } @@ -74,18 +78,18 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [ managerAddress: node.ManagerAddr, availability: node.Availability, status: node.Status, - nodeLabels: node.Labels + nodeLabels: node.Labels, }; } function transformPlugins(pluginsList, type) { return pluginsList - .filter(function(plugin) { - return plugin.Type === type; - }) - .map(function(plugin) { - return plugin.Name; - }); + .filter(function (plugin) { + return plugin.Type === type; + }) + .map(function (plugin) { + return plugin.Name; + }); } - } + }, ]); diff --git a/app/docker/views/nodes/node-details/node-details-view.html b/app/docker/views/nodes/node-details/node-details-view.html index c2dd7c7e2..571d2dde0 100644 --- a/app/docker/views/nodes/node-details/node-details-view.html +++ b/app/docker/views/nodes/node-details/node-details-view.html @@ -12,8 +12,5 @@ job-url="docker.nodes.node.job" jobs="$ctrl.jobs" > - + diff --git a/app/docker/views/nodes/node-details/node-details-view.js b/app/docker/views/nodes/node-details/node-details-view.js index e0ba268cf..929b4f4ad 100644 --- a/app/docker/views/nodes/node-details/node-details-view.js +++ b/app/docker/views/nodes/node-details/node-details-view.js @@ -1,4 +1,4 @@ angular.module('portainer.docker').component('nodeDetailsView', { templateUrl: './node-details-view.html', - controller: 'NodeDetailsViewController' + controller: 'NodeDetailsViewController', }); diff --git a/app/docker/views/nodes/node-job/node-job-controller.js b/app/docker/views/nodes/node-job/node-job-controller.js index 9f1173d09..f4f47d363 100644 --- a/app/docker/views/nodes/node-job/node-job-controller.js +++ b/app/docker/views/nodes/node-job/node-job-controller.js @@ -1,5 +1,8 @@ angular.module('portainer.docker').controller('NodeJobController', [ - '$stateParams', 'NodeService', 'HttpRequestHelper', 'Notifications', + '$stateParams', + 'NodeService', + 'HttpRequestHelper', + 'Notifications', function NodeJobController($stateParams, NodeService, HttpRequestHelper, Notifications) { var ctrl = this; ctrl.$onInit = $onInit; @@ -8,13 +11,13 @@ angular.module('portainer.docker').controller('NodeJobController', [ ctrl.nodeId = $stateParams.id; NodeService.node(ctrl.nodeId) - .then(function onNodeLoaded(node) { - HttpRequestHelper.setPortainerAgentTargetHeader(node.Hostname); - ctrl.node = node; - }) - .catch(function onError(err) { - Notifications.error('Unable to retrieve host information', err); - }); + .then(function onNodeLoaded(node) { + HttpRequestHelper.setPortainerAgentTargetHeader(node.Hostname); + ctrl.node = node; + }) + .catch(function onError(err) { + Notifications.error('Unable to retrieve host information', err); + }); } - } + }, ]); diff --git a/app/docker/views/nodes/node-job/node-job.html b/app/docker/views/nodes/node-job/node-job.html index 90ae92d14..a842fa746 100644 --- a/app/docker/views/nodes/node-job/node-job.html +++ b/app/docker/views/nodes/node-job/node-job.html @@ -1,7 +1,7 @@ - Swarm > {{ $ctrl.node.Hostname }} > execute job + Swarm > {{ $ctrl.node.Hostname }} > execute job @@ -9,9 +9,7 @@
- +
diff --git a/app/docker/views/nodes/node-job/node-job.js b/app/docker/views/nodes/node-job/node-job.js index 334752fff..b659b4e71 100644 --- a/app/docker/views/nodes/node-job/node-job.js +++ b/app/docker/views/nodes/node-job/node-job.js @@ -1,4 +1,4 @@ angular.module('portainer.docker').component('nodeJobView', { templateUrl: './node-job.html', - controller: 'NodeJobController' + controller: 'NodeJobController', }); diff --git a/app/docker/views/secrets/create/createSecretController.js b/app/docker/views/secrets/create/createSecretController.js index b488ed37d..cbd654c77 100644 --- a/app/docker/views/secrets/create/createSecretController.js +++ b/app/docker/views/secrets/create/createSecretController.js @@ -1,89 +1,95 @@ import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel'; -angular.module('portainer.docker') -.controller('CreateSecretController', ['$scope', '$state', 'Notifications', 'SecretService', 'LabelHelper', 'Authentication', 'ResourceControlService', 'FormValidator', -function ($scope, $state, Notifications, SecretService, LabelHelper, Authentication, ResourceControlService, FormValidator) { +angular.module('portainer.docker').controller('CreateSecretController', [ + '$scope', + '$state', + 'Notifications', + 'SecretService', + 'LabelHelper', + 'Authentication', + 'ResourceControlService', + 'FormValidator', + function ($scope, $state, Notifications, SecretService, LabelHelper, Authentication, ResourceControlService, FormValidator) { + $scope.formValues = { + Name: '', + Data: '', + Labels: [], + encodeSecret: true, + AccessControlData: new AccessControlFormData(), + }; - $scope.formValues = { - Name: '', - Data: '', - Labels: [], - encodeSecret: true, - AccessControlData: new AccessControlFormData() - }; + $scope.state = { + formValidationError: '', + actionInProgress: false, + }; - $scope.state = { - formValidationError: '', - actionInProgress: false - }; + $scope.addLabel = function () { + $scope.formValues.Labels.push({ key: '', value: '' }); + }; - $scope.addLabel = function() { - $scope.formValues.Labels.push({ key: '', value: ''}); - }; + $scope.removeLabel = function (index) { + $scope.formValues.Labels.splice(index, 1); + }; - $scope.removeLabel = function(index) { - $scope.formValues.Labels.splice(index, 1); - }; - - function prepareLabelsConfig(config) { - config.Labels = LabelHelper.fromKeyValueToLabelHash($scope.formValues.Labels); - } - - function prepareSecretData(config) { - if ($scope.formValues.encodeSecret) { - config.Data = btoa(unescape(encodeURIComponent($scope.formValues.Data))); - } else { - config.Data = $scope.formValues.Data; - } - } - - function prepareConfiguration() { - var config = {}; - config.Name = $scope.formValues.Name; - prepareSecretData(config); - prepareLabelsConfig(config); - return config; - } - - function validateForm(accessControlData, isAdmin) { - $scope.state.formValidationError = ''; - var error = ''; - error = FormValidator.validateAccessControl(accessControlData, isAdmin); - - if (error) { - $scope.state.formValidationError = error; - return false; - } - return true; - } - - $scope.create = function () { - - const accessControlData = $scope.formValues.AccessControlData; - const userDetails = Authentication.getUserDetails(); - const isAdmin = Authentication.isAdmin(); - - if (!validateForm(accessControlData, isAdmin)) { - return; + function prepareLabelsConfig(config) { + config.Labels = LabelHelper.fromKeyValueToLabelHash($scope.formValues.Labels); } - $scope.state.actionInProgress = true; - var secretConfiguration = prepareConfiguration(); - SecretService.create(secretConfiguration) - .then(function success(data) { - const userId = userDetails.ID; - const resourceControl = data.Portainer.ResourceControl; - return ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); - }) - .then(function success() { - Notifications.success('Secret successfully created'); - $state.go('docker.secrets', {}, {reload: true}); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to create secret'); - }) - .finally(function final() { - $scope.state.actionInProgress = false; - }); - }; -}]); + function prepareSecretData(config) { + if ($scope.formValues.encodeSecret) { + config.Data = btoa(unescape(encodeURIComponent($scope.formValues.Data))); + } else { + config.Data = $scope.formValues.Data; + } + } + + function prepareConfiguration() { + var config = {}; + config.Name = $scope.formValues.Name; + prepareSecretData(config); + prepareLabelsConfig(config); + return config; + } + + function validateForm(accessControlData, isAdmin) { + $scope.state.formValidationError = ''; + var error = ''; + error = FormValidator.validateAccessControl(accessControlData, isAdmin); + + if (error) { + $scope.state.formValidationError = error; + return false; + } + return true; + } + + $scope.create = function () { + const accessControlData = $scope.formValues.AccessControlData; + const userDetails = Authentication.getUserDetails(); + const isAdmin = Authentication.isAdmin(); + + if (!validateForm(accessControlData, isAdmin)) { + return; + } + + $scope.state.actionInProgress = true; + var secretConfiguration = prepareConfiguration(); + SecretService.create(secretConfiguration) + .then(function success(data) { + const userId = userDetails.ID; + const resourceControl = data.Portainer.ResourceControl; + return ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); + }) + .then(function success() { + Notifications.success('Secret successfully created'); + $state.go('docker.secrets', {}, { reload: true }); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to create secret'); + }) + .finally(function final() { + $scope.state.actionInProgress = false; + }); + }; + }, +]); diff --git a/app/docker/views/secrets/create/createsecret.html b/app/docker/views/secrets/create/createsecret.html index 167e373f7..fae2453fa 100644 --- a/app/docker/views/secrets/create/createsecret.html +++ b/app/docker/views/secrets/create/createsecret.html @@ -1,8 +1,6 @@ - - Secrets > Add secret - + Secrets > Add secret
@@ -14,7 +12,7 @@
- +
@@ -33,9 +31,7 @@ Encode secret - +
@@ -43,20 +39,18 @@
- - add label - + add label
name - +
value - +
- diff --git a/app/docker/views/secrets/edit/secret.html b/app/docker/views/secrets/edit/secret.html index 857820d18..6375294eb 100644 --- a/app/docker/views/secrets/edit/secret.html +++ b/app/docker/views/secrets/edit/secret.html @@ -24,7 +24,9 @@
@@ -54,10 +56,6 @@ - + diff --git a/app/docker/views/secrets/edit/secretController.js b/app/docker/views/secrets/edit/secretController.js index 15aecfc1f..69fa6077c 100644 --- a/app/docker/views/secrets/edit/secretController.js +++ b/app/docker/views/secrets/edit/secretController.js @@ -1,27 +1,31 @@ -angular.module('portainer.docker') -.controller('SecretController', ['$scope', '$transition$', '$state', 'SecretService', 'Notifications', -function ($scope, $transition$, $state, SecretService, Notifications) { +angular.module('portainer.docker').controller('SecretController', [ + '$scope', + '$transition$', + '$state', + 'SecretService', + 'Notifications', + function ($scope, $transition$, $state, SecretService, Notifications) { + $scope.removeSecret = function removeSecret(secretId) { + SecretService.remove(secretId) + .then(function success() { + Notifications.success('Secret successfully removed'); + $state.go('docker.secrets', {}); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove secret'); + }); + }; - $scope.removeSecret = function removeSecret(secretId) { - SecretService.remove(secretId) - .then(function success() { - Notifications.success('Secret successfully removed'); - $state.go('docker.secrets', {}); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove secret'); - }); - }; + function initView() { + SecretService.secret($transition$.params().id) + .then(function success(data) { + $scope.secret = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve secret details'); + }); + } - function initView() { - SecretService.secret($transition$.params().id) - .then(function success(data) { - $scope.secret = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve secret details'); - }); - } - - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/secrets/secrets.html b/app/docker/views/secrets/secrets.html index 76c8205d7..a6ddde5af 100644 --- a/app/docker/views/secrets/secrets.html +++ b/app/docker/views/secrets/secrets.html @@ -10,12 +10,14 @@
diff --git a/app/docker/views/secrets/secretsController.js b/app/docker/views/secrets/secretsController.js index 98f44e5e3..69d22b196 100644 --- a/app/docker/views/secrets/secretsController.js +++ b/app/docker/views/secrets/secretsController.js @@ -1,44 +1,47 @@ -angular.module('portainer.docker') -.controller('SecretsController', ['$scope', '$state', 'SecretService', 'Notifications', -function ($scope, $state, SecretService, Notifications) { - - $scope.removeAction = function (selectedItems) { - var actionCount = selectedItems.length; - angular.forEach(selectedItems, function (secret) { - SecretService.remove(secret.Id) - .then(function success() { - Notifications.success('Secret successfully removed', secret.Name); - var index = $scope.secrets.indexOf(secret); - $scope.secrets.splice(index, 1); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove secret'); - }) - .finally(function final() { - --actionCount; - if (actionCount === 0) { - $state.reload(); - } +angular.module('portainer.docker').controller('SecretsController', [ + '$scope', + '$state', + 'SecretService', + 'Notifications', + function ($scope, $state, SecretService, Notifications) { + $scope.removeAction = function (selectedItems) { + var actionCount = selectedItems.length; + angular.forEach(selectedItems, function (secret) { + SecretService.remove(secret.Id) + .then(function success() { + Notifications.success('Secret successfully removed', secret.Name); + var index = $scope.secrets.indexOf(secret); + $scope.secrets.splice(index, 1); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove secret'); + }) + .finally(function final() { + --actionCount; + if (actionCount === 0) { + $state.reload(); + } + }); }); - }); - }; + }; - $scope.getSecrets = getSecrets; + $scope.getSecrets = getSecrets; - function getSecrets() { - SecretService.secrets() - .then(function success(data) { - $scope.secrets = data; - }) - .catch(function error(err) { - $scope.secrets = []; - Notifications.error('Failure', err, 'Unable to retrieve secrets'); - }); - } + function getSecrets() { + SecretService.secrets() + .then(function success(data) { + $scope.secrets = data; + }) + .catch(function error(err) { + $scope.secrets = []; + Notifications.error('Failure', err, 'Unable to retrieve secrets'); + }); + } - function initView() { - getSecrets(); - } + function initView() { + getSecrets(); + } - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/services/create/createServiceController.js b/app/docker/views/services/create/createServiceController.js index 477fb6f65..212519bd5 100644 --- a/app/docker/views/services/create/createServiceController.js +++ b/app/docker/views/services/create/createServiceController.js @@ -2,529 +2,584 @@ import _ from 'lodash-es'; import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel'; import { PorImageRegistryModel } from 'Docker/models/porImageRegistry'; -require('./includes/update-restart.html') -require('./includes/secret.html') -require('./includes/config.html') -require('./includes/resources-placement.html') +require('./includes/update-restart.html'); +require('./includes/secret.html'); +require('./includes/config.html'); +require('./includes/resources-placement.html'); -angular.module('portainer.docker') -.controller('CreateServiceController', ['$q', '$scope', '$state', '$timeout', 'Service', 'ServiceHelper', 'ConfigService', 'ConfigHelper', 'SecretHelper', 'SecretService', 'VolumeService', 'NetworkService', 'ImageHelper', 'LabelHelper', 'Authentication', 'ResourceControlService', 'Notifications', 'FormValidator', 'PluginService', 'RegistryService', 'HttpRequestHelper', 'NodeService', 'SettingsService', 'WebhookService','EndpointProvider', -function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, ConfigHelper, SecretHelper, SecretService, VolumeService, NetworkService, ImageHelper, LabelHelper, Authentication, ResourceControlService, Notifications, FormValidator, PluginService, RegistryService, HttpRequestHelper, NodeService, SettingsService, WebhookService,EndpointProvider) { - - $scope.formValues = { - Name: '', - RegistryModel: new PorImageRegistryModel(), - Mode: 'replicated', - Replicas: 1, - Command: '', - EntryPoint: '', - WorkingDir: '', - User: '', - Env: [], - Labels: [], - ContainerLabels: [], - Volumes: [], - Network: '', - ExtraNetworks: [], - HostsEntries: [], - Ports: [], - Parallelism: 1, - PlacementConstraints: [], - PlacementPreferences: [], - UpdateDelay: '0s', - UpdateOrder: 'stop-first', - FailureAction: 'pause', - Secrets: [], - Configs: [], - AccessControlData: new AccessControlFormData(), - CpuLimit: 0, - CpuReservation: 0, - MemoryLimit: 0, - MemoryReservation: 0, - MemoryLimitUnit: 'MB', - MemoryReservationUnit: 'MB', - RestartCondition: 'any', - RestartDelay: '5s', - RestartMaxAttempts: 0, - RestartWindow: '0s', - LogDriverName: '', - LogDriverOpts: [], - Webhook: false - }; - - $scope.state = { - formValidationError: '', - actionInProgress: false - }; - - $scope.refreshSlider = function () { - $timeout(function () { - $scope.$broadcast('rzSliderForceRender'); - }); - }; - - $scope.addPortBinding = function() { - $scope.formValues.Ports.push({ PublishedPort: '', TargetPort: '', Protocol: 'tcp', PublishMode: 'ingress' }); - }; - - $scope.removePortBinding = function(index) { - $scope.formValues.Ports.splice(index, 1); - }; - - $scope.addExtraNetwork = function() { - $scope.formValues.ExtraNetworks.push({ Name: '' }); - }; - - $scope.removeExtraNetwork = function(index) { - $scope.formValues.ExtraNetworks.splice(index, 1); - }; - - $scope.addHostsEntry = function() { - $scope.formValues.HostsEntries.push({}); - }; - - $scope.removeHostsEntry = function(index) { - $scope.formValues.HostsEntries.splice(index, 1); - }; - - $scope.addVolume = function() { - $scope.formValues.Volumes.push({ Source: '', Target: '', ReadOnly: false, Type: 'volume' }); - }; - - $scope.removeVolume = function(index) { - $scope.formValues.Volumes.splice(index, 1); - }; - - $scope.addConfig = function() { - $scope.formValues.Configs.push({}); - }; - - $scope.removeConfig = function(index) { - $scope.formValues.Configs.splice(index, 1); - }; - - $scope.addSecret = function() { - $scope.formValues.Secrets.push({ overrideTarget: false }); - }; - - $scope.removeSecret = function(index) { - $scope.formValues.Secrets.splice(index, 1); - }; - - $scope.addEnvironmentVariable = function() { - $scope.formValues.Env.push({ name: '', value: ''}); - }; - - $scope.removeEnvironmentVariable = function(index) { - $scope.formValues.Env.splice(index, 1); - }; - - $scope.addPlacementConstraint = function() { - $scope.formValues.PlacementConstraints.push({ key: '', operator: '==', value: '' }); - }; - - $scope.removePlacementConstraint = function(index) { - $scope.formValues.PlacementConstraints.splice(index, 1); - }; - - $scope.addPlacementPreference = function() { - $scope.formValues.PlacementPreferences.push({ strategy: 'spread', value: '' }); - }; - - $scope.removePlacementPreference = function(index) { - $scope.formValues.PlacementPreferences.splice(index, 1); - }; - - $scope.addLabel = function() { - $scope.formValues.Labels.push({ key: '', value: ''}); - }; - - $scope.removeLabel = function(index) { - $scope.formValues.Labels.splice(index, 1); - }; - - $scope.addContainerLabel = function() { - $scope.formValues.ContainerLabels.push({ key: '', value: ''}); - }; - - $scope.removeContainerLabel = function(index) { - $scope.formValues.ContainerLabels.splice(index, 1); - }; - - $scope.addLogDriverOpt = function() { - $scope.formValues.LogDriverOpts.push({ name: '', value: ''}); - }; - - $scope.removeLogDriverOpt = function(index) { - $scope.formValues.LogDriverOpts.splice(index, 1); - }; - - function prepareImageConfig(config, input) { - var imageConfig = ImageHelper.createImageConfigForContainer(input.RegistryModel); - config.TaskTemplate.ContainerSpec.Image = imageConfig.fromImage; - } - - function preparePortsConfig(config, input) { - var ports = []; - input.Ports.forEach(function (binding) { - var port = { - Protocol: binding.Protocol, - PublishMode: binding.PublishMode - }; - if (binding.TargetPort) { - port.TargetPort = +binding.TargetPort; - if (binding.PublishedPort) { - port.PublishedPort = +binding.PublishedPort; - } - ports.push(port); - } - }); - config.EndpointSpec.Ports = ports; - } - - function prepareSchedulingConfig(config, input) { - if (input.Mode === 'replicated') { - config.Mode.Replicated = { - Replicas: input.Replicas - }; - } else { - config.Mode.Global = {}; - } - } - - function commandToArray(cmd) { - var tokens = [].concat.apply([], cmd.split('\'').map(function(v,i) { - return i%2 ? v : v.split(' '); - })).filter(Boolean); - return tokens; - } - - function prepareCommandConfig(config, input) { - if (input.EntryPoint) { - config.TaskTemplate.ContainerSpec.Command = commandToArray(input.EntryPoint); - } - if (input.Command) { - config.TaskTemplate.ContainerSpec.Args = commandToArray(input.Command); - } - if (input.User) { - config.TaskTemplate.ContainerSpec.User = input.User; - } - if (input.WorkingDir) { - config.TaskTemplate.ContainerSpec.Dir = input.WorkingDir; - } - } - - function prepareEnvConfig(config, input) { - var env = []; - input.Env.forEach(function (v) { - if (v.name) { - env.push(v.name + '=' + v.value); - } - }); - config.TaskTemplate.ContainerSpec.Env = env; - } - - function prepareLabelsConfig(config, input) { - config.Labels = LabelHelper.fromKeyValueToLabelHash(input.Labels); - config.TaskTemplate.ContainerSpec.Labels = LabelHelper.fromKeyValueToLabelHash(input.ContainerLabels); - } - - function createMountObjectFromVolume(volumeObject, target, readonly) { - return { - Target: target, - Source: volumeObject.Id, - Type: 'volume', - ReadOnly: readonly, - VolumeOptions: { - Labels: volumeObject.Labels, - DriverConfig: { - Name: volumeObject.Driver, - Options: volumeObject.Options - } - } +angular.module('portainer.docker').controller('CreateServiceController', [ + '$q', + '$scope', + '$state', + '$timeout', + 'Service', + 'ServiceHelper', + 'ConfigService', + 'ConfigHelper', + 'SecretHelper', + 'SecretService', + 'VolumeService', + 'NetworkService', + 'ImageHelper', + 'LabelHelper', + 'Authentication', + 'ResourceControlService', + 'Notifications', + 'FormValidator', + 'PluginService', + 'RegistryService', + 'HttpRequestHelper', + 'NodeService', + 'SettingsService', + 'WebhookService', + 'EndpointProvider', + function ( + $q, + $scope, + $state, + $timeout, + Service, + ServiceHelper, + ConfigService, + ConfigHelper, + SecretHelper, + SecretService, + VolumeService, + NetworkService, + ImageHelper, + LabelHelper, + Authentication, + ResourceControlService, + Notifications, + FormValidator, + PluginService, + RegistryService, + HttpRequestHelper, + NodeService, + SettingsService, + WebhookService, + EndpointProvider + ) { + $scope.formValues = { + Name: '', + RegistryModel: new PorImageRegistryModel(), + Mode: 'replicated', + Replicas: 1, + Command: '', + EntryPoint: '', + WorkingDir: '', + User: '', + Env: [], + Labels: [], + ContainerLabels: [], + Volumes: [], + Network: '', + ExtraNetworks: [], + HostsEntries: [], + Ports: [], + Parallelism: 1, + PlacementConstraints: [], + PlacementPreferences: [], + UpdateDelay: '0s', + UpdateOrder: 'stop-first', + FailureAction: 'pause', + Secrets: [], + Configs: [], + AccessControlData: new AccessControlFormData(), + CpuLimit: 0, + CpuReservation: 0, + MemoryLimit: 0, + MemoryReservation: 0, + MemoryLimitUnit: 'MB', + MemoryReservationUnit: 'MB', + RestartCondition: 'any', + RestartDelay: '5s', + RestartMaxAttempts: 0, + RestartWindow: '0s', + LogDriverName: '', + LogDriverOpts: [], + Webhook: false, }; - } - function prepareVolumes(config, input) { - input.Volumes.forEach(function (volume) { - if (volume.Source && volume.Target) { - if (volume.Type !== 'volume') { - config.TaskTemplate.ContainerSpec.Mounts.push(volume); - } else { - var volumeObject = volume.Source; - var mount = createMountObjectFromVolume(volumeObject, volume.Target, volume.ReadOnly); - config.TaskTemplate.ContainerSpec.Mounts.push(mount); - } - } - }); - } + $scope.state = { + formValidationError: '', + actionInProgress: false, + }; - function prepareNetworks(config, input) { - var networks = []; - if (input.Network) { - networks.push({ Target: input.Network }); - } - input.ExtraNetworks.forEach(function (network) { - networks.push({ Target: network.Name }); - }); - config.Networks = _.uniqWith(networks, _.isEqual); - } - - function prepareHostsEntries(config, input) { - var hostsEntries = []; - if (input.HostsEntries) { - input.HostsEntries.forEach(function (host_ip) { - if (host_ip.value && host_ip.value.indexOf(':') && host_ip.value.split(':').length === 2) { - var keyVal = host_ip.value.split(':'); - // Hosts file format, IP_address canonical_hostname - hostsEntries.push(keyVal[1] + ' ' + keyVal[0]); - } + $scope.refreshSlider = function () { + $timeout(function () { + $scope.$broadcast('rzSliderForceRender'); }); - if (hostsEntries.length > 0) { - config.TaskTemplate.ContainerSpec.Hosts = hostsEntries; - } - } - } - - function prepareUpdateConfig(config, input) { - config.UpdateConfig = { - Parallelism: input.Parallelism || 0, - Delay: ServiceHelper.translateHumanDurationToNanos(input.UpdateDelay) || 0, - FailureAction: input.FailureAction, - Order: input.UpdateOrder }; - } - function prepareRestartPolicy(config, input) { - config.TaskTemplate.RestartPolicy = { - Condition: input.RestartCondition || 'any', - Delay: ServiceHelper.translateHumanDurationToNanos(input.RestartDelay) || 5000000000, - MaxAttempts: input.RestartMaxAttempts || 0, - Window: ServiceHelper.translateHumanDurationToNanos(input.RestartWindow) || 0 + $scope.addPortBinding = function () { + $scope.formValues.Ports.push({ PublishedPort: '', TargetPort: '', Protocol: 'tcp', PublishMode: 'ingress' }); }; - } - function preparePlacementConfig(config, input) { - config.TaskTemplate.Placement.Constraints = ServiceHelper.translateKeyValueToPlacementConstraints(input.PlacementConstraints); - config.TaskTemplate.Placement.Preferences = ServiceHelper.translateKeyValueToPlacementPreferences(input.PlacementPreferences); - } + $scope.removePortBinding = function (index) { + $scope.formValues.Ports.splice(index, 1); + }; - function prepareConfigConfig(config, input) { - if (input.Configs) { - var configs = []; - angular.forEach(input.Configs, function(config) { - if (config.model) { - var s = ConfigHelper.configConfig(config.model); - s.File.Name = config.FileName || s.File.Name; - configs.push(s); - } - }); - config.TaskTemplate.ContainerSpec.Configs = configs; + $scope.addExtraNetwork = function () { + $scope.formValues.ExtraNetworks.push({ Name: '' }); + }; + + $scope.removeExtraNetwork = function (index) { + $scope.formValues.ExtraNetworks.splice(index, 1); + }; + + $scope.addHostsEntry = function () { + $scope.formValues.HostsEntries.push({}); + }; + + $scope.removeHostsEntry = function (index) { + $scope.formValues.HostsEntries.splice(index, 1); + }; + + $scope.addVolume = function () { + $scope.formValues.Volumes.push({ Source: '', Target: '', ReadOnly: false, Type: 'volume' }); + }; + + $scope.removeVolume = function (index) { + $scope.formValues.Volumes.splice(index, 1); + }; + + $scope.addConfig = function () { + $scope.formValues.Configs.push({}); + }; + + $scope.removeConfig = function (index) { + $scope.formValues.Configs.splice(index, 1); + }; + + $scope.addSecret = function () { + $scope.formValues.Secrets.push({ overrideTarget: false }); + }; + + $scope.removeSecret = function (index) { + $scope.formValues.Secrets.splice(index, 1); + }; + + $scope.addEnvironmentVariable = function () { + $scope.formValues.Env.push({ name: '', value: '' }); + }; + + $scope.removeEnvironmentVariable = function (index) { + $scope.formValues.Env.splice(index, 1); + }; + + $scope.addPlacementConstraint = function () { + $scope.formValues.PlacementConstraints.push({ key: '', operator: '==', value: '' }); + }; + + $scope.removePlacementConstraint = function (index) { + $scope.formValues.PlacementConstraints.splice(index, 1); + }; + + $scope.addPlacementPreference = function () { + $scope.formValues.PlacementPreferences.push({ strategy: 'spread', value: '' }); + }; + + $scope.removePlacementPreference = function (index) { + $scope.formValues.PlacementPreferences.splice(index, 1); + }; + + $scope.addLabel = function () { + $scope.formValues.Labels.push({ key: '', value: '' }); + }; + + $scope.removeLabel = function (index) { + $scope.formValues.Labels.splice(index, 1); + }; + + $scope.addContainerLabel = function () { + $scope.formValues.ContainerLabels.push({ key: '', value: '' }); + }; + + $scope.removeContainerLabel = function (index) { + $scope.formValues.ContainerLabels.splice(index, 1); + }; + + $scope.addLogDriverOpt = function () { + $scope.formValues.LogDriverOpts.push({ name: '', value: '' }); + }; + + $scope.removeLogDriverOpt = function (index) { + $scope.formValues.LogDriverOpts.splice(index, 1); + }; + + function prepareImageConfig(config, input) { + var imageConfig = ImageHelper.createImageConfigForContainer(input.RegistryModel); + config.TaskTemplate.ContainerSpec.Image = imageConfig.fromImage; } - } - function prepareSecretConfig(config, input) { - if (input.Secrets) { - var secrets = []; - angular.forEach(input.Secrets, function(secret) { - if (secret.model) { - var s = SecretHelper.secretConfig(secret.model); - s.File.Name = s.SecretName; - if (secret.overrideTarget && secret.target && secret.target !== '') { - s.File.Name = secret.target; + function preparePortsConfig(config, input) { + var ports = []; + input.Ports.forEach(function (binding) { + var port = { + Protocol: binding.Protocol, + PublishMode: binding.PublishMode, + }; + if (binding.TargetPort) { + port.TargetPort = +binding.TargetPort; + if (binding.PublishedPort) { + port.PublishedPort = +binding.PublishedPort; } - secrets.push(s); + ports.push(port); } }); - config.TaskTemplate.ContainerSpec.Secrets = secrets; + config.EndpointSpec.Ports = ports; } - } - function prepareResourcesCpuConfig(config, input) { - // CPU Limit - if (input.CpuLimit > 0) { - config.TaskTemplate.Resources.Limits.NanoCPUs = input.CpuLimit * 1000000000; + function prepareSchedulingConfig(config, input) { + if (input.Mode === 'replicated') { + config.Mode.Replicated = { + Replicas: input.Replicas, + }; + } else { + config.Mode.Global = {}; + } } - // CPU Reservation - if (input.CpuReservation > 0) { - config.TaskTemplate.Resources.Reservations.NanoCPUs = input.CpuReservation * 1000000000; - } - } - function prepareResourcesMemoryConfig(config, input) { - // Memory Limit - Round to 0.125 - var memoryLimit = (Math.round(input.MemoryLimit * 8) / 8).toFixed(3); - memoryLimit *= 1024 * 1024; - if (input.MemoryLimitUnit === 'GB') { - memoryLimit *= 1024; + function commandToArray(cmd) { + var tokens = [].concat + .apply( + [], + cmd.split("'").map(function (v, i) { + return i % 2 ? v : v.split(' '); + }) + ) + .filter(Boolean); + return tokens; } - if (memoryLimit > 0) { - config.TaskTemplate.Resources.Limits.MemoryBytes = memoryLimit; - } - // Memory Resevation - Round to 0.125 - var memoryReservation = (Math.round(input.MemoryReservation * 8) / 8).toFixed(3); - memoryReservation *= 1024 * 1024; - if (input.MemoryReservationUnit === 'GB') { - memoryReservation *= 1024; - } - if (memoryReservation > 0) { - config.TaskTemplate.Resources.Reservations.MemoryBytes = memoryReservation; - } - } - function prepareLogDriverConfig(config, input) { - var logOpts = {}; - if (input.LogDriverName) { - config.TaskTemplate.LogDriver = { Name: input.LogDriverName }; - if (input.LogDriverName !== 'none') { - input.LogDriverOpts.forEach(function (opt) { - if (opt.name) { - logOpts[opt.name] = opt.value; + function prepareCommandConfig(config, input) { + if (input.EntryPoint) { + config.TaskTemplate.ContainerSpec.Command = commandToArray(input.EntryPoint); + } + if (input.Command) { + config.TaskTemplate.ContainerSpec.Args = commandToArray(input.Command); + } + if (input.User) { + config.TaskTemplate.ContainerSpec.User = input.User; + } + if (input.WorkingDir) { + config.TaskTemplate.ContainerSpec.Dir = input.WorkingDir; + } + } + + function prepareEnvConfig(config, input) { + var env = []; + input.Env.forEach(function (v) { + if (v.name) { + env.push(v.name + '=' + v.value); + } + }); + config.TaskTemplate.ContainerSpec.Env = env; + } + + function prepareLabelsConfig(config, input) { + config.Labels = LabelHelper.fromKeyValueToLabelHash(input.Labels); + config.TaskTemplate.ContainerSpec.Labels = LabelHelper.fromKeyValueToLabelHash(input.ContainerLabels); + } + + function createMountObjectFromVolume(volumeObject, target, readonly) { + return { + Target: target, + Source: volumeObject.Id, + Type: 'volume', + ReadOnly: readonly, + VolumeOptions: { + Labels: volumeObject.Labels, + DriverConfig: { + Name: volumeObject.Driver, + Options: volumeObject.Options, + }, + }, + }; + } + + function prepareVolumes(config, input) { + input.Volumes.forEach(function (volume) { + if (volume.Source && volume.Target) { + if (volume.Type !== 'volume') { + config.TaskTemplate.ContainerSpec.Mounts.push(volume); + } else { + var volumeObject = volume.Source; + var mount = createMountObjectFromVolume(volumeObject, volume.Target, volume.ReadOnly); + config.TaskTemplate.ContainerSpec.Mounts.push(mount); + } + } + }); + } + + function prepareNetworks(config, input) { + var networks = []; + if (input.Network) { + networks.push({ Target: input.Network }); + } + input.ExtraNetworks.forEach(function (network) { + networks.push({ Target: network.Name }); + }); + config.Networks = _.uniqWith(networks, _.isEqual); + } + + function prepareHostsEntries(config, input) { + var hostsEntries = []; + if (input.HostsEntries) { + input.HostsEntries.forEach(function (host_ip) { + if (host_ip.value && host_ip.value.indexOf(':') && host_ip.value.split(':').length === 2) { + var keyVal = host_ip.value.split(':'); + // Hosts file format, IP_address canonical_hostname + hostsEntries.push(keyVal[1] + ' ' + keyVal[0]); } }); - if (Object.keys(logOpts).length !== 0 && logOpts.constructor === Object) { - config.TaskTemplate.LogDriver.Options = logOpts; + if (hostsEntries.length > 0) { + config.TaskTemplate.ContainerSpec.Hosts = hostsEntries; } } } - } - function prepareConfiguration() { - var input = $scope.formValues; - var config = { - Name: input.Name, - TaskTemplate: { - ContainerSpec: { - Mounts: [] + function prepareUpdateConfig(config, input) { + config.UpdateConfig = { + Parallelism: input.Parallelism || 0, + Delay: ServiceHelper.translateHumanDurationToNanos(input.UpdateDelay) || 0, + FailureAction: input.FailureAction, + Order: input.UpdateOrder, + }; + } + + function prepareRestartPolicy(config, input) { + config.TaskTemplate.RestartPolicy = { + Condition: input.RestartCondition || 'any', + Delay: ServiceHelper.translateHumanDurationToNanos(input.RestartDelay) || 5000000000, + MaxAttempts: input.RestartMaxAttempts || 0, + Window: ServiceHelper.translateHumanDurationToNanos(input.RestartWindow) || 0, + }; + } + + function preparePlacementConfig(config, input) { + config.TaskTemplate.Placement.Constraints = ServiceHelper.translateKeyValueToPlacementConstraints(input.PlacementConstraints); + config.TaskTemplate.Placement.Preferences = ServiceHelper.translateKeyValueToPlacementPreferences(input.PlacementPreferences); + } + + function prepareConfigConfig(config, input) { + if (input.Configs) { + var configs = []; + angular.forEach(input.Configs, function (config) { + if (config.model) { + var s = ConfigHelper.configConfig(config.model); + s.File.Name = config.FileName || s.File.Name; + configs.push(s); + } + }); + config.TaskTemplate.ContainerSpec.Configs = configs; + } + } + + function prepareSecretConfig(config, input) { + if (input.Secrets) { + var secrets = []; + angular.forEach(input.Secrets, function (secret) { + if (secret.model) { + var s = SecretHelper.secretConfig(secret.model); + s.File.Name = s.SecretName; + if (secret.overrideTarget && secret.target && secret.target !== '') { + s.File.Name = secret.target; + } + secrets.push(s); + } + }); + config.TaskTemplate.ContainerSpec.Secrets = secrets; + } + } + + function prepareResourcesCpuConfig(config, input) { + // CPU Limit + if (input.CpuLimit > 0) { + config.TaskTemplate.Resources.Limits.NanoCPUs = input.CpuLimit * 1000000000; + } + // CPU Reservation + if (input.CpuReservation > 0) { + config.TaskTemplate.Resources.Reservations.NanoCPUs = input.CpuReservation * 1000000000; + } + } + + function prepareResourcesMemoryConfig(config, input) { + // Memory Limit - Round to 0.125 + var memoryLimit = (Math.round(input.MemoryLimit * 8) / 8).toFixed(3); + memoryLimit *= 1024 * 1024; + if (input.MemoryLimitUnit === 'GB') { + memoryLimit *= 1024; + } + if (memoryLimit > 0) { + config.TaskTemplate.Resources.Limits.MemoryBytes = memoryLimit; + } + // Memory Resevation - Round to 0.125 + var memoryReservation = (Math.round(input.MemoryReservation * 8) / 8).toFixed(3); + memoryReservation *= 1024 * 1024; + if (input.MemoryReservationUnit === 'GB') { + memoryReservation *= 1024; + } + if (memoryReservation > 0) { + config.TaskTemplate.Resources.Reservations.MemoryBytes = memoryReservation; + } + } + + function prepareLogDriverConfig(config, input) { + var logOpts = {}; + if (input.LogDriverName) { + config.TaskTemplate.LogDriver = { Name: input.LogDriverName }; + if (input.LogDriverName !== 'none') { + input.LogDriverOpts.forEach(function (opt) { + if (opt.name) { + logOpts[opt.name] = opt.value; + } + }); + if (Object.keys(logOpts).length !== 0 && logOpts.constructor === Object) { + config.TaskTemplate.LogDriver.Options = logOpts; + } + } + } + } + + function prepareConfiguration() { + var input = $scope.formValues; + var config = { + Name: input.Name, + TaskTemplate: { + ContainerSpec: { + Mounts: [], + }, + Placement: {}, + Resources: { + Limits: {}, + Reservations: {}, + }, }, - Placement: {}, - Resources: { - Limits: {}, - Reservations: {} - } - }, - Mode: {}, - EndpointSpec: {} + Mode: {}, + EndpointSpec: {}, + }; + prepareSchedulingConfig(config, input); + prepareImageConfig(config, input); + preparePortsConfig(config, input); + prepareCommandConfig(config, input); + prepareEnvConfig(config, input); + prepareLabelsConfig(config, input); + prepareVolumes(config, input); + prepareNetworks(config, input); + prepareHostsEntries(config, input); + prepareUpdateConfig(config, input); + prepareConfigConfig(config, input); + prepareSecretConfig(config, input); + preparePlacementConfig(config, input); + prepareResourcesCpuConfig(config, input); + prepareResourcesMemoryConfig(config, input); + prepareRestartPolicy(config, input); + prepareLogDriverConfig(config, input); + return config; + } + + function createNewService(config, accessControlData) { + const registryModel = $scope.formValues.RegistryModel; + var authenticationDetails = registryModel.Registry.Authentication ? RegistryService.encodedCredentials(registryModel.Registry) : ''; + HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails); + + Service.create(config) + .$promise.then(function success(data) { + const serviceId = data.ID; + const resourceControl = data.Portainer.ResourceControl; + const userId = Authentication.getUserDetails().ID; + const rcPromise = ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); + const webhookPromise = $q.when($scope.formValues.Webhook && WebhookService.createServiceWebhook(serviceId, EndpointProvider.endpointID())); + return $q.all([rcPromise, webhookPromise]); + }) + .then(function success() { + Notifications.success('Service successfully created'); + $state.go('docker.services', {}, { reload: true }); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to create service'); + }) + .finally(function final() { + $scope.state.actionInProgress = false; + }); + } + + function validateForm(accessControlData, isAdmin) { + $scope.state.formValidationError = ''; + var error = ''; + error = FormValidator.validateAccessControl(accessControlData, isAdmin); + + if (error) { + $scope.state.formValidationError = error; + return false; + } + return true; + } + + $scope.create = function createService() { + var accessControlData = $scope.formValues.AccessControlData; + + if (!validateForm(accessControlData, $scope.isAdmin)) { + return; + } + + $scope.state.actionInProgress = true; + var config = prepareConfiguration(); + createNewService(config, accessControlData); }; - prepareSchedulingConfig(config, input); - prepareImageConfig(config, input); - preparePortsConfig(config, input); - prepareCommandConfig(config, input); - prepareEnvConfig(config, input); - prepareLabelsConfig(config, input); - prepareVolumes(config, input); - prepareNetworks(config, input); - prepareHostsEntries(config, input); - prepareUpdateConfig(config, input); - prepareConfigConfig(config, input); - prepareSecretConfig(config, input); - preparePlacementConfig(config, input); - prepareResourcesCpuConfig(config, input); - prepareResourcesMemoryConfig(config, input); - prepareRestartPolicy(config, input); - prepareLogDriverConfig(config, input); - return config; - } - function createNewService(config, accessControlData) { - const registryModel = $scope.formValues.RegistryModel; - var authenticationDetails = registryModel.Registry.Authentication ? RegistryService.encodedCredentials(registryModel.Registry) : ''; - HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails); - - Service.create(config).$promise - .then(function success(data) { - const serviceId = data.ID; - const resourceControl = data.Portainer.ResourceControl; - const userId = Authentication.getUserDetails().ID; - const rcPromise = ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); - const webhookPromise = $q.when($scope.formValues.Webhook && WebhookService.createServiceWebhook(serviceId, EndpointProvider.endpointID())); - return $q.all([rcPromise, webhookPromise]); - }) - .then(function success() { - Notifications.success('Service successfully created'); - $state.go('docker.services', {}, {reload: true}); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to create service'); - }) - .finally(function final() { - $scope.state.actionInProgress = false; - }); - } - - function validateForm(accessControlData, isAdmin) { - $scope.state.formValidationError = ''; - var error = ''; - error = FormValidator.validateAccessControl(accessControlData, isAdmin); - - if (error) { - $scope.state.formValidationError = error; - return false; - } - return true; - } - - $scope.create = function createService() { - var accessControlData = $scope.formValues.AccessControlData; - - if (!validateForm(accessControlData, $scope.isAdmin)) { - return; - } - - $scope.state.actionInProgress = true; - var config = prepareConfiguration(); - createNewService(config, accessControlData); - }; - - function initSlidersMaxValuesBasedOnNodeData(nodes) { - var maxCpus = 0; - var maxMemory = 0; - for (var n in nodes) { - if (nodes[n].CPUs && nodes[n].CPUs > maxCpus) { - maxCpus = nodes[n].CPUs; + function initSlidersMaxValuesBasedOnNodeData(nodes) { + var maxCpus = 0; + var maxMemory = 0; + for (var n in nodes) { + if (nodes[n].CPUs && nodes[n].CPUs > maxCpus) { + maxCpus = nodes[n].CPUs; + } + if (nodes[n].Memory && nodes[n].Memory > maxMemory) { + maxMemory = nodes[n].Memory; + } } - if (nodes[n].Memory && nodes[n].Memory > maxMemory) { - maxMemory = nodes[n].Memory; + if (maxCpus > 0) { + $scope.state.sliderMaxCpu = maxCpus / 1000000000; + } else { + $scope.state.sliderMaxCpu = 32; + } + if (maxMemory > 0) { + $scope.state.sliderMaxMemory = Math.floor(maxMemory / 1000 / 1000); + } else { + $scope.state.sliderMaxMemory = 32768; } } - if (maxCpus > 0) { - $scope.state.sliderMaxCpu = maxCpus / 1000000000; - } else { - $scope.state.sliderMaxCpu = 32; + + function initView() { + var apiVersion = $scope.applicationState.endpoint.apiVersion; + + $q.all({ + volumes: VolumeService.volumes(), + networks: NetworkService.networks(true, true, false), + secrets: apiVersion >= 1.25 ? SecretService.secrets() : [], + configs: apiVersion >= 1.3 ? ConfigService.configs() : [], + nodes: NodeService.nodes(), + settings: SettingsService.publicSettings(), + availableLoggingDrivers: PluginService.loggingPlugins(apiVersion < 1.25), + }) + .then(function success(data) { + $scope.availableVolumes = data.volumes; + $scope.availableNetworks = data.networks; + $scope.availableSecrets = data.secrets; + $scope.availableConfigs = data.configs; + $scope.availableLoggingDrivers = data.availableLoggingDrivers; + initSlidersMaxValuesBasedOnNodeData(data.nodes); + $scope.allowBindMounts = data.settings.AllowBindMountsForRegularUsers; + $scope.isAdmin = Authentication.isAdmin(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to initialize view'); + }); } - if (maxMemory > 0) { - $scope.state.sliderMaxMemory = Math.floor(maxMemory / 1000 / 1000); - } else { - $scope.state.sliderMaxMemory = 32768; - } - } - function initView() { - var apiVersion = $scope.applicationState.endpoint.apiVersion; - - $q.all({ - volumes: VolumeService.volumes(), - networks: NetworkService.networks(true, true, false), - secrets: apiVersion >= 1.25 ? SecretService.secrets() : [], - configs: apiVersion >= 1.30 ? ConfigService.configs() : [], - nodes: NodeService.nodes(), - settings: SettingsService.publicSettings(), - availableLoggingDrivers: PluginService.loggingPlugins(apiVersion < 1.25) - }) - .then(function success(data) { - $scope.availableVolumes = data.volumes; - $scope.availableNetworks = data.networks; - $scope.availableSecrets = data.secrets; - $scope.availableConfigs = data.configs; - $scope.availableLoggingDrivers = data.availableLoggingDrivers; - initSlidersMaxValuesBasedOnNodeData(data.nodes); - $scope.allowBindMounts = data.settings.AllowBindMountsForRegularUsers; - $scope.isAdmin = Authentication.isAdmin(); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to initialize view'); - }); - } - - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/services/create/createservice.html b/app/docker/views/services/create/createservice.html index 458148975..3494a88f0 100644 --- a/app/docker/views/services/create/createservice.html +++ b/app/docker/views/services/create/createservice.html @@ -1,8 +1,6 @@ - - Services > Add service - + Services > Add service
@@ -14,7 +12,7 @@
- +
@@ -22,11 +20,7 @@ Image configuration
- +
Scheduling @@ -48,7 +42,7 @@ - +
@@ -68,7 +62,7 @@
host - +
@@ -77,7 +71,7 @@
container - +
@@ -108,11 +102,12 @@
- +
@@ -125,7 +120,13 @@
- @@ -150,7 +151,7 @@
  • Labels
  • Update config & Restart
  • Secrets
  • -
  • Configs
  • +
  • Configs
  • Resources & Placement
  • @@ -165,7 +166,7 @@
    - +
    @@ -173,7 +174,7 @@
    - +
    @@ -181,11 +182,11 @@
    - +
    - +
    @@ -202,11 +203,11 @@
    name - +
    value - +

    - Logging driver for service that will override the default docker daemon driver. Select Default logging driver if you don't want to override it. Supported logging drivers can be found in the Docker documentation. + Logging driver for service that will override the default docker daemon driver. Select Default logging driver if you don't want to override it. Supported + logging drivers can be found + in the Docker documentation.

    @@ -242,9 +245,16 @@
    - + add logging driver option
    @@ -253,11 +263,11 @@
    option - +
    value - +
    - -
    @@ -292,7 +300,7 @@
    container - +
    @@ -314,7 +322,11 @@
    volume -
    @@ -322,7 +334,7 @@
    host - +
    @@ -395,7 +407,7 @@
    value - +
    -
    +
    @@ -114,11 +114,11 @@
    strategy - +
    value - +
    + Order @@ -212,28 +222,28 @@
    + {{ layer.Order }} + {{ layer.Size | humansize }}
    -
    - + {{ layer.CreatedBy | imagelayercommand }}
    diff --git a/app/docker/views/images/edit/imageController.js b/app/docker/views/images/edit/imageController.js index c13cd72ef..6a0471445 100644 --- a/app/docker/views/images/edit/imageController.js +++ b/app/docker/views/images/edit/imageController.js @@ -1,152 +1,167 @@ import _ from 'lodash-es'; import { PorImageRegistryModel } from 'Docker/models/porImageRegistry'; -angular.module('portainer.docker') -.controller('ImageController', ['$q', '$scope', '$transition$', '$state', '$timeout', 'ImageService', 'ImageHelper', 'RegistryService', 'Notifications', 'HttpRequestHelper', 'ModalService', 'FileSaver', 'Blob', -function ($q, $scope, $transition$, $state, $timeout, ImageService, ImageHelper, RegistryService, Notifications, HttpRequestHelper, ModalService, FileSaver, Blob) { - $scope.formValues = { - RegistryModel: new PorImageRegistryModel() - }; +angular.module('portainer.docker').controller('ImageController', [ + '$q', + '$scope', + '$transition$', + '$state', + '$timeout', + 'ImageService', + 'ImageHelper', + 'RegistryService', + 'Notifications', + 'HttpRequestHelper', + 'ModalService', + 'FileSaver', + 'Blob', + function ($q, $scope, $transition$, $state, $timeout, ImageService, ImageHelper, RegistryService, Notifications, HttpRequestHelper, ModalService, FileSaver, Blob) { + $scope.formValues = { + RegistryModel: new PorImageRegistryModel(), + }; - $scope.state = { - exportInProgress: false - }; + $scope.state = { + exportInProgress: false, + }; - $scope.sortType = 'Order'; - $scope.sortReverse = false; + $scope.sortType = 'Order'; + $scope.sortReverse = false; - $scope.order = function(sortType) { - $scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false; - $scope.sortType = sortType; - }; + $scope.order = function (sortType) { + $scope.sortReverse = $scope.sortType === sortType ? !$scope.sortReverse : false; + $scope.sortType = sortType; + }; - $scope.toggleLayerCommand = function(layerId) { - $('#layer-command-expander'+layerId+' span').toggleClass('glyphicon-plus-sign glyphicon-minus-sign'); - $('#layer-command-'+layerId+'-short').toggle(); - $('#layer-command-'+layerId+'-full').toggle(); - }; + $scope.toggleLayerCommand = function (layerId) { + $('#layer-command-expander' + layerId + ' span').toggleClass('glyphicon-plus-sign glyphicon-minus-sign'); + $('#layer-command-' + layerId + '-short').toggle(); + $('#layer-command-' + layerId + '-full').toggle(); + }; - $scope.tagImage = function() { - const registryModel = $scope.formValues.RegistryModel; + $scope.tagImage = function () { + const registryModel = $scope.formValues.RegistryModel; - const image = ImageHelper.createImageConfigForContainer(registryModel); + const image = ImageHelper.createImageConfigForContainer(registryModel); - ImageService.tagImage($transition$.params().id, image.fromImage) - .then(function success() { - Notifications.success('Image successfully tagged'); - $state.go('docker.images.image', {id: $transition$.params().id}, {reload: true}); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to tag image'); - }); - }; + ImageService.tagImage($transition$.params().id, image.fromImage) + .then(function success() { + Notifications.success('Image successfully tagged'); + $state.go('docker.images.image', { id: $transition$.params().id }, { reload: true }); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to tag image'); + }); + }; - $scope.pushTag = function(repository) { - $('#uploadResourceHint').show(); - RegistryService.retrievePorRegistryModelFromRepository(repository) - .then(function success(registryModel) { - return ImageService.pushImage(registryModel); - }) - .then(function success() { - Notifications.success('Image successfully pushed', repository); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to push image to repository'); - }) - .finally(function final() { - $('#uploadResourceHint').hide(); - }); - }; + $scope.pushTag = function (repository) { + $('#uploadResourceHint').show(); + RegistryService.retrievePorRegistryModelFromRepository(repository) + .then(function success(registryModel) { + return ImageService.pushImage(registryModel); + }) + .then(function success() { + Notifications.success('Image successfully pushed', repository); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to push image to repository'); + }) + .finally(function final() { + $('#uploadResourceHint').hide(); + }); + }; - $scope.pullTag = function(repository) { - $('#downloadResourceHint').show(); - RegistryService.retrievePorRegistryModelFromRepository(repository) - .then(function success(registryModel) { - return ImageService.pullImage(registryModel, false); - }) - .then(function success() { - Notifications.success('Image successfully pulled', repository); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to pull image'); - }) - .finally(function final() { - $('#downloadResourceHint').hide(); - }); - }; + $scope.pullTag = function (repository) { + $('#downloadResourceHint').show(); + RegistryService.retrievePorRegistryModelFromRepository(repository) + .then(function success(registryModel) { + return ImageService.pullImage(registryModel, false); + }) + .then(function success() { + Notifications.success('Image successfully pulled', repository); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to pull image'); + }) + .finally(function final() { + $('#downloadResourceHint').hide(); + }); + }; - $scope.removeTag = function(repository) { - ImageService.deleteImage(repository, false) - .then(function success() { - if ($scope.image.RepoTags.length === 1) { - Notifications.success('Image successfully deleted', repository); - $state.go('docker.images', {}, {reload: true}); - } else { - Notifications.success('Tag successfully deleted', repository); - $state.go('docker.images.image', {id: $transition$.params().id}, {reload: true}); - } - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove image'); - }); - }; + $scope.removeTag = function (repository) { + ImageService.deleteImage(repository, false) + .then(function success() { + if ($scope.image.RepoTags.length === 1) { + Notifications.success('Image successfully deleted', repository); + $state.go('docker.images', {}, { reload: true }); + } else { + Notifications.success('Tag successfully deleted', repository); + $state.go('docker.images.image', { id: $transition$.params().id }, { reload: true }); + } + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove image'); + }); + }; - $scope.removeImage = function (id) { - ImageService.deleteImage(id, false) - .then(function success() { - Notifications.success('Image successfully deleted', id); - $state.go('docker.images', {}, {reload: true}); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove image'); - }); - }; + $scope.removeImage = function (id) { + ImageService.deleteImage(id, false) + .then(function success() { + Notifications.success('Image successfully deleted', id); + $state.go('docker.images', {}, { reload: true }); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove image'); + }); + }; - function exportImage(image) { - HttpRequestHelper.setPortainerAgentTargetHeader(image.NodeName); - $scope.state.exportInProgress = true; - ImageService.downloadImages([image]) - .then(function success(data) { - var downloadData = new Blob([data.file], { type: 'application/x-tar' }); - FileSaver.saveAs(downloadData, 'images.tar'); - Notifications.success('Image successfully downloaded'); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to download image'); - }) - .finally(function final() { - $scope.state.exportInProgress = false; - }); - } + function exportImage(image) { + HttpRequestHelper.setPortainerAgentTargetHeader(image.NodeName); + $scope.state.exportInProgress = true; + ImageService.downloadImages([image]) + .then(function success(data) { + var downloadData = new Blob([data.file], { type: 'application/x-tar' }); + FileSaver.saveAs(downloadData, 'images.tar'); + Notifications.success('Image successfully downloaded'); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to download image'); + }) + .finally(function final() { + $scope.state.exportInProgress = false; + }); + } - $scope.exportImage = function (image) { - if (image.RepoTags.length === 0 || _.includes(image.RepoTags, '')) { - Notifications.warning('', 'Cannot download a untagged image'); - return; - } + $scope.exportImage = function (image) { + if (image.RepoTags.length === 0 || _.includes(image.RepoTags, '')) { + Notifications.warning('', 'Cannot download a untagged image'); + return; + } - ModalService.confirmImageExport(function (confirmed) { - if(!confirmed) { return; } - exportImage(image); - }); - }; + ModalService.confirmImageExport(function (confirmed) { + if (!confirmed) { + return; + } + exportImage(image); + }); + }; - function initView() { - HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); - var endpointProvider = $scope.applicationState.endpoint.mode.provider; - $q.all({ - image: ImageService.image($transition$.params().id), - history: endpointProvider !== 'VMWARE_VIC' ? ImageService.history($transition$.params().id) : [] - }) - .then(function success(data) { - $scope.image = data.image; - $scope.history = data.history; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve image details'); - $state.go('docker.images'); - }); - } + function initView() { + HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName); + var endpointProvider = $scope.applicationState.endpoint.mode.provider; + $q.all({ + image: ImageService.image($transition$.params().id), + history: endpointProvider !== 'VMWARE_VIC' ? ImageService.history($transition$.params().id) : [], + }) + .then(function success(data) { + $scope.image = data.image; + $scope.history = data.history; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve image details'); + $state.go('docker.images'); + }); + } - initView(); -}]); + initView(); + }, +]); diff --git a/app/docker/views/images/images.html b/app/docker/views/images/images.html index d8d82e043..9c7cb36b9 100644 --- a/app/docker/views/images/images.html +++ b/app/docker/views/images/images.html @@ -10,31 +10,29 @@
    - - + - +
    Deployment
    - - +
    - @@ -49,16 +47,18 @@
    diff --git a/app/docker/views/images/imagesController.js b/app/docker/views/images/imagesController.js index aed6f8cf6..1933af39f 100644 --- a/app/docker/views/images/imagesController.js +++ b/app/docker/views/images/imagesController.js @@ -1,137 +1,149 @@ import _ from 'lodash-es'; import { PorImageRegistryModel } from 'Docker/models/porImageRegistry'; -angular.module('portainer.docker') -.controller('ImagesController', ['$scope', '$state', 'ImageService', 'Notifications', 'ModalService', 'HttpRequestHelper', 'FileSaver', 'Blob', 'EndpointProvider', -function ($scope, $state, ImageService, Notifications, ModalService, HttpRequestHelper, FileSaver, Blob, EndpointProvider) { - $scope.state = { - actionInProgress: false, - exportInProgress: false - }; +angular.module('portainer.docker').controller('ImagesController', [ + '$scope', + '$state', + 'ImageService', + 'Notifications', + 'ModalService', + 'HttpRequestHelper', + 'FileSaver', + 'Blob', + 'EndpointProvider', + function ($scope, $state, ImageService, Notifications, ModalService, HttpRequestHelper, FileSaver, Blob, EndpointProvider) { + $scope.state = { + actionInProgress: false, + exportInProgress: false, + }; - $scope.formValues = { - RegistryModel: new PorImageRegistryModel(), - NodeName: null - }; + $scope.formValues = { + RegistryModel: new PorImageRegistryModel(), + NodeName: null, + }; - $scope.pullImage = function() { - const registryModel = $scope.formValues.RegistryModel; + $scope.pullImage = function () { + const registryModel = $scope.formValues.RegistryModel; - var nodeName = $scope.formValues.NodeName; - HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); + var nodeName = $scope.formValues.NodeName; + HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); - $scope.state.actionInProgress = true; - ImageService.pullImage(registryModel, false) - .then(function success() { - Notifications.success('Image successfully pulled', registryModel.Image); - $state.reload(); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to pull image'); - }) - .finally(function final() { - $scope.state.actionInProgress = false; - }); - }; + $scope.state.actionInProgress = true; + ImageService.pullImage(registryModel, false) + .then(function success() { + Notifications.success('Image successfully pulled', registryModel.Image); + $state.reload(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to pull image'); + }) + .finally(function final() { + $scope.state.actionInProgress = false; + }); + }; - $scope.confirmRemovalAction = function (selectedItems, force) { - ModalService.confirmImageForceRemoval(function (confirmed) { - if(!confirmed) { return; } - $scope.removeAction(selectedItems, force); - }); - }; - - function isAuthorizedToDownload(selectedItems) { - - for (var i = 0; i < selectedItems.length; i++) { - var image = selectedItems[i]; - - var untagged = _.find(image.RepoTags, function (item) { - return item.indexOf('') > -1; + $scope.confirmRemovalAction = function (selectedItems, force) { + ModalService.confirmImageForceRemoval(function (confirmed) { + if (!confirmed) { + return; + } + $scope.removeAction(selectedItems, force); }); + }; - if (untagged) { - Notifications.warning('', 'Cannot download a untagged image'); + function isAuthorizedToDownload(selectedItems) { + for (var i = 0; i < selectedItems.length; i++) { + var image = selectedItems[i]; + + var untagged = _.find(image.RepoTags, function (item) { + return item.indexOf('') > -1; + }); + + if (untagged) { + Notifications.warning('', 'Cannot download a untagged image'); + return false; + } + } + + if (_.uniqBy(selectedItems, 'NodeName').length > 1) { + Notifications.warning('', 'Cannot download images from different nodes at the same time'); return false; } + + return true; } - if (_.uniqBy(selectedItems, 'NodeName').length > 1) { - Notifications.warning('', 'Cannot download images from different nodes at the same time'); - return false; + function exportImages(images) { + HttpRequestHelper.setPortainerAgentTargetHeader(images[0].NodeName); + $scope.state.exportInProgress = true; + ImageService.downloadImages(images) + .then(function success(data) { + var downloadData = new Blob([data.file], { type: 'application/x-tar' }); + FileSaver.saveAs(downloadData, 'images.tar'); + Notifications.success('Image(s) successfully downloaded'); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to download image(s)'); + }) + .finally(function final() { + $scope.state.exportInProgress = false; + }); } - return true; - } + $scope.downloadAction = function (selectedItems) { + if (!isAuthorizedToDownload(selectedItems)) { + return; + } - function exportImages(images) { - HttpRequestHelper.setPortainerAgentTargetHeader(images[0].NodeName); - $scope.state.exportInProgress = true; - ImageService.downloadImages(images) - .then(function success(data) { - var downloadData = new Blob([data.file], { type: 'application/x-tar' }); - FileSaver.saveAs(downloadData, 'images.tar'); - Notifications.success('Image(s) successfully downloaded'); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to download image(s)'); - }) - .finally(function final() { - $scope.state.exportInProgress = false; - }); - } - - $scope.downloadAction = function (selectedItems) { - if (!isAuthorizedToDownload(selectedItems)) { - return; - } - - ModalService.confirmImageExport(function (confirmed) { - if(!confirmed) { return; } - exportImages(selectedItems); - }); - }; - - $scope.removeAction = function (selectedItems, force) { - var actionCount = selectedItems.length; - angular.forEach(selectedItems, function (image) { - HttpRequestHelper.setPortainerAgentTargetHeader(image.NodeName); - ImageService.deleteImage(image.Id, force) - .then(function success() { - Notifications.success('Image successfully removed', image.Id); - var index = $scope.images.indexOf(image); - $scope.images.splice(index, 1); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to remove image'); - }) - .finally(function final() { - --actionCount; - if (actionCount === 0) { - $state.reload(); + ModalService.confirmImageExport(function (confirmed) { + if (!confirmed) { + return; } + exportImages(selectedItems); }); - }); - }; + }; - $scope.offlineMode = false; + $scope.removeAction = function (selectedItems, force) { + var actionCount = selectedItems.length; + angular.forEach(selectedItems, function (image) { + HttpRequestHelper.setPortainerAgentTargetHeader(image.NodeName); + ImageService.deleteImage(image.Id, force) + .then(function success() { + Notifications.success('Image successfully removed', image.Id); + var index = $scope.images.indexOf(image); + $scope.images.splice(index, 1); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove image'); + }) + .finally(function final() { + --actionCount; + if (actionCount === 0) { + $state.reload(); + } + }); + }); + }; - $scope.getImages = getImages; - function getImages() { - ImageService.images(true) - .then(function success(data) { - $scope.images = data; - $scope.offlineMode = EndpointProvider.offlineMode(); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve images'); - $scope.images = []; - }); - } + $scope.offlineMode = false; - function initView() { - getImages(); - } + $scope.getImages = getImages; + function getImages() { + ImageService.images(true) + .then(function success(data) { + $scope.images = data; + $scope.offlineMode = EndpointProvider.offlineMode(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve images'); + $scope.images = []; + }); + } - initView(); -}]); + function initView() { + getImages(); + } + + initView(); + }, +]); diff --git a/app/docker/views/images/import/importImageController.js b/app/docker/views/images/import/importImageController.js index b993a614f..d8d7d0027 100644 --- a/app/docker/views/images/import/importImageController.js +++ b/app/docker/views/images/import/importImageController.js @@ -1,31 +1,35 @@ -angular.module('portainer.docker') -.controller('ImportImageController', ['$scope', '$state', 'ImageService', 'Notifications', 'HttpRequestHelper', -function ($scope, $state, ImageService, Notifications, HttpRequestHelper) { +angular.module('portainer.docker').controller('ImportImageController', [ + '$scope', + '$state', + 'ImageService', + 'Notifications', + 'HttpRequestHelper', + function ($scope, $state, ImageService, Notifications, HttpRequestHelper) { + $scope.state = { + actionInProgress: false, + }; - $scope.state = { - actionInProgress: false - }; + $scope.formValues = { + UploadFile: null, + NodeName: null, + }; - $scope.formValues = { - UploadFile: null, - NodeName: null - }; + $scope.uploadImage = function () { + $scope.state.actionInProgress = true; - $scope.uploadImage = function() { - $scope.state.actionInProgress = true; - - var nodeName = $scope.formValues.NodeName; - HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); - var file = $scope.formValues.UploadFile; - ImageService.uploadImage(file) - .then(function success() { - Notifications.success('Images successfully uploaded'); - }) - .catch(function error(err) { - Notifications.error('Failure', err.message, 'Unable to upload image'); - }) - .finally(function final() { - $scope.state.actionInProgress = false; - }); - }; -}]); + var nodeName = $scope.formValues.NodeName; + HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); + var file = $scope.formValues.UploadFile; + ImageService.uploadImage(file) + .then(function success() { + Notifications.success('Images successfully uploaded'); + }) + .catch(function error(err) { + Notifications.error('Failure', err.message, 'Unable to upload image'); + }) + .finally(function final() { + $scope.state.actionInProgress = false; + }); + }; + }, +]); diff --git a/app/docker/views/images/import/importimage.html b/app/docker/views/images/import/importimage.html index 6a6b20f31..5f10e4562 100644 --- a/app/docker/views/images/import/importimage.html +++ b/app/docker/views/images/import/importimage.html @@ -1,8 +1,6 @@ - - Images > Import image - + Images > Import image
    @@ -21,7 +19,9 @@
    - + {{ formValues.UploadFile.name }} @@ -34,8 +34,7 @@ Deployment
    - - +
    @@ -44,8 +43,13 @@
    - @@ -57,4 +61,4 @@
    -
    \ No newline at end of file +
    diff --git a/app/docker/views/networks/create/createNetworkController.js b/app/docker/views/networks/create/createNetworkController.js index a592582a6..233c221f1 100644 --- a/app/docker/views/networks/create/createNetworkController.js +++ b/app/docker/views/networks/create/createNetworkController.js @@ -1,218 +1,235 @@ import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel'; import { MacvlanFormData } from '../../../components/network-macvlan-form/networkMacvlanFormModel'; -angular.module('portainer.docker') - .controller('CreateNetworkController', ['$q', '$scope', '$state', 'PluginService', 'Notifications', 'NetworkService', 'LabelHelper', 'Authentication', 'ResourceControlService', 'FormValidator', 'HttpRequestHelper', - function ($q, $scope, $state, PluginService, Notifications, NetworkService, LabelHelper, Authentication, ResourceControlService, FormValidator, HttpRequestHelper) { +angular.module('portainer.docker').controller('CreateNetworkController', [ + '$q', + '$scope', + '$state', + 'PluginService', + 'Notifications', + 'NetworkService', + 'LabelHelper', + 'Authentication', + 'ResourceControlService', + 'FormValidator', + 'HttpRequestHelper', + function ($q, $scope, $state, PluginService, Notifications, NetworkService, LabelHelper, Authentication, ResourceControlService, FormValidator, HttpRequestHelper) { + $scope.formValues = { + DriverOptions: [], + Subnet: '', + Gateway: '', + IPRange: '', + AuxAddress: '', + Labels: [], + AccessControlData: new AccessControlFormData(), + NodeName: null, + Macvlan: new MacvlanFormData(), + }; - $scope.formValues = { - DriverOptions: [], - Subnet: '', - Gateway: '', - IPRange: '', - AuxAddress: '', - Labels: [], - AccessControlData: new AccessControlFormData(), - NodeName: null, - Macvlan: new MacvlanFormData() - }; + $scope.state = { + formValidationError: '', + actionInProgress: false, + }; - $scope.state = { - formValidationError: '', - actionInProgress: false - }; + $scope.availableNetworkDrivers = []; - $scope.availableNetworkDrivers = []; + $scope.config = { + Driver: 'bridge', + CheckDuplicate: true, + Internal: false, + Attachable: false, + // Force IPAM Driver to 'default', should not be required. + // See: https://github.com/docker/docker/issues/25735 + IPAM: { + Driver: 'default', + Config: [], + }, + Labels: {}, + }; - $scope.config = { - Driver: 'bridge', - CheckDuplicate: true, - Internal: false, - Attachable: false, - // Force IPAM Driver to 'default', should not be required. - // See: https://github.com/docker/docker/issues/25735 - IPAM: { - Driver: 'default', - Config: [] - }, - Labels: {} - }; + $scope.addDriverOption = function () { + $scope.formValues.DriverOptions.push({ + name: '', + value: '', + }); + }; - $scope.addDriverOption = function () { - $scope.formValues.DriverOptions.push({ - name: '', - value: '' - }); - }; + $scope.removeDriverOption = function (index) { + $scope.formValues.DriverOptions.splice(index, 1); + }; - $scope.removeDriverOption = function (index) { - $scope.formValues.DriverOptions.splice(index, 1); - }; + $scope.addLabel = function () { + $scope.formValues.Labels.push({ + key: '', + value: '', + }); + }; - $scope.addLabel = function () { - $scope.formValues.Labels.push({ - key: '', - value: '' - }); - }; + $scope.removeLabel = function (index) { + $scope.formValues.Labels.splice(index, 1); + }; - $scope.removeLabel = function (index) { - $scope.formValues.Labels.splice(index, 1); - }; - - function prepareIPAMConfiguration(config) { - if ($scope.formValues.Subnet) { - var ipamConfig = {}; - ipamConfig.Subnet = $scope.formValues.Subnet; - if ($scope.formValues.Gateway) { - ipamConfig.Gateway = $scope.formValues.Gateway; - } - if ($scope.formValues.IPRange) { - ipamConfig.IPRange = $scope.formValues.IPRange; - } - if ($scope.formValues.AuxAddress) { - ipamConfig.AuxAddress = $scope.formValues.AuxAddress; - } - config.IPAM.Config.push(ipamConfig); + function prepareIPAMConfiguration(config) { + if ($scope.formValues.Subnet) { + var ipamConfig = {}; + ipamConfig.Subnet = $scope.formValues.Subnet; + if ($scope.formValues.Gateway) { + ipamConfig.Gateway = $scope.formValues.Gateway; } - } - - function prepareDriverOptions(config) { - var options = {}; - $scope.formValues.DriverOptions.forEach(function (option) { - options[option.name] = option.value; - }); - config.Options = options; - } - - function prepareLabelsConfig(config) { - config.Labels = LabelHelper.fromKeyValueToLabelHash($scope.formValues.Labels); - } - - function prepareConfiguration() { - var config = angular.copy($scope.config); - prepareIPAMConfiguration(config); - prepareDriverOptions(config); - prepareLabelsConfig(config); - return config; - } - - function modifyNetworkConfigurationForMacvlanConfigOnly(config) { - config.Internal = null; - config.Attachable = null; - config.ConfigOnly = true; - config.Options.parent = $scope.formValues.Macvlan.ParentNetworkCard; - } - - function modifyNetworkConfigurationForMacvlanConfigFrom(config, selectedNetworkConfig) { - config.ConfigFrom = { - Network: selectedNetworkConfig.Name - }; - if ($scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') { - config.Scope = 'swarm'; - } else { - config.Scope = 'local'; + if ($scope.formValues.IPRange) { + ipamConfig.IPRange = $scope.formValues.IPRange; } + if ($scope.formValues.AuxAddress) { + ipamConfig.AuxAddress = $scope.formValues.AuxAddress; + } + config.IPAM.Config.push(ipamConfig); } - - function validateForm(accessControlData, isAdmin) { - $scope.state.formValidationError = ''; - var error = ''; - error = FormValidator.validateAccessControl(accessControlData, isAdmin); - - if (error) { - $scope.state.formValidationError = error; - return false; - } - return true; - } - - function createNetwork(context) { - HttpRequestHelper.setPortainerAgentTargetHeader(context.nodeName); - HttpRequestHelper.setPortainerAgentManagerOperation(context.managerOperation); - - $scope.state.actionInProgress = true; - NetworkService.create(context.networkConfiguration) - .then(function success(data) { - const userId = context.userDetails.ID; - const accessControlData = context.accessControlData; - const resourceControl = data.Portainer.ResourceControl; - return ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); - }) - .then(function success() { - Notifications.success('Network successfully created'); - if (context.reload) { - $state.go('docker.networks', {}, { - reload: true - }); - } - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'An error occured during network creation'); - }) - .finally(function final() { - $scope.state.actionInProgress = false; - }); - } - - $scope.create = function () { - var networkConfiguration = prepareConfiguration(); - var accessControlData = $scope.formValues.AccessControlData; - var userDetails = Authentication.getUserDetails(); - var isAdmin = Authentication.isAdmin(); - - if (!validateForm(accessControlData, isAdmin)) { - return; - } - - var creationContext = { - nodeName: $scope.formValues.NodeName, - managerOperation: false, - networkConfiguration: networkConfiguration, - userDetails: userDetails, - accessControlData: accessControlData, - reload: true - }; - - if ($scope.applicationState.endpoint.mode.agentProxy && $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && $scope.config.Driver === 'overlay') { - creationContext.managerOperation = true; - } - - if ($scope.config.Driver === 'macvlan') { - if ($scope.formValues.Macvlan.Scope === 'local') { - modifyNetworkConfigurationForMacvlanConfigOnly(networkConfiguration); - } else if ($scope.formValues.Macvlan.Scope === 'swarm') { - var selectedNetworkConfig = $scope.formValues.Macvlan.SelectedNetworkConfig; - modifyNetworkConfigurationForMacvlanConfigFrom(networkConfiguration, selectedNetworkConfig); - creationContext.nodeName = selectedNetworkConfig.NodeName; - } - } - - if ($scope.config.Driver === 'macvlan' && $scope.formValues.Macvlan.Scope === 'local' && - $scope.applicationState.endpoint.mode.agentProxy && $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') { - var selectedNodes = $scope.formValues.Macvlan.DatatableState.selectedItems; - selectedNodes.forEach(function (node, idx) { - creationContext.nodeName = node.Hostname; - creationContext.reload = idx === selectedNodes.length - 1 ? true : false; - createNetwork(creationContext); - }); - } else { - createNetwork(creationContext); - } - }; - - function initView() { - var apiVersion = $scope.applicationState.endpoint.apiVersion; - - PluginService.networkPlugins(apiVersion < 1.25) - .then(function success(data) { - $scope.availableNetworkDrivers = data; - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to retrieve network drivers'); - }); - } - - initView(); } - ]); + + function prepareDriverOptions(config) { + var options = {}; + $scope.formValues.DriverOptions.forEach(function (option) { + options[option.name] = option.value; + }); + config.Options = options; + } + + function prepareLabelsConfig(config) { + config.Labels = LabelHelper.fromKeyValueToLabelHash($scope.formValues.Labels); + } + + function prepareConfiguration() { + var config = angular.copy($scope.config); + prepareIPAMConfiguration(config); + prepareDriverOptions(config); + prepareLabelsConfig(config); + return config; + } + + function modifyNetworkConfigurationForMacvlanConfigOnly(config) { + config.Internal = null; + config.Attachable = null; + config.ConfigOnly = true; + config.Options.parent = $scope.formValues.Macvlan.ParentNetworkCard; + } + + function modifyNetworkConfigurationForMacvlanConfigFrom(config, selectedNetworkConfig) { + config.ConfigFrom = { + Network: selectedNetworkConfig.Name, + }; + if ($scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') { + config.Scope = 'swarm'; + } else { + config.Scope = 'local'; + } + } + + function validateForm(accessControlData, isAdmin) { + $scope.state.formValidationError = ''; + var error = ''; + error = FormValidator.validateAccessControl(accessControlData, isAdmin); + + if (error) { + $scope.state.formValidationError = error; + return false; + } + return true; + } + + function createNetwork(context) { + HttpRequestHelper.setPortainerAgentTargetHeader(context.nodeName); + HttpRequestHelper.setPortainerAgentManagerOperation(context.managerOperation); + + $scope.state.actionInProgress = true; + NetworkService.create(context.networkConfiguration) + .then(function success(data) { + const userId = context.userDetails.ID; + const accessControlData = context.accessControlData; + const resourceControl = data.Portainer.ResourceControl; + return ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); + }) + .then(function success() { + Notifications.success('Network successfully created'); + if (context.reload) { + $state.go( + 'docker.networks', + {}, + { + reload: true, + } + ); + } + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'An error occured during network creation'); + }) + .finally(function final() { + $scope.state.actionInProgress = false; + }); + } + + $scope.create = function () { + var networkConfiguration = prepareConfiguration(); + var accessControlData = $scope.formValues.AccessControlData; + var userDetails = Authentication.getUserDetails(); + var isAdmin = Authentication.isAdmin(); + + if (!validateForm(accessControlData, isAdmin)) { + return; + } + + var creationContext = { + nodeName: $scope.formValues.NodeName, + managerOperation: false, + networkConfiguration: networkConfiguration, + userDetails: userDetails, + accessControlData: accessControlData, + reload: true, + }; + + if ($scope.applicationState.endpoint.mode.agentProxy && $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && $scope.config.Driver === 'overlay') { + creationContext.managerOperation = true; + } + + if ($scope.config.Driver === 'macvlan') { + if ($scope.formValues.Macvlan.Scope === 'local') { + modifyNetworkConfigurationForMacvlanConfigOnly(networkConfiguration); + } else if ($scope.formValues.Macvlan.Scope === 'swarm') { + var selectedNetworkConfig = $scope.formValues.Macvlan.SelectedNetworkConfig; + modifyNetworkConfigurationForMacvlanConfigFrom(networkConfiguration, selectedNetworkConfig); + creationContext.nodeName = selectedNetworkConfig.NodeName; + } + } + + if ( + $scope.config.Driver === 'macvlan' && + $scope.formValues.Macvlan.Scope === 'local' && + $scope.applicationState.endpoint.mode.agentProxy && + $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' + ) { + var selectedNodes = $scope.formValues.Macvlan.DatatableState.selectedItems; + selectedNodes.forEach(function (node, idx) { + creationContext.nodeName = node.Hostname; + creationContext.reload = idx === selectedNodes.length - 1 ? true : false; + createNetwork(creationContext); + }); + } else { + createNetwork(creationContext); + } + }; + + function initView() { + var apiVersion = $scope.applicationState.endpoint.apiVersion; + + PluginService.networkPlugins(apiVersion < 1.25) + .then(function success(data) { + $scope.availableNetworkDrivers = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve network drivers'); + }); + } + + initView(); + }, +]); diff --git a/app/docker/views/networks/create/createnetwork.html b/app/docker/views/networks/create/createnetwork.html index 03711c36c..fedcad7bc 100644 --- a/app/docker/views/networks/create/createnetwork.html +++ b/app/docker/views/networks/create/createnetwork.html @@ -1,8 +1,6 @@ - - Networks > Add network - + Networks > Add network
    @@ -14,7 +12,7 @@
    - +
    @@ -28,7 +26,7 @@ - +
    @@ -37,7 +35,10 @@
    add driver option @@ -48,11 +49,11 @@
    name - +
    value - +
    @@ -144,19 +143,25 @@ Enable manual container attachment
    -
    +
    Deployment
    - - +
    @@ -168,8 +173,13 @@
    - @@ -182,4 +192,4 @@
    -
    \ No newline at end of file + diff --git a/app/docker/views/networks/edit/network.html b/app/docker/views/networks/edit/network.html index b5ee95ce0..b0be069f4 100644 --- a/app/docker/views/networks/edit/network.html +++ b/app/docker/views/networks/edit/network.html @@ -20,7 +20,9 @@
    ID {{ network.Id }} - +
    {{ container.Name }}{{ container.Name }} {{ container.IPv4Address || '-' }} {{ container.IPv6Address || '-' }} {{ container.MacAddress || '-' }} - +
    ID {{ secret.Id }} - +
    @@ -25,9 +22,18 @@ - + diff --git a/app/docker/views/services/edit/includes/constraints.html b/app/docker/views/services/edit/includes/constraints.html index 69c681e4e..372bd6660 100644 --- a/app/docker/views/services/edit/includes/constraints.html +++ b/app/docker/views/services/edit/includes/constraints.html @@ -11,7 +11,7 @@

    There are no placement constraints for this service.

    -
    {{ config.Name }}{{ config.Name }} - + {{ config.Uid }} {{ config.Gid }}
    +
    @@ -23,12 +23,27 @@ - + - +
    Name
    - +
    - @@ -36,7 +51,15 @@
    - +
    CMD{{ service.Command|command }}{{ service.Command | command }}

    Command to execute. @@ -15,7 +17,9 @@

    Args{{ service.Arguments }}{{ service.Arguments }}

    Arguments passed to command in container. diff --git a/app/docker/views/services/edit/includes/containerlabels.html b/app/docker/views/services/edit/includes/containerlabels.html index 0ebac64b2..6a75a84d1 100644 --- a/app/docker/views/services/edit/includes/containerlabels.html +++ b/app/docker/views/services/edit/includes/containerlabels.html @@ -11,7 +11,7 @@

    There are no container labels for this service.

    - +
    @@ -23,13 +23,29 @@
    Label
    name - +
    value - + + diff --git a/app/docker/views/services/edit/includes/environmentvariables.html b/app/docker/views/services/edit/includes/environmentvariables.html index aa9298057..32e4d425f 100644 --- a/app/docker/views/services/edit/includes/environmentvariables.html +++ b/app/docker/views/services/edit/includes/environmentvariables.html @@ -11,7 +11,7 @@

    There are no environment variables for this service.

    - +
    @@ -23,13 +23,21 @@
    Name
    name - +
    value - +