Skip to content

Commit

Permalink
refactor: move bound to spec
Browse files Browse the repository at this point in the history
  • Loading branch information
siyul-park committed Dec 18, 2024
1 parent 3e98d3f commit dee5558
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 173 deletions.
16 changes: 11 additions & 5 deletions pkg/chart/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,20 @@ func (l *Linker) Link(chrt *Chart) error {

symbols := make([]*symbol.Symbol, 0, len(specs))
for _, sp := range specs {
if bind, err := l.scheme.Bind(sp); err != nil {
unstructured := &spec.Unstructured{}
if err := spec.Convert(sp, unstructured); err != nil {
for _, sb := range symbols {
sb.Close()
_ = sb.Close()
}
return nil, err
} else if decode, err := l.scheme.Decode(bind); err != nil {
} else if err := unstructured.Build(); err != nil {
for _, sb := range symbols {
sb.Close()
_ = sb.Close()
}
return nil, err
} else if decode, err := l.scheme.Decode(unstructured); err != nil {
for _, sb := range symbols {
_ = sb.Close()
}
return nil, err
} else {
Expand All @@ -75,7 +81,7 @@ func (l *Linker) Link(chrt *Chart) error {
n, err := l.scheme.Compile(sp)
if err != nil {
for _, sb := range symbols {
sb.Close()
_ = sb.Close()
}
return nil, err
}
Expand Down
22 changes: 13 additions & 9 deletions pkg/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func New(config Config) *Runtime {
})

for _, kind := range config.Scheme.Kinds() {
chartTable.Insert(&chart.Chart{
_ = chartTable.Insert(&chart.Chart{
ID: uuid.Must(uuid.NewV7()),
Namespace: config.Namespace,
Name: kind,
Expand Down Expand Up @@ -195,7 +195,7 @@ func (r *Runtime) Reconcile(ctx context.Context) error {
}
}

r.symbolLoader.Load(ctx, specs...)
_ = r.symbolLoader.Load(ctx, specs...)
case event, ok := <-secretStream.Next():
if !ok {
return nil
Expand All @@ -211,13 +211,17 @@ func (r *Runtime) Reconcile(ctx context.Context) error {

var specs []spec.Spec
for _, id := range r.symbolTable.Keys() {
sb := r.symbolTable.Lookup(id)
if sb != nil && r.scheme.IsBound(sb.Spec, secrets...) {
specs = append(specs, sb.Spec)
if sb := r.symbolTable.Lookup(id); sb != nil {
unstructured := &spec.Unstructured{}
if err := spec.Convert(sb.Spec, unstructured); err != nil {
return err
} else if unstructured.IsBound(secrets...) {
specs = append(specs, sb.Spec)
}
}
}

r.symbolLoader.Load(ctx, specs...)
_ = r.symbolLoader.Load(ctx, specs...)
case event, ok := <-chartStream.Next():
if !ok {
return nil
Expand Down Expand Up @@ -246,11 +250,11 @@ func (r *Runtime) Reconcile(ctx context.Context) error {
}

for _, sp := range specs {
r.symbolTable.Free(sp.GetID())
_, _ = r.symbolTable.Free(sp.GetID())
}

r.chartLoader.Load(ctx, &chart.Chart{ID: event.ID})
r.symbolLoader.Load(ctx, specs...)
_ = r.chartLoader.Load(ctx, &chart.Chart{ID: event.ID})
_ = r.symbolLoader.Load(ctx, specs...)
}
}
}
Expand Down
84 changes: 0 additions & 84 deletions pkg/scheme/scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package scheme

import (
"github.com/gofrs/uuid"
"github.com/siyul-park/uniflow/pkg/resource"
"github.com/siyul-park/uniflow/pkg/secret"
"github.com/siyul-park/uniflow/pkg/template"
"reflect"
"slices"
"sync"
Expand Down Expand Up @@ -116,87 +113,6 @@ func (s *Scheme) Codec(kind string) Codec {
return s.codecs[kind]
}

// IsBound checks if the spec is bound to any of the provided secrets.
func (s *Scheme) IsBound(sp spec.Spec, secrets ...*secret.Secret) bool {
for _, values := range sp.GetEnv() {
for _, val := range values {
examples := make([]*secret.Secret, 0, 2)
if val.ID != uuid.Nil {
examples = append(examples, &secret.Secret{ID: val.ID})
}
if val.Name != "" {
examples = append(examples, &secret.Secret{Namespace: sp.GetNamespace(), Name: val.Name})
}

for _, scrt := range secrets {
if len(resource.Match(scrt, examples...)) > 0 {
return true
}
}
}
}
return false
}

// Bind processes the given spec.Spec by resolving its environment variables using provided secrets.
func (s *Scheme) Bind(sp spec.Spec, secrets ...*secret.Secret) (spec.Spec, error) {
s.mu.RLock()
defer s.mu.RUnlock()

unstructured := &spec.Unstructured{}
if err := spec.Convert(sp, unstructured); err != nil {
return nil, err
}

env := map[string]any{}
for key, values := range unstructured.GetEnv() {
for i, val := range values {
example := &secret.Secret{
ID: val.ID,
Namespace: sp.GetNamespace(),
Name: val.Name,
}

var scrt *secret.Secret
for _, s := range secrets {
if (!s.IsIdentified() && !val.IsIdentified()) || len(resource.Match(s, example)) > 0 {
scrt = s
break
}
}

if scrt != nil {
v, err := template.Execute(val.Data, scrt.Data)
if err != nil {
return nil, err
}

val.ID = scrt.GetID()
val.Name = scrt.GetName()
val.Data = v
values[i] = val
}

if !val.IsIdentified() || scrt != nil {
env[key] = val.Data
}
}

if _, ok := env[key]; !ok {
return nil, errors.WithStack(encoding.ErrUnsupportedValue)
}
}

if len(env) > 0 {
if fields, err := template.Execute(unstructured.Fields, env); err != nil {
return nil, err
} else {
unstructured.Fields = fields.(map[string]any)
}
}
return unstructured, nil
}

// Decode converts the input spec.Spec into a registered structured type if one exists.
func (s *Scheme) Decode(sp spec.Spec) (spec.Spec, error) {
s.mu.RLock()
Expand Down
61 changes: 0 additions & 61 deletions pkg/scheme/scheme_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package scheme

import (
"github.com/siyul-park/uniflow/pkg/secret"
"testing"

"github.com/go-faker/faker/v4"
Expand Down Expand Up @@ -68,66 +67,6 @@ func TestScheme_Codec(t *testing.T) {
assert.False(t, ok)
}

func TestScheme_IsBound(t *testing.T) {
s := New()

sec1 := &secret.Secret{
ID: uuid.Must(uuid.NewV7()),
}
sec2 := &secret.Secret{
ID: uuid.Must(uuid.NewV7()),
}

meta := &spec.Meta{
ID: uuid.Must(uuid.NewV7()),
Kind: faker.UUIDHyphenated(),
Env: map[string][]spec.Value{
"FOO": {
{
ID: sec1.ID,
Data: "foo",
},
},
},
}

assert.True(t, s.IsBound(meta, sec1))
assert.False(t, s.IsBound(meta, sec2))
}

func TestScheme_Bind(t *testing.T) {
s := New()
kind := faker.UUIDHyphenated()

s.AddKnownType(kind, &spec.Meta{})

sec := &secret.Secret{
ID: uuid.Must(uuid.NewV7()),
Data: faker.UUIDHyphenated(),
}
meta := &spec.Unstructured{
Meta: spec.Meta{
ID: uuid.Must(uuid.NewV7()),
Kind: kind,
Env: map[string][]spec.Value{
"FOO": {
{
ID: sec.ID,
Data: "{{ . }}",
},
},
},
},
Fields: map[string]any{
"foo": "{{ .FOO }}",
},
}

bind, err := s.Bind(meta, sec)
assert.NoError(t, err)
assert.Equal(t, sec.Data, bind.GetEnv()["FOO"][0].Data)
}

func TestScheme_Decode(t *testing.T) {
s := New()
kind := faker.UUIDHyphenated()
Expand Down
66 changes: 66 additions & 0 deletions pkg/spec/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package spec

import (
"github.com/gofrs/uuid"
"github.com/pkg/errors"
"github.com/siyul-park/uniflow/pkg/encoding"
"github.com/siyul-park/uniflow/pkg/resource"
"github.com/siyul-park/uniflow/pkg/secret"
"github.com/siyul-park/uniflow/pkg/template"
"github.com/siyul-park/uniflow/pkg/types"
)

Expand Down Expand Up @@ -163,6 +167,68 @@ func (m *Meta) SetEnv(val map[string][]Value) {
m.Env = val
}

// IsBound checks if the spec is bound to any provided secrets.
func (m *Meta) IsBound(secrets ...*secret.Secret) bool {
for _, values := range m.Env {
for _, val := range values {
var examples []*secret.Secret
if val.ID != uuid.Nil {
examples = append(examples, &secret.Secret{ID: val.ID})
}
if val.Name != "" {
examples = append(examples, &secret.Secret{Namespace: m.Namespace, Name: val.Name})
}

for _, scrt := range secrets {
if len(resource.Match(scrt, examples...)) > 0 {
return true
}
}
}
}
return false
}

// Bind processes the spec by resolving environment variables using provided secrets.
func (m *Meta) Bind(secrets ...*secret.Secret) error {
for _, values := range m.Env {
ok := false
for i, val := range values {
example := &secret.Secret{
ID: val.ID,
Namespace: m.Namespace,
Name: val.Name,
}

var scrt *secret.Secret
for _, s := range secrets {
if (!s.IsIdentified() && !val.IsIdentified()) || len(resource.Match(s, example)) > 0 {
scrt = s
break
}
}

if scrt != nil {
v, err := template.Execute(val.Data, scrt.Data)
if err != nil {
return err
}

val.ID = scrt.GetID()
val.Name = scrt.GetName()
val.Data = v
values[i] = val
}

ok = ok || !val.IsIdentified() || scrt != nil
}
if !ok {
return errors.WithStack(encoding.ErrUnsupportedValue)
}
}
return nil
}

// IsIdentified checks whether the Value instance has a unique identifier or name.
func (v *Value) IsIdentified() bool {
return v.ID != uuid.Nil || v.Name != ""
Expand Down
Loading

0 comments on commit dee5558

Please sign in to comment.