Skip to content

Commit

Permalink
Extend envoy to support resource translations
Browse files Browse the repository at this point in the history
  • Loading branch information
tjerman committed Sep 22, 2021
1 parent a33856b commit 895b40d
Show file tree
Hide file tree
Showing 38 changed files with 1,891 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package {{ .Package }}

{{ template "header-gentext.tpl" }}
{{ template "header-definitions.tpl" . }}

import (
systemTypes "github.com/cortezaproject/corteza-server/system/types"
{{- range .Imports }}
{{ . }}
{{- end }}
)

{{- range .Def }}
{{ $Component := .Component }}
{{ $Resource := .Resource }}
{{ $GoType := printf "types.%s" .Resource }}
func (r *{{export $Component}}{{$Resource}}) EncodeTranslations() ([]*ResourceTranslation, error) {
out := make([]*ResourceTranslation, 0, 10)
rr := r.Res.EncodeTranslations()
rr.SetLanguage(defaultLanguage)
res, ref, pp := r.ResourceTranslationParts()
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
{{ if .Locale.Extended }}
tmp, err := r.encodeTranslations()
return append(out, tmp...), err
{{ else }}
return out, nil
{{- end }}
}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package {{ .Package }}

{{ template "header-gentext.tpl" }}
{{ template "header-definitions.tpl" . }}

import (
"fmt"
"strings"
{{- range .Imports }}
{{ . }}
{{- end }}
)


