Skip to content

Commit afcfa79

Browse files
committed
Add package label for functions and trigger function update when the package updated
1 parent 9393c4b commit afcfa79

File tree

6 files changed

+507
-56
lines changed

6 files changed

+507
-56
lines changed

.github/workflows/lint.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Lint
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
lint:
9+
name: Run on Ubuntu
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Clone the code
13+
uses: actions/checkout@v4
14+
15+
- name: Setup Go
16+
uses: actions/setup-go@v5
17+
with:
18+
go-version-file: ./operator/go.mod
19+
20+
- name: Run linter
21+
uses: golangci/golangci-lint-action@v6
22+
with:
23+
version: v1.63.4

operator/examples/function.yaml

Lines changed: 0 additions & 17 deletions
This file was deleted.

operator/examples/package.yaml

Lines changed: 0 additions & 15 deletions
This file was deleted.

operator/internal/controller/function_controller.go

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ package controller
1919
import (
2020
"context"
2121
"fmt"
22+
"reflect"
23+
2224
"github.com/FunctionStream/function-stream/operator/utils"
2325
"k8s.io/apimachinery/pkg/util/json"
24-
"reflect"
2526

2627
"gopkg.in/yaml.v3"
2728
appsv1 "k8s.io/api/apps/v1"
@@ -33,8 +34,10 @@ import (
3334
ctrl "sigs.k8s.io/controller-runtime"
3435
"sigs.k8s.io/controller-runtime/pkg/builder"
3536
"sigs.k8s.io/controller-runtime/pkg/client"
37+
"sigs.k8s.io/controller-runtime/pkg/handler"
3638
logf "sigs.k8s.io/controller-runtime/pkg/log"
3739
"sigs.k8s.io/controller-runtime/pkg/predicate"
40+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3841

3942
fsv1alpha1 "github.com/FunctionStream/function-stream/operator/api/v1alpha1"
4043
)
@@ -81,7 +84,17 @@ func (r *FunctionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
8184
return ctrl.Result{}, err
8285
}
8386

84-
// 2. Get Package
87+
// 2. Ensure Function has package label
88+
if fn.Labels == nil {
89+
fn.Labels = make(map[string]string)
90+
}
91+
labelUpdated := false
92+
if fn.Labels["package"] != fn.Spec.Package {
93+
fn.Labels["package"] = fn.Spec.Package
94+
labelUpdated = true
95+
}
96+
97+
// 3. Get Package
8598
var pkg fsv1alpha1.Package
8699
if err := r.Get(ctx, types.NamespacedName{Name: fn.Spec.Package, Namespace: req.Namespace}, &pkg); err != nil {
87100
log.Error(err, "Failed to get Package", "package", fn.Spec.Package)
@@ -95,14 +108,14 @@ func (r *FunctionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
95108
return ctrl.Result{}, fmt.Errorf("package %s has no image", fn.Spec.Package)
96109
}
97110

98-
// 3. Build config yaml content
111+
// 4. Build config yaml content
99112
configYaml, err := buildFunctionConfigYaml(&fn, r.Config)
100113
if err != nil {
101114
log.Error(err, "Failed to marshal config yaml")
102115
return ctrl.Result{}, err
103116
}
104117

105-
// 4. Build Deployment
118+
// 5. Build Deployment
106119
deployName := fmt.Sprintf("function-%s", fn.Name)
107120
var replicas int32 = 1
108121
labels := map[string]string{
@@ -132,19 +145,17 @@ EOF
132145
},
133146
Spec: corev1.PodSpec{
134147
InitContainers: []corev1.Container{{
135-
Name: "init-config",
136-
Image: image,
137-
ImagePullPolicy: corev1.PullIfNotPresent,
138-
Command: []string{"/bin/sh", "-c", initCommand},
148+
Name: "init-config",
149+
Image: image,
150+
Command: []string{"/bin/sh", "-c", initCommand},
139151
VolumeMounts: []corev1.VolumeMount{{
140152
Name: "function-config",
141153
MountPath: "/config",
142154
}},
143155
}},
144156
Containers: []corev1.Container{{
145-
Name: "function",
146-
Image: image,
147-
ImagePullPolicy: corev1.PullIfNotPresent,
157+
Name: "function",
158+
Image: image,
148159
VolumeMounts: []corev1.VolumeMount{{
149160
Name: "function-config",
150161
MountPath: "/config",
@@ -168,7 +179,7 @@ EOF
168179
return ctrl.Result{}, err
169180
}
170181

171-
// 5. Create or Update Deployment
182+
// 6. Create or Update Deployment
172183
var existingDeploy appsv1.Deployment
173184
deployErr := r.Get(ctx, types.NamespacedName{Name: deployName, Namespace: fn.Namespace}, &existingDeploy)
174185
if deployErr == nil {
@@ -199,6 +210,24 @@ EOF
199210
}
200211
}
201212

213+
// 8. Update Function labels if needed
214+
if labelUpdated {
215+
// Re-fetch the Function to ensure we have the latest version
216+
var latestFn fsv1alpha1.Function
217+
if err := r.Get(ctx, req.NamespacedName, &latestFn); err != nil {
218+
log.Error(err, "Failed to get latest Function for label update")
219+
return ctrl.Result{}, err
220+
}
221+
// Apply our label changes to the latest version
222+
if latestFn.Labels == nil {
223+
latestFn.Labels = make(map[string]string)
224+
}
225+
latestFn.Labels["package"] = fn.Spec.Package
226+
if err := r.Update(ctx, &latestFn); err != nil {
227+
return utils.HandleReconcileError(log, err, "Conflict when updating Function labels, will retry automatically")
228+
}
229+
}
230+
202231
return ctrl.Result{}, nil
203232
}
204233

@@ -280,6 +309,38 @@ func (r *FunctionReconciler) SetupWithManager(mgr ctrl.Manager) error {
280309
return ctrl.NewControllerManagedBy(mgr).
281310
For(&fsv1alpha1.Function{}).
282311
Owns(&appsv1.Deployment{}, builder.WithPredicates(functionLabelPredicate)).
312+
Watches(
313+
&fsv1alpha1.Package{},
314+
handler.EnqueueRequestsFromMapFunc(r.mapPackageToFunctions),
315+
).
283316
Named("function").
284317
Complete(r)
285318
}
319+
320+
// mapPackageToFunctions maps Package changes to related Functions
321+
func (r *FunctionReconciler) mapPackageToFunctions(ctx context.Context, obj client.Object) []reconcile.Request {
322+
packageObj, ok := obj.(*fsv1alpha1.Package)
323+
if !ok {
324+
return nil
325+
}
326+
327+
// Get Functions that reference this Package using label selector
328+
var functions fsv1alpha1.FunctionList
329+
if err := r.List(ctx, &functions,
330+
client.InNamespace(packageObj.Namespace),
331+
client.MatchingLabels(map[string]string{"package": packageObj.Name})); err != nil {
332+
return nil
333+
}
334+
335+
var requests []reconcile.Request
336+
for _, function := range functions.Items {
337+
requests = append(requests, reconcile.Request{
338+
NamespacedName: types.NamespacedName{
339+
Name: function.Name,
340+
Namespace: function.Namespace,
341+
},
342+
})
343+
}
344+
345+
return requests
346+
}

0 commit comments

Comments
 (0)