Files
upstream-corteza/server/compose/envoy/yaml_decode.go
upstream-mirror 7e385fc126
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
2026-09-18 01:22:23 +05:00

493 lines
12 KiB
Go

package envoy
import (
"fmt"
"strings"
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/y7s"
"github.com/modern-go/reflect2"
"gopkg.in/yaml.v3"
)
const (
ComposeRecordDatasourceAuxType = "corteza::compose:record-datasource"
)
func (d *auxYamlDoc) unmarshalYAML(k string, n *yaml.Node) (out envoyx.NodeSet, err error) { return }
func (d *auxYamlDoc) unmarshalChartConfigNode(r *types.Chart, n *yaml.Node) (refs map[string]envoyx.Ref, idents envoyx.Identifiers, err error) {
err = y7s.EachMap(n, func(k, v *yaml.Node) error {
if k.Value != "reports" {
return nil
}
if y7s.IsSeq(v) {
var (
auxRefs = make(map[string]envoyx.Ref)
auxIdents envoyx.Identifiers
i = -1
)
err = y7s.EachSeq(v, func(c *yaml.Node) error {
i++
auxRefs, auxIdents, err = d.unmarshalChartConfigReportNode(r, c, i)
refs = envoyx.MergeRefs(refs, auxRefs)
idents = idents.Merge(auxIdents)
return err
})
if err != nil {
return err
}
} else {
refs, idents, err = d.unmarshalChartConfigReportNode(r, v, 0)
return err
}
return nil
})
return
}
func (d *auxYamlDoc) unmarshalChartConfigReportNode(r *types.Chart, n *yaml.Node, index int) (refs map[string]envoyx.Ref, idents envoyx.Identifiers, err error) {
err = y7s.EachMap(n, func(k, v *yaml.Node) error {
switch strings.ToLower(k.Value) {
case "module", "mod", "moduleid", "module_id":
var auxi any
y7s.DecodeScalar(v, "moduleID", &auxi)
refs = map[string]envoyx.Ref{
fmt.Sprintf("Config.Reports.%d.ModuleID", index): {
ResourceType: types.ModuleResourceType,
Identifiers: envoyx.MakeIdentifiers(auxi),
},
}
}
return nil
})
return
}
func (d *auxYamlDoc) unmarshalPageBlocksNode(r *types.Page, n *yaml.Node) (refs map[string]envoyx.Ref, idents envoyx.Identifiers, err error) {
refs = map[string]envoyx.Ref{}
for index, b := range r.Blocks {
switch b.Kind {
case "RecordList":
refs = envoyx.MergeRefs(refs, getPageBlockRecordListRefs(b, index))
case "Automation":
refs = envoyx.MergeRefs(refs, getPageBlockAutomationRefs(b, index))
case "RecordOrganizer":
refs = envoyx.MergeRefs(refs, getPageBlockRecordOrganizerRefs(b, index))
case "Chart":
refs = envoyx.MergeRefs(refs, getPageBlockChartRefs(b, index))
case "Calendar":
refs = envoyx.MergeRefs(refs, getPageBlockCalendarRefs(b, index))
case "Metric":
refs = envoyx.MergeRefs(refs, getPageBlockMetricRefs(b, index))
case "Comment":
refs = envoyx.MergeRefs(refs, getPageBlockCommentRefs(b, index))
case "Progress":
refs = envoyx.MergeRefs(refs, getPageBlockProgressRefs(b, index))
}
}
return
}
func getPageBlockRecordListRefs(b types.PageBlock, index int) (refs map[string]envoyx.Ref) {
refs = make(map[string]envoyx.Ref)
id := optString(b.Options, "module", "moduleID")
if id == "" || id == "0" {
return
}
refs[fmt.Sprintf("Blocks.%d.Options.ModuleID", index)] = envoyx.Ref{
ResourceType: types.ModuleResourceType,
Identifiers: envoyx.MakeIdentifiers(id),
}
return
}
func getPageBlockChartRefs(b types.PageBlock, index int) (refs map[string]envoyx.Ref) {
refs = make(map[string]envoyx.Ref)
id := optString(b.Options, "chart", "chartID")
if id == "" || id == "0" {
return
}
refs[fmt.Sprintf("Blocks.%d.Options.ChartID", index)] = envoyx.Ref{
ResourceType: types.ChartResourceType,
Identifiers: envoyx.MakeIdentifiers(id),
}
return
}
func getPageBlockCalendarRefs(b types.PageBlock, index int) (refs map[string]envoyx.Ref) {
refs = make(map[string]envoyx.Ref)
ff, _ := b.Options["feeds"].([]interface{})
for j, f := range ff {
feed, _ := f.(map[string]interface{})
opt, _ := (feed["options"]).(map[string]interface{})
id := optString(opt, "module", "moduleID")
if id == "" || id == "0" {
return
}
refs[fmt.Sprintf("Blocks.%d.Options.feeds.%d.ModuleID", index, j)] = envoyx.Ref{
ResourceType: types.ModuleResourceType,
Identifiers: envoyx.MakeIdentifiers(id),
}
}
return
}
func getPageBlockMetricRefs(b types.PageBlock, index int) (refs map[string]envoyx.Ref) {
refs = make(map[string]envoyx.Ref)
mm, _ := b.Options["metrics"].([]interface{})
for j, m := range mm {
mops, _ := m.(map[string]interface{})
id := optString(mops, "module", "moduleID")
if id == "" || id == "0" {
return
}
refs[fmt.Sprintf("Blocks.%d.Options.metrics.%d.ModuleID", index, j)] = envoyx.Ref{
ResourceType: types.ModuleResourceType,
Identifiers: envoyx.MakeIdentifiers(id),
}
}
return
}
func getPageBlockCommentRefs(b types.PageBlock, index int) (refs map[string]envoyx.Ref) {
// Same difference
return getPageBlockRecordListRefs(b, index)
}
func getPageBlockProgressRefs(b types.PageBlock, index int) (refs map[string]envoyx.Ref) {
refs = make(map[string]envoyx.Ref)
var aux *envoyx.Ref
aux = getPageBlockProgressValueRefs(b.Options["minValue"])
if aux != nil {
refs[fmt.Sprintf("Blocks.%d.Options.minValue.ModuleID", index)] = *aux
}
aux = getPageBlockProgressValueRefs(b.Options["maxValue"])
if aux != nil {
refs[fmt.Sprintf("Blocks.%d.Options.maxValue.ModuleID", index)] = *aux
}
aux = getPageBlockProgressValueRefs(b.Options["value"])
if aux != nil {
refs[fmt.Sprintf("Blocks.%d.Options.value.ModuleID", index)] = *aux
}
return
}
func getPageBlockProgressValueRefs(val any) (ref *envoyx.Ref) {
if reflect2.IsNil(val) {
return
}
opt, ok := val.(map[string]interface{})
if !ok {
return
}
id := optString(opt, "module", "moduleID")
if id == "" || id == "0" {
return
}
return &envoyx.Ref{
ResourceType: types.ModuleResourceType,
Identifiers: envoyx.MakeIdentifiers(id),
}
}
func getPageBlockRecordOrganizerRefs(b types.PageBlock, index int) (refs map[string]envoyx.Ref) {
// Same difference
return getPageBlockRecordListRefs(b, index)
}
func getPageBlockAutomationRefs(b types.PageBlock, index int) (refs map[string]envoyx.Ref) {
refs = make(map[string]envoyx.Ref)
bb, _ := b.Options["buttons"].([]interface{})
for buttonIx, b := range bb {
button, _ := b.(map[string]interface{})
id := optString(button, "workflow", "workflowID")
if id == "" || id == "0" {
return
}
refs[fmt.Sprintf("Blocks.%d.Options.buttons.%d.WorkflowID", index, buttonIx)] = envoyx.Ref{
ResourceType: automationTypes.WorkflowResourceType,
Identifiers: envoyx.MakeIdentifiers(id),
}
}
return
}
func optString(opt map[string]interface{}, kk ...string) string {
for _, k := range kk {
if vr, has := opt[k]; has {
v, _ := vr.(string)
return v
}
}
return ""
}
func (d *auxYamlDoc) unmarshalModuleFieldOptionsNode(r *types.ModuleField, n *yaml.Node) (refs map[string]envoyx.Ref, idents envoyx.Identifiers, err error) {
refs = make(map[string]envoyx.Ref)
err = y7s.EachMap(n, func(k, v *yaml.Node) error {
switch strings.ToLower(k.Value) {
case "module", "module_id", "moduleid":
var aux any
err = y7s.DecodeScalar(v, "moduleID", &aux)
if err != nil {
return err
}
refs["Options.ModuleID"] = envoyx.Ref{
ResourceType: types.ModuleResourceType,
Identifiers: envoyx.MakeIdentifiers(aux),
}
default:
return nil
}
return nil
})
return
}
func (d *auxYamlDoc) unmarshalModuleFieldDefaultValueNode(r *types.ModuleField, n *yaml.Node) (refs map[string]envoyx.Ref, idents envoyx.Identifiers, err error) {
var rvs = types.RecordValueSet{}
switch n.Kind {
case yaml.ScalarNode:
rvs = rvs.Set(&types.RecordValue{Value: n.Value})
case yaml.SequenceNode:
_ = y7s.EachSeq(n, func(v *yaml.Node) error {
rvs = rvs.Set(&types.RecordValue{Value: n.Value, Place: uint(len(rvs))})
return nil
})
}
r.DefaultValue = rvs
return
}
func (d *auxYamlDoc) unmarshalModuleFieldExpressionsNode(r *types.ModuleField, n *yaml.Node) (refs map[string]envoyx.Ref, idents envoyx.Identifiers, err error) {
err = y7s.EachMap(n, func(k *yaml.Node, v *yaml.Node) error {
switch k.Value {
case "sanitizer":
var aux string
err = y7s.DecodeScalar(v, "sanitizer", &aux)
if err != nil {
return err
}
r.Expressions.Sanitizers = append(r.Expressions.Sanitizers, aux)
case "sanitizers":
return y7s.EachSeq(v, func(san *yaml.Node) error {
r.Expressions.Sanitizers = append(r.Expressions.Sanitizers, san.Value)
return nil
})
case "validator":
var aux types.ModuleFieldValidator
err = v.Decode(&aux)
if err != nil {
return err
}
r.Expressions.Validators = append(r.Expressions.Validators, aux)
case "validators":
return y7s.Each(v, func(k *yaml.Node, v *yaml.Node) error {
var aux types.ModuleFieldValidator
if y7s.IsKind(v, yaml.MappingNode) {
err = v.Decode(&aux)
if err != nil {
return err
}
} else {
aux.Test = k.Value
aux.Error = v.Value
}
r.Expressions.Validators = append(r.Expressions.Validators, aux)
return nil
})
case "formatter":
r.Expressions.Formatters = append(r.Expressions.Formatters, v.Value)
return nil
case "formatters":
return y7s.EachSeq(v, func(san *yaml.Node) error {
r.Expressions.Formatters = append(r.Expressions.Formatters, san.Value)
return nil
})
}
return nil
})
return
}
func (d *auxYamlDoc) postProcessNestedModuleNodes(nn envoyx.NodeSet) (out envoyx.NodeSet, err error) {
// Get all references from all module fields
refs := make(map[string]envoyx.Ref)
for _, n := range nn {
if n.ResourceType != types.ModuleFieldResourceType {
continue
}
if len(n.References) == 0 {
continue
}
r, ok := n.References["Options.ModuleID"]
if !ok {
continue
}
refs[fmt.Sprintf("%s.module", n.Identifiers.FriendlyIdentifier())] = r
refs[fmt.Sprintf("%s.datasource", n.Identifiers.FriendlyIdentifier())] = envoyx.Ref{
ResourceType: ComposeRecordDatasourceAuxType,
Identifiers: r.Identifiers,
Scope: r.Scope,
Optional: true,
}
}
// Update datasources with references
for _, n := range nn {
if n.Datasource == nil {
continue
}
n.References = envoyx.MergeRefs(n.References, refs)
}
out = nn
return
}
func (d *auxYamlDoc) unmarshalPagesExtendedNode(dctx documentContext, n *yaml.Node, meta ...*yaml.Node) (out envoyx.NodeSet, err error) {
return d.unmarshalPageNode(dctx, n, meta...)
}
func (d *auxYamlDoc) unmarshalSourceExtendedNode(dctx documentContext, n *yaml.Node, meta ...*yaml.Node) (out envoyx.NodeSet, err error) {
var r envoyx.DatasourceMapping
// @todo we're omitting errors because there will be a bunch due to invalid
// resource field types. This might be a bit unstable as other errors may
// also get ignored.
//
// A potential fix would be to firstly unmarshal into an any, check errors
// and then unmarshal into the resource while omitting errors.
n.Decode(&r)
err = y7s.EachMap(n, func(k, n *yaml.Node) error {
var auxNodeValue any
_ = auxNodeValue
switch strings.ToLower(k.Value) {
case "origin", "from":
err = y7s.DecodeScalar(n, "origin", &r.SourceIdent)
if err != nil {
return err
}
case "key", "index", "pk":
if !y7s.IsKind(n, yaml.SequenceNode) {
r.KeyField = []string{n.Value}
} else {
r.KeyField = make([]string, 0, 3)
y7s.EachSeq(n, func(n *yaml.Node) error {
r.KeyField = append(r.KeyField, n.Value)
return nil
})
}
case "map":
return n.Decode(&r.Mapping)
}
return nil
})
// @todo for now we only support record datasources; extend when needed
auxN := &envoyx.Node{
Datasource: &RecordDatasource{
Mapping: r,
},
ResourceType: ComposeRecordDatasourceAuxType,
Identifiers: dctx.parentIdent,
}
auxN.References, auxN.Scope = d.procMappingRefs(r.References)
out = append(out, auxN)
return
}
func (d *auxYamlDoc) procMappingRefs(in map[string]string) (out map[string]envoyx.Ref, scope envoyx.Scope) {
out = make(map[string]envoyx.Ref)
nsII := envoyx.MakeIdentifiers(in["namespace"])
if len(nsII.Slice) > 0 {
scope = envoyx.Scope{
ResourceType: types.NamespaceResourceType,
Identifiers: nsII,
}
}
if len(nsII.Slice) > 0 {
out["NamespaceID"] = envoyx.Ref{
ResourceType: types.NamespaceResourceType,
Identifiers: nsII,
Scope: scope,
}
}
modII := envoyx.MakeIdentifiers(in["module"])
if len(modII.Slice) > 0 {
out["ModuleID"] = envoyx.Ref{
ResourceType: types.ModuleResourceType,
Identifiers: envoyx.MakeIdentifiers(in["module"]),
Scope: scope,
}
}
return
}