diff --git a/cmd/crossplane/core/core.go b/cmd/crossplane/core/core.go index b486b654322..3e8097b4cbf 100644 --- a/cmd/crossplane/core/core.go +++ b/cmd/crossplane/core/core.go @@ -107,7 +107,8 @@ type startCommand struct { XpkgCacheDir string `aliases:"cache-dir" default:"/cache/xpkg" env:"XPKG_CACHE_DIR,CACHE_DIR" help:"Directory used for caching package images." short:"c"` - PackageRuntime string `default:"Deployment" env:"PACKAGE_RUNTIME" help:"The package runtime to use for packages with a runtime (e.g. Providers and Functions)" placeholder:"runtime | runtime1=package1;runtime2=package2"` + PackageRuntime string `default:"Deployment" env:"PACKAGE_RUNTIME" help:"The package runtime to use for packages with a runtime (e.g. Providers and Functions)" placeholder:"runtime | runtime1=package1;runtime2=package2"` + FunctionEndpointSuffix string `env:"FUNCTION_ENDPOINT_SUFFIX" help:"DNS suffix appended to function service endpoints."` SyncInterval time.Duration `default:"1h" help:"How often all resources will be double-checked for drift from the desired state." short:"s"` PollInterval time.Duration `default:"1m" help:"How often individual resources will be checked for drift from the desired state."` @@ -654,6 +655,7 @@ func (c *startCommand) Run(s *runtime.Scheme, log logging.Logger) error { //noli ServiceAccount: c.ServiceAccount, PackageRuntime: pr, MaxConcurrentPackageEstablishers: c.MaxConcurrentPackageEstablishers, + FunctionEndpointSuffix: c.FunctionEndpointSuffix, } if err := pkg.Setup(mgr, po); err != nil { diff --git a/internal/controller/pkg/controller/options.go b/internal/controller/pkg/controller/options.go index 5682921bbe1..276c0fe85f9 100644 --- a/internal/controller/pkg/controller/options.go +++ b/internal/controller/pkg/controller/options.go @@ -42,4 +42,6 @@ type Options struct { // MaxConcurrentPackageEstablishers is the maximum number of goroutines to use // for establishing Providers, Configurations and Functions. MaxConcurrentPackageEstablishers int + + FunctionEndpointSuffix string } diff --git a/internal/controller/pkg/runtime/reconciler.go b/internal/controller/pkg/runtime/reconciler.go index 8741d9dd75b..0458bfe3d74 100644 --- a/internal/controller/pkg/runtime/reconciler.go +++ b/internal/controller/pkg/runtime/reconciler.go @@ -220,7 +220,7 @@ func SetupFunctionRevision(mgr ctrl.Manager, o controller.Options) error { WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name), o.EventFilterFunctions...)), //nolint:staticcheck // TODO(adamwg) Update crossplane-runtime to the new events API. WithNamespace(o.Namespace), WithServiceAccount(o.ServiceAccount), - WithRuntimeHooks(NewFunctionHooks(mgr.GetClient())), + WithRuntimeHooks(NewFunctionHooks(mgr.GetClient(), o.FunctionEndpointSuffix)), WithFeatureFlags(o.Features), WithConfigStore(xpkg.NewImageConfigStore(mgr.GetClient(), o.Namespace)), ) diff --git a/internal/controller/pkg/runtime/runtime_function.go b/internal/controller/pkg/runtime/runtime_function.go index af8ac958780..85912fde755 100644 --- a/internal/controller/pkg/runtime/runtime_function.go +++ b/internal/controller/pkg/runtime/runtime_function.go @@ -48,16 +48,18 @@ const ( // FunctionHooks performs runtime operations for function packages. type FunctionHooks struct { - client resource.ClientApplicator + client resource.ClientApplicator + endpointSuffix string } // NewFunctionHooks returns a new FunctionHooks. -func NewFunctionHooks(client client.Client) *FunctionHooks { +func NewFunctionHooks(client client.Client, endpointSuffix string) *FunctionHooks { return &FunctionHooks{ client: resource.ClientApplicator{ Client: client, Applicator: resource.NewAPIPatchingApplicator(client), }, + endpointSuffix: endpointSuffix, } } @@ -101,15 +103,24 @@ func (h *FunctionHooks) Pre(ctx context.Context, pr v1.PackageRevisionWithRuntim return errors.Errorf("cannot apply function package hooks to %T", pr) } - fRev.Status.Endpoint = fmt.Sprintf(ServiceEndpointFmt, svc.Name, svc.Namespace, GRPCPort) + if h.endpointSuffix != "" { + fRev.Status.Endpoint = fmt.Sprintf(ServiceEndpointFmt, svc.Name, svc.Namespace+"."+h.endpointSuffix, GRPCPort) + } else { + fRev.Status.Endpoint = fmt.Sprintf(ServiceEndpointFmt, svc.Name, svc.Namespace, GRPCPort) + } secServer := build.TLSServerSecret() if err := h.client.Applicator.Apply(ctx, secServer); err != nil { return errors.Wrap(err, errApplyFunctionSecret) } + dnsNames := initializer.DNSNamesForService(svc.Name, svc.Namespace) + if h.endpointSuffix != "" { + dnsNames = append(dnsNames, svc.Name+"."+svc.Namespace+"."+h.endpointSuffix) + } + if err := initializer.NewTLSCertificateGenerator(secServer.Namespace, initializer.RootCACertSecretName, - initializer.TLSCertificateGeneratorWithServerSecretName(secServer.GetName(), initializer.DNSNamesForService(svc.Name, svc.Namespace)), + initializer.TLSCertificateGeneratorWithServerSecretName(secServer.GetName(), dnsNames), initializer.TLSCertificateGeneratorWithOwner([]metav1.OwnerReference{meta.AsController(meta.TypedReferenceTo(pr, pr.GetObjectKind().GroupVersionKind()))})).Run(ctx, h.client.Client); err != nil { return errors.Wrapf(err, "cannot generate TLS certificates for %q", pr.GetLabels()[v1.LabelParentPackage]) } diff --git a/internal/controller/pkg/runtime/runtime_function_test.go b/internal/controller/pkg/runtime/runtime_function_test.go index bfda2c8eb0c..2b7136c3222 100644 --- a/internal/controller/pkg/runtime/runtime_function_test.go +++ b/internal/controller/pkg/runtime/runtime_function_test.go @@ -40,10 +40,11 @@ import ( func TestFunctionPreHook(t *testing.T) { type args struct { - client client.Client - pkg runtime.Object - rev v1.PackageRevisionWithRuntime - manifests ManifestBuilder + client client.Client + pkg runtime.Object + rev v1.PackageRevisionWithRuntime + manifests ManifestBuilder + endpointSuffix string } type want struct { @@ -115,11 +116,71 @@ func TestFunctionPreHook(t *testing.T) { }, }, }, + "SuccessWithEndpointSuffix": { + reason: "Successful run of pre hook with endpoint suffix.", + args: args{ + endpointSuffix: "suffix.example.com", + pkg: &pkgmetav1.Function{ + Spec: pkgmetav1.FunctionSpec{}, + }, + rev: &v1.FunctionRevision{ + Spec: v1.FunctionRevisionSpec{ + PackageRevisionSpec: v1.PackageRevisionSpec{ + DesiredState: v1.PackageRevisionActive, + }, + PackageRevisionRuntimeSpec: v1.PackageRevisionRuntimeSpec{ + TLSServerSecretName: ptr.To("some-server-secret"), + }, + }, + }, + manifests: &MockManifestBuilder{ + ServiceFn: func(_ ...ServiceOverride) *corev1.Service { + return &corev1.Service{} + }, + TLSServerSecretFn: func() *corev1.Secret { + return &corev1.Secret{} + }, + }, + client: &test.MockClient{ + MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error { + if svc, ok := obj.(*corev1.Service); ok { + svc.Name = "some-service" + svc.Namespace = "some-namespace" + } + return nil + }, + MockPatch: func(_ context.Context, _ client.Object, _ client.Patch, _ ...client.PatchOption) error { + return nil + }, + MockUpdate: func(_ context.Context, _ client.Object, _ ...client.UpdateOption) error { + return nil + }, + }, + }, + want: want{ + rev: &v1.FunctionRevision{ + Spec: v1.FunctionRevisionSpec{ + PackageRevisionSpec: v1.PackageRevisionSpec{ + DesiredState: v1.PackageRevisionActive, + }, + PackageRevisionRuntimeSpec: v1.PackageRevisionRuntimeSpec{ + TLSServerSecretName: ptr.To("some-server-secret"), + }, + }, + Status: v1.FunctionRevisionStatus{ + Endpoint: fmt.Sprintf(ServiceEndpointFmt, "some-service", "some-namespace.suffix.example.com", revision.ServicePort), + PackageRevisionRuntimeStatus: v1.PackageRevisionRuntimeStatus{ + TLSServerSecretName: ptr.To("some-server-secret"), + }, + }, + }, + }, + }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { - h := NewFunctionHooks(tc.args.client) + h := NewFunctionHooks(tc.args.client, tc.args.endpointSuffix) err := h.Pre(context.TODO(), tc.args.rev, tc.args.manifests) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { @@ -584,7 +645,7 @@ func TestFunctionPostHook(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { - h := NewFunctionHooks(tc.args.client) + h := NewFunctionHooks(tc.args.client, "") err := h.Post(context.TODO(), tc.args.rev, tc.args.manifests) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { @@ -689,7 +750,7 @@ func TestFunctionDeactivateHook(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { - h := NewFunctionHooks(tc.args.client) + h := NewFunctionHooks(tc.args.client, "") err := h.Deactivate(context.TODO(), tc.args.rev, tc.args.manifests) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {