Skip to content

Commit c45e172

Browse files
creydrmatejvasekclaude
authored
Use correct describer in pipelines provider (#3600)
* Use correct describer in pipelines provider * Update integration test to catch different describers * Update permissions for integration tests * fix: use in-cluster dialer for raw/keda pipeline tests The pipeline integration test was failing for raw and keda deployers because their services are only reachable via cluster-internal DNS (*.default.svc). The test used a plain http.Get which can't resolve these names from the runner. Use an in-cluster dialer (socat pod) for raw/keda, matching the pattern already used in deployer integration tests. Signed-off-by: Matej Vašek <matejvasek@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> --------- Signed-off-by: Matej Vašek <matejvasek@gmail.com> Co-authored-by: Matej Vašek <matejvasek@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ada57d2 commit c45e172

7 files changed

Lines changed: 115 additions & 58 deletions

File tree

hack/cluster.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,12 @@ tekton() {
529529
$KUBECTL wait pod --for=condition=Ready --timeout=180s -n tekton-pipelines -l "app=tekton-pipelines-webhook"
530530
sleep 10
531531

532+
# Grant permissions for Knative resources (services, routes, etc.)
532533
$KUBECTL create clusterrolebinding "${namespace}:knative-serving-namespaced-admin" --clusterrole=knative-serving-namespaced-admin --serviceaccount="${namespace}:default"
534+
# Grant permissions for standard Kubernetes resources (deployments, services, etc.) needed by k8s deployer
535+
$KUBECTL create clusterrolebinding "${namespace}:admin" --clusterrole=admin --serviceaccount="${namespace}:default"
536+
# Grant permissions for HTTPScaledObject Keda resources needed by keda deployer
537+
$KUBECTL create clusterrolebinding "${namespace}:keda-add-ons-http-operator" --clusterrole=keda-add-ons-http-operator --serviceaccount="${namespace}:default"
533538

534539
echo "${green}✅ Tekton${reset}"
535540
}

pkg/functions/client.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ type Instance struct {
188188
Subscriptions []Subscription `json:"subscriptions" yaml:"subscriptions"`
189189
Labels map[string]string `json:"labels" yaml:"labels" xml:"-"`
190190
Middleware Middleware `json:"middleware,omitempty" yaml:"middleware,omitempty"`
191+
Generation int64 `json:"generation,omitempty" yaml:"generation,omitempty"`
191192
}
192193

193194
// Subscriptions currently active to event sources

pkg/k8s/describer.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func (d *Describer) Describe(ctx context.Context, name, namespace string) (fn.In
8585
Middleware: fn.Middleware{
8686
Version: middlewareVersion,
8787
},
88+
Generation: deployment.Generation,
8889
}
8990

9091
return description, nil

pkg/keda/describer.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ func (d *Describer) Describe(ctx context.Context, name, namespace string) (fn.In
104104
Middleware: fn.Middleware{
105105
Version: middlewareVersion,
106106
},
107+
Generation: deployment.Generation,
107108
}
108109

109110
return description, nil

pkg/knative/describer.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,13 @@ func (d *Describer) Describe(ctx context.Context, name, namespace string) (fn.In
8282
}
8383

8484
description := fn.Instance{
85-
Name: name,
86-
Namespace: namespace,
87-
Deployer: KnativeDeployerName,
88-
Route: primaryRouteURL,
89-
Routes: routeURLs,
90-
Labels: service.Labels,
85+
Name: name,
86+
Namespace: namespace,
87+
Deployer: KnativeDeployerName,
88+
Route: primaryRouteURL,
89+
Routes: routeURLs,
90+
Labels: service.Labels,
91+
Generation: service.Generation,
9192
}
9293

9394
// get used image (including the sha)

pkg/pipelines/tekton/pipelines_int_test.go

Lines changed: 83 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"knative.dev/func/pkg/docker"
2626
fn "knative.dev/func/pkg/functions"
2727
"knative.dev/func/pkg/k8s"
28+
"knative.dev/func/pkg/keda"
2829
"knative.dev/func/pkg/knative"
2930
"knative.dev/func/pkg/oci"
3031
"knative.dev/func/pkg/pipelines/tekton"
@@ -44,26 +45,34 @@ const (
4445
TestNamespace = "default"
4546
)
4647

47-
func newRemoteTestClient(verbose bool, opts ...fn.Option) *fn.Client {
48+
func newRemoteTestClient(verbose bool, deployer string, opts ...fn.Option) *fn.Client {
4849
baseOpts := []fn.Option{
4950
fn.WithBuilder(buildpacks.NewBuilder(buildpacks.WithVerbose(verbose))),
5051
fn.WithPusher(docker.NewPusher(docker.WithCredentialsProvider(testCP))),
51-
fn.WithDeployer(knative.NewDeployer(knative.WithDeployerVerbose(verbose))),
52-
fn.WithDescribers(knative.NewDescriber(verbose), k8s.NewDescriber(verbose)),
53-
fn.WithListers(knative.NewLister(verbose), k8s.NewLister(verbose)),
54-
fn.WithRemovers(knative.NewRemover(verbose), k8s.NewRemover(verbose)),
52+
fn.WithDescribers(knative.NewDescriber(verbose), k8s.NewDescriber(verbose), keda.NewDescriber(verbose)),
53+
fn.WithListers(knative.NewLister(verbose), k8s.NewLister(verbose), keda.NewLister(verbose)),
54+
fn.WithRemovers(knative.NewRemover(verbose), k8s.NewRemover(verbose), keda.NewRemover(verbose)),
5555
fn.WithPipelinesProvider(tekton.NewPipelinesProvider(tekton.WithCredentialsProvider(testCP), tekton.WithVerbose(verbose))),
5656
}
57+
58+
switch deployer {
59+
case k8s.KubernetesDeployerName:
60+
baseOpts = append(baseOpts, fn.WithDeployer(k8s.NewDeployer(k8s.WithDeployerVerbose(verbose))))
61+
case keda.KedaDeployerName:
62+
baseOpts = append(baseOpts, fn.WithDeployer(keda.NewDeployer(keda.WithDeployerVerbose(verbose))))
63+
case knative.KnativeDeployerName:
64+
baseOpts = append(baseOpts, fn.WithDeployer(knative.NewDeployer(knative.WithDeployerVerbose(verbose))))
65+
}
66+
5767
return fn.New(append(baseOpts, opts...)...)
5868
}
5969

6070
// assertFunctionEchoes returns without error when the function of the given
6171
// name echoes a parameter sent via a Get request.
62-
func assertFunctionEchoes(url string) (err error) {
72+
func assertFunctionEchoes(httpClient *http.Client, url string) (err error) {
6373
token := time.Now().Format("20060102150405.000000000")
6474

65-
// res, err := http.Get("http://testremote-default.default.localtest.me?token=" + token)
66-
res, err := http.Get(url + "?token=" + token)
75+
res, err := httpClient.Get(url + "?token=" + token)
6776
if err != nil {
6877
return
6978
}
@@ -82,6 +91,28 @@ func assertFunctionEchoes(url string) (err error) {
8291
return
8392
}
8493

94+
// httpClientForDeployer returns an HTTP client appropriate for the deployer type.
95+
// Raw and keda deployers expose cluster-internal services, so an in-cluster
96+
// dialer is needed. Knative services are externally accessible via ingress.
97+
func httpClientForDeployer(t *testing.T, ctx context.Context, deployer string) *http.Client {
98+
switch deployer {
99+
case k8s.KubernetesDeployerName, keda.KedaDeployerName:
100+
dialer, err := k8s.NewInClusterDialer(ctx, k8s.GetClientConfig())
101+
if err != nil {
102+
t.Fatalf("failed to create in-cluster dialer: %v", err)
103+
}
104+
t.Cleanup(func() { _ = dialer.Close() })
105+
return &http.Client{
106+
Transport: &http.Transport{
107+
DialContext: dialer.DialContext,
108+
},
109+
Timeout: time.Minute,
110+
}
111+
default:
112+
return http.DefaultClient
113+
}
114+
}
115+
85116
func tektonTestsEnabled(t *testing.T) (enabled bool) {
86117
enabled, _ = strconv.ParseBool(os.Getenv("FUNC_INT_TEKTON_ENABLED"))
87118
if !enabled {
@@ -114,41 +145,51 @@ func TestInt_Remote_Default(t *testing.T) {
114145
t.Skip()
115146
}
116147
skipOnUnsupportedArch(t)
117-
_ = fromCleanEnvironment(t)
118-
var (
119-
err error
120-
url string
121-
verbose = false
122-
ctx, cancel = signal.NotifyContext(t.Context(), os.Interrupt)
123-
client = newRemoteTestClient(verbose,
124-
fn.WithRepository("https://github.com/functions-dev/templates"))
125-
)
126-
defer cancel()
127-
128-
f := fn.Function{
129-
Name: "testremote-default",
130-
Runtime: "go",
131-
Template: "echo",
132-
Registry: TestRegistry,
133-
Namespace: TestNamespace,
134-
Build: fn.BuildSpec{
135-
Builder: "pack", // TODO: test "s2i". Currently it causes a 'no space left on device' error in GH actions.
136-
},
137-
}
138148

139-
if f, err = client.Init(f); err != nil {
140-
t.Fatal(err)
141-
}
142-
143-
if url, f, err = client.RunPipeline(ctx, f); err != nil {
144-
t.Fatal(err)
145-
}
146-
defer func() {
147-
_ = client.Remove(ctx, "", "", f, true)
148-
}()
149-
150-
if err := assertFunctionEchoes(url); err != nil {
151-
t.Fatal(err)
149+
for _, d := range []string{knative.KnativeDeployerName, k8s.KubernetesDeployerName, keda.KedaDeployerName} {
150+
t.Run(d, func(t *testing.T) {
151+
_ = fromCleanEnvironment(t)
152+
var (
153+
err error
154+
url string
155+
verbose = false
156+
ctx, cancel = signal.NotifyContext(t.Context(), os.Interrupt)
157+
client = newRemoteTestClient(verbose, d,
158+
fn.WithRepository("https://github.com/functions-dev/templates"))
159+
)
160+
defer cancel()
161+
162+
f := fn.Function{
163+
Name: "testremote-default",
164+
Runtime: "go",
165+
Template: "echo",
166+
Registry: TestRegistry,
167+
Namespace: TestNamespace,
168+
Build: fn.BuildSpec{
169+
Builder: "pack", // TODO: test "s2i". Currently it causes a 'no space left on device' error in GH actions.
170+
},
171+
Deploy: fn.DeploySpec{
172+
Deployer: d,
173+
},
174+
}
175+
176+
if f, err = client.Init(f); err != nil {
177+
t.Fatal(err)
178+
}
179+
180+
if url, f, err = client.RunPipeline(ctx, f); err != nil {
181+
t.Fatal(err)
182+
}
183+
defer func() {
184+
_ = client.Remove(ctx, "", "", f, true)
185+
}()
186+
187+
httpClient := httpClientForDeployer(t, ctx, d)
188+
189+
if err := assertFunctionEchoes(httpClient, url); err != nil {
190+
t.Fatal(err)
191+
}
192+
})
152193
}
153194
}
154195

pkg/pipelines/tekton/pipelines_provider.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
fn "knative.dev/func/pkg/functions"
3232
"knative.dev/func/pkg/k8s"
3333
fnlabels "knative.dev/func/pkg/k8s/labels"
34+
"knative.dev/func/pkg/keda"
3435
"knative.dev/func/pkg/knative"
3536
"knative.dev/func/pkg/oci"
3637
"knative.dev/pkg/apis"
@@ -236,27 +237,33 @@ func (pp *PipelinesProvider) Run(ctx context.Context, f fn.Function) (string, fn
236237
return "", f, fmt.Errorf("function pipeline run has failed with message: \n\n%s", message)
237238
}
238239

239-
kClient, err := knative.NewServingClient(namespace)
240-
if err != nil {
241-
return "", f, fmt.Errorf("problem in retrieving status of deployed function: %v", err)
240+
var describer fn.Describer
241+
switch f.Deploy.Deployer {
242+
case k8s.KubernetesDeployerName:
243+
describer = k8s.NewDescriber(false)
244+
case keda.KedaDeployerName:
245+
describer = keda.NewDescriber(false)
246+
default:
247+
// default to knative
248+
describer = knative.NewDescriber(false)
242249
}
243250

244-
ksvc, err := kClient.GetService(ctx, f.Name)
251+
obj, err := describer.Describe(ctx, f.Name, f.Namespace)
245252
if err != nil {
246253
return "", f, fmt.Errorf("problem in retrieving status of deployed function: %v", err)
247254
}
248255

249-
if ksvc.Generation == 1 {
250-
fmt.Fprintf(os.Stderr, "✅ Function deployed in namespace %q and exposed at URL: \n %s\n", ksvc.Namespace, ksvc.Status.URL.String())
256+
if obj.Generation == 1 {
257+
fmt.Fprintf(os.Stderr, "✅ Function deployed in namespace %q and exposed at URL: \n %s\n", obj.Namespace, obj.Route)
251258
} else {
252-
fmt.Fprintf(os.Stderr, "✅ Function updated in namespace %q and exposed at URL: \n %s\n", ksvc.Namespace, ksvc.Status.URL.String())
259+
fmt.Fprintf(os.Stderr, "✅ Function updated in namespace %q and exposed at URL: \n %s\n", obj.Namespace, obj.Route)
253260
}
254261

255-
if ksvc.Namespace != namespace {
256-
fmt.Fprintf(os.Stderr, "Warning: Final ksvc namespace %q does not match expected %q", ksvc.Namespace, namespace)
262+
if obj.Namespace != namespace {
263+
fmt.Fprintf(os.Stderr, "Warning: Final function namespace %q does not match expected %q", obj.Namespace, namespace)
257264
}
258265

259-
return ksvc.Status.URL.String(), f, nil
266+
return obj.Route, f, nil
260267
}
261268

262269
// Creates tar stream with the function sources as they were in "./source" directory.

0 commit comments

Comments
 (0)