mirror of https://github.com/portainer/portainer
feat(templates): fix an issue with templates initialization and update settings view
parent
5563ff60fc
commit
f371dc5402
|
@ -5,16 +5,14 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/portainer/portainer/api/bolt/edgegroup"
|
|
||||||
"github.com/portainer/portainer/api/bolt/edgestack"
|
|
||||||
"github.com/portainer/portainer/api/bolt/endpointrelation"
|
|
||||||
"github.com/portainer/portainer/api/bolt/tunnelserver"
|
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/portainer/portainer/api"
|
"github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/bolt/dockerhub"
|
"github.com/portainer/portainer/api/bolt/dockerhub"
|
||||||
|
"github.com/portainer/portainer/api/bolt/edgegroup"
|
||||||
|
"github.com/portainer/portainer/api/bolt/edgestack"
|
||||||
"github.com/portainer/portainer/api/bolt/endpoint"
|
"github.com/portainer/portainer/api/bolt/endpoint"
|
||||||
"github.com/portainer/portainer/api/bolt/endpointgroup"
|
"github.com/portainer/portainer/api/bolt/endpointgroup"
|
||||||
|
"github.com/portainer/portainer/api/bolt/endpointrelation"
|
||||||
"github.com/portainer/portainer/api/bolt/extension"
|
"github.com/portainer/portainer/api/bolt/extension"
|
||||||
"github.com/portainer/portainer/api/bolt/migrator"
|
"github.com/portainer/portainer/api/bolt/migrator"
|
||||||
"github.com/portainer/portainer/api/bolt/registry"
|
"github.com/portainer/portainer/api/bolt/registry"
|
||||||
|
@ -26,6 +24,7 @@ import (
|
||||||
"github.com/portainer/portainer/api/bolt/tag"
|
"github.com/portainer/portainer/api/bolt/tag"
|
||||||
"github.com/portainer/portainer/api/bolt/team"
|
"github.com/portainer/portainer/api/bolt/team"
|
||||||
"github.com/portainer/portainer/api/bolt/teammembership"
|
"github.com/portainer/portainer/api/bolt/teammembership"
|
||||||
|
"github.com/portainer/portainer/api/bolt/tunnelserver"
|
||||||
"github.com/portainer/portainer/api/bolt/user"
|
"github.com/portainer/portainer/api/bolt/user"
|
||||||
"github.com/portainer/portainer/api/bolt/version"
|
"github.com/portainer/portainer/api/bolt/version"
|
||||||
"github.com/portainer/portainer/api/bolt/webhook"
|
"github.com/portainer/portainer/api/bolt/webhook"
|
||||||
|
@ -40,7 +39,7 @@ const (
|
||||||
type Store struct {
|
type Store struct {
|
||||||
path string
|
path string
|
||||||
db *bolt.DB
|
db *bolt.DB
|
||||||
checkForDataMigration bool
|
isNew bool
|
||||||
fileService portainer.FileService
|
fileService portainer.FileService
|
||||||
RoleService *role.Service
|
RoleService *role.Service
|
||||||
DockerHubService *dockerhub.Service
|
DockerHubService *dockerhub.Service
|
||||||
|
@ -69,6 +68,7 @@ func NewStore(storePath string, fileService portainer.FileService) (*Store, erro
|
||||||
store := &Store{
|
store := &Store{
|
||||||
path: storePath,
|
path: storePath,
|
||||||
fileService: fileService,
|
fileService: fileService,
|
||||||
|
isNew: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
databasePath := path.Join(storePath, databaseFileName)
|
databasePath := path.Join(storePath, databaseFileName)
|
||||||
|
@ -77,10 +77,8 @@ func NewStore(storePath string, fileService portainer.FileService) (*Store, erro
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !databaseFileExists {
|
if databaseFileExists {
|
||||||
store.checkForDataMigration = false
|
store.isNew = false
|
||||||
} else {
|
|
||||||
store.checkForDataMigration = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return store, nil
|
return store, nil
|
||||||
|
@ -106,9 +104,16 @@ func (store *Store) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNew returns true if the database was just created and false if it is re-using
|
||||||
|
// existing data.
|
||||||
|
func (store *Store) IsNew() bool {
|
||||||
|
return store.isNew
|
||||||
|
}
|
||||||
|
|
||||||
// MigrateData automatically migrate the data based on the DBVersion.
|
// MigrateData automatically migrate the data based on the DBVersion.
|
||||||
|
// This process is only triggered on an existing database, not if the database was just created.
|
||||||
func (store *Store) MigrateData() error {
|
func (store *Store) MigrateData() error {
|
||||||
if !store.checkForDataMigration {
|
if store.isNew {
|
||||||
return store.VersionService.StoreDBVersion(portainer.DBVersion)
|
return store.VersionService.StoreDBVersion(portainer.DBVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,55 @@ import portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
// Init creates the default data set.
|
// Init creates the default data set.
|
||||||
func (store *Store) Init() error {
|
func (store *Store) Init() error {
|
||||||
|
_, err := store.SettingsService.Settings()
|
||||||
|
if err == portainer.ErrObjectNotFound {
|
||||||
|
defaultSettings := &portainer.Settings{
|
||||||
|
AuthenticationMethod: portainer.AuthenticationInternal,
|
||||||
|
BlackListedLabels: make([]portainer.Pair, 0),
|
||||||
|
LDAPSettings: portainer.LDAPSettings{
|
||||||
|
AnonymousMode: true,
|
||||||
|
AutoCreateUsers: true,
|
||||||
|
TLSConfig: portainer.TLSConfiguration{},
|
||||||
|
SearchSettings: []portainer.LDAPSearchSettings{
|
||||||
|
portainer.LDAPSearchSettings{},
|
||||||
|
},
|
||||||
|
GroupSearchSettings: []portainer.LDAPGroupSearchSettings{
|
||||||
|
portainer.LDAPGroupSearchSettings{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OAuthSettings: portainer.OAuthSettings{},
|
||||||
|
AllowBindMountsForRegularUsers: true,
|
||||||
|
AllowPrivilegedModeForRegularUsers: true,
|
||||||
|
AllowVolumeBrowserForRegularUsers: false,
|
||||||
|
EnableHostManagementFeatures: false,
|
||||||
|
EdgeAgentCheckinInterval: portainer.DefaultEdgeAgentCheckinIntervalInSeconds,
|
||||||
|
TemplatesURL: portainer.DefaultTemplatesURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = store.SettingsService.UpdateSettings(defaultSettings)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = store.DockerHubService.DockerHub()
|
||||||
|
if err == portainer.ErrObjectNotFound {
|
||||||
|
defaultDockerHub := &portainer.DockerHub{
|
||||||
|
Authentication: false,
|
||||||
|
Username: "",
|
||||||
|
Password: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := store.DockerHubService.UpdateDockerHub(defaultDockerHub)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
groups, err := store.EndpointGroupService.EndpointGroups()
|
groups, err := store.EndpointGroupService.EndpointGroups()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -235,48 +235,14 @@ func initStatus(endpointManagement, snapshot bool, flags *portainer.CLIFlags) *p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDockerHub(dockerHubService portainer.DockerHubService) error {
|
func updateSettingsFromFlags(settingsService portainer.SettingsService, flags *portainer.CLIFlags) error {
|
||||||
_, err := dockerHubService.DockerHub()
|
settings, err := settingsService.Settings()
|
||||||
if err == portainer.ErrObjectNotFound {
|
if err != nil {
|
||||||
dockerhub := &portainer.DockerHub{
|
|
||||||
Authentication: false,
|
|
||||||
Username: "",
|
|
||||||
Password: "",
|
|
||||||
}
|
|
||||||
return dockerHubService.UpdateDockerHub(dockerhub)
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
settings.LogoURL = *flags.Logo
|
||||||
}
|
settings.SnapshotInterval = *flags.SnapshotInterval
|
||||||
|
|
||||||
func initSettings(settingsService portainer.SettingsService, flags *portainer.CLIFlags) error {
|
|
||||||
_, err := settingsService.Settings()
|
|
||||||
if err == portainer.ErrObjectNotFound {
|
|
||||||
settings := &portainer.Settings{
|
|
||||||
LogoURL: *flags.Logo,
|
|
||||||
AuthenticationMethod: portainer.AuthenticationInternal,
|
|
||||||
LDAPSettings: portainer.LDAPSettings{
|
|
||||||
AnonymousMode: true,
|
|
||||||
AutoCreateUsers: true,
|
|
||||||
TLSConfig: portainer.TLSConfiguration{},
|
|
||||||
SearchSettings: []portainer.LDAPSearchSettings{
|
|
||||||
portainer.LDAPSearchSettings{},
|
|
||||||
},
|
|
||||||
GroupSearchSettings: []portainer.LDAPGroupSearchSettings{
|
|
||||||
portainer.LDAPGroupSearchSettings{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OAuthSettings: portainer.OAuthSettings{},
|
|
||||||
AllowBindMountsForRegularUsers: true,
|
|
||||||
AllowPrivilegedModeForRegularUsers: true,
|
|
||||||
AllowVolumeBrowserForRegularUsers: false,
|
|
||||||
EnableHostManagementFeatures: false,
|
|
||||||
SnapshotInterval: *flags.SnapshotInterval,
|
|
||||||
EdgeAgentCheckinInterval: portainer.DefaultEdgeAgentCheckinIntervalInSeconds,
|
|
||||||
TemplatesURL: portainer.DefaultTemplatesURL,
|
|
||||||
}
|
|
||||||
|
|
||||||
if *flags.Templates != "" {
|
if *flags.Templates != "" {
|
||||||
settings.TemplatesURL = *flags.Templates
|
settings.TemplatesURL = *flags.Templates
|
||||||
|
@ -284,24 +250,9 @@ func initSettings(settingsService portainer.SettingsService, flags *portainer.CL
|
||||||
|
|
||||||
if *flags.Labels != nil {
|
if *flags.Labels != nil {
|
||||||
settings.BlackListedLabels = *flags.Labels
|
settings.BlackListedLabels = *flags.Labels
|
||||||
} else {
|
|
||||||
settings.BlackListedLabels = make([]portainer.Pair, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return settingsService.UpdateSettings(settings)
|
return settingsService.UpdateSettings(settings)
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func retrieveFirstEndpointFromDatabase(endpointService portainer.EndpointService) *portainer.Endpoint {
|
|
||||||
endpoints, err := endpointService.Endpoints()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
return &endpoints[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadAndParseKeyPair(fileService portainer.FileService, signatureService portainer.DigitalSignatureService) error {
|
func loadAndParseKeyPair(fileService portainer.FileService, signatureService portainer.DigitalSignatureService) error {
|
||||||
|
@ -522,10 +473,12 @@ func main() {
|
||||||
|
|
||||||
composeStackManager := initComposeStackManager(*flags.Data, reverseTunnelService)
|
composeStackManager := initComposeStackManager(*flags.Data, reverseTunnelService)
|
||||||
|
|
||||||
err = initSettings(store.SettingsService, flags)
|
if store.IsNew() {
|
||||||
|
err = updateSettingsFromFlags(store.SettingsService, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
jobScheduler := initJobScheduler()
|
jobScheduler := initJobScheduler()
|
||||||
|
|
||||||
|
@ -548,11 +501,6 @@ func main() {
|
||||||
|
|
||||||
jobScheduler.Start()
|
jobScheduler.Start()
|
||||||
|
|
||||||
err = initDockerHub(store.DockerHubService)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
applicationStatus := initStatus(endpointManagement, *flags.Snapshot, flags)
|
applicationStatus := initStatus(endpointManagement, *flags.Snapshot, flags)
|
||||||
|
|
||||||
err = initEndpoint(flags, store.EndpointService, snapshotter)
|
err = initEndpoint(flags, store.EndpointService, snapshotter)
|
||||||
|
|
|
@ -73,6 +73,7 @@ type (
|
||||||
Open() error
|
Open() error
|
||||||
Init() error
|
Init() error
|
||||||
Close() error
|
Close() error
|
||||||
|
IsNew() bool
|
||||||
MigrateData() error
|
MigrateData() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,16 +46,7 @@
|
||||||
<div class="col-sm-12 form-section-title">
|
<div class="col-sm-12 form-section-title">
|
||||||
App Templates
|
App Templates
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div>
|
||||||
<div class="col-sm-12">
|
|
||||||
<label for="toggle_templates" class="control-label text-left">
|
|
||||||
Use external templates
|
|
||||||
<portainer-tooltip position="bottom" message="When using external templates, in-app template management will be disabled."></portainer-tooltip>
|
|
||||||
</label>
|
|
||||||
<label class="switch" style="margin-left: 20px;"> <input type="checkbox" name="toggle_templates" ng-model="formValues.externalTemplates" /><i></i> </label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div ng-if="formValues.externalTemplates">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<span class="col-sm-12 text-muted small">
|
<span class="col-sm-12 text-muted small">
|
||||||
You can specify the URL to your own template definitions file here. See
|
You can specify the URL to your own template definitions file here. See
|
||||||
|
@ -67,7 +58,7 @@
|
||||||
URL
|
URL
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-11">
|
<div class="col-sm-11">
|
||||||
<input type="text" class="form-control" ng-model="settings.TemplatesURL" id="templates_url" placeholder="https://myserver.mydomain/templates.json" />
|
<input type="text" class="form-control" ng-model="settings.TemplatesURL" id="templates_url" placeholder="https://myserver.mydomain/templates.json" required/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -157,7 +148,7 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-primary btn-sm"
|
class="btn btn-primary btn-sm"
|
||||||
ng-click="saveApplicationSettings()"
|
ng-click="saveApplicationSettings()"
|
||||||
ng-disabled="state.actionInProgress"
|
ng-disabled="state.actionInProgress || !settings.TemplatesURL"
|
||||||
button-spinner="state.actionInProgress"
|
button-spinner="state.actionInProgress"
|
||||||
>
|
>
|
||||||
<span ng-hide="state.actionInProgress">Save settings</span>
|
<span ng-hide="state.actionInProgress">Save settings</span>
|
||||||
|
|
|
@ -25,7 +25,6 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
|
|
||||||
$scope.formValues = {
|
$scope.formValues = {
|
||||||
customLogo: false,
|
customLogo: false,
|
||||||
externalTemplates: false,
|
|
||||||
restrictBindMounts: false,
|
restrictBindMounts: false,
|
||||||
restrictPrivilegedMode: false,
|
restrictPrivilegedMode: false,
|
||||||
labelName: '',
|
labelName: '',
|
||||||
|
@ -60,10 +59,6 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
settings.LogoURL = '';
|
settings.LogoURL = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$scope.formValues.externalTemplates) {
|
|
||||||
settings.TemplatesURL = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.AllowBindMountsForRegularUsers = !$scope.formValues.restrictBindMounts;
|
settings.AllowBindMountsForRegularUsers = !$scope.formValues.restrictBindMounts;
|
||||||
settings.AllowPrivilegedModeForRegularUsers = !$scope.formValues.restrictPrivilegedMode;
|
settings.AllowPrivilegedModeForRegularUsers = !$scope.formValues.restrictPrivilegedMode;
|
||||||
settings.AllowVolumeBrowserForRegularUsers = $scope.formValues.enableVolumeBrowser;
|
settings.AllowVolumeBrowserForRegularUsers = $scope.formValues.enableVolumeBrowser;
|
||||||
|
@ -98,12 +93,10 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
var settings = data;
|
var settings = data;
|
||||||
$scope.settings = settings;
|
$scope.settings = settings;
|
||||||
|
|
||||||
if (settings.LogoURL !== '') {
|
if (settings.LogoURL !== '') {
|
||||||
$scope.formValues.customLogo = true;
|
$scope.formValues.customLogo = true;
|
||||||
}
|
}
|
||||||
if (settings.TemplatesURL !== '') {
|
|
||||||
$scope.formValues.externalTemplates = true;
|
|
||||||
}
|
|
||||||
$scope.formValues.restrictBindMounts = !settings.AllowBindMountsForRegularUsers;
|
$scope.formValues.restrictBindMounts = !settings.AllowBindMountsForRegularUsers;
|
||||||
$scope.formValues.restrictPrivilegedMode = !settings.AllowPrivilegedModeForRegularUsers;
|
$scope.formValues.restrictPrivilegedMode = !settings.AllowPrivilegedModeForRegularUsers;
|
||||||
$scope.formValues.enableVolumeBrowser = settings.AllowVolumeBrowserForRegularUsers;
|
$scope.formValues.enableVolumeBrowser = settings.AllowVolumeBrowserForRegularUsers;
|
||||||
|
|
Loading…
Reference in New Issue