// Parse generates resource setting logic for each resource
//
// Resources with "envoy: false" are skipped
//
// This function is auto-generated
func ParseResourceTranslation(res string) (string, *Ref, []*Ref, error) {
if res == "" {
return "", nil, nil, fmt.Errorf("empty resource")
}

sp := "/"

if strings.Index(res, "corteza::") == 0 {
res = res[9:]
}

res = strings.TrimSpace(res)
res = strings.TrimRight(res, sp)
rr := strings.Split(res, sp)

// only service defined (corteza::system, corteza::compose, ...)
if len(rr) == 1 {
return "", nil, nil, fmt.Errorf("only service defined: %s", res)
}

// full thing
resourceType, path := rr[0], rr[1:]
for p := 1; p < len(path); p++ {
if path[p] == "*" {
return "", nil, nil, fmt.Errorf("path wildcard not allowed for locale resources: '%s'", res)
}
}

// make the resource provide the slice of parent resources we should nest under
switch resourceType {
{{- range .Def }}
case {{ unexport .Component "types" }}.{{ export .Resource }}ResourceTranslationType:
if len(path) != {{ len .Locale.Resource.References }} {
return "", nil, nil, fmt.Errorf("expecting {{ len .Locale.Resource.References }} reference components in path, got %d", len(path))
}
{{- if gt (len .Locale.Resource.References) 0 }}
ref, pp, err := {{ export .Component .Resource }}ResourceTranslationReferences(
{{- range $i, $r := .Locale.Resource.References }}
// {{ unexport $r.Resource }}
path[{{ $i }}],
{{ end }}
)
return {{ unexport .Component "types" }}.{{ export .Resource }}ResourceTranslationType, ref, pp, err
{{ else }}

// Component resource, no path
return {{ unexport .Component "types" }}.{{ export .Resource }}ResourceTranslationType, nil, nil, nil
{{- end }}
{{- end}}
}

// return unhandled resource as-is
return resourceType, nil, nil, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package {{ .Package }}

{{ template "header-gentext.tpl" }}
{{ template "header-definitions.tpl" . }}

import (
{{- range .Imports }}
{{ . }}
{{- end }}
)

{{- range .Def }}
{{- if .Locale }}
{{- if gt (len .Locale.Resource.References) 0 }}
// {{ export .Component .Resource }}ResourceTranslationReferences generates Locale references
//
// Resources with "envoy: false" are skipped
//
// This function is auto-generated
func {{ export .Component .Resource }}ResourceTranslationReferences({{- range .Locale.Resource.References }}{{ unexport .Resource }} string, {{- end }}) (res *Ref, pp []*Ref, err error) {
{{- range .Locale.Resource.References }}
{{- if eq .Field "ID" }}
res = &Ref{ResourceType: types.{{ export .Resource }}ResourceType, Identifiers: MakeIdentifiers({{ unexport .Resource }})}
{{- else }}
pp = append(pp, &Ref{ResourceType: types.{{ export .Resource }}ResourceType, Identifiers: MakeIdentifiers({{ unexport .Resource }})})
{{- end }}
{{- end }}

return
}
{{- end }}
{{- end }}
{{- end }}
86 changes: 86 additions & 0 deletions pkg/codegen-v3/internal/gen/envoy.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ func Envoy(t *template.Template, dd []*def.Document) error {
return List{
"resource rbac parse": envoyResourceRbacUnmarshal,
"resource rbac references": envoyResourceRbacReferences,

"resource translation": envoyResourceTranslation,
"resource translation parse": envoyResourceTranslationUnmarshal,
"resource translation references": envoyResourceTranslationReferences,
}.Generate(t, dd)
}

Expand Down Expand Up @@ -80,3 +84,85 @@ func envoyResourceRbacReferences(t *template.Template, dd []*def.Document) (err

return
}

func envoyResourceTranslation(t *template.Template, dd []*def.Document) (err error) {
const (
templateName = "envoy/resource-resource_translation.go.tpl"
outputPathTpl = "pkg/envoy/resource/resource_translation.gen.go"
)

dd = filter(dd, func(d *def.Document) bool { return d.Envoy && d.Locale != nil })

// build list of component type imports
ctImports := make([]string, 0)

w := tpl.Wrap{
Package: "resource",
Def: dd,
Imports: append(collectImports(dd...), ctImports...),
}

err = tpl.GoTemplate(outputPathTpl, t.Lookup(templateName), w)
if err != nil {
return
}

return
}

func envoyResourceTranslationUnmarshal(t *template.Template, dd []*def.Document) (err error) {
const (
templateName = "envoy/resource-resource_translation_parse.go.tpl"
outputPathTpl = "pkg/envoy/resource/resource_translation_parse.gen.go"
)

dd = filter(dd, func(d *def.Document) bool { return d.Envoy && d.Locale != nil })

// build list of component type imports
ctImports := make([]string, 0)
for _, d := range dd {
imp := d.Component + "Types " + cImport(d.Component, "types")
if !slice.HasString(ctImports, imp) {
ctImports = append(ctImports, imp)
}
}

w := tpl.Wrap{
Package: "resource",
Def: dd,
Imports: append(collectImports(dd...), ctImports...),
}

err = tpl.GoTemplate(outputPathTpl, t.Lookup(templateName), w)
if err != nil {
return
}

return
}

func envoyResourceTranslationReferences(t *template.Template, dd []*def.Document) (err error) {
const (
templateName = "envoy/resource-resource_translation_references.go.tpl"
outputPathTpl = "pkg/envoy/resource/resource_translation_references_%s.gen.go"
)

dd = filter(dd, func(d *def.Document) bool { return d.Envoy && d.Locale != nil })

for component, perComponent := range partByComponent(dd) {

w := tpl.Wrap{
Package: "resource",
Component: component,
Def: perComponent,
Imports: append(collectImports(perComponent...), cImport(component, "types")),
}

err = tpl.GoTemplate(fmt.Sprintf(outputPathTpl, component), t.Lookup(templateName), w)
if err != nil {
return
}
}

return
}
65 changes: 65 additions & 0 deletions pkg/envoy/locale.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package envoy

import "github.com/cortezaproject/corteza-server/pkg/envoy/resource"

// NormalizeResourceTranslations takes the provided resource.ResourceTranslation
// and merges duplicates based on the Priority parameter
func NormalizeResourceTranslations(rr ...resource.Interface) []resource.Interface {
out := make([]resource.Interface, 0, len(rr))
locales := make([]*resource.ResourceTranslation, 0, len(rr))

// - collect all locale resources
for _, r := range rr {
if l, ok := r.(*resource.ResourceTranslation); ok {
locales = append(locales, l)
} else {
out = append(out, r)
}
}

// make an index
var byResource map[string][2]*resource.ResourceTranslation
byResource = make(map[string][2]*resource.ResourceTranslation)

for _, locale := range locales {
pp := byResource[locale.RefResource]
pp[locale.Priority] = locale
byResource[locale.RefResource] = pp
}

// squash index by priority ascending
for _, pp := range byResource {
var aux *resource.ResourceTranslation
seen := make(map[string]bool)

for _, p := range pp {
if p == nil {
continue
}

if aux == nil {
aux = p
} else {
for _, r := range p.Res {
if seen[r.Lang.String()+r.K] {
continue
}

aux.Res = append(aux.Res, r)
}
}

for _, r := range p.Res {
if r.K != "" {
seen[r.Lang.String()+r.K] = true
}
}
}

if aux != nil {
out = append(out, aux)
}
}

return out
}
3 changes: 3 additions & 0 deletions pkg/envoy/marshaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ func CollectNodes(ii ...interface{}) (nn []resource.Interface, err error) {
case resource.Interface:
nn = append(nn, c)

case []resource.Interface:
nn = append(nn, c...)

case Marshaller:
if tmp, err := c.MarshalEnvoy(); err != nil {
return nil, err
Expand Down
5 changes: 0 additions & 5 deletions pkg/envoy/resource/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package resource

import (
"fmt"
"strconv"

"github.com/cortezaproject/corteza-server/system/types"
)
Expand Down Expand Up @@ -38,10 +37,6 @@ func (r *Application) SysID() uint64 {
return r.Res.ID
}

func (r *Application) Ref() string {
return firstOkString(r.Res.Name, strconv.FormatUint(r.Res.ID, 10))
}

// FindApplication looks for the app in the resource set
func FindApplication(rr InterfaceSet, ii Identifiers) (ap *types.Application) {
var apRes *Application
Expand Down
12 changes: 8 additions & 4 deletions pkg/envoy/resource/automation_workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ func (r *AutomationWorkflow) AddAutomationTrigger(res *types.Trigger) *Automatio
return t
}

func (r *AutomationWorkflow) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
ref = r.Ref()
path = nil
resource = fmt.Sprintf(types.WorkflowResourceTranslationTpl(), types.WorkflowResourceTranslationType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))

return
}

func (r *AutomationWorkflow) AddAutomationWorkflowStep(res *types.WorkflowStep) *AutomationWorkflowStep {
s := &AutomationWorkflowStep{
base: &base{},
Expand Down Expand Up @@ -107,10 +115,6 @@ func (r *AutomationWorkflow) SysID() uint64 {
return r.Res.ID
}

func (r *AutomationWorkflow) Ref() string {
return firstOkString(r.Res.Handle, r.Res.Meta.Name, strconv.FormatUint(r.Res.ID, 10))
}

// FindAutomationWorkflow looks for the workflow in the resource set
func FindAutomationWorkflow(rr InterfaceSet, ii Identifiers) (ns *types.Workflow) {
var wfRes *AutomationWorkflow
Expand Down
12 changes: 8 additions & 4 deletions pkg/envoy/resource/compose_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,18 @@ func (r *ComposeChart) SysID() uint64 {
return r.Res.ID
}

func (r *ComposeChart) Ref() string {
return firstOkString(r.Res.Handle, r.Res.Name, strconv.FormatUint(r.Res.ID, 10))
}

func (r *ComposeChart) RBACPath() []*Ref {
return []*Ref{r.RefNs}
}

func (r *ComposeChart) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
ref = r.Ref()
path = []*Ref{r.RefNs}
resource = fmt.Sprintf(types.ChartResourceTranslationTpl(), types.ChartResourceTranslationType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))

return
}

// FindComposeChart looks for the chart in the resources
func FindComposeChart(rr InterfaceSet, ii Identifiers) (ch *types.Chart) {
var chRes *ComposeChart
Expand Down
Loading

0 comments on commit 895b40d

Please sign in to comment.