Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions sdk/contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ WriteOutput writes the content to the specifies file at the path /kratix/output/

WriteStatus writes the specified status to the `/kratix/metadata/status.yaml`

**`WriteLabels(map[string]string) error`**

WriteLabels writes the specified labels to the `/kratix/metadata/labels.yaml`. These labels will be merged with the existing resource labels after the pipeline completes.

**`WriteDestinationSelectors([]DestinationSelector) error`**

WriteDestinationSelectors writes the specified Destination Selectors to the `/kratix/metadata/destination_selectors.yaml`
Expand Down Expand Up @@ -70,6 +74,10 @@ PublishStatus updates the status of the provided resource with the provided stat

ReadStatus reads the /kratix/metadata/status.yaml

**`ReadLabels() (map[string]string, error)`**

ReadLabels reads the /kratix/metadata/labels.yaml

## Promise Interface

The SDK interface implements the core functions for interacting with a Promise
Expand Down
43 changes: 42 additions & 1 deletion work-creator/cmd/update_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
func updateStatusCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-status",
Short: "Update status of Kubernetes resources",
Short: "Update status and labels of Kubernetes resources",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
return runUpdateStatus(ctx)
Expand All @@ -29,6 +29,7 @@ func updateStatusCmd() *cobra.Command {
func runUpdateStatus(ctx context.Context) error {
workspaceDir := "/work-creator-files"
statusFile := filepath.Join(workspaceDir, "metadata", "status.yaml")
labelsFile := filepath.Join(workspaceDir, "metadata", "labels.yaml")

params := helpers.GetParametersFromEnv()

Expand All @@ -44,6 +45,32 @@ func runUpdateStatus(ctx context.Context) error {
return fmt.Errorf("failed to get existing object: %w", err)
}

// Handle labels update
incomingLabels, err := readLabelsFile(labelsFile)
if err != nil {
return fmt.Errorf("failed to load incoming labels: %w", err)
}

if len(incomingLabels) > 0 {
existingLabels := existingObj.GetLabels()
if existingLabels == nil {
existingLabels = map[string]string{}
}
mergedLabels := lib.MergeLabels(existingLabels, incomingLabels)
existingObj.SetLabels(mergedLabels)

if _, err = objectClient.Update(ctx, existingObj, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("failed to update labels: %w", err)
}

// Re-fetch the object after labels update to get the latest resourceVersion
existingObj, err = objectClient.Get(ctx, params.ObjectName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to get existing object after labels update: %w", err)
}
}

// Handle status update
existingStatus := map[string]any{}
if existingObj.Object["status"] != nil {
existingStatus = existingObj.Object["status"].(map[string]any)
Expand Down Expand Up @@ -84,3 +111,17 @@ func readStatusFile(statusFile string) (map[string]any, error) {
}
return incomingStatus, nil
}

func readLabelsFile(labelsFile string) (map[string]string, error) {
incomingLabels := map[string]string{}
if _, err := os.Stat(labelsFile); err == nil {
incomingLabelsBytes, err := os.ReadFile(labelsFile)
if err != nil {
return nil, fmt.Errorf("failed to read labels file: %w", err)
}
if err := yaml.Unmarshal(incomingLabelsBytes, &incomingLabels); err != nil {
return nil, fmt.Errorf("failed to unmarshal incoming labels: %w", err)
}
}
return incomingLabels, nil
}
19 changes: 19 additions & 0 deletions work-creator/lib/status_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@ func MergeStatuses(existing map[string]any, incoming map[string]any) map[string]
return mergeRecursive(existing, incoming)
}

// MergeLabels takes two label maps and returns a new label map that is a
// merge of the two. If a key exists in both maps, the value from the incoming
// map will be used.
func MergeLabels(existing map[string]string, incoming map[string]string) map[string]string {
result := make(map[string]string)

// First, copy all keys from existing
for k, v := range existing {
result[k] = v
}

// Then merge or overwrite with incoming
for k, v := range incoming {
result[k] = v
}

return result
}

// MarkAsCompleted takes a status map and returns a new status map with the
// "ConfigureWorkflowCompleted" condition set to true. It will also update the
// "message" field to "Resource requested" if the message is currently
Expand Down
47 changes: 47 additions & 0 deletions work-creator/lib/status_updater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,53 @@ import (

var _ = Describe("StatusUpdater", func() {

Describe("MergeLabels", func() {
It("merges the two maps", func() {
existing := map[string]string{
"existing-key": "existing-value",
"shared-key": "old-value",
}
incoming := map[string]string{
"incoming-key": "incoming-value",
"shared-key": "new-value",
}
result := lib.MergeLabels(existing, incoming)
Expect(result).To(SatisfyAll(
HaveKeyWithValue("existing-key", "existing-value"),
HaveKeyWithValue("incoming-key", "incoming-value"),
HaveKeyWithValue("shared-key", "new-value"),
))
Expect(result).To(HaveLen(3))
})

It("returns incoming labels when existing is empty", func() {
existing := map[string]string{}
incoming := map[string]string{
"key1": "value1",
"key2": "value2",
}
result := lib.MergeLabels(existing, incoming)
Expect(result).To(Equal(incoming))
})

It("returns existing labels when incoming is empty", func() {
existing := map[string]string{
"key1": "value1",
"key2": "value2",
}
incoming := map[string]string{}
result := lib.MergeLabels(existing, incoming)
Expect(result).To(Equal(existing))
})

It("returns empty map when both are empty", func() {
existing := map[string]string{}
incoming := map[string]string{}
result := lib.MergeLabels(existing, incoming)
Expect(result).To(BeEmpty())
})
})

Describe("MergeStatuses", func() {
It("merges the two maps", func() {
existing := map[string]any{
Expand Down