diff --git a/server/automation/envoy/store_decode.gen.go b/server/automation/envoy/store_decode.gen.go index 27e1ee138..3ccfa1ffa 100644 --- a/server/automation/envoy/store_decode.gen.go +++ b/server/automation/envoy/store_decode.gen.go @@ -163,32 +163,38 @@ func (d StoreDecoder) decodeWorkflow(ctx context.Context, s store.Storer, dl dal r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "OwnedBy": envoyx.Ref{ + } + } + if r.OwnedBy > 0 { + refs["OwnedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.OwnedBy), - }, - // Handle references - "RunAs": envoyx.Ref{ + } + } + if r.RunAs > 0 { + refs["RunAs"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.RunAs), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, + } } var scope envoyx.Scope @@ -232,32 +238,38 @@ func (d StoreDecoder) decodeTrigger(ctx context.Context, s store.Storer, dl dal. r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "OwnedBy": envoyx.Ref{ + } + } + if r.OwnedBy > 0 { + refs["OwnedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.OwnedBy), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, - // Handle references - "WorkflowID": envoyx.Ref{ + } + } + if r.WorkflowID > 0 { + refs["WorkflowID"] = envoyx.Ref{ ResourceType: "corteza::automation:workflow", Identifiers: envoyx.MakeIdentifiers(r.WorkflowID), - }, + } } var scope envoyx.Scope diff --git a/server/automation/envoy/store_encode.go b/server/automation/envoy/store_encode.go index 8b8a9a2aa..4976f5ffd 100644 --- a/server/automation/envoy/store_encode.go +++ b/server/automation/envoy/store_encode.go @@ -1,8 +1,15 @@ package envoy -import "github.com/cortezaproject/corteza/server/automation/types" +import ( + "time" + + "github.com/cortezaproject/corteza/server/automation/types" +) func (e StoreEncoder) setWorkflowDefaults(res *types.Workflow) (err error) { + if res.CreatedAt.IsZero() { + res.CreatedAt = time.Now() + } return } @@ -11,6 +18,9 @@ func (e StoreEncoder) validateWorkflow(res *types.Workflow) (err error) { } func (e StoreEncoder) setTriggerDefaults(res *types.Trigger) (err error) { + if res.CreatedAt.IsZero() { + res.CreatedAt = time.Now() + } return } diff --git a/server/automation/envoy/yaml_decode.gen.go b/server/automation/envoy/yaml_decode.gen.go index ac25f7a71..6064bc239 100644 --- a/server/automation/envoy/yaml_decode.gen.go +++ b/server/automation/envoy/yaml_decode.gen.go @@ -17,6 +17,7 @@ import ( "github.com/cortezaproject/corteza/server/pkg/rbac" "github.com/cortezaproject/corteza/server/pkg/y7s" systemTypes "github.com/cortezaproject/corteza/server/system/types" + "github.com/spf13/cast" "golang.org/x/text/language" "gopkg.in/yaml.v3" ) @@ -206,7 +207,7 @@ func (d *auxYamlDoc) unmarshalWorkflowNode(dctx documentContext, n *yaml.Node, m auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -224,6 +225,12 @@ func (d *auxYamlDoc) unmarshalWorkflowNode(dctx documentContext, n *yaml.Node, m if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -237,6 +244,12 @@ func (d *auxYamlDoc) unmarshalWorkflowNode(dctx documentContext, n *yaml.Node, m if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -270,6 +283,12 @@ func (d *auxYamlDoc) unmarshalWorkflowNode(dctx documentContext, n *yaml.Node, m if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["OwnedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -283,6 +302,12 @@ func (d *auxYamlDoc) unmarshalWorkflowNode(dctx documentContext, n *yaml.Node, m if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["RunAs"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -296,6 +321,12 @@ func (d *auxYamlDoc) unmarshalWorkflowNode(dctx documentContext, n *yaml.Node, m if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -385,6 +416,11 @@ func (d *auxYamlDoc) unmarshalWorkflowNode(dctx documentContext, n *yaml.Node, m } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -483,7 +519,7 @@ func (d *auxYamlDoc) unmarshalTriggerNode(dctx documentContext, n *yaml.Node, me auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig ) _ = auxOut _ = refs @@ -500,6 +536,12 @@ func (d *auxYamlDoc) unmarshalTriggerNode(dctx documentContext, n *yaml.Node, me if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -513,6 +555,12 @@ func (d *auxYamlDoc) unmarshalTriggerNode(dctx documentContext, n *yaml.Node, me if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -536,6 +584,12 @@ func (d *auxYamlDoc) unmarshalTriggerNode(dctx documentContext, n *yaml.Node, me if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["OwnedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -549,6 +603,12 @@ func (d *auxYamlDoc) unmarshalTriggerNode(dctx documentContext, n *yaml.Node, me if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -562,6 +622,12 @@ func (d *auxYamlDoc) unmarshalTriggerNode(dctx documentContext, n *yaml.Node, me if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["WorkflowID"] = envoyx.Ref{ ResourceType: "corteza::automation:workflow", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -627,6 +693,11 @@ func (d *auxYamlDoc) unmarshalTriggerNode(dctx documentContext, n *yaml.Node, me } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -776,7 +847,7 @@ func unmarshalLocaleNode(n *yaml.Node) (out envoyx.NodeSet, err error) { // Envoy config unmarshal logic // // // // // // // // // // // // // // // // // // // // // // // // // -func (d *auxYamlDoc) decodeEnvoyConfig(n *yaml.Node) (out envoyx.NodeConfig) { +func (d *auxYamlDoc) decodeEnvoyConfig(n *yaml.Node) (out envoyx.EnvoyConfig) { y7s.EachMap(n, func(k, v *yaml.Node) (err error) { switch strings.ToLower(k.Value) { case "skipif", "skip": diff --git a/server/automation/envoy/yaml_encode.gen.go b/server/automation/envoy/yaml_encode.gen.go index 00533fd98..4123ba1e7 100644 --- a/server/automation/envoy/yaml_encode.gen.go +++ b/server/automation/envoy/yaml_encode.gen.go @@ -72,6 +72,10 @@ func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt strin if err != nil { return } + default: + // When this encoder doesn't handle any node it shouldn't write anything; + // this just removes the need for an extra check at the end. + return } return yaml.NewEncoder(w).Encode(out) @@ -280,7 +284,7 @@ func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, e return nil, nil } - tz := p.Config.PreferredTimezone + tz := p.Encoder.PreferredTimezone if tz != "" { tzL, err := time.LoadLocation(tz) if err != nil { @@ -289,7 +293,7 @@ func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, e t = t.In(tzL) } - ly := p.Config.PreferredTimeLayout + ly := p.Encoder.PreferredTimeLayout if ly == "" { ly = time.RFC3339 } @@ -315,7 +319,7 @@ func (e YamlEncoder) encodeRef(p envoyx.EncodeParams, id uint64, field string, n return id, nil } - return node.Identifiers.FriendlyIdentifier(), nil + return parent.Identifiers.FriendlyIdentifier(), nil } // // // // // // // // // // // // // // // // // // // // // // // // // diff --git a/server/codegen/assets/templates/gocode/envoy/store_decode.go.tpl b/server/codegen/assets/templates/gocode/envoy/store_decode.go.tpl index 225091414..cc7ad129b 100644 --- a/server/codegen/assets/templates/gocode/envoy/store_decode.go.tpl +++ b/server/codegen/assets/templates/gocode/envoy/store_decode.go.tpl @@ -190,17 +190,19 @@ func (d StoreDecoder) decode{{.expIdent}}(ctx context.Context, s store.Storer, d {{- end }} ) - refs := map[string]envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} {{- range .model.attributes -}} {{- if eq .dal.type "Ref" }} - // Handle references - "{{ .expIdent }}": envoyx.Ref{ - ResourceType: "{{ .dal.refModelResType }}", - Identifiers: envoyx.MakeIdentifiers(r.{{.expIdent}}), - }, + if r.{{.expIdent}} > 0 { + refs["{{ .expIdent }}"] = envoyx.Ref{ + ResourceType: "{{ .dal.refModelResType }}", + Identifiers: envoyx.MakeIdentifiers(r.{{.expIdent}}), + } + } {{- end }} {{- end }} - } {{ if .envoy.store.extendedRefDecoder }} refs = envoyx.MergeRefs(refs, d.decode{{.expIdent}}Refs(r)) diff --git a/server/codegen/assets/templates/gocode/envoy/store_encode.go.tpl b/server/codegen/assets/templates/gocode/envoy/store_encode.go.tpl index e8e6e08b3..51acec653 100644 --- a/server/codegen/assets/templates/gocode/envoy/store_encode.go.tpl +++ b/server/codegen/assets/templates/gocode/envoy/store_encode.go.tpl @@ -11,7 +11,6 @@ import ( "github.com/cortezaproject/corteza/server/pkg/expr" "github.com/cortezaproject/corteza/server/pkg/id" "github.com/cortezaproject/corteza/server/store" - {{- range .imports }} "{{ . }}" {{- end }} @@ -221,6 +220,12 @@ func (e StoreEncoder) encode{{.expIdent}}(ctx context.Context, p envoyx.EncodePa } } + {{ if .envoy.store.sanitizeBeforeSave }} + // Custom resource sanitization before saving. + // This can be used to cleanup arbitrary config fields. + e.sanitize{{.expIdent}}BeforeSave(n.Resource.(*types.{{.expIdent}})) + {{ end }} + // Flush to the DB err = store.Upsert{{.store.expIdent}}(ctx, s, n.Resource.(*types.{{.expIdent}})) if err != nil { diff --git a/server/codegen/assets/templates/gocode/envoy/yaml_decode.go.tpl b/server/codegen/assets/templates/gocode/envoy/yaml_decode.go.tpl index 3631c2816..f295ca14f 100644 --- a/server/codegen/assets/templates/gocode/envoy/yaml_decode.go.tpl +++ b/server/codegen/assets/templates/gocode/envoy/yaml_decode.go.tpl @@ -13,6 +13,7 @@ import ( "github.com/cortezaproject/corteza/server/pkg/rbac" "github.com/cortezaproject/corteza/server/pkg/y7s" "golang.org/x/text/language" + "github.com/spf13/cast" "gopkg.in/yaml.v3" {{- range .imports }} @@ -245,7 +246,7 @@ func (d *auxYamlDoc) unmarshal{{ .expIdent }}Node(dctx documentContext, n *yaml. auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig {{- if .rbac }} rbacNodes envoyx.NodeSet {{- end }} @@ -293,7 +294,7 @@ func (d *auxYamlDoc) unmarshal{{ .expIdent }}Node(dctx documentContext, n *yaml. "{{ $l }}"{{if not (eq $i (sub (len $identKeys) 1))}},{{end}} {{- end}}: - {{- if and $attr.envoy.yaml.identKeyAlias (gt (len $attr.envoy.yaml.identKeyAlias) 0) }} + {{- if and $attr.envoy.yaml.identKeyAlias (gt (len $attr.envoy.yaml.identKeyAlias) 0) (not (eq $attr.dal.type "Ref")) }} // Handle field alias // // @todo consider adding an is empty check before overwriting @@ -318,6 +319,12 @@ func (d *auxYamlDoc) unmarshal{{ .expIdent }}Node(dctx documentContext, n *yaml. if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["{{ $attr.expIdent }}"] = envoyx.Ref{ ResourceType: "{{ $attr.dal.refModelResType }}", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -513,6 +520,11 @@ func (d *auxYamlDoc) unmarshal{{ .expIdent }}Node(dctx documentContext, n *yaml. } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -694,7 +706,7 @@ func unmarshalLocaleNode(n *yaml.Node) (out envoyx.NodeSet, err error) { // Envoy config unmarshal logic // // // // // // // // // // // // // // // // // // // // // // // // // -func (d *auxYamlDoc) decodeEnvoyConfig(n *yaml.Node) (out envoyx.NodeConfig) { +func (d *auxYamlDoc) decodeEnvoyConfig(n *yaml.Node) (out envoyx.EnvoyConfig) { y7s.EachMap(n, func(k, v *yaml.Node) (err error) { switch strings.ToLower(k.Value) { case "skipif", "skip": diff --git a/server/codegen/assets/templates/gocode/envoy/yaml_encode.go.tpl b/server/codegen/assets/templates/gocode/envoy/yaml_encode.go.tpl index 51381a593..139cd0af0 100644 --- a/server/codegen/assets/templates/gocode/envoy/yaml_encode.go.tpl +++ b/server/codegen/assets/templates/gocode/envoy/yaml_encode.go.tpl @@ -51,7 +51,7 @@ func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt strin switch rt { {{- range .resources }} - {{- if .envoy.omit}} + {{- if or .envoy.omit .envoy.yaml.omitEncoder}} {{continue}} {{ end -}} @@ -66,6 +66,10 @@ func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt strin return } {{ end -}} + default: + // When this encoder doesn't handle any node it shouldn't write anything; + // this just removes the need for an extra check at the end. + return } return yaml.NewEncoder(w).Encode(out) @@ -169,7 +173,25 @@ func (e YamlEncoder) encode{{.expIdent}}(ctx context.Context, p envoyx.EncodePar */}} {{ $p := (index $cmp.parents (sub (len $cmp.parents) 1)) }} {{ if (eq $p.handle $a.ident) }} + {{ if eq $cmp.ident "moduleField"}} + // When processing module fields, we need to filter out the ones that + // don't belong to this module + // + // @todo offload this to dependency resolution; this is a hack + children := tt.ChildrenForResourceType(node, types.ModuleFieldResourceType) + + var proc envoyx.NodeSet + selfRef := node.ToRef() + for _, c := range children { + if c.References["ModuleID"].Equals(selfRef) { + proc = append(proc, c) + } + } + + aux, err = e.encodeModuleFields(ctx, p, proc, tt) + {{- else }} aux, err = e.encode{{$cmp.expIdent}}s(ctx, p, tt.ChildrenForResourceType(node, types.{{$cmp.expIdent}}ResourceType), tt) + {{- end }} if err != nil { return } @@ -210,7 +232,7 @@ func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, e return nil, nil } - tz := p.Config.PreferredTimezone + tz := p.Encoder.PreferredTimezone if tz != "" { tzL, err := time.LoadLocation(tz) if err != nil { @@ -219,7 +241,7 @@ func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, e t = t.In(tzL) } - ly := p.Config.PreferredTimeLayout + ly := p.Encoder.PreferredTimeLayout if ly == "" { ly = time.RFC3339 } @@ -243,7 +265,7 @@ func (e YamlEncoder) encodeRef(p envoyx.EncodeParams, id uint64, field string, n return id, nil } - return node.Identifiers.FriendlyIdentifier(), nil + return parent.Identifiers.FriendlyIdentifier(), nil } diff --git a/server/codegen/schema/component.cue b/server/codegen/schema/component.cue index 8f0e9aae3..0b1060e74 100644 --- a/server/codegen/schema/component.cue +++ b/server/codegen/schema/component.cue @@ -17,6 +17,10 @@ import ( fqrt: platform + "::" + handle + envoy: { + omit: bool | *false + } + // All known RBAC operations for this component rbac: #rbacComponent & { operations: { diff --git a/server/codegen/schema/resource.cue b/server/codegen/schema/resource.cue index 2edb80f05..4db967380 100644 --- a/server/codegen/schema/resource.cue +++ b/server/codegen/schema/resource.cue @@ -177,6 +177,8 @@ import ( // referencing this resource identKeys: [...string] | *([identKeyLabel]+identKeyAlias) + omitEncoder: bool | *false + extendedResourcePostProcess: bool | *false extendedResourceDecoders: [...{ ident: string @@ -215,5 +217,8 @@ import ( // extendedDecoder is called after the built-in which you can use // to append additional nodes into. extendedDecoder: bool | *false + + // the resource calls a sanitizer function before saving to the database + sanitizeBeforeSave: bool | *false } } diff --git a/server/codegen/server.envoy.cue b/server/codegen/server.envoy.cue index 6ac3d50c4..54e3d40d5 100644 --- a/server/codegen/server.envoy.cue +++ b/server/codegen/server.envoy.cue @@ -8,7 +8,7 @@ import ( [...schema.#codegen] & [ - for cmp in app.corteza.components { + for cmp in app.corteza.components if !cmp.envoy.omit { template: "gocode/envoy/yaml_decode.go.tpl" output: "\(cmp.ident)/envoy/yaml_decode.gen.go" payload: { @@ -22,7 +22,7 @@ import ( resources: [ for res in cmp.resources { res }] } }, - for cmp in app.corteza.components { + for cmp in app.corteza.components if !cmp.envoy.omit { template: "gocode/envoy/store_decode.go.tpl" output: "\(cmp.ident)/envoy/store_decode.gen.go" payload: { @@ -36,7 +36,7 @@ import ( resources: [ for res in cmp.resources { res }] } }, - for cmp in app.corteza.components { + for cmp in app.corteza.components if !cmp.envoy.omit { template: "gocode/envoy/store_encode.go.tpl" output: "\(cmp.ident)/envoy/store_encode.gen.go" payload: { @@ -50,7 +50,7 @@ import ( resources: [ for res in cmp.resources { res }] } }, - for cmp in app.corteza.components { + for cmp in app.corteza.components if !cmp.envoy.omit { template: "gocode/envoy/yaml_encode.go.tpl" output: "\(cmp.ident)/envoy/yaml_encode.gen.go" payload: { @@ -72,7 +72,7 @@ import ( payload: { package: "envoyx" - components: [for cmp in app.corteza.components { + components: [for cmp in app.corteza.components if !cmp.envoy.omit { ident: cmp.ident, resources: cmp.resources }] @@ -85,7 +85,7 @@ import ( payload: { package: "envoyx" - components: [for cmp in app.corteza.components { + components: [for cmp in app.corteza.components if !cmp.envoy.omit { ident: cmp.ident, resources: cmp.resources }] diff --git a/server/compose/chart.cue b/server/compose/chart.cue index 7eb285620..6b5a7f0ea 100644 --- a/server/compose/chart.cue +++ b/server/compose/chart.cue @@ -10,6 +10,8 @@ chart: { ] model: { + defaultSetter: true + ident: "compose_chart" attributes: { id: schema.IdField & { diff --git a/server/compose/envoy/store_decode.gen.go b/server/compose/envoy/store_decode.gen.go index df63178f7..b2c0491ff 100644 --- a/server/compose/envoy/store_decode.gen.go +++ b/server/compose/envoy/store_decode.gen.go @@ -218,12 +218,14 @@ func (d StoreDecoder) decodeChart(ctx context.Context, s store.Storer, dl dal.Fu r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "NamespaceID": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.NamespaceID > 0 { + refs["NamespaceID"] = envoyx.Ref{ ResourceType: "corteza::compose:namespace", Identifiers: envoyx.MakeIdentifiers(r.NamespaceID), - }, + } } refs = envoyx.MergeRefs(refs, d.decodeChartRefs(r)) @@ -300,12 +302,14 @@ func (d StoreDecoder) decodeModule(ctx context.Context, s store.Storer, dl dal.F r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "NamespaceID": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.NamespaceID > 0 { + refs["NamespaceID"] = envoyx.Ref{ ResourceType: "corteza::compose:namespace", Identifiers: envoyx.MakeIdentifiers(r.NamespaceID), - }, + } } var scope envoyx.Scope @@ -387,12 +391,14 @@ func (d StoreDecoder) decodeModuleField(ctx context.Context, s store.Storer, dl r.Name, ) - refs := map[string]envoyx.Ref{ - // Handle references - "ModuleID": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.ModuleID > 0 { + refs["ModuleID"] = envoyx.Ref{ ResourceType: "corteza::compose:module", Identifiers: envoyx.MakeIdentifiers(r.ModuleID), - }, + } } refs = envoyx.MergeRefs(refs, d.decodeModuleFieldRefs(r)) @@ -442,6 +448,8 @@ func (d StoreDecoder) decodeNamespace(ctx context.Context, s store.Storer, dl da r.Slug, ) + // Handle references + // Omit any non-defined values refs := map[string]envoyx.Ref{} var scope envoyx.Scope @@ -508,22 +516,26 @@ func (d StoreDecoder) decodePage(ctx context.Context, s store.Storer, dl dal.Ful r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "ModuleID": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.ModuleID > 0 { + refs["ModuleID"] = envoyx.Ref{ ResourceType: "corteza::compose:module", Identifiers: envoyx.MakeIdentifiers(r.ModuleID), - }, - // Handle references - "NamespaceID": envoyx.Ref{ + } + } + if r.NamespaceID > 0 { + refs["NamespaceID"] = envoyx.Ref{ ResourceType: "corteza::compose:namespace", Identifiers: envoyx.MakeIdentifiers(r.NamespaceID), - }, - // Handle references - "SelfID": envoyx.Ref{ + } + } + if r.SelfID > 0 { + refs["SelfID"] = envoyx.Ref{ ResourceType: "corteza::compose:page", Identifiers: envoyx.MakeIdentifiers(r.SelfID), - }, + } } refs = envoyx.MergeRefs(refs, d.decodePageRefs(r)) diff --git a/server/compose/envoy/store_decode.go b/server/compose/envoy/store_decode.go index c434ab62e..54c61e4a4 100644 --- a/server/compose/envoy/store_decode.go +++ b/server/compose/envoy/store_decode.go @@ -101,9 +101,13 @@ func (d StoreDecoder) extendedModuleDecoder(ctx context.Context, s store.Storer, for _, f := range ff { f.Scope = b.Scope - f.References = envoyx.MergeRefs(b.References, map[string]envoyx.Ref{ + f.References = envoyx.MergeRefs(f.References, b.References, map[string]envoyx.Ref{ "ModuleID": b.ToRef(), }) + for k, ref := range f.References { + ref.Scope = b.Scope + f.References[k] = ref + } mod.Fields = append(mod.Fields, f.Resource.(*types.ModuleField)) } @@ -134,6 +138,11 @@ func (d StoreDecoder) decodeChartRefs(c *types.Chart) (refs map[string]envoyx.Re func (d StoreDecoder) decodeModuleFieldRefs(c *types.ModuleField) (refs map[string]envoyx.Ref) { refs = make(map[string]envoyx.Ref, 1) + refs["NamespaceID"] = envoyx.Ref{ + ResourceType: types.NamespaceResourceType, + Identifiers: envoyx.MakeIdentifiers(c.NamespaceID), + } + id := c.Options.UInt64("moduleID") if id == 0 { return diff --git a/server/compose/envoy/store_encode.gen.go b/server/compose/envoy/store_encode.gen.go index 0da3d703f..526881dad 100644 --- a/server/compose/envoy/store_encode.gen.go +++ b/server/compose/envoy/store_encode.gen.go @@ -616,6 +616,10 @@ func (e StoreEncoder) encodeModuleField(ctx context.Context, p envoyx.EncodePara } } + // Custom resource sanitization before saving. + // This can be used to cleanup arbitrary config fields. + e.sanitizeModuleFieldBeforeSave(n.Resource.(*types.ModuleField)) + // Flush to the DB err = store.UpsertComposeModuleField(ctx, s, n.Resource.(*types.ModuleField)) if err != nil { diff --git a/server/compose/envoy/store_encode.go b/server/compose/envoy/store_encode.go index c186fd23a..e82b81f4a 100644 --- a/server/compose/envoy/store_encode.go +++ b/server/compose/envoy/store_encode.go @@ -39,6 +39,10 @@ func (e StoreEncoder) setModuleFieldDefaults(res *types.ModuleField) (err error) res.CreatedAt = time.Now() } + if res.Kind == "" { + res.Kind = "String" + } + // Update validator ID maxValidatorID := uint64(0) for _, v := range res.Expressions.Validators { @@ -57,6 +61,11 @@ func (e StoreEncoder) setModuleFieldDefaults(res *types.ModuleField) (err error) return } +func (e StoreEncoder) sanitizeModuleFieldBeforeSave(f *types.ModuleField) (err error) { + delete(f.Options, "module") + return +} + func (e StoreEncoder) validateModuleField(*types.ModuleField) (err error) { return } @@ -89,10 +98,11 @@ func (e StoreEncoder) setPageDefaults(res *types.Page) (err error) { } } - for _, b := range res.Blocks { + for i, b := range res.Blocks { if b.BlockID == 0 { b.BlockID = maxPageBlockID + 1 maxPageBlockID++ + res.Blocks[i] = b } } diff --git a/server/compose/envoy/yaml_decode.gen.go b/server/compose/envoy/yaml_decode.gen.go index e81f4c128..5caa2cbd6 100644 --- a/server/compose/envoy/yaml_decode.gen.go +++ b/server/compose/envoy/yaml_decode.gen.go @@ -17,6 +17,7 @@ import ( "github.com/cortezaproject/corteza/server/pkg/rbac" "github.com/cortezaproject/corteza/server/pkg/y7s" systemTypes "github.com/cortezaproject/corteza/server/system/types" + "github.com/spf13/cast" "golang.org/x/text/language" "gopkg.in/yaml.v3" ) @@ -231,7 +232,7 @@ func (d *auxYamlDoc) unmarshalChartNode(dctx documentContext, n *yaml.Node, meta auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -283,18 +284,17 @@ func (d *auxYamlDoc) unmarshalChartNode(dctx documentContext, n *yaml.Node, meta break case "namespaceid", "namespace", "namespace_id", "ns": - // Handle field alias - // - // @todo consider adding an is empty check before overwriting - err = y7s.DecodeScalar(n, "namespaceID", &r.NamespaceID) - if err != nil { - return err - } // Handle references err = y7s.DecodeScalar(n, "namespaceID", &auxNodeValue) if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["NamespaceID"] = envoyx.Ref{ ResourceType: "corteza::compose:namespace", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -398,6 +398,11 @@ func (d *auxYamlDoc) unmarshalChartNode(dctx documentContext, n *yaml.Node, meta } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -533,7 +538,7 @@ func (d *auxYamlDoc) unmarshalModuleNode(dctx documentContext, n *yaml.Node, met auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -566,18 +571,17 @@ func (d *auxYamlDoc) unmarshalModuleNode(dctx documentContext, n *yaml.Node, met break case "namespaceid", "namespace", "namespace_id", "ns", "ns_id": - // Handle field alias - // - // @todo consider adding an is empty check before overwriting - err = y7s.DecodeScalar(n, "namespaceID", &r.NamespaceID) - if err != nil { - return err - } // Handle references err = y7s.DecodeScalar(n, "namespaceID", &auxNodeValue) if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["NamespaceID"] = envoyx.Ref{ ResourceType: "corteza::compose:namespace", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -703,6 +707,11 @@ func (d *auxYamlDoc) unmarshalModuleNode(dctx documentContext, n *yaml.Node, met } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -827,7 +836,7 @@ func (d *auxYamlDoc) unmarshalModuleFieldNode(dctx documentContext, n *yaml.Node auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -893,6 +902,12 @@ func (d *auxYamlDoc) unmarshalModuleFieldNode(dctx documentContext, n *yaml.Node if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["ModuleID"] = envoyx.Ref{ ResourceType: "corteza::compose:module", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1025,6 +1040,11 @@ func (d *auxYamlDoc) unmarshalModuleFieldNode(dctx documentContext, n *yaml.Node } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -1144,7 +1164,7 @@ func (d *auxYamlDoc) unmarshalNamespaceNode(dctx documentContext, n *yaml.Node, auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -1328,6 +1348,11 @@ func (d *auxYamlDoc) unmarshalNamespaceNode(dctx documentContext, n *yaml.Node, } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -1482,7 +1507,7 @@ func (d *auxYamlDoc) unmarshalPageNode(dctx documentContext, n *yaml.Node, meta auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -1533,12 +1558,18 @@ func (d *auxYamlDoc) unmarshalPageNode(dctx documentContext, n *yaml.Node, meta break - case "moduleid": + case "moduleid", "module": // Handle references err = y7s.DecodeScalar(n, "moduleID", &auxNodeValue) if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["ModuleID"] = envoyx.Ref{ ResourceType: "corteza::compose:module", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1546,12 +1577,18 @@ func (d *auxYamlDoc) unmarshalPageNode(dctx documentContext, n *yaml.Node, meta break - case "namespaceid": + case "namespaceid", "namespace": // Handle references err = y7s.DecodeScalar(n, "namespaceID", &auxNodeValue) if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["NamespaceID"] = envoyx.Ref{ ResourceType: "corteza::compose:namespace", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1560,18 +1597,17 @@ func (d *auxYamlDoc) unmarshalPageNode(dctx documentContext, n *yaml.Node, meta break case "selfid", "parent": - // Handle field alias - // - // @todo consider adding an is empty check before overwriting - err = y7s.DecodeScalar(n, "selfID", &r.SelfID) - if err != nil { - return err - } // Handle references err = y7s.DecodeScalar(n, "selfID", &auxNodeValue) if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["SelfID"] = envoyx.Ref{ ResourceType: "corteza::compose:page", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1699,6 +1735,11 @@ func (d *auxYamlDoc) unmarshalPageNode(dctx documentContext, n *yaml.Node, meta } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -1868,7 +1909,7 @@ func unmarshalLocaleNode(n *yaml.Node) (out envoyx.NodeSet, err error) { // Envoy config unmarshal logic // // // // // // // // // // // // // // // // // // // // // // // // // -func (d *auxYamlDoc) decodeEnvoyConfig(n *yaml.Node) (out envoyx.NodeConfig) { +func (d *auxYamlDoc) decodeEnvoyConfig(n *yaml.Node) (out envoyx.EnvoyConfig) { y7s.EachMap(n, func(k, v *yaml.Node) (err error) { switch strings.ToLower(k.Value) { case "skipif", "skip": diff --git a/server/compose/envoy/yaml_decode.go b/server/compose/envoy/yaml_decode.go index b1f9353d0..e776fa8fb 100644 --- a/server/compose/envoy/yaml_decode.go +++ b/server/compose/envoy/yaml_decode.go @@ -169,7 +169,7 @@ func getPageBlockCalendarRefs(b types.PageBlock, index int) (refs map[string]env } refs[fmt.Sprintf("Blocks.%d.Options.feeds.%d.ModuleID", index, j)] = envoyx.Ref{ - ResourceType: types.ChartResourceType, + ResourceType: types.ModuleResourceType, Identifiers: envoyx.MakeIdentifiers(id), } } @@ -190,7 +190,7 @@ func getPageBlockMetricRefs(b types.PageBlock, index int) (refs map[string]envoy } refs[fmt.Sprintf("Blocks.%d.Options.metrics.%d.ModuleID", index, j)] = envoyx.Ref{ - ResourceType: types.ChartResourceType, + ResourceType: types.ModuleResourceType, Identifiers: envoyx.MakeIdentifiers(id), } } diff --git a/server/compose/envoy/yaml_encode.gen.go b/server/compose/envoy/yaml_encode.gen.go index 4d8bda46e..6d444e486 100644 --- a/server/compose/envoy/yaml_encode.gen.go +++ b/server/compose/envoy/yaml_encode.gen.go @@ -102,6 +102,10 @@ func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt strin return } + default: + // When this encoder doesn't handle any node it shouldn't write anything; + // this just removes the need for an extra check at the end. + return } return yaml.NewEncoder(w).Encode(out) @@ -211,10 +215,6 @@ func (e YamlEncoder) encodeModule(ctx context.Context, p envoyx.EncodeParams, no if err != nil { return } - auxFields, err := e.encodeModuleFieldsC(ctx, p, tt, node, res, res.Fields) - if err != nil { - return - } auxNamespaceID, err := e.encodeRef(p, res.NamespaceID, "NamespaceID", node, tt) if err != nil { @@ -229,7 +229,6 @@ func (e YamlEncoder) encodeModule(ctx context.Context, p envoyx.EncodeParams, no "config", res.Config, "createdAt", auxCreatedAt, "deletedAt", auxDeletedAt, - "fields", auxFields, "handle", res.Handle, "moduleID", res.ID, "meta", res.Meta, @@ -245,7 +244,21 @@ func (e YamlEncoder) encodeModule(ctx context.Context, p envoyx.EncodeParams, no var aux *yaml.Node _ = aux - aux, err = e.encodeModuleFields(ctx, p, tt.ChildrenForResourceType(node, types.ModuleFieldResourceType), tt) + // When processing module fields, we need to filter out the ones that + // don't belong to this module + // + // @todo offload this to dependency resolution; this is a hack + children := tt.ChildrenForResourceType(node, types.ModuleFieldResourceType) + + var proc envoyx.NodeSet + selfRef := node.ToRef() + for _, c := range children { + if c.References["ModuleID"].Equals(selfRef) { + proc = append(proc, c) + } + } + + aux, err = e.encodeModuleFields(ctx, p, proc, tt) if err != nil { return } @@ -528,7 +541,7 @@ func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, e return nil, nil } - tz := p.Config.PreferredTimezone + tz := p.Encoder.PreferredTimezone if tz != "" { tzL, err := time.LoadLocation(tz) if err != nil { @@ -537,7 +550,7 @@ func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, e t = t.In(tzL) } - ly := p.Config.PreferredTimeLayout + ly := p.Encoder.PreferredTimeLayout if ly == "" { ly = time.RFC3339 } @@ -563,7 +576,7 @@ func (e YamlEncoder) encodeRef(p envoyx.EncodeParams, id uint64, field string, n return id, nil } - return node.Identifiers.FriendlyIdentifier(), nil + return parent.Identifiers.FriendlyIdentifier(), nil } // // // // // // // // // // // // // // // // // // // // // // // // // diff --git a/server/compose/envoy/yaml_encode.go b/server/compose/envoy/yaml_encode.go index ae7bc1cad..5f94d74ed 100644 --- a/server/compose/envoy/yaml_encode.go +++ b/server/compose/envoy/yaml_encode.go @@ -42,7 +42,10 @@ func (e YamlEncoder) encodeChartConfigC(ctx context.Context, p envoyx.EncodePara } } - return reports, nil + return y7s.MakeMap( + "reports", reports, + "colorScheme", cfg.ColorScheme, + ) } func (e YamlEncoder) encodeModuleFieldsC(ctx context.Context, p envoyx.EncodeParams, tt envoyx.Traverser, n *envoyx.Node, mod *types.Module, fields types.ModuleFieldSet) (_ any, err error) { @@ -210,11 +213,12 @@ func (e YamlEncoder) encodePageBlockC(ctx context.Context, p envoyx.EncodeParams break } - return + return b, nil } -func (e YamlEncoder) cleanupPageblockRecordList(b types.PageBlock) (_ types.PageBlock) { - rawFF, has := b.Options["fields"] +func (e YamlEncoder) cleanupPageblockRecordList(b types.PageBlock) (out types.PageBlock) { + out = b + rawFF, has := out.Options["fields"] if !has { return } @@ -236,7 +240,7 @@ func (e YamlEncoder) cleanupPageblockRecordList(b types.PageBlock) (_ types.Page } } - b.Options["fields"] = retFF + out.Options["fields"] = retFF return b } diff --git a/server/compose/module.cue b/server/compose/module.cue index d65bf49ed..849537b58 100644 --- a/server/compose/module.cue +++ b/server/compose/module.cue @@ -56,7 +56,7 @@ module: { omitGetter: true envoy: { yaml: { - customEncoder: true + omitEncoder: true } } } diff --git a/server/compose/module_field.cue b/server/compose/module_field.cue index bc73106e9..da0678951 100644 --- a/server/compose/module_field.cue +++ b/server/compose/module_field.cue @@ -11,6 +11,8 @@ moduleField: { ] model: { + defaultSetter: true + ident: "compose_module_field" attributes: { id: schema.IdField & { @@ -139,6 +141,7 @@ moduleField: { handleField: "" customFilterBuilder: true extendedRefDecoder: true + sanitizeBeforeSave: true } } diff --git a/server/compose/page.cue b/server/compose/page.cue index 61aee8db9..ab69122e4 100644 --- a/server/compose/page.cue +++ b/server/compose/page.cue @@ -10,6 +10,8 @@ page: { ] model: { + defaultSetter: true + ident: "compose_page" attributes: { id: schema.IdField @@ -38,12 +40,22 @@ page: { goType: "uint64", storeIdent: "rel_module" dal: { type: "Ref", refModelResType: "corteza::compose:module" } + envoy: { + yaml: { + identKeyAlias: ["module"] + } + } } namespace_id: { ident: "namespaceID", goType: "uint64", storeIdent: "rel_namespace" dal: { type: "Ref", refModelResType: "corteza::compose:namespace" } + envoy: { + yaml: { + identKeyAlias: ["namespace"] + } + } } config: { diff --git a/server/compose/types/chart.go b/server/compose/types/chart.go index 7a421af5d..168c99c7a 100644 --- a/server/compose/types/chart.go +++ b/server/compose/types/chart.go @@ -165,6 +165,28 @@ func (c Chart) encodeTranslations() (out locale.ResourceTranslationSet) { return } +func (c *Chart) setValue(name string, pos uint, value any) (err error) { + pp := strings.Split(name, ".") + + switch pp[0] { + case "Config": + if pp[1] == "Reports" { + return c.Config.Reports[cast.ToInt(pp[2])].setValue(pp[3], 0, value) + } + } + + return +} + +func (r *ChartConfigReport) setValue(name string, pos uint, value any) (err error) { + switch name { + case "moduleID", "ModuleID": + r.ModuleID = cast.ToUint64(value) + } + + return +} + // FindByHandle finds chart by it's handle func (set ChartSet) FindByHandle(handle string) *Chart { for i := range set { diff --git a/server/compose/types/getters_setters.gen.go b/server/compose/types/getters_setters.gen.go index bbd0526c0..d31c474be 100644 --- a/server/compose/types/getters_setters.gen.go +++ b/server/compose/types/getters_setters.gen.go @@ -106,6 +106,9 @@ func (r *Chart) SetValue(name string, pos uint, value any) (err error) { case "updatedAt", "UpdatedAt": return cast2.TimePtr(value, &r.UpdatedAt) + default: + return r.setValue(name, pos, value) + } return nil } @@ -210,6 +213,9 @@ func (r *ModuleField) SetValue(name string, pos uint, value any) (err error) { case "updatedAt", "UpdatedAt": return cast2.TimePtr(value, &r.UpdatedAt) + default: + return r.setValue(name, pos, value) + } return nil } @@ -318,6 +324,9 @@ func (r *Page) SetValue(name string, pos uint, value any) (err error) { case "weight", "Weight": return cast2.Int(value, &r.Weight) + default: + return r.setValue(name, pos, value) + } return nil } diff --git a/server/compose/types/module_field.go b/server/compose/types/module_field.go index 7f5485281..42becf9bd 100644 --- a/server/compose/types/module_field.go +++ b/server/compose/types/module_field.go @@ -570,5 +570,17 @@ func (f ModuleField) IsSensitive() bool { return f.Config.Privacy.SensitivityLevelID > 0 } +func (f *ModuleField) setValue(name string, pos uint, value any) (err error) { + switch name { + // @todo consider moving this to the .cue definition; figure out why it wasn't yet + case "NamespaceID", "namespaceID": + f.NamespaceID = cast.ToUint64(value) + case "Options.ModuleID": + f.Options["moduleID"] = cast.ToString(value) + } + + return +} + func (p *ModuleFieldConfig) Scan(src any) error { return sql.ParseJSON(src, p) } func (p ModuleFieldConfig) Value() (driver.Value, error) { return json.Marshal(p) } diff --git a/server/compose/types/page.go b/server/compose/types/page.go index 78a833d1f..7624caa40 100644 --- a/server/compose/types/page.go +++ b/server/compose/types/page.go @@ -343,6 +343,55 @@ func (p *Page) encodeRecordListButtons(bb []interface{}, blockID uint64) (out lo return } +func (p *Page) setValue(name string, pos uint, value any) (err error) { + pp := strings.Split(name, ".") + switch pp[0] { + case "Blocks": + return p.Blocks[cast.ToUint(pp[1])].setValue(strings.Join(pp[2:], "."), pos, value) + } + + return +} + +func (b *PageBlock) setValue(name string, pos uint, value any) (err error) { + pp := strings.Split(name, ".") + + switch pp[0] { + case "Options": + return b.setOptionValue(pp[1:], pos, value) + } + + return +} + +func (b *PageBlock) setOptionValue(path []string, pos uint, value any) (err error) { + switch path[0] { + case "feeds": + // Get the feed on the correct index in the correct type + feed := (b.Options["feeds"].([]any))[cast.ToInt(path[1])].(map[string]any) + + // Getthe feed options in the correct type + options := feed["options"].(map[string]any) + + // Set the value + options["moduleID"] = cast.ToString(value) + + case "metrics": + // Get the metric on the correct index in the correct type + metric := (b.Options["metrics"].([]any))[cast.ToInt(path[1])].(map[string]any) + + metric["moduleID"] = cast.ToString(value) + + case "moduleID", "ModuleID": + b.Options["moduleID"] = cast.ToString(value) + + case "chartID", "ChartID": + b.Options["chartID"] = cast.ToString(value) + } + + return +} + // FindByHandle finds page by it's handle func (set PageSet) FindByHandle(handle string) *Page { for i := range set { diff --git a/server/federation/component.cue b/server/federation/component.cue index b93a809d8..2262f0b32 100644 --- a/server/federation/component.cue +++ b/server/federation/component.cue @@ -15,6 +15,10 @@ component: schema.#component & { "module-mapping": moduleMapping } + envoy: { + omit: true + } + rbac: operations: { "grant": description: "Manage federation permissions" "pair": description: "Pair federation nodes" diff --git a/server/pkg/envoyx/dep.go b/server/pkg/envoyx/dep.go index b9740156a..1c756a00a 100644 --- a/server/pkg/envoyx/dep.go +++ b/server/pkg/envoyx/dep.go @@ -1,12 +1,12 @@ package envoyx type ( - // depGraph provides a collection of optionally connected subgraphs + // DepGraph provides a collection of optionally connected subgraphs // // Each subgraph is dedicated for a specific node scope. // A subgraph with scoped nodes may be connected to the subgraph with no // defined scope. - depGraph struct { + DepGraph struct { graphs []*depSubgraph } @@ -37,7 +37,7 @@ type ( // // We firstly group the nodes by scope, then build a subgraph for each scope, // and lastly merge the subgraphs into a single graph. -func BuildDepGraph(nn ...*Node) (out *depGraph) { +func BuildDepGraph(nn ...*Node) (out *DepGraph) { scopes := scopeNodes(nn...) aux := make([]*depSubgraph, 0, len(scopes)) @@ -224,8 +224,8 @@ func buildDepSubgraph(nn NodeSet) (out *depSubgraph) { // The subgraphs can be connected in case a scoped node would reference a // unscoped node (unscoped nodes can not reference scoped nodes, nor can nodes // from different scopes -- unneeded and removes some complexity). -func buildDepGraph(gg ...*depSubgraph) (out *depGraph) { - out = &depGraph{ +func buildDepGraph(gg ...*depSubgraph) (out *DepGraph) { + out = &DepGraph{ graphs: make([]*depSubgraph, 0, len(gg)), } @@ -283,7 +283,7 @@ func buildDepGraph(gg ...*depSubgraph) (out *depGraph) { // // For the most part, these are all resources with no parent resources. // If all resources define parents, then some home brew logic is ran -func (g depGraph) Roots() (out NodeSet) { +func (g DepGraph) Roots() (out NodeSet) { for _, sg := range g.graphs { out = append(out, sg.Roots()...) } @@ -291,7 +291,7 @@ func (g depGraph) Roots() (out NodeSet) { } // ParentForRef returns a parent node of n which matches ref (nil if none) -func (g depGraph) ParentForRef(n *Node, ref Ref) (out *Node) { +func (g DepGraph) ParentForRef(n *Node, ref Ref) (out *Node) { for _, sg := range g.graphs { out = sg.ParentForRef(n, ref) if out != nil { @@ -302,7 +302,7 @@ func (g depGraph) ParentForRef(n *Node, ref Ref) (out *Node) { } // ChildrenForResourceType returns child nodes of n which match the resource type -func (g depGraph) ChildrenForResourceType(n *Node, rt string) (out NodeSet) { +func (g DepGraph) ChildrenForResourceType(n *Node, rt string) (out NodeSet) { for _, sg := range g.graphs { out = sg.ChildrenForResourceType(n, rt) if out != nil { @@ -313,7 +313,7 @@ func (g depGraph) ChildrenForResourceType(n *Node, rt string) (out NodeSet) { } // Children returns all child nodes of n -func (g depGraph) Children(n *Node) (out NodeSet) { +func (g DepGraph) Children(n *Node) (out NodeSet) { for _, sg := range g.graphs { out = sg.Children(n) if out != nil { @@ -324,7 +324,7 @@ func (g depGraph) Children(n *Node) (out NodeSet) { } // MissingRegs returns a slice of all refs that are requested but not found in the graph -func (g depGraph) MissingRefs() (out []map[string]Ref) { +func (g DepGraph) MissingRefs() (out []map[string]Ref) { for _, sg := range g.graphs { for _, n := range sg.nodes { if len(n.missingReferences) == 0 { @@ -337,7 +337,7 @@ func (g depGraph) MissingRefs() (out []map[string]Ref) { return } -func (g depGraph) allNodes() (out []*depNode) { +func (g DepGraph) allNodes() (out []*depNode) { for _, sg := range g.graphs { out = append(out, sg.nodes...) } diff --git a/server/pkg/envoyx/envoy.go b/server/pkg/envoyx/envoy.go index 882b0a12c..1f0e4f780 100644 --- a/server/pkg/envoyx/envoy.go +++ b/server/pkg/envoyx/envoy.go @@ -9,7 +9,7 @@ import ( ) type ( - service struct { + Service struct { decoders map[decodeType][]Decoder encoders map[encodeType][]Encoder @@ -90,7 +90,7 @@ type ( ) var ( - global *service + global *Service ex = expr.NewParser() ) @@ -112,17 +112,17 @@ const ( ) // New initializes a new Envoy service -func New() *service { - return &service{} +func New() *Service { + return &Service{} } // SetGlobal sets the global envoy service -func SetGlobal(n *service) { +func SetGlobal(n *Service) { global = n } -// Service gets the global envoy service -func Service() *service { +// Global gets the global envoy service +func Global() *Service { if global == nil { panic("global service not defined") } @@ -131,7 +131,7 @@ func Service() *service { } // Decode returns a set of envoy Nodes based on the given decode params -func (svc *service) Decode(ctx context.Context, p DecodeParams) (nn NodeSet, err error) { +func (svc *Service) Decode(ctx context.Context, p DecodeParams) (nn NodeSet, err error) { err = p.validate() if err != nil { return @@ -149,20 +149,25 @@ func (svc *service) Decode(ctx context.Context, p DecodeParams) (nn NodeSet, err return } -func (svc *service) Bake(ctx context.Context, p EncodeParams, nodes ...*Node) (err error) { +func (svc *Service) Bake(ctx context.Context, p EncodeParams, nodes ...*Node) (gg *DepGraph, err error) { err = svc.bakeEnvoyConfig(p.Envoy, nodes...) if err != nil { return } err = svc.bakeExpressions(nodes...) + if err != nil { + return + } + + gg = BuildDepGraph(nodes...) return } // Encode encodes Corteza resources bases on the provided encode params // // use the BuildDepGraph function to build the default dependency graph. -func (svc *service) Encode(ctx context.Context, p EncodeParams, dg *depGraph) (err error) { +func (svc *Service) Encode(ctx context.Context, p EncodeParams, dg *DepGraph) (err error) { err = p.validate() if err != nil { return @@ -179,21 +184,33 @@ func (svc *service) Encode(ctx context.Context, p EncodeParams, dg *depGraph) (e return } -func (svc *service) AddDecoder(t decodeType, dd ...Decoder) { +func (svc *Service) AddDecoder(t decodeType, dd ...Decoder) { if svc.decoders == nil { svc.decoders = make(map[decodeType][]Decoder) } svc.decoders[t] = append(svc.decoders[t], dd...) } -func (svc *service) AddEncoder(t encodeType, ee ...Encoder) { +func (svc *Service) AddEncoder(t encodeType, ee ...Encoder) { if svc.encoders == nil { svc.encoders = make(map[encodeType][]Encoder) } + if svc.preparers == nil { + svc.preparers = make(map[encodeType][]Preparer) + } svc.encoders[t] = append(svc.encoders[t], ee...) + + for _, e := range ee { + p, ok := e.(Preparer) + if !ok { + continue + } + + svc.preparers[t] = append(svc.preparers[t], p) + } } -func (svc *service) AddPreparer(t encodeType, pp ...Preparer) { +func (svc *Service) AddPreparer(t encodeType, pp ...Preparer) { if svc.preparers == nil { svc.preparers = make(map[encodeType][]Preparer) } @@ -242,7 +259,7 @@ func CastMergeAlg(v string) (mergeAlg mergeAlg) { return } -func (svc *service) bakeEnvoyConfig(dft EnvoyConfig, nodes ...*Node) (err error) { +func (svc *Service) bakeEnvoyConfig(dft EnvoyConfig, nodes ...*Node) (err error) { for _, n := range nodes { n.Config = svc.mergeEnvoyConfigs(n.Config, dft) } @@ -250,7 +267,7 @@ func (svc *service) bakeEnvoyConfig(dft EnvoyConfig, nodes ...*Node) (err error) return } -func (svc *service) bakeExpressions(nodes ...*Node) (err error) { +func (svc *Service) bakeExpressions(nodes ...*Node) (err error) { for _, n := range nodes { if n.Config.SkipIf == "" { continue @@ -265,7 +282,7 @@ func (svc *service) bakeExpressions(nodes ...*Node) (err error) { return } -func (svc *service) mergeEnvoyConfigs(a, b EnvoyConfig) (c EnvoyConfig) { +func (svc *Service) mergeEnvoyConfigs(a, b EnvoyConfig) (c EnvoyConfig) { c = a if c.MergeAlg == OnConflictDefault { c.MergeAlg = b.MergeAlg diff --git a/server/pkg/envoyx/envoy_test.go b/server/pkg/envoyx/envoy_test.go index 09e23cf14..6f600f348 100644 --- a/server/pkg/envoyx/envoy_test.go +++ b/server/pkg/envoyx/envoy_test.go @@ -30,7 +30,7 @@ func TestBake(t *testing.T) { SkipIf: "true", }, } - err := (&service{}).Bake(ctx, EncodeParams{Envoy: EnvoyConfig{MergeAlg: OnConflictPanic, SkipIf: "false"}}, a, b, c) + _, err := (&Service{}).Bake(ctx, EncodeParams{Envoy: EnvoyConfig{MergeAlg: OnConflictPanic, SkipIf: "false"}}, a, b, c) req.NoError(err) req.Equal(OnConflictPanic, a.Config.MergeAlg) @@ -57,7 +57,7 @@ func TestBake(t *testing.T) { }, } - err := (&service{}).Bake(ctx, EncodeParams{}, a, b) + _, err := (&Service{}).Bake(ctx, EncodeParams{}, a, b) req.NoError(err) req.Nil(a.Config.SkipIfEval) diff --git a/server/pkg/envoyx/io.go b/server/pkg/envoyx/io.go index 2dfff79ad..ad72bc679 100644 --- a/server/pkg/envoyx/io.go +++ b/server/pkg/envoyx/io.go @@ -9,7 +9,7 @@ import ( "strings" ) -func (nvyx *service) decodeUri(ctx context.Context, p DecodeParams) (nn NodeSet, err error) { +func (nvyx *Service) decodeUri(ctx context.Context, p DecodeParams) (nn NodeSet, err error) { aUri, ok := p.Params["uri"] if !ok { err = fmt.Errorf("cannot decode URI: no uri parameter provided") @@ -48,7 +48,7 @@ func (nvyx *service) decodeUri(ctx context.Context, p DecodeParams) (nn NodeSet, } } -func (nvyx *service) encodeIo(ctx context.Context, dg *depGraph, p EncodeParams) (err error) { +func (nvyx *Service) encodeIo(ctx context.Context, dg *DepGraph, p EncodeParams) (err error) { for rt, nn := range NodesByResourceType(dg.Roots()...) { for _, se := range nvyx.encoders[EncodeTypeIo] { err = se.Encode(ctx, p, rt, OmitPlaceholderNodes(nn...), dg) @@ -61,7 +61,7 @@ func (nvyx *service) encodeIo(ctx context.Context, dg *depGraph, p EncodeParams) return } -func (nvyx *service) decodeDirectory(ctx context.Context, p DecodeParams, path string) (nn NodeSet, err error) { +func (nvyx *Service) decodeDirectory(ctx context.Context, p DecodeParams, path string) (nn NodeSet, err error) { return nn, filepath.Walk(path, func(path string, info fs.FileInfo, err error) error { if err != nil { return err @@ -82,7 +82,7 @@ func (nvyx *service) decodeDirectory(ctx context.Context, p DecodeParams, path s }) } -func (nvyx *service) decodeFile(ctx context.Context, p DecodeParams, path string) (nn NodeSet, err error) { +func (nvyx *Service) decodeFile(ctx context.Context, p DecodeParams, path string) (nn NodeSet, err error) { var aux NodeSet f, err := os.Open(path) if err != nil { diff --git a/server/pkg/envoyx/node.go b/server/pkg/envoyx/node.go index 31bc8f731..005d85125 100644 --- a/server/pkg/envoyx/node.go +++ b/server/pkg/envoyx/node.go @@ -127,14 +127,17 @@ func OmitPlaceholderNodes(nn ...*Node) (out NodeSet) { return } -func MergeRefs(a, b map[string]Ref) (c map[string]Ref) { +func MergeRefs(a map[string]Ref, bb ...map[string]Ref) (c map[string]Ref) { c = make(map[string]Ref) for k, v := range a { c[k] = v } - for k, v := range b { - c[k] = v + + for _, b := range bb { + for k, v := range b { + c[k] = v + } } return @@ -187,6 +190,20 @@ func (r Ref) ResourceFilter() (out map[string]ResourceFilter) { return } +func (a Ref) Equals(b Ref) bool { + if a.ResourceType != b.ResourceType { + return false + } + if !a.Scope.Equals(b.Scope) { + return false + } + if !a.Identifiers.HasIntersection(b.Identifiers) { + return false + } + + return true +} + func (a Scope) Equals(b Scope) bool { if a.IsEmpty() && b.IsEmpty() { return true diff --git a/server/pkg/envoyx/store.go b/server/pkg/envoyx/store.go index e83f01d4c..bcdc5ef8e 100644 --- a/server/pkg/envoyx/store.go +++ b/server/pkg/envoyx/store.go @@ -1,8 +1,10 @@ package envoyx -import "context" +import ( + "context" +) -func (svc *service) decodeStore(ctx context.Context, p DecodeParams) (nn NodeSet, err error) { +func (svc *Service) decodeStore(ctx context.Context, p DecodeParams) (nn NodeSet, err error) { var aux NodeSet for _, d := range svc.decoders[DecodeTypeStore] { aux, err = d.Decode(ctx, p) @@ -15,7 +17,7 @@ func (svc *service) decodeStore(ctx context.Context, p DecodeParams) (nn NodeSet return } -func (svc *service) encodeStore(ctx context.Context, dg *depGraph, p EncodeParams) (err error) { +func (svc *Service) encodeStore(ctx context.Context, dg *DepGraph, p EncodeParams) (err error) { // Prepping // // @note this is ok for now but if we add things like importing into diff --git a/server/pkg/envoyx/utils.gen.go b/server/pkg/envoyx/utils.gen.go index 79a5b37bc..e16706c0f 100644 --- a/server/pkg/envoyx/utils.gen.go +++ b/server/pkg/envoyx/utils.gen.go @@ -22,10 +22,6 @@ var ( "corteza::compose:page": true, "corteza::compose:record": true, - "corteza::federation:exposed-module": true, - "corteza::federation:module-mapping": true, - - "corteza::federation:shared-module": true, "corteza::compose:record-datasource": true, } diff --git a/server/system/apigw_filter.cue b/server/system/apigw_filter.cue index 3f59b929b..6bffdf82a 100644 --- a/server/system/apigw_filter.cue +++ b/server/system/apigw_filter.cue @@ -15,6 +15,7 @@ apigw_filter: { route: { sortable: true, goType: "uint64", storeIdent: "rel_route" dal: { type: "Ref", refModelResType: "corteza::system:apigw-route" } + identAlias: ["route", "Route", "ApigwRouteID"] envoy: { store: { omitRefFilter: true @@ -61,6 +62,7 @@ apigw_filter: { envoy: { yaml: { supportMappedInput: false + omitEncoder: true } store: { handleField: "" diff --git a/server/system/application.cue b/server/system/application.cue index e09e0a8eb..668c9b6c5 100644 --- a/server/system/application.cue +++ b/server/system/application.cue @@ -36,6 +36,9 @@ application: { store: { omitRefFilter: true } + yaml: { + identKeyAlias: ["owner"] + } } } created_at: schema.SortableTimestampNowField diff --git a/server/system/auth_client.cue b/server/system/auth_client.cue index a065edfe3..831119617 100644 --- a/server/system/auth_client.cue +++ b/server/system/auth_client.cue @@ -92,7 +92,6 @@ auth_client: { } envoy: { - scoped: true yaml: { supportMappedInput: true mappedField: "Handle" diff --git a/server/system/envoy/store_decode.gen.go b/server/system/envoy/store_decode.gen.go index 06801e991..abd48966f 100644 --- a/server/system/envoy/store_decode.gen.go +++ b/server/system/envoy/store_decode.gen.go @@ -263,12 +263,14 @@ func (d StoreDecoder) decodeApplication(ctx context.Context, s store.Storer, dl r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "OwnerID": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.OwnerID > 0 { + refs["OwnerID"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.OwnerID), - }, + } } var scope envoyx.Scope @@ -328,27 +330,32 @@ func (d StoreDecoder) decodeApigwRoute(ctx context.Context, s store.Storer, dl d r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "Group": envoyx.Ref{ + } + } + if r.Group > 0 { + refs["Group"] = envoyx.Ref{ ResourceType: "corteza::system:apigw-group", Identifiers: envoyx.MakeIdentifiers(r.Group), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, + } } var scope envoyx.Scope @@ -414,27 +421,32 @@ func (d StoreDecoder) decodeApigwFilter(ctx context.Context, s store.Storer, dl r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "Route": envoyx.Ref{ + } + } + if r.Route > 0 { + refs["Route"] = envoyx.Ref{ ResourceType: "corteza::system:apigw-route", Identifiers: envoyx.MakeIdentifiers(r.Route), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, + } } var scope envoyx.Scope @@ -491,38 +503,38 @@ func (d StoreDecoder) decodeAuthClient(ctx context.Context, s store.Storer, dl d r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "OwnedBy": envoyx.Ref{ + } + } + if r.OwnedBy > 0 { + refs["OwnedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.OwnedBy), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, + } } refs = envoyx.MergeRefs(refs, d.decodeAuthClientRefs(r)) var scope envoyx.Scope - scope = envoyx.Scope{ - ResourceType: types.AuthClientResourceType, - Identifiers: ii, - } - out = append(out, &envoyx.Node{ Resource: r, @@ -579,31 +591,30 @@ func (d StoreDecoder) decodeQueue(ctx context.Context, s store.Storer, dl dal.Fu r.Queue, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, + } } var scope envoyx.Scope - scope = envoyx.Scope{ - ResourceType: types.QueueResourceType, - Identifiers: ii, - } - out = append(out, &envoyx.Node{ Resource: r, @@ -656,27 +667,32 @@ func (d StoreDecoder) decodeReport(ctx context.Context, s store.Storer, dl dal.F r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "OwnedBy": envoyx.Ref{ + } + } + if r.OwnedBy > 0 { + refs["OwnedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.OwnedBy), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, + } } var scope envoyx.Scope @@ -737,6 +753,8 @@ func (d StoreDecoder) decodeRole(ctx context.Context, s store.Storer, dl dal.Ful r.ID, ) + // Handle references + // Omit any non-defined values refs := map[string]envoyx.Ref{} var scope envoyx.Scope @@ -797,12 +815,14 @@ func (d StoreDecoder) decodeTemplate(ctx context.Context, s store.Storer, dl dal r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "OwnerID": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.OwnerID > 0 { + refs["OwnerID"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.OwnerID), - }, + } } var scope envoyx.Scope @@ -863,6 +883,8 @@ func (d StoreDecoder) decodeUser(ctx context.Context, s store.Storer, dl dal.Ful r.ID, ) + // Handle references + // Omit any non-defined values refs := map[string]envoyx.Ref{} var scope envoyx.Scope @@ -923,22 +945,26 @@ func (d StoreDecoder) decodeDalConnection(ctx context.Context, s store.Storer, d r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, + } } refs = envoyx.MergeRefs(refs, d.decodeDalConnectionRefs(r)) @@ -1001,22 +1027,26 @@ func (d StoreDecoder) decodeDalSensitivityLevel(ctx context.Context, s store.Sto r.ID, ) - refs := map[string]envoyx.Ref{ - // Handle references - "CreatedBy": envoyx.Ref{ + // Handle references + // Omit any non-defined values + refs := map[string]envoyx.Ref{} + if r.CreatedBy > 0 { + refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.CreatedBy), - }, - // Handle references - "DeletedBy": envoyx.Ref{ + } + } + if r.DeletedBy > 0 { + refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.DeletedBy), - }, - // Handle references - "UpdatedBy": envoyx.Ref{ + } + } + if r.UpdatedBy > 0 { + refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy), - }, + } } var scope envoyx.Scope diff --git a/server/system/envoy/yaml_decode.gen.go b/server/system/envoy/yaml_decode.gen.go index 30b2e9d53..2472ad73b 100644 --- a/server/system/envoy/yaml_decode.gen.go +++ b/server/system/envoy/yaml_decode.gen.go @@ -17,6 +17,7 @@ import ( "github.com/cortezaproject/corteza/server/pkg/y7s" "github.com/cortezaproject/corteza/server/system/types" systemTypes "github.com/cortezaproject/corteza/server/system/types" + "github.com/spf13/cast" "golang.org/x/text/language" "gopkg.in/yaml.v3" ) @@ -298,7 +299,7 @@ func (d *auxYamlDoc) unmarshalApplicationNode(dctx documentContext, n *yaml.Node auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -320,12 +321,18 @@ func (d *auxYamlDoc) unmarshalApplicationNode(dctx documentContext, n *yaml.Node break - case "ownerid": + case "ownerid", "owner": // Handle references err = y7s.DecodeScalar(n, "ownerID", &auxNodeValue) if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["OwnerID"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -407,6 +414,11 @@ func (d *auxYamlDoc) unmarshalApplicationNode(dctx documentContext, n *yaml.Node } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -540,7 +552,7 @@ func (d *auxYamlDoc) unmarshalApigwRouteNode(dctx documentContext, n *yaml.Node, auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -558,6 +570,12 @@ func (d *auxYamlDoc) unmarshalApigwRouteNode(dctx documentContext, n *yaml.Node, if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -571,6 +589,12 @@ func (d *auxYamlDoc) unmarshalApigwRouteNode(dctx documentContext, n *yaml.Node, if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -584,6 +608,12 @@ func (d *auxYamlDoc) unmarshalApigwRouteNode(dctx documentContext, n *yaml.Node, if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["Group"] = envoyx.Ref{ ResourceType: "corteza::system:apigw-group", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -607,6 +637,12 @@ func (d *auxYamlDoc) unmarshalApigwRouteNode(dctx documentContext, n *yaml.Node, if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -696,6 +732,11 @@ func (d *auxYamlDoc) unmarshalApigwRouteNode(dctx documentContext, n *yaml.Node, } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -794,7 +835,7 @@ func (d *auxYamlDoc) unmarshalApigwFilterNode(dctx documentContext, n *yaml.Node auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig ) _ = auxOut _ = refs @@ -811,6 +852,12 @@ func (d *auxYamlDoc) unmarshalApigwFilterNode(dctx documentContext, n *yaml.Node if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -824,6 +871,12 @@ func (d *auxYamlDoc) unmarshalApigwFilterNode(dctx documentContext, n *yaml.Node if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -847,6 +900,12 @@ func (d *auxYamlDoc) unmarshalApigwFilterNode(dctx documentContext, n *yaml.Node if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["Route"] = envoyx.Ref{ ResourceType: "corteza::system:apigw-route", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -860,6 +919,12 @@ func (d *auxYamlDoc) unmarshalApigwFilterNode(dctx documentContext, n *yaml.Node if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -925,6 +990,11 @@ func (d *auxYamlDoc) unmarshalApigwFilterNode(dctx documentContext, n *yaml.Node } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -1024,7 +1094,7 @@ func (d *auxYamlDoc) unmarshalAuthClientNode(dctx documentContext, n *yaml.Node, auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -1042,6 +1112,12 @@ func (d *auxYamlDoc) unmarshalAuthClientNode(dctx documentContext, n *yaml.Node, if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1055,6 +1131,12 @@ func (d *auxYamlDoc) unmarshalAuthClientNode(dctx documentContext, n *yaml.Node, if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1088,6 +1170,12 @@ func (d *auxYamlDoc) unmarshalAuthClientNode(dctx documentContext, n *yaml.Node, if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["OwnedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1120,6 +1208,12 @@ func (d *auxYamlDoc) unmarshalAuthClientNode(dctx documentContext, n *yaml.Node, if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1153,15 +1247,6 @@ func (d *auxYamlDoc) unmarshalAuthClientNode(dctx documentContext, n *yaml.Node, return } - // Define the scope - // - // This resource is scoped with no parent resources so this resource is the - // root itself (generally the namespace -- the only currently supported scenario). - scope = envoyx.Scope{ - ResourceType: types.AuthClientResourceType, - Identifiers: ii, - } - // Apply the scope to all of the references of the same type for k, ref := range refs { if ref.ResourceType != scope.ResourceType { @@ -1210,6 +1295,11 @@ func (d *auxYamlDoc) unmarshalAuthClientNode(dctx documentContext, n *yaml.Node, } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -1229,8 +1319,6 @@ func (d *auxYamlDoc) unmarshalAuthClientNode(dctx documentContext, n *yaml.Node, Identifiers: ii, References: refs, - Scope: scope, - Config: envoyConfig, } // Update RBAC resource nodes with references regarding the resource @@ -1329,7 +1417,7 @@ func (d *auxYamlDoc) unmarshalQueueNode(dctx documentContext, n *yaml.Node, meta auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -1347,6 +1435,12 @@ func (d *auxYamlDoc) unmarshalQueueNode(dctx documentContext, n *yaml.Node, meta if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1360,6 +1454,12 @@ func (d *auxYamlDoc) unmarshalQueueNode(dctx documentContext, n *yaml.Node, meta if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1393,6 +1493,12 @@ func (d *auxYamlDoc) unmarshalQueueNode(dctx documentContext, n *yaml.Node, meta if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1426,15 +1532,6 @@ func (d *auxYamlDoc) unmarshalQueueNode(dctx documentContext, n *yaml.Node, meta return } - // Define the scope - // - // This resource is scoped with no parent resources so this resource is the - // root itself (generally the namespace -- the only currently supported scenario). - scope = envoyx.Scope{ - ResourceType: types.QueueResourceType, - Identifiers: ii, - } - // Apply the scope to all of the references of the same type for k, ref := range refs { if ref.ResourceType != scope.ResourceType { @@ -1483,6 +1580,11 @@ func (d *auxYamlDoc) unmarshalQueueNode(dctx documentContext, n *yaml.Node, meta } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -1502,8 +1604,6 @@ func (d *auxYamlDoc) unmarshalQueueNode(dctx documentContext, n *yaml.Node, meta Identifiers: ii, References: refs, - Scope: scope, - Config: envoyConfig, } // Update RBAC resource nodes with references regarding the resource @@ -1602,7 +1702,7 @@ func (d *auxYamlDoc) unmarshalReportNode(dctx documentContext, n *yaml.Node, met auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -1620,6 +1720,12 @@ func (d *auxYamlDoc) unmarshalReportNode(dctx documentContext, n *yaml.Node, met if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1633,6 +1739,12 @@ func (d *auxYamlDoc) unmarshalReportNode(dctx documentContext, n *yaml.Node, met if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1666,6 +1778,12 @@ func (d *auxYamlDoc) unmarshalReportNode(dctx documentContext, n *yaml.Node, met if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["OwnedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1679,6 +1797,12 @@ func (d *auxYamlDoc) unmarshalReportNode(dctx documentContext, n *yaml.Node, met if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -1760,6 +1884,11 @@ func (d *auxYamlDoc) unmarshalReportNode(dctx documentContext, n *yaml.Node, met } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -1877,7 +2006,7 @@ func (d *auxYamlDoc) unmarshalRoleNode(dctx documentContext, n *yaml.Node, meta auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -1983,6 +2112,11 @@ func (d *auxYamlDoc) unmarshalRoleNode(dctx documentContext, n *yaml.Node, meta } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -2100,7 +2234,7 @@ func (d *auxYamlDoc) unmarshalTemplateNode(dctx documentContext, n *yaml.Node, m auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -2138,6 +2272,12 @@ func (d *auxYamlDoc) unmarshalTemplateNode(dctx documentContext, n *yaml.Node, m if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["OwnerID"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -2219,6 +2359,11 @@ func (d *auxYamlDoc) unmarshalTemplateNode(dctx documentContext, n *yaml.Node, m } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -2336,7 +2481,7 @@ func (d *auxYamlDoc) unmarshalUserNode(dctx documentContext, n *yaml.Node, meta auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -2461,6 +2606,11 @@ func (d *auxYamlDoc) unmarshalUserNode(dctx documentContext, n *yaml.Node, meta } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -2578,7 +2728,7 @@ func (d *auxYamlDoc) unmarshalDalConnectionNode(dctx documentContext, n *yaml.No auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig rbacNodes envoyx.NodeSet ) _ = auxOut @@ -2596,6 +2746,12 @@ func (d *auxYamlDoc) unmarshalDalConnectionNode(dctx documentContext, n *yaml.No if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -2609,6 +2765,12 @@ func (d *auxYamlDoc) unmarshalDalConnectionNode(dctx documentContext, n *yaml.No if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -2642,6 +2804,12 @@ func (d *auxYamlDoc) unmarshalDalConnectionNode(dctx documentContext, n *yaml.No if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -2723,6 +2891,11 @@ func (d *auxYamlDoc) unmarshalDalConnectionNode(dctx documentContext, n *yaml.No } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -2840,7 +3013,7 @@ func (d *auxYamlDoc) unmarshalDalSensitivityLevelNode(dctx documentContext, n *y auxOut envoyx.NodeSet nestedNodes envoyx.NodeSet scope envoyx.Scope - envoyConfig envoyx.NodeConfig + envoyConfig envoyx.EnvoyConfig ) _ = auxOut _ = refs @@ -2857,6 +3030,12 @@ func (d *auxYamlDoc) unmarshalDalSensitivityLevelNode(dctx documentContext, n *y if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["CreatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -2870,6 +3049,12 @@ func (d *auxYamlDoc) unmarshalDalSensitivityLevelNode(dctx documentContext, n *y if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["DeletedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -2903,6 +3088,12 @@ func (d *auxYamlDoc) unmarshalDalSensitivityLevelNode(dctx documentContext, n *y if err != nil { return err } + + // Omit if not defined + tmp := cast.ToString(auxNodeValue) + if tmp == "0" || tmp == "" { + break + } refs["UpdatedBy"] = envoyx.Ref{ ResourceType: "corteza::system:user", Identifiers: envoyx.MakeIdentifiers(auxNodeValue), @@ -2968,6 +3159,11 @@ func (d *auxYamlDoc) unmarshalDalSensitivityLevelNode(dctx documentContext, n *y } for f, ref := range refs { + // Only inherit root references + // @todo improve; this is a hack + if strings.Contains(f, ".") { + continue + } a.References[f] = ref } } @@ -3117,7 +3313,7 @@ func unmarshalLocaleNode(n *yaml.Node) (out envoyx.NodeSet, err error) { // Envoy config unmarshal logic // // // // // // // // // // // // // // // // // // // // // // // // // -func (d *auxYamlDoc) decodeEnvoyConfig(n *yaml.Node) (out envoyx.NodeConfig) { +func (d *auxYamlDoc) decodeEnvoyConfig(n *yaml.Node) (out envoyx.EnvoyConfig) { y7s.EachMap(n, func(k, v *yaml.Node) (err error) { switch strings.ToLower(k.Value) { case "skipif", "skip": diff --git a/server/system/envoy/yaml_decode.go b/server/system/envoy/yaml_decode.go index 80a5f3ffb..0118dd891 100644 --- a/server/system/envoy/yaml_decode.go +++ b/server/system/envoy/yaml_decode.go @@ -70,6 +70,8 @@ func (d *auxYamlDoc) unmarshalAuthClientSecurityNode(r *types.AuthClient, n *yam } func roleSliceToRefs(k string, n *yaml.Node) (refs map[string]envoyx.Ref) { + refs = make(map[string]envoyx.Ref, len(n.Content)) + i := 0 y7s.EachSeq(n, func(n *yaml.Node) error { refs[fmt.Sprintf("%s.%d", k, i)] = envoyx.Ref{ diff --git a/server/system/envoy/yaml_encode.gen.go b/server/system/envoy/yaml_encode.gen.go index c36cfe112..a8913434d 100644 --- a/server/system/envoy/yaml_encode.gen.go +++ b/server/system/envoy/yaml_encode.gen.go @@ -71,16 +71,7 @@ func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt strin if err != nil { return } - case types.ApigwFilterResourceType: - aux, err = e.encodeApigwFilters(ctx, p, nodes, tt) - if err != nil { - return - } - // Root level resources are always encoded as a map - out, err = y7s.AddMap(out, "apigwFilter", aux) - if err != nil { - return - } + case types.AuthClientResourceType: aux, err = e.encodeAuthClients(ctx, p, nodes, tt) if err != nil { @@ -165,6 +156,10 @@ func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt strin if err != nil { return } + default: + // When this encoder doesn't handle any node it shouldn't write anything; + // this just removes the need for an extra check at the end. + return } return yaml.NewEncoder(w).Encode(out) @@ -869,7 +864,6 @@ func (e YamlEncoder) encodeUser(ctx context.Context, p envoyx.EncodeParams, node "kind", res.Kind, "meta", res.Meta, "name", res.Name, - "roles", res.Roles, "suspendedAt", auxSuspendedAt, "updatedAt", auxUpdatedAt, "username", res.Username, @@ -1046,7 +1040,7 @@ func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, e return nil, nil } - tz := p.Config.PreferredTimezone + tz := p.Encoder.PreferredTimezone if tz != "" { tzL, err := time.LoadLocation(tz) if err != nil { @@ -1055,7 +1049,7 @@ func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, e t = t.In(tzL) } - ly := p.Config.PreferredTimeLayout + ly := p.Encoder.PreferredTimeLayout if ly == "" { ly = time.RFC3339 } @@ -1081,7 +1075,7 @@ func (e YamlEncoder) encodeRef(p envoyx.EncodeParams, id uint64, field string, n return id, nil } - return node.Identifiers.FriendlyIdentifier(), nil + return parent.Identifiers.FriendlyIdentifier(), nil } // // // // // // // // // // // // // // // // // // // // // // // // // diff --git a/server/system/queue.cue b/server/system/queue.cue index 6dfad3d7f..6a54329fc 100644 --- a/server/system/queue.cue +++ b/server/system/queue.cue @@ -59,7 +59,6 @@ queue: { } envoy: { - scoped: true yaml: { supportMappedInput: true mappedField: "Queue" diff --git a/server/system/types/getters_setters.gen.go b/server/system/types/getters_setters.gen.go index 83c6446b9..f158c1240 100644 --- a/server/system/types/getters_setters.gen.go +++ b/server/system/types/getters_setters.gen.go @@ -190,7 +190,7 @@ func (r *ApigwFilter) GetValue(name string, pos uint) (any, error) { return r.Kind, nil case "ref", "Ref": return r.Ref, nil - case "route", "Route": + case "route", "Route", "ApigwRouteID": return r.Route, nil case "updatedAt", "UpdatedAt": return r.UpdatedAt, nil @@ -221,7 +221,7 @@ func (r *ApigwFilter) SetValue(name string, pos uint, value any) (err error) { return cast2.String(value, &r.Kind) case "ref", "Ref": return cast2.String(value, &r.Ref) - case "route", "Route": + case "route", "Route", "ApigwRouteID": return cast2.Uint64(value, &r.Route) case "updatedAt", "UpdatedAt": return cast2.TimePtr(value, &r.UpdatedAt) diff --git a/server/system/user.cue b/server/system/user.cue index 16f96e78e..295fc0c6b 100644 --- a/server/system/user.cue +++ b/server/system/user.cue @@ -32,6 +32,7 @@ user: { envoy: { yaml: { customDecoder: true + omitEncoder: true } } } diff --git a/server/tests/envoy/import_export_test.go b/server/tests/envoy/import_export_test.go new file mode 100644 index 000000000..ad598bdb5 --- /dev/null +++ b/server/tests/envoy/import_export_test.go @@ -0,0 +1,367 @@ +package envoy + +import ( + "context" + "fmt" + "os" + "testing" + + automationTypes "github.com/cortezaproject/corteza/server/automation/types" + "github.com/cortezaproject/corteza/server/compose/types" + "github.com/cortezaproject/corteza/server/pkg/envoyx" + "github.com/cortezaproject/corteza/server/pkg/filter" + "github.com/cortezaproject/corteza/server/store" + systemTypes "github.com/cortezaproject/corteza/server/system/types" + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/require" +) + +func TestImportExport(t *testing.T) { + var ( + ctx = context.Background() + req = require.New(t) + nodes envoyx.NodeSet + gg *envoyx.DepGraph + err error + ) + + cleanup(t) + + // The test + // + // * imports some YAML files + // * checks the DB state + // * exports the DB into a YAML + // * clears the DB + // * imports the YAML + // * checks the DB state the same way as before + // + // The above outlined flow allows us to trivially check if the data is both + // imported and exported correctly. + // + // The initial step could also manually populate the DB but the YAML import + // is more convenient. + + t.Run("initial import", func(t *testing.T) { + t.Run("parse configs", func(t *testing.T) { + nodes, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{ + Type: envoyx.DecodeTypeURI, + Params: map[string]any{ + "uri": "file://testdata/full", + }, + }) + req.NoError(err) + }) + + t.Run("bake", func(t *testing.T) { + gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{ + Type: envoyx.EncodeTypeStore, + Params: map[string]any{ + "storer": defaultStore, + "dal": defaultDal, + }, + }, nodes...) + req.NoError(err) + }) + + t.Run("import into DB", func(t *testing.T) { + err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{ + Type: envoyx.EncodeTypeStore, + Params: map[string]any{ + "storer": defaultStore, + "dal": defaultDal, + }, + }, gg) + req.NoError(err) + }) + + assertState(ctx, t, defaultStore, req) + }) + + // Prepare a temp file where we'll dump the YAML into + auxFile, err := os.CreateTemp(os.TempDir(), "*.yaml") + req.NoError(err) + spew.Dump(auxFile.Name()) + // defer os.Remove(auxFile.Name()) + defer auxFile.Close() + + t.Run("export", func(t *testing.T) { + t.Run("export from DB", func(t *testing.T) { + nodes, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{ + Type: envoyx.DecodeTypeStore, + Params: map[string]any{ + "storer": defaultStore, + }, + Filter: map[string]envoyx.ResourceFilter{ + types.ChartResourceType: {}, + types.ModuleResourceType: {}, + types.NamespaceResourceType: {}, + types.PageResourceType: {}, + + systemTypes.ApplicationResourceType: {}, + systemTypes.ApigwRouteResourceType: {}, + systemTypes.AuthClientResourceType: {}, + systemTypes.QueueResourceType: {}, + systemTypes.ReportResourceType: {}, + systemTypes.RoleResourceType: {}, + systemTypes.TemplateResourceType: {}, + systemTypes.UserResourceType: {}, + systemTypes.DalConnectionResourceType: {}, + systemTypes.DalSensitivityLevelResourceType: {}, + + automationTypes.WorkflowResourceType: {}, + }, + }) + req.NoError(err) + }) + + t.Run("bake", func(t *testing.T) { + gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{ + Type: envoyx.EncodeTypeStore, + Params: map[string]any{ + "storer": defaultStore, + "dal": defaultDal, + }, + }, nodes...) + req.NoError(err) + }) + + t.Run("write file", func(t *testing.T) { + err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{ + Type: envoyx.EncodeTypeIo, + Params: map[string]any{ + "writer": auxFile, + }, + }, gg) + req.NoError(err) + }) + }) + + cleanup(t) + + t.Run("second import", func(t *testing.T) { + t.Run("yaml parse", func(t *testing.T) { + nodes, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{ + Type: envoyx.DecodeTypeURI, + Params: map[string]any{ + "uri": fmt.Sprintf("file://%s", auxFile.Name()), + }, + }) + req.NoError(err) + }) + + t.Run("bake", func(t *testing.T) { + gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{ + Type: envoyx.EncodeTypeStore, + Params: map[string]any{ + "storer": defaultStore, + "dal": defaultDal, + }, + }, nodes...) + req.NoError(err) + }) + + t.Run("run import", func(t *testing.T) { + err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{ + Type: envoyx.EncodeTypeStore, + Params: map[string]any{ + "storer": defaultStore, + "dal": defaultDal, + }, + }, gg) + req.NoError(err) + }) + + assertState(ctx, t, defaultStore, req) + }) +} + +func assertState(ctx context.Context, t *testing.T, s store.Storer, req *require.Assertions) { + t.Run("check state", func(t *testing.T) { + t.Run("corteza::compose", func(t *testing.T) { + // Namespaces + ns, err := store.LookupComposeNamespaceBySlug(ctx, s, "test_ns_1") + req.NoError(err) + req.NotNil(ns) + + // Modules + modules, _, err := store.SearchComposeModules(ctx, s, types.ModuleFilter{ + NamespaceID: ns.ID, + Sorting: filter.Sorting{ + Sort: filter.SortExprSet{{Column: "handle", Descending: false}}, + }, + }) + req.NoError(err) + + mod1 := modules.FindByHandle("test_ns_1_mod_1") + req.NotNil(mod1) + + mod2 := modules.FindByHandle("test_ns_1_mod_2") + req.NotNil(mod2) + + // Fields + fields, _, err := store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ + ModuleID: []uint64{mod1.ID, mod2.ID}, + }) + req.NoError(err) + + assignModuleFields(modules, fields) + + req.Len(mod1.Fields, 2) + req.Len(mod2.Fields, 2) + + req.Equal(mod1.ID, mod2.Fields.FindByName("test_ns_1_mod_2_f1").Options.UInt64("moduleID")) + req.Equal(mod2.ID, mod2.Fields.FindByName("test_ns_1_mod_2_f2").Options.UInt64("moduleID")) + + // Charts + charts, _, err := store.SearchComposeCharts(ctx, s, types.ChartFilter{ + NamespaceID: ns.ID, + }) + req.NoError(err) + ch1 := charts.FindByHandle("test_ns_1_chart_1") + req.NotNil(ch1) + + req.Equal(mod1.ID, ch1.Config.Reports[0].ModuleID) + req.Equal(mod2.ID, ch1.Config.Reports[1].ModuleID) + + // Pages + pages, _, err := store.SearchComposePages(ctx, s, types.PageFilter{ + NamespaceID: ns.ID, + }) + req.NoError(err) + + pg1 := pages.FindByHandle("test_ns_1_page_1") + req.NotNil(pg1) + + req.Len(pg1.Blocks, 7) + // @todo test page block references + // spew.Dump(pg1.Blocks) + + rpg1 := pages.FindByHandle("test_ns_1_record_page_1") + req.NotNil(rpg1) + req.Equal(mod1.ID, rpg1.ModuleID) + }) + t.Run("corteza::system", func(t *testing.T) { + // Users + users, _, err := store.SearchUsers(ctx, s, systemTypes.UserFilter{}) + req.NoError(err) + req.Len(users, 1) + + u1 := users[0] + req.Equal("test_user_1", u1.Handle) + + // ApigwRoutes + apigwroutes, _, err := store.SearchApigwRoutes(ctx, s, systemTypes.ApigwRouteFilter{}) + req.NoError(err) + req.Len(apigwroutes, 1) + + r1 := apigwroutes[0] + req.Equal("/test/endpoint/1", r1.Endpoint) + req.Equal(u1.ID, r1.CreatedBy) + req.Equal(u1.ID, r1.UpdatedBy) + + // ApigwFilters + apigwfilter, _, err := store.SearchApigwFilters(ctx, s, systemTypes.ApigwFilterFilter{}) + req.NoError(err) + req.Len(apigwfilter, 1) + + f1 := apigwfilter[0] + req.Equal(r1.ID, f1.Route) + + // AuthClients + clients, _, err := store.SearchAuthClients(ctx, s, systemTypes.AuthClientFilter{}) + req.NoError(err) + req.Len(clients, 1) + + c1 := clients[0] + req.Equal("test_authclient_1", c1.Handle) + req.Equal(u1.ID, c1.OwnedBy) + req.Equal(u1.ID, c1.CreatedBy) + req.Equal(u1.ID, c1.UpdatedBy) + + // Queues + queues, _, err := store.SearchQueues(ctx, s, systemTypes.QueueFilter{}) + req.NoError(err) + req.Len(queues, 1) + + q1 := queues[0] + req.Equal("test_queue_1", q1.Queue) + req.Equal(u1.ID, q1.CreatedBy) + req.Equal(u1.ID, q1.UpdatedBy) + + // Reports + reports, _, err := store.SearchReports(ctx, s, systemTypes.ReportFilter{}) + req.NoError(err) + req.Len(reports, 1) + + rp1 := reports[0] + req.Equal("test_report_1", rp1.Handle) + req.Equal(u1.ID, rp1.OwnedBy) + req.Equal(u1.ID, rp1.CreatedBy) + req.Equal(u1.ID, rp1.UpdatedBy) + + // Roles + roles, _, err := store.SearchRoles(ctx, s, systemTypes.RoleFilter{}) + req.NoError(err) + + rl1 := roles[0] + req.Equal("test_role_1", rl1.Handle) + + // Templates + templates, _, err := store.SearchTemplates(ctx, s, systemTypes.TemplateFilter{}) + req.NoError(err) + req.Len(templates, 1) + + tpl1 := templates[0] + req.Equal("test_template_1", tpl1.Handle) + req.Equal(u1.ID, tpl1.OwnerID) + + // DalConnections + connections, _, err := store.SearchDalConnections(ctx, s, systemTypes.DalConnectionFilter{}) + req.NoError(err) + req.Len(connections, 1) + conn1 := connections[0] + req.Equal("test_connection_1", conn1.Handle) + + req.Equal(u1.ID, conn1.CreatedBy) + req.Equal(u1.ID, conn1.UpdatedBy) + + // DalSensitivityLevels + dalsensitivitylevels, _, err := store.SearchDalSensitivityLevels(ctx, s, systemTypes.DalSensitivityLevelFilter{}) + req.NoError(err) + req.Len(dalsensitivitylevels, 1) + sens1 := dalsensitivitylevels[0] + + req.Equal("test_sensitivity_level_1", sens1.Handle) + req.Equal(u1.ID, sens1.CreatedBy) + req.Equal(u1.ID, sens1.UpdatedBy) + }) + t.Run("corteza::automation", func(t *testing.T) { + // Workflows + workflows, _, err := store.SearchAutomationWorkflows(ctx, s, automationTypes.WorkflowFilter{}) + req.NoError(err) + req.Len(workflows, 1) + + wf1 := workflows[0] + req.Equal("test_workflow_1", wf1.Handle) + + // Triggers + triggers, _, err := store.SearchAutomationTriggers(ctx, s, automationTypes.TriggerFilter{}) + req.NoError(err) + req.Len(triggers, 1) + + t1 := triggers[0] + req.Equal(wf1.ID, t1.WorkflowID) + }) + }) +} + +func assignModuleFields(modules types.ModuleSet, fields types.ModuleFieldSet) { + for _, m := range modules { + for _, f := range fields { + if m.ID == f.ModuleID { + m.Fields = append(m.Fields, f) + } + } + } +} diff --git a/server/tests/envoy/main_test.go b/server/tests/envoy/main_test.go new file mode 100644 index 000000000..52a46f2a6 --- /dev/null +++ b/server/tests/envoy/main_test.go @@ -0,0 +1,169 @@ +package envoy + +import ( + "context" + "os" + "testing" + "time" + + automationEnvoy "github.com/cortezaproject/corteza/server/automation/envoy" + composeEnvoy "github.com/cortezaproject/corteza/server/compose/envoy" + systemEnvoy "github.com/cortezaproject/corteza/server/system/envoy" + + "github.com/cortezaproject/corteza/server/pkg/cli" + "github.com/cortezaproject/corteza/server/pkg/dal" + "github.com/cortezaproject/corteza/server/pkg/envoyx" + "github.com/cortezaproject/corteza/server/pkg/id" + "github.com/cortezaproject/corteza/server/store" + "github.com/cortezaproject/corteza/server/system/service" + sysTypes "github.com/cortezaproject/corteza/server/system/types" + "github.com/cortezaproject/corteza/server/tests/helpers" + _ "github.com/joho/godotenv/autoload" + "go.uber.org/zap" +) + +var ( + defaultEnvoy *envoyx.Service + defaultStore store.Storer + defaultDal dal.FullService +) + +func init() { + helpers.RecursiveDotEnvLoad() +} + +func TestMain(m *testing.M) { + InitTestApp() + os.Exit(m.Run()) +} + +func InitTestApp() { + ctx := cli.Context() + + if defaultStore == nil { + initStore(ctx) + } + + if defaultDal == nil { + initDalSvc(ctx) + } + + if defaultEnvoy == nil { + initSvc(ctx) + } +} + +func initStore(ctx context.Context) { + var err error + dsn := "sqlite3+debug://file::memory:?cache=shared&mode=memory" + defaultStore, err = store.Connect(ctx, zap.NewNop(), dsn, true) + if err != nil { + panic(err) + } + + err = store.Upgrade(ctx, zap.NewNop(), defaultStore) + if err != nil { + panic(err) + } +} + +func initDalSvc(ctx context.Context) { + var err error + defaultDal, err = dal.New(zap.NewNop(), true) + if err != nil { + panic(err) + } + + conn := &sysTypes.DalConnection{ + ID: id.Next(), + Handle: sysTypes.DalPrimaryConnectionHandle, + Type: sysTypes.DalPrimaryConnectionResourceType, + + Meta: sysTypes.ConnectionMeta{ + Name: "Primary Database", + }, + + Config: sysTypes.ConnectionConfig{ + DAL: &sysTypes.ConnectionConfigDAL{ + ModelIdent: "compose_record", + }, + }, + + CreatedAt: time.Now(), + } + + cw, err := service.MakeDalConnection(conn, defaultStore.ToDalConn()) + if err != nil { + panic(err) + } + err = defaultDal.ReplaceConnection(ctx, cw, true) + if err != nil { + panic(err) + } +} + +func cleanup(t *testing.T) { + var ( + ctx = context.Background() + ) + + err := collect( + store.TruncateComposeCharts(ctx, defaultStore), + store.TruncateComposeModules(ctx, defaultStore), + store.TruncateComposeModuleFields(ctx, defaultStore), + store.TruncateComposeNamespaces(ctx, defaultStore), + store.TruncateComposePages(ctx, defaultStore), + + store.TruncateApplications(ctx, defaultStore), + store.TruncateApigwRoutes(ctx, defaultStore), + store.TruncateApigwFilters(ctx, defaultStore), + store.TruncateAuthClients(ctx, defaultStore), + store.TruncateQueues(ctx, defaultStore), + store.TruncateReports(ctx, defaultStore), + store.TruncateRoles(ctx, defaultStore), + store.TruncateTemplates(ctx, defaultStore), + store.TruncateUsers(ctx, defaultStore), + store.TruncateDalConnections(ctx, defaultStore), + store.TruncateDalSensitivityLevels(ctx, defaultStore), + + store.TruncateAutomationWorkflows(ctx, defaultStore), + store.TruncateAutomationTriggers(ctx, defaultStore), + ) + if err != nil { + t.Fatalf("failed to decode scenario data: %v", err) + } +} + +func collect(ee ...error) error { + for _, e := range ee { + if e != nil { + return e + } + } + return nil +} + +func initSvc(ctx context.Context) { + defaultEnvoy = envoyx.New() + defaultEnvoy.AddDecoder(envoyx.DecodeTypeURI, + composeEnvoy.YamlDecoder{}, + systemEnvoy.YamlDecoder{}, + automationEnvoy.YamlDecoder{}, + ) + defaultEnvoy.AddDecoder(envoyx.DecodeTypeStore, + composeEnvoy.StoreDecoder{}, + systemEnvoy.StoreDecoder{}, + automationEnvoy.StoreDecoder{}, + ) + + defaultEnvoy.AddEncoder(envoyx.EncodeTypeIo, + composeEnvoy.YamlEncoder{}, + systemEnvoy.YamlEncoder{}, + automationEnvoy.YamlEncoder{}, + ) + defaultEnvoy.AddEncoder(envoyx.EncodeTypeStore, + composeEnvoy.StoreEncoder{}, + systemEnvoy.StoreEncoder{}, + automationEnvoy.StoreEncoder{}, + ) +} diff --git a/server/tests/envoy/testdata/full/full.yaml b/server/tests/envoy/testdata/full/full.yaml new file mode 100644 index 000000000..bef1438e1 --- /dev/null +++ b/server/tests/envoy/testdata/full/full.yaml @@ -0,0 +1,178 @@ +namespace: + test_ns_1: + name: Test Namespace 1 + enabled: true + + modules: + test_ns_1_mod_1: + name: Test Namespace 1 Module 1 + fields: + test_ns_1_mod_1_f1: + title: Test Namespace 1 Module 1 Field 1 + test_ns_1_mod_1_f2: + title: Test Namespace 1 Module 1 Field 2 + kind: Number + + test_ns_1_mod_2: + name: Test Namespace 1 Module 2 + fields: + test_ns_1_mod_2_f1: + title: Test Namespace 1 Module 2 Field 1 + kind: Record + options: + module: test_ns_1_mod_1 + test_ns_1_mod_2_f2: + title: Test Namespace 1 Module 2 Field 2 + kind: Record + options: + module: test_ns_1_mod_2 + + charts: + test_ns_1_chart_1: + name: Test Namespace 1 Chart 1 + config: + reports: + - filter: true + module: test_ns_1_mod_1 + - filter: true + module: test_ns_1_mod_2 + + pages: + test_ns_1_page_1: + title: Test Namespace 1 Page 1 + visible: true + blocks: + - title: Test Namespace 1 Page 1 Block 1 + kind: RecordList + options: + module: test_ns_1_mod_1 + - title: Test Namespace 1 Page 1 Block 2 + kind: Automation + # @todo + # options: + + - title: Test Namespace 1 Page 1 Block 3 + kind: RecordOrganizer + options: + module: test_ns_1_mod_1 + + - title: Test Namespace 1 Page 1 Block 4 + kind: Chart + options: + chart: test_ns_1_chart_1 + + - title: Test Namespace 1 Page 1 Block 5 + kind: Calendar + options: + feeds: + - options: + module: test_ns_1_mod_1 + + - title: Test Namespace 1 Page 1 Block 6 + kind: Metric + options: + metrics: + - module: test_ns_1_mod_1 + + - title: Test Namespace 1 Page 1 Block 7 + kind: Comment + options: + module: test_ns_1_mod_1 + pages: + test_ns_1_record_page_1: + title: Test Namespace 1 Record Page 1 + module: test_ns_1_mod_1 + +application: + test_app_1: + enabled: true + owner: test_user_1 + +endpoints: + /test/endpoint/1: + method: GET + enabled: true + createdBy: test_user_1 + updatedBy: test_user_1 + filters: + - ref: r1 + kind: prefilter + enabled: true + createdBy: test_user_1 + updatedBy: test_user_1 + +authclient: + test_authclient_1: + secret: 123123 + security: + impersonateUser: test_user_1 + permittedRoles: + - test_role_1 + prohibitedRoles: + - test_role_2 + forcedRoles: + - test_role_3 + ownedBy: test_user_1 + createdBy: test_user_1 + updatedBy: test_user_1 + +queue: + test_queue_1: + consumer: workflow + createdBy: test_user_1 + updatedBy: test_user_1 + +report: + test_report_1: + meta: + name: Test Report 1 + Description: Test Report 1 Description + ownedBy: test_user_1 + createdBy: test_user_1 + updatedBy: test_user_1 + +role: + test_role_1: + name: Test Role 1 + test_role_2: + name: Test Role 2 + test_role_3: + name: Test Role 3 + +template: + test_template_1: + meta: + short: Test Template 1 + description: Test Template 1 Description + ownerID: test_user_1 + +user: + test_user_1: + name: Test User 1 + email: test_user_1@example.com + emailConfirmed: true + +connection: + test_connection_1: + meta: + name: Test Connection 1 + createdBy: test_user_1 + updatedBy: test_user_1 + +sensitivity_level: + test_sensitivity_level_1: + meta: + name: Test Sensitivity Level 1 + description: Test sensitivity Level 1 Description + createdBy: test_user_1 + updatedBy: test_user_1 + +workflow: + test_workflow_1: + enabled: true + meta: + name: Test Workflow 1 + triggers: + - enabled: true + stepID: 12 + resourceType: corteza::compose:namespace