Skip to content

Commit 373e731

Browse files
committed
Adding executor field and metadata in cloudevent payload
Signed-off-by: Jian Qiu <jqiu@redhat.com>
1 parent 3fc951c commit 373e731

7 files changed

Lines changed: 260 additions & 22 deletions

File tree

pkg/cloudevents/clients/work/agent/codec/manifestbundle.go

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package codec
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"strconv"
67

@@ -75,6 +76,13 @@ func (c *ManifestBundleCodec) Encode(source string, eventType types.CloudEventsT
7576

7677
evt.SetExtension(types.ExtensionStatusHash, statusHash)
7778

79+
// set the work's meta data to its cloud event
80+
metaJson, err := json.Marshal(work.ObjectMeta)
81+
if err != nil {
82+
return nil, err
83+
}
84+
evt.SetExtension(types.ExtensionWorkMeta, string(metaJson))
85+
7886
manifestBundleStatus := &payload.ManifestBundleStatus{
7987
Conditions: work.Status.Conditions,
8088
ResourceStatus: work.Status.ResourceStatus.Manifests,
@@ -126,24 +134,41 @@ func (c *ManifestBundleCodec) Decode(evt *cloudevents.Event) (*workv1.ManifestWo
126134
return nil, fmt.Errorf("failed to get clustername extension: %v", err)
127135
}
128136

137+
metaObj := metav1.ObjectMeta{}
138+
if workMetaExtension, ok := evtExtensions[types.ExtensionWorkMeta]; ok {
139+
metaJson, err := cloudeventstypes.ToString(workMetaExtension)
140+
if err != nil {
141+
return nil, err
142+
}
143+
144+
if err := json.Unmarshal([]byte(metaJson), &metaObj); err != nil {
145+
return nil, err
146+
}
147+
}
148+
149+
metaObj.UID = kubetypes.UID(resourceID)
150+
metaObj.Name = resourceName
151+
metaObj.Namespace = clusterName
152+
metaObj.ResourceVersion = fmt.Sprintf("%d", resourceVersion)
153+
// if generation is not set, set it the same as resourceVersion
154+
if metaObj.Generation == 0 {
155+
metaObj.Generation = int64(resourceVersion)
156+
}
157+
if metaObj.Annotations == nil {
158+
metaObj.Annotations = map[string]string{}
159+
}
160+
metaObj.Annotations[common.CloudEventsDataTypeAnnotationKey] = eventType.CloudEventsDataType.String()
161+
if metaObj.Labels == nil {
162+
metaObj.Labels = map[string]string{}
163+
}
164+
metaObj.Labels[common.CloudEventsOriginalSourceLabelKey] = evt.Source()
165+
129166
// Use the event's resource version as the current work's generation and resource version.
130167
// In the event case, the event's resource version should correspond to its spec change.
131168
// We can use the resource version to determine the spec of a work whether changed.
132169
work := &workv1.ManifestWork{
133-
TypeMeta: metav1.TypeMeta{},
134-
ObjectMeta: metav1.ObjectMeta{
135-
UID: kubetypes.UID(resourceID),
136-
Generation: int64(resourceVersion),
137-
ResourceVersion: fmt.Sprintf("%d", resourceVersion),
138-
Name: resourceName,
139-
Namespace: clusterName,
140-
Labels: map[string]string{
141-
common.CloudEventsOriginalSourceLabelKey: evt.Source(),
142-
},
143-
Annotations: map[string]string{
144-
common.CloudEventsDataTypeAnnotationKey: eventType.CloudEventsDataType.String(),
145-
},
146-
},
170+
TypeMeta: metav1.TypeMeta{},
171+
ObjectMeta: metaObj,
147172
}
148173

149174
if _, ok := evtExtensions[types.ExtensionDeletionTimestamp]; ok {
@@ -170,6 +195,7 @@ func (c *ManifestBundleCodec) Decode(evt *cloudevents.Event) (*workv1.ManifestWo
170195
},
171196
DeleteOption: manifests.DeleteOption,
172197
ManifestConfigs: manifests.ManifestConfigs,
198+
Executor: manifests.Executer,
173199
}
174200

175201
// validate the manifests

pkg/cloudevents/clients/work/agent/codec/manifestbundle_test.go

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,39 @@ func TestManifestBundleEncode(t *testing.T) {
9090
},
9191
},
9292
},
93+
{
94+
name: "encode a manifestwork status with metadata",
95+
eventType: types.CloudEventsType{
96+
CloudEventsDataType: payload.ManifestBundleEventDataType,
97+
SubResource: types.SubResourceStatus,
98+
Action: "test",
99+
},
100+
work: &workv1.ManifestWork{
101+
ObjectMeta: metav1.ObjectMeta{
102+
UID: "test",
103+
ResourceVersion: "13",
104+
Name: "test-work",
105+
Namespace: "test-namespace",
106+
Labels: map[string]string{
107+
"cloudevents.open-cluster-management.io/originalsource": "source1",
108+
"test-label": "test-value",
109+
},
110+
Annotations: map[string]string{
111+
"test-annotation": "test-value",
112+
},
113+
Finalizers: []string{"test-finalizer"},
114+
},
115+
Status: workv1.ManifestWorkStatus{
116+
Conditions: []metav1.Condition{},
117+
ResourceStatus: workv1.ManifestResourceStatus{},
118+
},
119+
},
120+
},
93121
}
94122

