Skip to content

Commit

Permalink
feat: added guid (uuids) to resource state
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Meier <[email protected]>
  • Loading branch information
astromechza committed May 10, 2024
1 parent 0d013dd commit 69defc4
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 0 deletions.
15 changes: 15 additions & 0 deletions framework/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package framework

import (
"crypto/rand"
"fmt"
"maps"
"reflect"
Expand Down Expand Up @@ -50,6 +51,8 @@ type ScoreWorkloadState[WorkloadExtras any] struct {

// ScoreResourceState is the state stored and tracked for each resource.
type ScoreResourceState[ResourceExtras any] struct {
// Guid is a uuid assigned to this "instance" of the resource.
Guid string `yaml:"guid"`
// Type is the resource type.
Type string `yaml:"type"`
// Class is the resource class or 'default' if not provided.
Expand Down Expand Up @@ -105,6 +108,17 @@ func (s *State[StateExtras, WorkloadExtras, ResourceExtras]) WithWorkload(spec *
return &out, nil
}

// uuidV4 generates a uuid v4 string without dependencies
func uuidV4() string {
// read 16 random bytes
d := make([]byte, 16)
_, _ = rand.Read(d)
// set the version to version 4 (the top 4 bits of the 7th byte)
d[6] = (d[6] & 0b_0000_1111) | 0b_0100_0000
// format and print the output
return fmt.Sprintf("%x-%x-%x-%x-%x", d[:4], d[4:6], d[6:8], d[8:10], d[10:])
}

// WithPrimedResources returns a new copy of State with all workload resources resolved to at least their initial type,
// class and id. New resources will have an empty provider set. Existing resources will not be touched.
// This is not a deep copy, but any writes are executed in a copy-on-write manner to avoid modifying the source.
Expand All @@ -122,6 +136,7 @@ func (s *State[StateExtras, WorkloadExtras, ResourceExtras]) WithPrimedResources
resUid := NewResourceUid(workloadName, resName, res.Type, res.Class, res.Id)
if existing, ok := out.Resources[resUid]; !ok {
out.Resources[resUid] = ScoreResourceState[ResourceExtras]{
Guid: uuidV4(),
Type: resUid.Type(),
Class: resUid.Class(),
Id: resUid.Id(),
Expand Down
20 changes: 20 additions & 0 deletions framework/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ func mustAddWorkload(t *testing.T, s *State[NoExtras, NoExtras, NoExtras], spec
return n
}

func checkAndResetGuids[s any](t *testing.T, resources map[ResourceUid]ScoreResourceState[s]) {
for uid, s := range resources {
assert.NotEmpty(t, s.Guid)
s.Guid = "00000000-0000-0000-0000-000000000000"
resources[uid] = s
}
}

func TestWithWorkload(t *testing.T) {
start := new(State[NoExtras, NoExtras, NoExtras])

Expand Down Expand Up @@ -132,23 +140,29 @@ resources:
next, err := next.WithPrimedResources()
require.NoError(t, err)
assert.Len(t, start.Resources, 0)
checkAndResetGuids(t, next.Resources)

assert.Equal(t, map[ResourceUid]ScoreResourceState[NoExtras]{
"thing.default#example.one": {
Guid: "00000000-0000-0000-0000-000000000000",
Type: "thing", Class: "default", Id: "example.one", State: map[string]interface{}{}, Outputs: map[string]interface{}{},
SourceWorkload: "example",
},
"thing2.banana#example.two": {
Guid: "00000000-0000-0000-0000-000000000000",
Type: "thing2", Class: "banana", Id: "example.two", State: map[string]interface{}{}, Outputs: map[string]interface{}{},
SourceWorkload: "example",
},
"thing3.apple#dog": {
Guid: "00000000-0000-0000-0000-000000000000",
Type: "thing3", Class: "apple", Id: "dog", State: map[string]interface{}{},
Metadata: map[string]interface{}{"annotations": score.ResourceMetadata{"foo": "bar"}},
Params: map[string]interface{}{"color": "green"},
SourceWorkload: "example",
Outputs: map[string]interface{}{},
},
"thing4.default#elephant": {
Guid: "00000000-0000-0000-0000-000000000000",
Type: "thing4", Class: "default", Id: "elephant", State: map[string]interface{}{},
Metadata: map[string]interface{}{"x": "y"},
Params: map[string]interface{}{"color": "blue"},
Expand Down Expand Up @@ -242,18 +256,22 @@ resources:
require.NoError(t, err)
assert.Len(t, start.Resources, 0)
assert.Len(t, next.Resources, 3)
checkAndResetGuids(t, next.Resources)
assert.Equal(t, map[ResourceUid]ScoreResourceState[NoExtras]{
"thing.default#example1.one": {
Guid: "00000000-0000-0000-0000-000000000000",
Type: "thing", Class: "default", Id: "example1.one", State: map[string]interface{}{},
SourceWorkload: "example1",
Outputs: map[string]interface{}{},
},
"thing.default#example2.one": {
Guid: "00000000-0000-0000-0000-000000000000",
Type: "thing", Class: "default", Id: "example2.one", State: map[string]interface{}{},
SourceWorkload: "example2",
Outputs: map[string]interface{}{},
},
"thing2.default#dog": {
Guid: "00000000-0000-0000-0000-000000000000",
Type: "thing2", Class: "default", Id: "dog", State: map[string]interface{}{},
SourceWorkload: "example1",
Outputs: map[string]interface{}{},
Expand Down Expand Up @@ -393,6 +411,7 @@ func TestCustomExtras(t *testing.T) {
s := new(State[customStateExtras, customWorkloadExtras, customResourceExtras])
s.Resources = map[ResourceUid]ScoreResourceState[customResourceExtras]{
"thing.default#shared": {
Guid: "00000000-0000-0000-0000-000000000000",
Type: "thing", Class: "default", Id: "shared",
Metadata: map[string]interface{}{},
Params: map[string]interface{}{},
Expand Down Expand Up @@ -427,6 +446,7 @@ func TestCustomExtras(t *testing.T) {
},
"resources": map[string]interface{}{
"thing.default#shared": map[string]interface{}{
"guid": "00000000-0000-0000-0000-000000000000",
"type": "thing",
"class": "default",
"id": "shared",
Expand Down

0 comments on commit 69defc4

Please sign in to comment.