Skip to content

Commit 79b3af7

Browse files
committed
feat(snc): add serverless profiles for Knative Serving and Eventing
Add three serverless profiles: - serverless-serving: installs OpenShift Serverless operator and KnativeServing - serverless-eventing: installs OpenShift Serverless operator and KnativeEventing - serverless: installs OpenShift Serverless operator with both KnativeServing and KnativeEventing Extract shared deployServerlessOperator helper so the operator is installed once and reused across profiles. Move all profile code into a dedicated profile subpackage (pkg/target/service/snc/profile/) for better modularity.
1 parent c283c05 commit 79b3af7

10 files changed

Lines changed: 346 additions & 79 deletions

File tree

cmd/mapt/cmd/aws/services/snc.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
maptContext "github.com/redhat-developer/mapt/pkg/manager/context"
66
openshiftsnc "github.com/redhat-developer/mapt/pkg/provider/aws/action/snc"
77
sncApi "github.com/redhat-developer/mapt/pkg/target/service/snc"
8+
"github.com/redhat-developer/mapt/pkg/target/service/snc/profile"
89
"github.com/spf13/cobra"
910
"github.com/spf13/pflag"
1011
"github.com/spf13/viper"
@@ -24,7 +25,7 @@ const (
2425
disableClusterReadinessDesc = "If this flag is set it will skip the checks for the cluster readiness. In this case the kubeconfig can not be generated"
2526

2627
sncProfile = "profile"
27-
sncProfileDesc = "comma separated list of profiles to apply on the SNC cluster. Profiles available: virtualization"
28+
sncProfileDesc = "comma separated list of profiles to apply on the SNC cluster. Profiles available: virtualization, serverless-serving, serverless-eventing, serverless"
2829
)
2930

