diff --git a/api/bolt/migrate_dbversion4.go b/api/bolt/migrate_dbversion4.go new file mode 100644 index 000000000..ace64f51e --- /dev/null +++ b/api/bolt/migrate_dbversion4.go @@ -0,0 +1,16 @@ +package bolt + +func (m *Migrator) updateSettingsToVersion5() error { + legacySettings, err := m.SettingsService.Settings() + if err != nil { + return err + } + legacySettings.AllowBindMountsForRegularUsers = true + + err = m.SettingsService.StoreSettings(legacySettings) + if err != nil { + return err + } + + return nil +} diff --git a/api/bolt/migrator.go b/api/bolt/migrator.go index faba56157..2730fe7e9 100644 --- a/api/bolt/migrator.go +++ b/api/bolt/migrator.go @@ -65,6 +65,14 @@ func (m *Migrator) Migrate() error { } } + // https://github.com/portainer/portainer/issues/1235 + if m.CurrentDBVersion < 5 { + err := m.updateSettingsToVersion5() + if err != nil { + return err + } + } + err := m.VersionService.StoreDBVersion(portainer.DBVersion) if err != nil { return err diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go index 0b536c895..ac8c7f57d 100644 --- a/api/cmd/portainer/main.go +++ b/api/cmd/portainer/main.go @@ -125,6 +125,7 @@ func initSettings(settingsService portainer.SettingsService, flags *portainer.CL portainer.LDAPSearchSettings{}, }, }, + AllowBindMountsForRegularUsers: true, } if *flags.Templates != "" { diff --git a/api/http/handler/settings.go b/api/http/handler/settings.go index 52e957f6d..8e3679e6f 100644 --- a/api/http/handler/settings.go +++ b/api/http/handler/settings.go @@ -45,18 +45,20 @@ func NewSettingsHandler(bouncer *security.RequestBouncer) *SettingsHandler { type ( publicSettingsResponse struct { - LogoURL string `json:"LogoURL"` - DisplayExternalContributors bool `json:"DisplayExternalContributors"` - AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"` + LogoURL string `json:"LogoURL"` + DisplayExternalContributors bool `json:"DisplayExternalContributors"` + AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"` + AllowBindMountsForRegularUsers bool `json:"AllowBindMountsForRegularUsers"` } putSettingsRequest struct { - TemplatesURL string `valid:"required"` - LogoURL string `valid:""` - BlackListedLabels []portainer.Pair `valid:""` - DisplayExternalContributors bool `valid:""` - AuthenticationMethod int `valid:"required"` - LDAPSettings portainer.LDAPSettings `valid:""` + TemplatesURL string `valid:"required"` + LogoURL string `valid:""` + BlackListedLabels []portainer.Pair `valid:""` + DisplayExternalContributors bool `valid:""` + AuthenticationMethod int `valid:"required"` + LDAPSettings portainer.LDAPSettings `valid:""` + AllowBindMountsForRegularUsers bool `valid:""` } putSettingsLDAPCheckRequest struct { @@ -85,9 +87,10 @@ func (handler *SettingsHandler) handleGetPublicSettings(w http.ResponseWriter, r } publicSettings := &publicSettingsResponse{ - LogoURL: settings.LogoURL, - DisplayExternalContributors: settings.DisplayExternalContributors, - AuthenticationMethod: settings.AuthenticationMethod, + LogoURL: settings.LogoURL, + DisplayExternalContributors: settings.DisplayExternalContributors, + AuthenticationMethod: settings.AuthenticationMethod, + AllowBindMountsForRegularUsers: settings.AllowBindMountsForRegularUsers, } encodeJSON(w, publicSettings, handler.Logger) @@ -109,11 +112,12 @@ func (handler *SettingsHandler) handlePutSettings(w http.ResponseWriter, r *http } settings := &portainer.Settings{ - TemplatesURL: req.TemplatesURL, - LogoURL: req.LogoURL, - BlackListedLabels: req.BlackListedLabels, - DisplayExternalContributors: req.DisplayExternalContributors, - LDAPSettings: req.LDAPSettings, + TemplatesURL: req.TemplatesURL, + LogoURL: req.LogoURL, + BlackListedLabels: req.BlackListedLabels, + DisplayExternalContributors: req.DisplayExternalContributors, + LDAPSettings: req.LDAPSettings, + AllowBindMountsForRegularUsers: req.AllowBindMountsForRegularUsers, } if req.AuthenticationMethod == 1 { diff --git a/api/portainer.go b/api/portainer.go index 539f9745b..bfbac90a9 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -70,12 +70,13 @@ type ( // Settings represents the application settings. Settings struct { - TemplatesURL string `json:"TemplatesURL"` - LogoURL string `json:"LogoURL"` - BlackListedLabels []Pair `json:"BlackListedLabels"` - DisplayExternalContributors bool `json:"DisplayExternalContributors"` - AuthenticationMethod AuthenticationMethod `json:"AuthenticationMethod"` - LDAPSettings LDAPSettings `json:"LDAPSettings"` + TemplatesURL string `json:"TemplatesURL"` + LogoURL string `json:"LogoURL"` + BlackListedLabels []Pair `json:"BlackListedLabels"` + DisplayExternalContributors bool `json:"DisplayExternalContributors"` + AuthenticationMethod AuthenticationMethod `json:"AuthenticationMethod"` + LDAPSettings LDAPSettings `json:"LDAPSettings"` + AllowBindMountsForRegularUsers bool `json:"AllowBindMountsForRegularUsers"` } // User represents a user account. @@ -348,7 +349,7 @@ const ( // APIVersion is the version number of the Portainer API. APIVersion = "1.14.2" // DBVersion is the version number of the Portainer database. - DBVersion = 4 + DBVersion = 5 // DefaultTemplatesURL represents the default URL for the templates definitions. DefaultTemplatesURL = "https://raw.githubusercontent.com/portainer/templates/master/templates.json" ) diff --git a/app/components/createContainer/createContainerController.js b/app/components/createContainer/createContainerController.js index a9da83b59..77c44cff7 100644 --- a/app/components/createContainer/createContainerController.js +++ b/app/components/createContainer/createContainerController.js @@ -1,8 +1,8 @@ // @@OLD_SERVICE_CONTROLLER: this service should be rewritten to use services. // See app/components/templates/templatesController.js as a reference. angular.module('createContainer', []) -.controller('CreateContainerController', ['$q', '$scope', '$state', '$transition$', '$filter', 'Container', 'ContainerHelper', 'Image', 'ImageHelper', 'Volume', 'NetworkService', 'ResourceControlService', 'Authentication', 'Notifications', 'ContainerService', 'ImageService', 'FormValidator', 'ModalService', 'RegistryService', -function ($q, $scope, $state, $transition$, $filter, Container, ContainerHelper, Image, ImageHelper, Volume, NetworkService, ResourceControlService, Authentication, Notifications, ContainerService, ImageService, FormValidator, ModalService, RegistryService) { +.controller('CreateContainerController', ['$q', '$scope', '$state', '$transition$', '$filter', 'Container', 'ContainerHelper', 'Image', 'ImageHelper', 'Volume', 'NetworkService', 'ResourceControlService', 'Authentication', 'Notifications', 'ContainerService', 'ImageService', 'FormValidator', 'ModalService', 'RegistryService', 'SettingsService', +function ($q, $scope, $state, $transition$, $filter, Container, ContainerHelper, Image, ImageHelper, Volume, NetworkService, ResourceControlService, Authentication, Notifications, ContainerService, ImageService, FormValidator, ModalService, RegistryService, SettingsService) { $scope.formValues = { alwaysPull: true, @@ -482,6 +482,16 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerHelper, Notifications.error('Failure', e, 'Unable to retrieve running containers'); }); + SettingsService.publicSettings() + .then(function success(data) { + $scope.allowBindMounts = data.AllowBindMountsForRegularUsers; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve application settings'); + }); + + var userDetails = Authentication.getUserDetails(); + $scope.isAdmin = userDetails.role === 1 ? true : false; } function validateForm(accessControlData, isAdmin) { diff --git a/app/components/createContainer/createcontainer.html b/app/components/createContainer/createcontainer.html index fd282d5b8..fe61cd720 100644 --- a/app/components/createContainer/createcontainer.html +++ b/app/components/createContainer/createcontainer.html @@ -235,7 +235,7 @@ -