95123
for _, c := range cases {
96124
t.Run(c.name, func(t *testing.T) {
97-
_, err := NewManifestBundleCodec().Encode("cluster1-work-agent", c.eventType, c.work)
125+
evt, err := NewManifestBundleCodec().Encode("cluster1-work-agent", c.eventType, c.work)
98126
if c.expectedErr {
99127
if err == nil {
100128
t.Errorf("expected an error, but failed")
@@ -105,6 +133,23 @@ func TestManifestBundleEncode(t *testing.T) {
105133
if err != nil {
106134
t.Errorf("unexpected error %v", err)
107135
}
136+
137+
// Verify that ExtensionWorkMeta is set when encoding manifestwork status
138+
if c.work != nil && evt != nil {
139+
workMetaExt := evt.Extensions()[types.ExtensionWorkMeta]
140+
if workMetaExt == nil {
141+
t.Errorf("expected ExtensionWorkMeta to be set")
142+
} else {
143+
// Verify the metadata can be unmarshaled
144+
var metaObj metav1.ObjectMeta
145+
if err := json.Unmarshal([]byte(workMetaExt.(string)), &metaObj); err != nil {
146+
t.Errorf("failed to unmarshal metadata: %v", err)
147+
}
148+
if metaObj.UID != c.work.ObjectMeta.UID {
149+
t.Errorf("expected UID %s, got %s", c.work.ObjectMeta.UID, metaObj.UID)
150+
}
151+
}
152+
}
108153
})
109154
}
110155
}
@@ -255,11 +300,57 @@ func TestManifestBundleDecode(t *testing.T) {
255300
return &evt
256301
}(),
257302
},
303+
{
304+
name: "decode a cloudevent with metadata extension",
305+
event: func() *cloudevents.Event {
306+
metaJson, err := json.Marshal(metav1.ObjectMeta{
307+
UID: "original-uid",
308+
ResourceVersion: "5",
309+
Name: "original-name",
310+
Namespace: "original-namespace",
311+
Labels: map[string]string{"original-label": "original-value"},
312+
Annotations: map[string]string{"original-annotation": "original-value"},
313+
Finalizers: []string{"original-finalizer"},
314+
})
315+
if err != nil {
316+
t.Fatal(err)
317+
}
318+
evt := cloudevents.NewEvent()
319+
evt.SetSource("source1")
320+
evt.SetType("io.open-cluster-management.works.v1alpha1.manifestbundles.spec.test")
321+
evt.SetExtension("resourceid", "test")
322+
evt.SetExtension("resourceversion", "13")
323+
evt.SetExtension("clustername", "cluster1")
324+
evt.SetExtension("resourcename", "work1")
325+
evt.SetExtension(types.ExtensionWorkMeta, string(metaJson))
326+
if err := evt.SetData(cloudevents.ApplicationJSON, &payload.ManifestBundle{
327+
Manifests: []workv1.Manifest{
328+
{
329+
RawExtension: runtime.RawExtension{
330+
Raw: toConfigMap(t),
331+
},
332+
},
333+
},
334+
Executer: &workv1.ManifestWorkExecutor{
335+
Subject: workv1.ManifestWorkExecutorSubject{
336+
Type: workv1.ExecutorSubjectTypeServiceAccount,
337+
ServiceAccount: &workv1.ManifestWorkSubjectServiceAccount{
338+
Name: "test-sa",
339+
Namespace: "test-ns",
340+
},
341+
},
342+
},
343+
}); err != nil {
344+
t.Fatal(err)
345+
}
346+
return &evt
347+
}(),
348+
},
258349
}
259350