3031
func GetOpenshiftSNCCmd() *cobra.Command {
@@ -59,7 +60,7 @@ func createSNC() *cobra.Command {
5960
}
6061
profiles := viper.GetStringSlice(sncProfile)
6162
computeReq := params.ComputeRequestArgs()
62-
if sncApi.ProfilesRequireNestedVirt(profiles) {
63+
if profile.RequireNestedVirt(profiles) {
6364
computeReq.NestedVirt = true
6465
}
6566
if _, err := openshiftsnc.Create(

docs/aws/openshift-snc.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,16 @@ mapt aws openshift-snc create \
6262
--profile virtualization
6363
```
6464

65-
Multiple profiles can be specified as a comma-separated list (e.g., `--profile virtualization,serverless`).
65+
Multiple profiles can be specified as a comma-separated list (e.g., `--profile virtualization,serverless-serving`).
6666

6767
### Available profiles
6868

6969
| Profile | Description |
7070
|---------|-------------|
7171
| `virtualization` | Installs [OpenShift Virtualization](https://docs.openshift.com/container-platform/latest/virt/about_virt/about-virt.html) (CNV) on the cluster, enabling virtual machines to run on the single-node cluster. When this profile is selected, nested virtualization is automatically enabled on the cloud instance. Because standard Nitro-based instances do not expose `/dev/kvm`, a bare metal instance is required.|
72+
| `serverless-serving` | Installs [OpenShift Serverless](https://docs.openshift.com/serverless/latest/about/about-serverless.html) and creates a KnativeServing instance, enabling serverless workloads (Knative Serving) on the cluster.|
73+
| `serverless-eventing` | Installs [OpenShift Serverless](https://docs.openshift.com/serverless/latest/about/about-serverless.html) and creates a KnativeEventing instance, enabling event-driven workloads (Knative Eventing) on the cluster.|
74+
| `serverless` | Installs [OpenShift Serverless](https://docs.openshift.com/serverless/latest/about/about-serverless.html) and creates both KnativeServing and KnativeEventing instances.|
7275

7376

7477
### Adding new profiles

pkg/provider/aws/action/snc/snc.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/redhat-developer/mapt/pkg/provider/util/command"
2929
"github.com/redhat-developer/mapt/pkg/provider/util/security"
3030
apiSNC "github.com/redhat-developer/mapt/pkg/target/service/snc"
31+
"github.com/redhat-developer/mapt/pkg/target/service/snc/profile"
3132
"github.com/redhat-developer/mapt/pkg/util"
3233
"github.com/redhat-developer/mapt/pkg/util/logging"
3334
resourcesUtil "github.com/redhat-developer/mapt/pkg/util/resources"
@@ -65,7 +66,7 @@ func Create(mCtxArgs *mc.ContextArgs, args *apiSNC.SNCArgs) (_ *apiSNC.SNCResult
6566
return nil, err
6667
}
6768
// Validate profiles
68-
if err := apiSNC.ValidateProfiles(args.Profiles); err != nil {
69+
if err := profile.Validate(args.Profiles); err != nil {
6970
return nil, err
7071
}
7172
// Compose request
@@ -266,18 +267,16 @@ func (r *openshiftSNCRequest) deploy(ctx *pulumi.Context) error {
266267
pulumi.ToSecret(kubeconfig))
267268
// Deploy profiles using Kubernetes provider
268269
if len(r.profiles) > 0 {
269-
k8sProvider, err := apiSNC.NewK8sProvider(ctx, "k8s-provider", kubeconfig)
270+
k8sProvider, err := profile.NewK8sProvider(ctx, "k8s-provider", kubeconfig)
270271
if err != nil {
271272
return err
272273
}
273-
for _, profileName := range r.profiles {
274-
if _, err := apiSNC.DeployProfile(ctx, profileName, &apiSNC.ProfileDeployArgs{
275-
K8sProvider: k8sProvider,
276-
Kubeconfig: kubeconfig,
277-
Prefix: *r.prefix,
278-
}); err != nil {
279-
return err
280-
}
274+
if err := profile.Deploy(ctx, r.profiles, &profile.DeployArgs{
275+
K8sProvider: k8sProvider,
276+
Kubeconfig: kubeconfig,
277+
Prefix: *r.prefix,
278+
}); err != nil {
279+
return err
281280
}
282281
}
283282
return nil
Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
package snc
1+
package profile
22

33
import (
44
"context"
55
"fmt"
66
"strings"
77
"time"
88

9-
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
10-
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
119
logging "github.com/redhat-developer/mapt/pkg/util/logging"
1210
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1311
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -16,13 +14,6 @@ import (
1614
"k8s.io/client-go/tools/clientcmd"
1715
)
1816

19-
// NewK8sProvider creates a Pulumi Kubernetes provider from a kubeconfig string output.
20-
func NewK8sProvider(ctx *pulumi.Context, name string, kubeconfig pulumi.StringOutput) (*kubernetes.Provider, error) {
21-
return kubernetes.NewProvider(ctx, name, &kubernetes.ProviderArgs{
22-
Kubeconfig: kubeconfig,
23-
})
24-
}
25-
2617
// waitForCRCondition polls a custom resource until a nested field matches the expected value.
2718
// jsonPath is a dot-separated path into the object (e.g. "status.phase" or
2819
// "status.conditions[?(@.type==\"Available\")].status") but here we use explicit
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package profile
2+
3+
import (
4+
"fmt"
5+
"slices"
6+
7+
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
8+
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
9+
)
10+
11+
const (
12+
ProfileVirtualization = "virtualization"
13+
ProfileServerlessServing = "serverless-serving"
14+
ProfileServerlessEventing = "serverless-eventing"
15+
ProfileServerless = "serverless"
16+
)
17+
18+
// validProfiles is the single source of truth for supported profile names.
19+
var validProfiles = []string{ProfileVirtualization, ProfileServerlessServing, ProfileServerlessEventing, ProfileServerless}
20+
21+
// DeployArgs holds the arguments needed by a profile to deploy
22+
// its resources on the SNC cluster.
23+
type DeployArgs struct {
24+
K8sProvider *kubernetes.Provider
25+
Kubeconfig pulumi.StringOutput
26+
Prefix string
27+
Deps []pulumi.Resource
28+
}
29+
30+
// Validate checks that all requested profiles are supported.
31+
func Validate(profiles []string) error {
32+
for _, p := range profiles {
33+
if !slices.Contains(validProfiles, p) {
34+
return fmt.Errorf("profile %q is not supported for SNC. Supported profiles: %v", p, validProfiles)
35+
}
36+
}
37+
return nil
38+
}
39+
40+
// Deploy deploys all requested profiles on the SNC cluster.
41+
// It ensures shared dependencies (e.g. the Serverless operator) are only
42+
// installed once, even when multiple serverless profiles are requested.
43+
func Deploy(ctx *pulumi.Context, profiles []string, args *DeployArgs) error {
44+
needServing := false
45+
needEventing := false
46+
47+
for _, p := range profiles {
48+
switch p {
49+
case ProfileVirtualization:
50+
if _, err := deployVirtualization(ctx, args); err != nil {
51+
return err
52+
}
53+
case ProfileServerlessServing:
54+
needServing = true
55+
case ProfileServerlessEventing:
56+
needEventing = true
57+
case ProfileServerless:
58+
needServing = true
59+
needEventing = true
60+
default:
61+
return fmt.Errorf("profile %q has no deploy function", p)
62+
}
63+
}
64+
65+
if needServing || needEventing {
66+
operatorReady, err := deployServerlessOperator(ctx, args)
67+
if err != nil {
68+
return err
69+
}
70+
if needServing {
71+
if _, err := deployKnativeServing(ctx, args, operatorReady); err != nil {
72+
return err
73+
}
74+
}
75+
if needEventing {
76+
if _, err := deployKnativeEventing(ctx, args, operatorReady); err != nil {
77+
return err
78+
}
79+
}
80+
}
81+
82+
return nil
83+
}
84+
85+
// RequireNestedVirt returns true if any of the given profiles
86+
// requires nested virtualization on the compute instance.
87+
func RequireNestedVirt(profiles []string) bool {
88+
return slices.Contains(profiles, ProfileVirtualization)
89+
}
90+
91+
// NewK8sProvider creates a Pulumi Kubernetes provider from a kubeconfig string output.
92+
func NewK8sProvider(ctx *pulumi.Context, name string, kubeconfig pulumi.StringOutput) (*kubernetes.Provider, error) {
93+
return kubernetes.NewProvider(ctx, name, &kubernetes.ProviderArgs{
94+
Kubeconfig: kubeconfig,
95+
})
96+
}

0 commit comments

Comments
 (0)