Add improve settings for compose
This commit is contained in:
@@ -67,7 +67,9 @@ func NewImporter(nsf namespaceFinder, mf moduleFinder, cf chartFinder, pf pageFi
|
||||
settings: s,
|
||||
}
|
||||
|
||||
imp.namespaces = NewNamespaceImporter(imp)
|
||||
if nsf != nil {
|
||||
imp.namespaces = NewNamespaceImporter(imp)
|
||||
}
|
||||
return imp
|
||||
}
|
||||
|
||||
@@ -102,22 +104,34 @@ func (imp *Importer) Cast(def interface{}) (err error) {
|
||||
deinterfacer.KVsetString(&nsHandle, "namespace", def)
|
||||
if nsHandle != "" {
|
||||
delete(def.(map[interface{}]interface{}), "namespace")
|
||||
return imp.namespaces.Cast(nsHandle, def)
|
||||
if imp.namespaces != nil {
|
||||
return imp.namespaces.Cast(nsHandle, def)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return deinterfacer.Each(def, func(index int, key string, val interface{}) (err error) {
|
||||
switch key {
|
||||
case "namespaces":
|
||||
return imp.namespaces.CastSet(val)
|
||||
if imp.namespaces != nil {
|
||||
return imp.namespaces.CastSet(val)
|
||||
}
|
||||
|
||||
case "namespace":
|
||||
return imp.namespaces.CastSet([]interface{}{val})
|
||||
if imp.namespaces != nil {
|
||||
return imp.namespaces.CastSet([]interface{}{val})
|
||||
}
|
||||
|
||||
case "settings":
|
||||
return imp.settings.CastSet(val)
|
||||
if imp.settings != nil {
|
||||
return imp.settings.CastSet(val)
|
||||
}
|
||||
|
||||
case "allow", "deny":
|
||||
return imp.permissions.CastResourcesSet(key, val)
|
||||
if imp.permissions != nil {
|
||||
return imp.permissions.CastResourcesSet(key, val)
|
||||
}
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("unexpected key %q", key)
|
||||
@@ -139,25 +153,32 @@ func (imp *Importer) Store(
|
||||
sk settings.ImportKeeper,
|
||||
roles sysTypes.RoleSet,
|
||||
) (err error) {
|
||||
err = imp.namespaces.Store(ctx, nsStore, mStore, cStore, pStore, rStore, asStore)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not import namespaces")
|
||||
if imp.namespaces != nil {
|
||||
err = imp.namespaces.Store(ctx, nsStore, mStore, cStore, pStore, rStore, asStore)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not import namespaces")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure we properly replace role handles with IDs
|
||||
_ = roles.Walk(func(role *sysTypes.Role) error {
|
||||
imp.permissions.UpdateRoles(role.Handle, role.ID)
|
||||
return nil
|
||||
})
|
||||
if imp.permissions != nil {
|
||||
_ = roles.Walk(func(role *sysTypes.Role) error {
|
||||
imp.permissions.UpdateRoles(role.Handle, role.ID)
|
||||
return nil
|
||||
})
|
||||
|
||||
err = imp.permissions.Store(ctx, pk)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not import permissions")
|
||||
err = imp.permissions.Store(ctx, pk)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not import permissions")
|
||||
}
|
||||
}
|
||||
|
||||
err = imp.settings.Store(ctx, sk)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not import settings")
|
||||
if imp.settings != nil {
|
||||
err = imp.settings.Store(ctx, sk)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not import settings")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -2,9 +2,11 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/importer"
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
@@ -12,21 +14,23 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
impAux "github.com/cortezaproject/corteza-server/pkg/importer"
|
||||
"github.com/cortezaproject/corteza-server/pkg/settings"
|
||||
provision "github.com/cortezaproject/corteza-server/provision/compose"
|
||||
)
|
||||
|
||||
func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) (err error) {
|
||||
c.Log.Debug("running configuration provision")
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
var provisioned bool
|
||||
|
||||
// Make sure we have all full access for provisioning
|
||||
ctx = auth.SetSuperUserContext(ctx)
|
||||
|
||||
if provisioned, err := isProvisioned(ctx); err != nil {
|
||||
if provisioned, err = isProvisioned(ctx); err != nil {
|
||||
return err
|
||||
} else if provisioned {
|
||||
c.Log.Debug("configuration already provisioned")
|
||||
return nil
|
||||
}
|
||||
|
||||
readers, err := impAux.ReadStatic(provision.Asset)
|
||||
@@ -34,6 +38,10 @@ func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) err
|
||||
return err
|
||||
}
|
||||
|
||||
if provisioned {
|
||||
return partialImportSettings(ctx, service.DefaultSettings, readers...)
|
||||
}
|
||||
|
||||
return errors.Wrap(
|
||||
importer.Import(ctx, nil, readers...),
|
||||
"could not provision configuration for compose service",
|
||||
@@ -45,3 +53,53 @@ func isProvisioned(ctx context.Context) (bool, error) {
|
||||
_, f, err := service.DefaultNamespace.With(ctx).Find(types.NamespaceFilter{})
|
||||
return f.Count > 0, err
|
||||
}
|
||||
|
||||
// Partial import of settings from provision files
|
||||
func partialImportSettings(ctx context.Context, ss service.SettingsService, ff ...io.Reader) (err error) {
|
||||
var (
|
||||
// decoded content from YAML files
|
||||
aux interface{}
|
||||
|
||||
si = settings.NewImporter()
|
||||
|
||||
// importer w/o permissions & roles
|
||||
// we need only settings
|
||||
imp = importer.NewImporter(nil, nil, nil, nil, nil, nil, si)
|
||||
|
||||
// current value
|
||||
current settings.ValueSet
|
||||
|
||||
// unexisting values
|
||||
unex settings.ValueSet
|
||||
)
|
||||
|
||||
for _, f := range ff {
|
||||
if err = yaml.NewDecoder(f).Decode(&aux); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = imp.Cast(aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ss = ss.With(ctx)
|
||||
|
||||
// Get all "current" settings storage
|
||||
current, err = ss.FindByPrefix("")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Compare current settings with imported, get all that do not exist yet
|
||||
if unex = si.GetValues(); len(unex) > 0 {
|
||||
// Store non existing
|
||||
err = ss.BulkSet(current.New(unex))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/automation"
|
||||
"github.com/cortezaproject/corteza-server/pkg/automation/corredor"
|
||||
@@ -64,6 +65,9 @@ var (
|
||||
// DefaultAutomationRunner runs automation scripts by listening to triggerManager and invoking Corredor service
|
||||
DefaultAutomationRunner automationRunner
|
||||
|
||||
// CurrentSettings represents current compose settings
|
||||
CurrentSettings = &types.Settings{}
|
||||
|
||||
DefaultNamespace NamespaceService
|
||||
DefaultImportSession ImportSessionService
|
||||
DefaultRecord RecordService
|
||||
@@ -122,7 +126,7 @@ func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
|
||||
}
|
||||
DefaultAccessControl = AccessControl(DefaultPermissions)
|
||||
|
||||
DefaultSettings = Settings(ctx, DefaultInternalSettings)
|
||||
DefaultSettings = Settings(ctx, DefaultInternalSettings, CurrentSettings)
|
||||
|
||||
DefaultNamespace = Namespace()
|
||||
DefaultModule = Module()
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
internalSettings "github.com/cortezaproject/corteza-server/pkg/settings"
|
||||
)
|
||||
@@ -22,6 +23,8 @@ type (
|
||||
|
||||
ac settingsAccessController
|
||||
internalSettings internalSettings.Service
|
||||
|
||||
current *types.Settings
|
||||
}
|
||||
|
||||
settingsAccessController interface {
|
||||
@@ -30,7 +33,7 @@ type (
|
||||
}
|
||||
|
||||
SettingsService interface {
|
||||
With(ctx context.Context) SettingsService
|
||||
With(ctx context.Context) *settings
|
||||
FindByPrefix(prefix string) (vv internalSettings.ValueSet, err error)
|
||||
Set(v *internalSettings.Value) (err error)
|
||||
BulkSet(vv internalSettings.ValueSet) (err error)
|
||||
@@ -38,15 +41,16 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func Settings(ctx context.Context, intSet internalSettings.Service) SettingsService {
|
||||
func Settings(ctx context.Context, intSet internalSettings.Service, current *types.Settings) *settings {
|
||||
return (&settings{
|
||||
internalSettings: intSet,
|
||||
ac: DefaultAccessControl,
|
||||
logger: DefaultLogger.Named("settings"),
|
||||
current: current,
|
||||
}).With(ctx)
|
||||
}
|
||||
|
||||
func (svc settings) With(ctx context.Context) SettingsService {
|
||||
func (svc settings) With(ctx context.Context) *settings {
|
||||
db := repository.DB(ctx)
|
||||
|
||||
return &settings{
|
||||
@@ -56,6 +60,8 @@ func (svc settings) With(ctx context.Context) SettingsService {
|
||||
logger: svc.logger,
|
||||
|
||||
internalSettings: svc.internalSettings.With(ctx),
|
||||
|
||||
current: svc.current,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,12 +77,28 @@ func (svc settings) FindByPrefix(prefix string) (vv internalSettings.ValueSet, e
|
||||
return svc.internalSettings.FindByPrefix(prefix)
|
||||
}
|
||||
|
||||
// UpdateCurrent loads settings values from storage and updates current settings variable
|
||||
//
|
||||
// It accesses internal settings directly because
|
||||
// we do not want any security checks for this
|
||||
func (svc settings) UpdateCurrent() error {
|
||||
if vv, err := svc.internalSettings.FindByPrefix(""); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return svc.updateCurrent(vv.KV())
|
||||
}
|
||||
}
|
||||
|
||||
func (svc settings) Set(v *internalSettings.Value) (err error) {
|
||||
if !svc.ac.CanManageSettings(svc.ctx) {
|
||||
return errors.New("not allowed to manage settings")
|
||||
}
|
||||
|
||||
return svc.internalSettings.Set(v)
|
||||
if err = svc.internalSettings.Set(v); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return svc.updateCurrent(internalSettings.KV{v.Name: v.Value})
|
||||
}
|
||||
|
||||
func (svc settings) BulkSet(vv internalSettings.ValueSet) (err error) {
|
||||
@@ -84,7 +106,34 @@ func (svc settings) BulkSet(vv internalSettings.ValueSet) (err error) {
|
||||
return errors.New("not allowed to manage settings")
|
||||
}
|
||||
|
||||
return svc.internalSettings.BulkSet(vv)
|
||||
var old internalSettings.ValueSet
|
||||
if old, err = svc.internalSettings.FindByPrefix(""); err != nil {
|
||||
return
|
||||
} else {
|
||||
vv = old.Changed(vv)
|
||||
}
|
||||
|
||||
if err = svc.internalSettings.BulkSet(vv); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range vv {
|
||||
svc.log(svc.ctx,
|
||||
zap.String("name", v.Name),
|
||||
zap.Stringer("value", v.Value)).Info("settings changed")
|
||||
}
|
||||
|
||||
return svc.updateCurrent(vv.KV())
|
||||
}
|
||||
|
||||
func (svc settings) updateCurrent(kv internalSettings.KV) (err error) {
|
||||
// update current settings with new values
|
||||
if err = kv.Decode(svc.current); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
svc.log(svc.ctx).Info("current settings updated")
|
||||
return
|
||||
}
|
||||
|
||||
func (svc settings) Get(name string, ownedBy uint64) (out *internalSettings.Value, err error) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package types
|
||||
|
||||
type (
|
||||
Settings struct {
|
||||
// UI related settings
|
||||
UI struct {
|
||||
// Emoji
|
||||
// @todo implementation
|
||||
NamespaceSwitcher struct {
|
||||
Enabled bool
|
||||
} `kv:"namespace-switcher"`
|
||||
} `kv:"ui"`
|
||||
|
||||
// Message related settings
|
||||
Record struct {
|
||||
// @todo implementation
|
||||
Attachments struct {
|
||||
// What is max size (in MB, so: MaxSize x 2^20)
|
||||
MaxSize uint `kv:"max-size"`
|
||||
|
||||
// List of mime-types we support,
|
||||
Mimetypes []string
|
||||
}
|
||||
}
|
||||
|
||||
// Page related settings
|
||||
Page struct {
|
||||
// @todo implementation
|
||||
Attachments struct {
|
||||
// What is max size (in MB, so: MaxSize x 2^20)
|
||||
MaxSize uint `kv:"max-size"`
|
||||
|
||||
// List of mime-types we support,
|
||||
Mimetypes []string
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -1,4 +1,8 @@
|
||||
settings:
|
||||
panel.namespace-switcher: false
|
||||
file.max-size: 100
|
||||
file.type.whitelist: []
|
||||
ui.namespace-switcher.enabled: false
|
||||
|
||||
record.attachments.max-size: 10
|
||||
record.attachments.mimetypes: []
|
||||
|
||||
page.attachments.max-size: 10
|
||||
page.attachments.mimetypes: []
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user