260351
for _, c := range cases {
261352
t.Run(c.name, func(t *testing.T) {
262-
_, err := NewManifestBundleCodec().Decode(c.event)
353+
work, err := NewManifestBundleCodec().Decode(c.event)
263354
if c.expectedErr {
264355
if err == nil {
265356
t.Errorf("expected an error, but failed")
@@ -270,6 +361,39 @@ func TestManifestBundleDecode(t *testing.T) {
270361
if err != nil {
271362
t.Errorf("unexpected error %v", err)
272363
}
364+
365+
// Additional verification for metadata extension test case
366+
if c.name == "decode a cloudevent with metadata extension" && work != nil {
367+
// Verify that original metadata from extension was merged correctly
368+
if work.ObjectMeta.Labels["original-label"] != "original-value" {
369+
t.Errorf("expected original-label to be preserved, got %v", work.ObjectMeta.Labels)
370+
}
371+
if work.ObjectMeta.Annotations["original-annotation"] != "original-value" {
372+
t.Errorf("expected original-annotation to be preserved, got %v", work.ObjectMeta.Annotations)
373+
}
374+
if len(work.ObjectMeta.Finalizers) == 0 || work.ObjectMeta.Finalizers[0] != "original-finalizer" {
375+
t.Errorf("expected original-finalizer to be preserved, got %v", work.ObjectMeta.Finalizers)
376+
}
377+
// Verify that event-specific metadata overrides
378+
if work.ObjectMeta.UID != "test" {
379+
t.Errorf("expected UID to be overridden to 'test', got %s", work.ObjectMeta.UID)
380+
}
381+
if work.ObjectMeta.Name != "work1" {
382+
t.Errorf("expected Name to be overridden to 'work1', got %s", work.ObjectMeta.Name)
383+
}
384+
if work.ObjectMeta.Namespace != "cluster1" {
385+
t.Errorf("expected Namespace to be overridden to 'cluster1', got %s", work.ObjectMeta.Namespace)
386+
}
387+
if work.ObjectMeta.ResourceVersion != "13" {
388+
t.Errorf("expected ResourceVersion to be overridden to '13', got %s", work.ObjectMeta.ResourceVersion)
389+
}
390+
// Verify Executor field
391+
if work.Spec.Executor == nil {
392+
t.Errorf("expected Executor to be set")
393+
} else if work.Spec.Executor.Subject.ServiceAccount.Name != "test-sa" {
394+
t.Errorf("expected Executor ServiceAccount name to be 'test-sa', got %s", work.Spec.Executor.Subject.ServiceAccount.Name)
395+
}
396+
}
273397
})
274398
}
275399
}

pkg/cloudevents/clients/work/payload/manifestbundle.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ type ManifestBundle struct {
2424

2525
// ManifestConfigs represents the configurations of manifests.
2626
ManifestConfigs []workv1.ManifestConfigOption `json:"manifestConfigs,omitempty"`
27+
28+
// Executer represents the executor of the manifests
29+
Executer *workv1.ManifestWorkExecutor `json:"executer,omitempty"`
2730
}
2831

2932
// ManifestBundleStatus represents the data in a cloudevent, it contains the status of a ManifestBundle on a managed

pkg/cloudevents/clients/work/source/codec/manifestbundle.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ import (
1818
"open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types"
1919
)
2020

21-
// ExtensionWorkMeta is an extension attribute for work meta data.
22-
const ExtensionWorkMeta = "metadata"
23-
2421
// ManifestBundleCodec is a codec to encode/decode a ManifestWork/cloudevent with ManifestBundle for a source.
2522
type ManifestBundleCodec struct{}
2623

@@ -56,7 +53,7 @@ func (c *ManifestBundleCodec) Encode(source string, eventType types.CloudEventsT
5653
if err != nil {
5754
return nil, err
5855
}
59-
evt.SetExtension(ExtensionWorkMeta, string(metaJson))
56+
evt.SetExtension(types.ExtensionWorkMeta, string(metaJson))
6057

6158
if !work.DeletionTimestamp.IsZero() {
6259
evt.SetExtension(types.ExtensionDeletionTimestamp, work.DeletionTimestamp.Time)
@@ -67,6 +64,7 @@ func (c *ManifestBundleCodec) Encode(source string, eventType types.CloudEventsT
6764
Manifests: work.Spec.Workload.Manifests,
6865
DeleteOption: work.Spec.DeleteOption,
6966
ManifestConfigs: work.Spec.ManifestConfigs,
67+
Executer: work.Spec.Executor,
7068
}
7169
if err := evt.SetData(cloudevents.ApplicationJSON, manifests); err != nil {
7270
return nil, fmt.Errorf("failed to encode manifestwork status to a cloudevent: %v", err)
@@ -119,7 +117,7 @@ func (c *ManifestBundleCodec) Decode(evt *cloudevents.Event) (*workv1.ManifestWo
119117
// the agent sends the work meta data back, restore the meta to the received work, otherwise only set the
120118
// UID and ResourceVersion to the received work, for the work's other meta data will be got from the work
121119
// client local cache.
122-
if workMetaExtension, ok := evtExtensions[ExtensionWorkMeta]; ok {
120+
if workMetaExtension, ok := evtExtensions[types.ExtensionWorkMeta]; ok {
123121
metaJson, err := cloudeventstypes.ToString(workMetaExtension)
124122
if err != nil {
125123
return nil, err
@@ -153,6 +151,7 @@ func (c *ManifestBundleCodec) Decode(evt *cloudevents.Event) (*workv1.ManifestWo
153151
work.Spec.Workload.Manifests = manifestStatus.ManifestBundle.Manifests
154152
work.Spec.DeleteOption = manifestStatus.ManifestBundle.DeleteOption
155153
work.Spec.ManifestConfigs = manifestStatus.ManifestBundle.ManifestConfigs
154+
work.Spec.Executor = manifestStatus.ManifestBundle.Executer
156155
}
157156

158157
work.Status = workv1.ManifestWorkStatus{

0 commit comments

Comments
 (0)