Port namespace import/export svc to Envoy v2
This commit is contained in:
@@ -6,25 +6,22 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
automationTypes "github.com/cortezaproject/corteza/server/automation/types"
|
||||
composeEnvoy "github.com/cortezaproject/corteza/server/compose/envoy"
|
||||
"github.com/cortezaproject/corteza/server/compose/rest/request"
|
||||
"github.com/cortezaproject/corteza/server/compose/service"
|
||||
"github.com/cortezaproject/corteza/server/compose/service/event"
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/api"
|
||||
"github.com/cortezaproject/corteza/server/pkg/corredor"
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoy"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoy/resource"
|
||||
envoyStore "github.com/cortezaproject/corteza/server/pkg/envoy/store"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoy/yaml"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza/server/pkg/locale"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
systemEnvoy "github.com/cortezaproject/corteza/server/system/envoy"
|
||||
systemService "github.com/cortezaproject/corteza/server/system/service"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
@@ -204,78 +201,52 @@ func (ctrl Namespace) Clone(ctx context.Context, r *request.NamespaceClone) (int
|
||||
Slug: r.Slug,
|
||||
}
|
||||
|
||||
resources, err := ctrl.gatherResources(ctx, r.NamespaceID)
|
||||
nodes, err := ctrl.gatherNodes(ctx, r.NamespaceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
decoder := func() (resource.InterfaceSet, error) {
|
||||
return resources, nil
|
||||
decoder := func() (envoyx.NodeSet, error) {
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
encoder := func(nn resource.InterfaceSet) error {
|
||||
// prepare for encoding
|
||||
se := envoyStore.NewStoreEncoder(service.DefaultStore, dal.Service(), &envoyStore.EncoderConfig{})
|
||||
bld := envoy.NewBuilder(se)
|
||||
g, err := bld.Build(ctx, nn...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return envoy.Encode(ctx, g, se)
|
||||
}
|
||||
|
||||
ns, err := ctrl.namespace.Clone(ctx, r.NamespaceID, dup, decoder, encoder)
|
||||
ns, err := ctrl.namespace.Clone(ctx, r.NamespaceID, dup, decoder)
|
||||
return ctrl.makePayload(ctx, ns, err)
|
||||
}
|
||||
|
||||
func (ctrl Namespace) Export(ctx context.Context, r *request.NamespaceExport) (out interface{}, err error) {
|
||||
// Get resources
|
||||
resources, err := ctrl.gatherResources(ctx, r.NamespaceID)
|
||||
nodes, err := ctrl.gatherNodes(ctx, r.NamespaceID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Encode
|
||||
ye := yaml.NewYamlEncoder(&yaml.EncoderConfig{})
|
||||
bld := envoy.NewBuilder(ye)
|
||||
g, err := bld.Build(ctx, resources...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
p := envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeIo,
|
||||
Params: map[string]any{},
|
||||
}
|
||||
|
||||
err = envoy.Encode(ctx, g, ye)
|
||||
evsvc := envoyx.Global()
|
||||
gg, err := evsvc.Bake(ctx, p, nil, nodes...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Archive encoded resources
|
||||
buf := bytes.NewBuffer(nil)
|
||||
w := zip.NewWriter(buf)
|
||||
zw := zip.NewWriter(buf)
|
||||
|
||||
var (
|
||||
f io.Writer
|
||||
bb []byte
|
||||
)
|
||||
for _, s := range ye.Stream() {
|
||||
// @todo generalize when needed
|
||||
f, err = w.Create(fmt.Sprintf("%s.yaml", s.Resource))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bb, err = ioutil.ReadAll(s.Source)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = f.Write(bb)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
f, err := zw.Create(fmt.Sprintf("%s.yaml", r.Filename))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = w.Close()
|
||||
p.Params["writer"] = f
|
||||
err = evsvc.Encode(ctx, p, gg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = zw.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -291,6 +262,7 @@ func (ctrl Namespace) ImportInit(ctx context.Context, r *request.NamespaceImport
|
||||
defer f.Close()
|
||||
|
||||
return ctrl.namespace.ImportInit(ctx, f, r.Upload.Size)
|
||||
// return ctrl.namespace.ImportInit(ctx, f, r.Upload.Header.Get("content-type"), r.Upload.Size)
|
||||
}
|
||||
|
||||
func (ctrl Namespace) ImportRun(ctx context.Context, r *request.NamespaceImportRun) (interface{}, error) {
|
||||
@@ -299,26 +271,9 @@ func (ctrl Namespace) ImportRun(ctx context.Context, r *request.NamespaceImportR
|
||||
Name: r.Name,
|
||||
Slug: r.Slug,
|
||||
}
|
||||
|
||||
encoder = func(nn resource.InterfaceSet) error {
|
||||
se := envoyStore.NewStoreEncoder(service.DefaultStore, dal.Service(), &envoyStore.EncoderConfig{})
|
||||
|
||||
bld := envoy.NewBuilder(se)
|
||||
g, err := bld.Build(ctx, nn...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = envoy.Encode(ctx, g, se)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
)
|
||||
|
||||
ns, err := ctrl.namespace.ImportRun(ctx, r.SessionID, dup, encoder)
|
||||
ns, err := ctrl.namespace.ImportRun(ctx, r.SessionID, dup)
|
||||
return ctrl.makePayload(ctx, ns, err)
|
||||
}
|
||||
|
||||
@@ -380,135 +335,129 @@ func (ctrl Namespace) makeFilterPayload(ctx context.Context, nn types.NamespaceS
|
||||
return nsp, nil
|
||||
}
|
||||
|
||||
func (ctrl Namespace) gatherResources(ctx context.Context, namespaceID uint64) (resources resource.InterfaceSet, err error) {
|
||||
func (ctrl Namespace) gatherNodes(ctx context.Context, namespaceID uint64) (resources envoyx.NodeSet, err error) {
|
||||
var (
|
||||
nsII resource.Identifiers
|
||||
nsII envoyx.Identifiers
|
||||
aux envoyx.NodeSet
|
||||
)
|
||||
|
||||
// Prepare resources
|
||||
resources, nsII, err = ctrl.exportCompose(ctx, namespaceID)
|
||||
aux, nsII, err = ctrl.exportCompose(ctx, namespaceID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resources = append(resources, aux...)
|
||||
|
||||
// Tweak exported resources
|
||||
resources = ctrl.tweakExport(ctx, resources, nsII)
|
||||
|
||||
// Role placeholders for RBAC
|
||||
var roleIndex map[uint64]*systemTypes.Role
|
||||
resources, roleIndex, err = ctrl.preparePlaceholders(ctx, resources)
|
||||
aux, err = ctrl.preparePlaceholders(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resources = append(resources, aux...)
|
||||
|
||||
// RBAC
|
||||
auxRBAC, err := ctrl.exportRBAC(ctx, roleIndex, resources)
|
||||
aux, err = ctrl.exportRBAC(ctx, resources)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resources = append(resources, aux...)
|
||||
|
||||
// Translations
|
||||
auxResTrans, err := ctrl.exportResourceTranslations(ctx, resources)
|
||||
aux, err = ctrl.exportResourceTranslations(ctx, resources)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resources = append(resources, auxRBAC...)
|
||||
resources = append(resources, auxResTrans...)
|
||||
resources = append(resources, aux...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ctrl Namespace) exportCompose(ctx context.Context, namespaceID uint64) (resources resource.InterfaceSet, nsII resource.Identifiers, err error) {
|
||||
func (ctrl Namespace) exportCompose(ctx context.Context, namespaceID uint64) (resources envoyx.NodeSet, nsII envoyx.Identifiers, err error) {
|
||||
// - namespace
|
||||
n, err := ctrl.namespace.FindByID(ctx, namespaceID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nsRes := resource.NewComposeNamespace(n)
|
||||
nsII = nsRes.Identifiers()
|
||||
resources = append(resources, nsRes)
|
||||
nsNode, err := composeEnvoy.NamespaceToEnvoyNode(n)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nsII = nsNode.Identifiers
|
||||
resources = append(resources, nsNode)
|
||||
|
||||
// - modules
|
||||
mm, _, err := ctrl.module.Find(ctx, types.ModuleFilter{NamespaceID: n.ID})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, m := range mm {
|
||||
km := resource.NewComposeModule(m, resource.MakeNamespaceRef(n.ID, n.Slug, n.Name))
|
||||
for _, f := range m.Fields {
|
||||
km.AddField(resource.NewComposeModuleField(f, km.RefNs, km.Ref()))
|
||||
var aux *envoyx.Node
|
||||
aux, err = composeEnvoy.ModuleToEnvoyNode(m)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resources = append(resources, aux)
|
||||
|
||||
for _, f := range m.Fields {
|
||||
aux, err = composeEnvoy.ModuleFieldToEnvoyNode(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resources = append(resources, aux)
|
||||
}
|
||||
resources = append(resources, km)
|
||||
}
|
||||
|
||||
// - pages
|
||||
pp, _, err := ctrl.page.Find(ctx, types.PageFilter{NamespaceID: n.ID})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, p := range pp {
|
||||
p, modRef, parentRef := resource.UnpackComposePage(p)
|
||||
resources = append(resources, resource.NewComposePage(
|
||||
p,
|
||||
resource.MakeNamespaceRef(n.ID, n.Slug, n.Name),
|
||||
modRef,
|
||||
parentRef,
|
||||
))
|
||||
var aux *envoyx.Node
|
||||
aux, err = composeEnvoy.PageToEnvoyNode(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resources = append(resources, aux)
|
||||
}
|
||||
|
||||
// - charts
|
||||
cc, _, err := ctrl.chart.Find(ctx, types.ChartFilter{NamespaceID: n.ID})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, c := range cc {
|
||||
refMods := make(resource.RefSet, 0, 2)
|
||||
for _, r := range c.Config.Reports {
|
||||
refMods = append(refMods, resource.MakeModuleRef(r.ModuleID, "", ""))
|
||||
var aux *envoyx.Node
|
||||
aux, err = composeEnvoy.ChartToEnvoyNode(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resources = append(resources, resource.NewComposeChart(
|
||||
c,
|
||||
resource.MakeNamespaceRef(n.ID, n.Slug, n.Name),
|
||||
refMods,
|
||||
))
|
||||
resources = append(resources, aux)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ctrl Namespace) exportRBAC(ctx context.Context, roleIndex map[uint64]*systemTypes.Role, base resource.InterfaceSet) (resources resource.InterfaceSet, err error) {
|
||||
func (ctrl Namespace) exportRBAC(ctx context.Context, base envoyx.NodeSet) (resources envoyx.NodeSet, err error) {
|
||||
// Prepare RBAC Rules
|
||||
rawRules := rbac.Global().Rules()
|
||||
rules := make([]*resource.RbacRule, 0, len(rawRules))
|
||||
for _, rule := range rawRules {
|
||||
_, ref, pp, err := resource.ParseRule(rule.Resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
role, ok := roleIndex[rule.RoleID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
rules = append(rules, resource.NewRbacRule(
|
||||
rule,
|
||||
resource.MakeRoleRef(role.ID, role.Handle, role.Name),
|
||||
ref,
|
||||
rule.Resource,
|
||||
pp...,
|
||||
))
|
||||
}
|
||||
|
||||
for _, r := range envoy.FilterRequestedRBACRules(base, rules) {
|
||||
resources = append(resources, r)
|
||||
resources, err = envoyx.RBACRulesForNodes(rawRules, base...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ctrl Namespace) exportResourceTranslations(ctx context.Context, base resource.InterfaceSet) (resources resource.InterfaceSet, err error) {
|
||||
func (ctrl Namespace) exportResourceTranslations(ctx context.Context, base envoyx.NodeSet) (resources envoyx.NodeSet, err error) {
|
||||
var (
|
||||
lsvc = locale.Global()
|
||||
tags = lsvc.Tags()
|
||||
translations = make([]*resource.ResourceTranslation, 0, 124)
|
||||
translations = make([]*locale.ResourceTranslation, 0, 128)
|
||||
|
||||
resKeyTrans map[string]map[string]*locale.ResourceTranslation
|
||||
)
|
||||
@@ -519,40 +468,31 @@ func (ctrl Namespace) exportResourceTranslations(ctx context.Context, base resou
|
||||
return
|
||||
}
|
||||
|
||||
for transRes, keyTrans := range resKeyTrans {
|
||||
rawTranslations := make(locale.ResourceTranslationSet, 0, len(resKeyTrans))
|
||||
for _, keyTrans := range resKeyTrans {
|
||||
for _, trans := range keyTrans {
|
||||
rawTranslations = append(rawTranslations, trans)
|
||||
translations = append(translations, trans)
|
||||
}
|
||||
|
||||
_, ref, pp, err := resource.ParseResourceTranslation(transRes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
translations = append(translations, resource.NewResourceTranslation(
|
||||
systemTypes.FromLocale(rawTranslations),
|
||||
ref.Identifiers.First(),
|
||||
ref,
|
||||
pp...,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
for _, t := range envoy.FilterRequiredResourceTranslations(base, translations) {
|
||||
resources = append(resources, t)
|
||||
}
|
||||
|
||||
resources, err = envoyx.ResourceTranslationsForNodes(systemTypes.FromLocale(translations), base...)
|
||||
return
|
||||
}
|
||||
|
||||
func (ctrl Namespace) tweakExport(ctx context.Context, resources resource.InterfaceSet, nsII resource.Identifiers) resource.InterfaceSet {
|
||||
oldNsRef := resource.MakeRef(types.NamespaceResourceType, nsII)
|
||||
prune := resource.RefSet{resource.MakeWildRef(automationTypes.WorkflowResourceType)}
|
||||
ns := resource.FindComposeNamespace(resources, nsII)
|
||||
func (ctrl Namespace) tweakExport(ctx context.Context, nodes envoyx.NodeSet, nsII envoyx.Identifiers) envoyx.NodeSet {
|
||||
nsRef := envoyx.Ref{
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: nsII,
|
||||
Scope: envoyx.Scope{
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: nsII,
|
||||
},
|
||||
}
|
||||
nsNode := envoyx.NodeForRef(nsRef, nodes...)
|
||||
|
||||
// - remove logo and icon references as attachments are not exported by default
|
||||
// @todo code in attachment exporting, most likely when we do attachment handling rework
|
||||
ns := nsNode.Resource.(*types.Namespace)
|
||||
ns.Meta.Icon = ""
|
||||
ns.Meta.IconID = 0
|
||||
ns.Meta.Logo = ""
|
||||
@@ -560,37 +500,30 @@ func (ctrl Namespace) tweakExport(ctx context.Context, resources resource.Interf
|
||||
ns.Meta.LogoEnabled = false
|
||||
|
||||
// - prune resources we won't preserve
|
||||
resources.SearchForReferences(oldNsRef).Walk(func(r resource.Interface) error {
|
||||
pp, ok := r.(resource.PrunableInterface)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
pref := envoyx.Ref{
|
||||
ResourceType: automationTypes.WorkflowResourceType,
|
||||
}
|
||||
for _, n := range nodes {
|
||||
n.Prune(pref)
|
||||
}
|
||||
|
||||
for _, p := range prune {
|
||||
pp.Prune(p)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return resources
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (ctrl Namespace) preparePlaceholders(ctx context.Context, base resource.InterfaceSet) (resources resource.InterfaceSet, roleIndex map[uint64]*systemTypes.Role, err error) {
|
||||
resources = base
|
||||
|
||||
// Get roles as we'll need them later for some resources
|
||||
roleIndex = make(map[uint64]*systemTypes.Role)
|
||||
func (ctrl Namespace) preparePlaceholders(ctx context.Context) (resources envoyx.NodeSet, err error) {
|
||||
rr, _, err := ctrl.role.Find(ctx, systemTypes.RoleFilter{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var aux *envoyx.Node
|
||||
for _, role := range rr {
|
||||
roleIndex[role.ID] = role
|
||||
aux, err = systemEnvoy.RoleToEnvoyNode(role)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Add them as placeholders since we don't want to export them
|
||||
r := resource.NewRole(role)
|
||||
r.MarkPlaceholder()
|
||||
resources = append(resources, r)
|
||||
aux.Placeholder = true
|
||||
resources = append(resources, aux)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza/server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoy/resource"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoy/yaml"
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/errors"
|
||||
"github.com/cortezaproject/corteza/server/pkg/eventbus"
|
||||
"github.com/cortezaproject/corteza/server/pkg/handle"
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/cortezaproject/corteza/server/pkg/locale"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
)
|
||||
|
||||
@@ -36,6 +37,7 @@ type (
|
||||
eventbus eventDispatcher
|
||||
store store.Storer
|
||||
locale ResourceTranslationsManagerService
|
||||
envoy *envoyx.Service
|
||||
}
|
||||
|
||||
namespaceImportSession struct {
|
||||
@@ -48,7 +50,7 @@ type (
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
|
||||
Resources resource.InterfaceSet `json:"-"`
|
||||
Nodes envoyx.NodeSet `json:"-"`
|
||||
}
|
||||
|
||||
namespaceAccessController interface {
|
||||
@@ -70,9 +72,9 @@ type (
|
||||
|
||||
Create(ctx context.Context, namespace *types.Namespace) (*types.Namespace, error)
|
||||
Update(ctx context.Context, namespace *types.Namespace) (*types.Namespace, error)
|
||||
Clone(ctx context.Context, namespaceID uint64, dup *types.Namespace, decoder func() (resource.InterfaceSet, error), encoder func(resource.InterfaceSet) error) (ns *types.Namespace, err error)
|
||||
Clone(ctx context.Context, namespaceID uint64, dup *types.Namespace, decoder func() (envoyx.NodeSet, error)) (ns *types.Namespace, err error)
|
||||
ImportInit(ctx context.Context, f multipart.File, size int64) (namespaceImportSession, error)
|
||||
ImportRun(ctx context.Context, sessionID uint64, dup *types.Namespace, encoder func(resource.InterfaceSet) error) (ns *types.Namespace, err error)
|
||||
ImportRun(ctx context.Context, sessionID uint64, dup *types.Namespace) (ns *types.Namespace, err error)
|
||||
DeleteByID(ctx context.Context, namespaceID uint64) error
|
||||
}
|
||||
|
||||
@@ -103,6 +105,7 @@ func Namespace() *namespace {
|
||||
actionlog: DefaultActionlog,
|
||||
store: DefaultStore,
|
||||
locale: DefaultResourceTranslation,
|
||||
envoy: envoyx.Global(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +272,7 @@ func (svc namespace) Update(ctx context.Context, upd *types.Namespace) (c *types
|
||||
return svc.updater(ctx, upd.ID, NamespaceActionUpdate, svc.handleUpdate(ctx, upd))
|
||||
}
|
||||
|
||||
func (svc namespace) Clone(ctx context.Context, namespaceID uint64, dup *types.Namespace, decoder func() (resource.InterfaceSet, error), encoder func(resource.InterfaceSet) error) (ns *types.Namespace, err error) {
|
||||
func (svc namespace) Clone(ctx context.Context, namespaceID uint64, dup *types.Namespace, decoder func() (envoyx.NodeSet, error)) (ns *types.Namespace, err error) {
|
||||
var (
|
||||
aProps = &namespaceActionProps{namespace: dup}
|
||||
)
|
||||
@@ -308,7 +311,12 @@ func (svc namespace) Clone(ctx context.Context, namespaceID uint64, dup *types.N
|
||||
}
|
||||
|
||||
aProps.setNamespace(dup)
|
||||
_, err = svc.envoyRun(ctx, nn, targetNs, dup, encoder)
|
||||
dup, err = svc.envoyRun(ctx, nn, targetNs, dup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = svc.reloadServices(ctx, dup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -334,6 +342,10 @@ func (svc namespace) ImportInit(ctx context.Context, f multipart.File, size int6
|
||||
err error
|
||||
ns *types.Namespace
|
||||
session namespaceImportSession
|
||||
nodes envoyx.NodeSet
|
||||
|
||||
esvc = envoyx.Global()
|
||||
nn envoyx.NodeSet
|
||||
)
|
||||
|
||||
err = func() error {
|
||||
@@ -363,26 +375,29 @@ func (svc namespace) ImportInit(ctx context.Context, f multipart.File, size int6
|
||||
return err
|
||||
}
|
||||
|
||||
// decode with Envoy
|
||||
yd := yaml.Decoder()
|
||||
nn := make([]resource.Interface, 0, 10)
|
||||
|
||||
for _, f := range archive.File {
|
||||
if f.FileInfo().IsDir() {
|
||||
for _, zf := range archive.File {
|
||||
if zf.FileInfo().IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
a, err := f.Open()
|
||||
f, err := zf.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.Close()
|
||||
defer f.Close()
|
||||
|
||||
mm, err := yd.Decode(ctx, a, nil)
|
||||
nn, _, err = esvc.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeIO,
|
||||
Params: map[string]any{
|
||||
"reader": f,
|
||||
"mime": "text/yaml",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nn = append(nn, mm...)
|
||||
|
||||
nodes = append(nodes, nn...)
|
||||
}
|
||||
|
||||
// store a session for later
|
||||
@@ -391,17 +406,15 @@ func (svc namespace) ImportInit(ctx context.Context, f multipart.File, size int6
|
||||
UserID: auth.GetIdentityFromContext(ctx).Identity(),
|
||||
|
||||
CreatedAt: *now(),
|
||||
Resources: nn,
|
||||
Nodes: nodes,
|
||||
}
|
||||
|
||||
// find the ns node
|
||||
for _, n := range nn {
|
||||
if nsn, ok := n.(*resource.ComposeNamespace); ok {
|
||||
ns = nsn.Res
|
||||
break
|
||||
for _, n := range nodes {
|
||||
if n.ResourceType == types.NamespaceResourceType {
|
||||
ns = n.Resource.(*types.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
if ns == nil {
|
||||
return NamespaceErrImportMissingNamespace()
|
||||
}
|
||||
@@ -419,7 +432,7 @@ func (svc namespace) ImportInit(ctx context.Context, f multipart.File, size int6
|
||||
return session, svc.recordAction(ctx, aProps, NamespaceActionImportInit, err)
|
||||
}
|
||||
|
||||
func (svc namespace) ImportRun(ctx context.Context, sessionID uint64, dup *types.Namespace, encoder func(resource.InterfaceSet) error) (ns *types.Namespace, err error) {
|
||||
func (svc namespace) ImportRun(ctx context.Context, sessionID uint64, dup *types.Namespace) (ns *types.Namespace, err error) {
|
||||
var (
|
||||
aProps = &namespaceActionProps{namespace: dup}
|
||||
)
|
||||
@@ -460,7 +473,12 @@ func (svc namespace) ImportRun(ctx context.Context, sessionID uint64, dup *types
|
||||
|
||||
aProps.setNamespace(dup)
|
||||
|
||||
newNS, err = svc.envoyRun(ctx, session.Resources, &types.Namespace{ID: session.NamespaceID, Slug: session.Slug, Name: session.Name}, dup, encoder)
|
||||
newNS, err = svc.envoyRun(ctx, session.Nodes, &types.Namespace{ID: session.NamespaceID, Slug: session.Slug, Name: session.Name}, dup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = svc.reloadServices(ctx, newNS)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -721,41 +739,98 @@ func (svc namespace) canImport(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc namespace) envoyRun(ctx context.Context, resources resource.InterfaceSet, oldNS, newNS *types.Namespace, encoder func(resource.InterfaceSet) error) (ns *types.Namespace, err error) {
|
||||
// Handle renames and references
|
||||
oldNsRef := resource.MakeRef(types.NamespaceResourceType, resource.MakeIdentifiers(oldNS.Slug, oldNS.Name, strconv.FormatUint(oldNS.ID, 10)))
|
||||
newNsRef := resource.MakeRef(types.NamespaceResourceType, resource.MakeIdentifiers(newNS.Slug, newNS.Name))
|
||||
func (svc namespace) envoyRun(ctx context.Context, nodes envoyx.NodeSet, oldNS, newNS *types.Namespace) (ns *types.Namespace, err error) {
|
||||
// Get the NS node
|
||||
oldRef := envoyx.Ref{
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers(oldNS.Slug, oldNS.ID),
|
||||
Scope: envoyx.Scope{
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers(oldNS.Slug, oldNS.ID),
|
||||
},
|
||||
}
|
||||
nsNode := envoyx.NodeForRef(oldRef, nodes...)
|
||||
auxNs := nsNode.Resource.(*types.Namespace)
|
||||
|
||||
auxNs := resource.FindComposeNamespace(resources, oldNsRef.Identifiers)
|
||||
// Handle renames and references
|
||||
auxNs.ID = 0
|
||||
auxNs.Name = newNS.Name
|
||||
auxNs.Slug = newNS.Slug
|
||||
newNS = auxNs
|
||||
ns = newNS
|
||||
|
||||
// Correct internal references
|
||||
// - namespace identifiers
|
||||
resources.SearchForIdentifiers(oldNsRef.ResourceType, oldNsRef.Identifiers).Walk(func(r resource.Interface) error {
|
||||
r.ReID(newNsRef.Identifiers)
|
||||
return nil
|
||||
})
|
||||
// - relations
|
||||
resources.SearchForReferences(oldNsRef).Walk(func(r resource.Interface) error {
|
||||
r.ReRef(resource.RefSet{oldNsRef}, resource.RefSet{newNsRef})
|
||||
return nil
|
||||
// Change the identifiers and references
|
||||
// - identifiers of the NS node
|
||||
nsNode.Identifiers = envoyx.MakeIdentifiers(newNS.Slug)
|
||||
nsNode.Scope.Identifiers = nsNode.Identifiers
|
||||
|
||||
// - all the child refs
|
||||
for _, n := range nodes {
|
||||
nr := make(map[string]envoyx.Ref)
|
||||
for k, r := range n.References {
|
||||
if r.ResourceType == types.NamespaceResourceType {
|
||||
r.Identifiers = nsNode.Identifiers
|
||||
}
|
||||
if r.Scope.ResourceType == types.NamespaceResourceType {
|
||||
r.Scope = nsNode.Scope
|
||||
}
|
||||
nr[k] = r
|
||||
}
|
||||
n.References = nr
|
||||
if n.Scope.ResourceType == nsNode.Scope.ResourceType {
|
||||
n.Scope = nsNode.Scope
|
||||
}
|
||||
}
|
||||
|
||||
// Get expected placeholder refs
|
||||
// - roles
|
||||
roles, _, err := svc.envoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": svc.store,
|
||||
"dal": dal.Service(),
|
||||
},
|
||||
Filter: map[string]envoyx.ResourceFilter{
|
||||
systemTypes.RoleResourceType: {},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, r := range roles {
|
||||
r.Placeholder = true
|
||||
}
|
||||
nodes = append(nodes, roles...)
|
||||
|
||||
// run the import
|
||||
err = encoder(resources)
|
||||
gg, err := svc.envoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": svc.store,
|
||||
"dal": dal.Service(),
|
||||
},
|
||||
}, nil, nodes...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = svc.envoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": svc.store,
|
||||
"dal": dal.Service(),
|
||||
},
|
||||
}, gg)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (svc namespace) reloadServices(ctx context.Context, ns *types.Namespace) (err error) {
|
||||
// Adjust name res. tr. since we're changing it
|
||||
if err = updateTranslations(ctx, svc.ac, svc.locale, &locale.ResourceTranslation{
|
||||
Resource: auxNs.ResourceTranslation(),
|
||||
Resource: ns.ResourceTranslation(),
|
||||
Key: types.LocaleKeyNamespaceName.Path,
|
||||
Msg: locale.SanitizeMessage(auxNs.Name),
|
||||
Msg: locale.SanitizeMessage(ns.Name),
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -353,6 +353,29 @@ func (p *Page) setValue(name string, pos uint, value any) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Page) Prune(rt string) {
|
||||
for i := len(p.Blocks) - 1; i >= 0; i-- {
|
||||
b := p.Blocks[i]
|
||||
|
||||
switch b.Kind {
|
||||
// Implement the rest when support is needed
|
||||
case "Automation":
|
||||
if rt != "corteza::automation:workflow" {
|
||||
continue
|
||||
}
|
||||
|
||||
p.removeBlock(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Page block utilities
|
||||
func (p *Page) removeBlock(i int) {
|
||||
// do the swap remove thing
|
||||
p.Blocks[i] = p.Blocks[len(p.Blocks)-1]
|
||||
p.Blocks = p.Blocks[:len(p.Blocks)-1]
|
||||
}
|
||||
|
||||
func (b *PageBlock) setValue(name string, pos uint, value any) (err error) {
|
||||
pp := strings.Split(name, ".")
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ func ResourceTranslationsForNodes(tt types.ResourceTranslationSet, nn ...*Node)
|
||||
dups := make(map[types.Lang]map[string]map[string]bool)
|
||||
|
||||
for _, n := range nn {
|
||||
if n.Placeholder {
|
||||
continue
|
||||
}
|
||||
|
||||
c, ok := n.Resource.(localer)
|
||||
if !ok {
|
||||
continue
|
||||
|
||||
@@ -19,6 +19,10 @@ func RBACRulesForNodes(rr rbac.RuleSet, nn ...*Node) (rules NodeSet, err error)
|
||||
dups := make(map[uint64]map[string]map[string]bool)
|
||||
|
||||
for _, n := range nn {
|
||||
if n.Placeholder {
|
||||
continue
|
||||
}
|
||||
|
||||
c, ok := n.Resource.(rbacer)
|
||||
if !ok {
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user