diff --git a/app/constants.js b/app/constants.js index 547c7d518..cb0e8f17f 100644 --- a/app/constants.js +++ b/app/constants.js @@ -22,6 +22,7 @@ angular .constant('API_ENDPOINT_TEAM_MEMBERSHIPS', 'api/team_memberships') .constant('API_ENDPOINT_TEMPLATES', 'api/templates') .constant('API_ENDPOINT_WEBHOOKS', 'api/webhooks') + .constant('API_ENDPOINT_BACKUP', 'api/backup') .constant('DEFAULT_TEMPLATES_URL', 'https://raw.githubusercontent.com/portainer/templates/master/templates.json') .constant('PAGINATION_MAX_ITEMS', 10) .constant('APPLICATION_CACHE_VALIDITY', 3600) diff --git a/app/portainer/rest/backup.js b/app/portainer/rest/backup.js new file mode 100644 index 000000000..50526c5b0 --- /dev/null +++ b/app/portainer/rest/backup.js @@ -0,0 +1,27 @@ +angular.module('portainer.app').factory('Backup', [ + '$resource', + 'API_ENDPOINT_BACKUP', + function BackupFactory($resource, API_ENDPOINT_BACKUP) { + 'use strict'; + return $resource( + API_ENDPOINT_BACKUP + '/:subResource/:action', + {}, + { + download: { + method: 'POST', + responseType: 'blob', + ignoreLoadingBar: true, + transformResponse: (data, headersGetter) => ({ + file: data, + name: headersGetter('Content-Disposition').replace('attachment; filename=', ''), + }), + }, + getS3Settings: { method: 'GET', params: { subResource: 's3', action: 'settings' } }, + saveS3Settings: { method: 'POST', params: { subResource: 's3', action: 'settings' } }, + exportS3Backup: { method: 'POST', params: { subResource: 's3', action: 'execute' } }, + restoreS3Backup: { method: 'POST', params: { subResource: 's3', action: 'restore' } }, + getBackupStatus: { method: 'GET', params: { subResource: 's3', action: 'status' } }, + } + ); + }, +]); diff --git a/app/portainer/services/api/backupService.js b/app/portainer/services/api/backupService.js new file mode 100644 index 000000000..1ff04cda0 --- /dev/null +++ b/app/portainer/services/api/backupService.js @@ -0,0 +1,90 @@ +angular.module('portainer.app').factory('BackupService', [ + '$q', + '$async', + 'Backup', + 'FileUploadService', + function BackupServiceFactory($q, $async, Backup, FileUploadService) { + 'use strict'; + const service = {}; + + service.downloadBackup = function (payload) { + return Backup.download({}, payload).$promise; + }; + + service.uploadBackup = function (file, password) { + return FileUploadService.uploadBackup(file, password); + }; + + service.getS3Settings = function () { + var deferred = $q.defer(); + + Backup.getS3Settings() + .$promise.then(function success(data) { + deferred.resolve(data); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve backup S3 settings', err: err }); + }); + + return deferred.promise; + }; + + service.saveS3Settings = function (payload) { + var deferred = $q.defer(); + + Backup.saveS3Settings({}, payload) + .$promise.then(function success(data) { + deferred.resolve(data); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to save backup S3 settings', err: err }); + }); + + return deferred.promise; + }; + + service.exportBackup = function (payload) { + var deferred = $q.defer(); + + Backup.exportS3Backup({}, payload) + .$promise.then(function success(data) { + deferred.resolve(data); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to export backup', err: err }); + }); + + return deferred.promise; + }; + + service.restoreFromS3 = function (payload) { + var deferred = $q.defer(); + + Backup.restoreS3Backup({}, payload) + .$promise.then(function success(data) { + deferred.resolve(data); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to restore backup from S3', err: err }); + }); + + return deferred.promise; + }; + + service.getBackupStatus = function () { + var deferred = $q.defer(); + + Backup.getBackupStatus() + .$promise.then(function success(data) { + deferred.resolve(data); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve backup status', err: err }); + }); + + return deferred.promise; + }; + + return service; + }, +]); diff --git a/app/portainer/services/fileUpload.js b/app/portainer/services/fileUpload.js index a9df4606a..81340d623 100644 --- a/app/portainer/services/fileUpload.js +++ b/app/portainer/services/fileUpload.js @@ -61,6 +61,16 @@ angular.module('portainer.app').factory('FileUploadService', [ }); }; + service.uploadBackup = function (file, password) { + return Upload.upload({ + url: 'api/restore', + data: { + file, + password, + }, + }); + }; + service.createSwarmStack = function (stackName, swarmId, file, env, endpointId) { return Upload.upload({ url: 'api/stacks?method=file&type=1&endpointId=' + endpointId, diff --git a/app/portainer/views/init/admin/initAdmin.html b/app/portainer/views/init/admin/initAdmin.html index b3643ea58..72921d19e 100644 --- a/app/portainer/views/init/admin/initAdmin.html +++ b/app/portainer/views/init/admin/initAdmin.html @@ -11,8 +11,17 @@
This field is required.
+