Skip to content

Commit 360527f

Browse files
Amos Mastbaumclaude
andcommitted
feat(openshift): add standalone RHOAI deployment on any OCP cluster
Extract the profile system (RHOAI, ServiceMesh, Serverless, etc.) from pkg/target/service/snc/profile/ into pkg/provider/openshift/profile/ so it can be used independently of SNC. The profile code had zero SNC dependencies — only the package path coupled it. Add new `mapt openshift rhoai create/destroy` command that deploys RHOAI on any existing OpenShift cluster given a kubeconfig path. This supports the AIPCC-19537 epic for RHAII integration testing on stable RHOAI. Usage: mapt openshift rhoai create --kubeconfig <path> --project-name <name> --backed-url <url> mapt openshift rhoai destroy --project-name <name> --backed-url <url> Profiles default to "ai" which installs the full RHOAI stack (ServiceMesh v2, Serverless, RHOAI operator, DataScienceCluster with KServe). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 20fee32 commit 360527f

17 files changed

Lines changed: 274 additions & 4 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
maptContext "github.com/redhat-developer/mapt/pkg/manager/context"
77
openshiftsnc "github.com/redhat-developer/mapt/pkg/provider/aws/action/snc"
88
sncApi "github.com/redhat-developer/mapt/pkg/target/service/snc"
9-
"github.com/redhat-developer/mapt/pkg/target/service/snc/profile"
9+
"github.com/redhat-developer/mapt/pkg/provider/openshift/profile"
1010
"github.com/spf13/cobra"
1111
"github.com/spf13/pflag"
1212
"github.com/spf13/viper"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package openshift
2+
3+
import (
4+
params "github.com/redhat-developer/mapt/cmd/mapt/cmd/params"
5+
"github.com/spf13/cobra"
6+
"github.com/spf13/pflag"
7+
"github.com/spf13/viper"
8+
)
9+
10+
const (
11+
cmd = "openshift"
12+
cmdDesc = "operations on existing OpenShift clusters"
13+
)
14+
15+
func GetCmd() *cobra.Command {
16+
c := &cobra.Command{
17+
Use: cmd,
18+
Short: cmdDesc,
19+
RunE: func(cmd *cobra.Command, args []string) error {
20+
if err := viper.BindPFlags(cmd.Flags()); err != nil {
21+
return err
22+
}
23+
return nil
24+
},
25+
}
26+
27+
flagSet := pflag.NewFlagSet(cmd, pflag.ExitOnError)
28+
params.AddCommonFlags(flagSet)
29+
c.PersistentFlags().AddFlagSet(flagSet)
30+
31+
c.AddCommand(getRHOAICmd())
32+
return c
33+
}

cmd/mapt/cmd/openshift/rhoai.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package openshift
2+
3+
import (
4+
params "github.com/redhat-developer/mapt/cmd/mapt/cmd/params"
5+
maptContext "github.com/redhat-developer/mapt/pkg/manager/context"
6+
rhoaiAction "github.com/redhat-developer/mapt/pkg/provider/openshift/action/rhoai"
7+
"github.com/spf13/cobra"
8+
"github.com/spf13/pflag"
9+
"github.com/spf13/viper"
10+
)
11+
12+
const (
13+
cmdRHOAI = "rhoai"
14+
cmdRHOAIDesc = "deploy Red Hat OpenShift AI on an existing OpenShift cluster"
15+
16+
kubeconfig = "kubeconfig"
17+
kubeconfigDesc = "path to the kubeconfig file for the target OpenShift cluster"
18+
19+
rhoaiProfile = "profile"
20+
rhoaiProfileDesc = "profiles to deploy (ai, virtualization, serverless-serving, serverless-eventing, serverless, servicemesh, nvidia)"
21+
)
22+
23+
func getRHOAICmd() *cobra.Command {
24+
c := &cobra.Command{
25+
Use: cmdRHOAI,
26+
Short: cmdRHOAIDesc,
27+
RunE: func(cmd *cobra.Command, args []string) error {
28+
if err := viper.BindPFlags(cmd.Flags()); err != nil {
29+
return err
30+
}
31+
return nil
32+
},
33+
}
34+
c.AddCommand(createRHOAI(), destroyRHOAI())
35+
return c
36+
}
37+
38+
func createRHOAI() *cobra.Command {
39+
c := &cobra.Command{
40+
Use: params.CreateCmdName,
41+
Short: params.CreateCmdName,
42+
RunE: func(cmd *cobra.Command, args []string) error {
43+
if err := viper.BindPFlags(cmd.Flags()); err != nil {
44+
return err
45+
}
46+
if err := viper.BindPFlags(cmd.InheritedFlags()); err != nil {
47+
return err
48+
}
49+
profiles := viper.GetStringSlice(rhoaiProfile)
50+
if len(profiles) == 0 {
51+
profiles = []string{"ai"}
52+
}
53+
return rhoaiAction.Create(
54+
&maptContext.ContextArgs{
55+
Context: cmd.Context(),
56+
ProjectName: viper.GetString(params.ProjectName),
57+
BackedURL: viper.GetString(params.BackedURL),
58+
Debug: viper.IsSet(params.Debug),
59+
DebugLevel: viper.GetUint(params.DebugLevel),
60+
Tags: viper.GetStringMapString(params.Tags),
61+
},
62+
&rhoaiAction.RHOAIArgs{
63+
KubeconfigPath: viper.GetString(kubeconfig),
64+
Profiles: profiles,
65+
})
66+
},
67+
}
68+
flagSet := pflag.NewFlagSet(params.CreateCmdName, pflag.ExitOnError)
69+
flagSet.StringP(kubeconfig, "", "", kubeconfigDesc)
70+
flagSet.StringSliceP(rhoaiProfile, "", []string{}, rhoaiProfileDesc)
71+
flagSet.StringToStringP(params.Tags, "", nil, params.TagsDesc)
72+
c.PersistentFlags().AddFlagSet(flagSet)
73+
_ = c.MarkFlagRequired(kubeconfig)
74+
return c
75+
}
76+
77+
func destroyRHOAI() *cobra.Command {
78+
c := &cobra.Command{
79+
Use: params.DestroyCmdName,
80+
Short: params.DestroyCmdName,
81+
RunE: func(cmd *cobra.Command, args []string) error {
82+
if err := viper.BindPFlags(cmd.Flags()); err != nil {
83+
return err
84+
}
85+
if err := viper.BindPFlags(cmd.InheritedFlags()); err != nil {
86+
return err
87+
}
88+
return rhoaiAction.Destroy(&maptContext.ContextArgs{
89+
Context: cmd.Context(),
90+
ProjectName: viper.GetString(params.ProjectName),
91+
BackedURL: viper.GetString(params.BackedURL),
92+
Debug: viper.IsSet(params.Debug),
93+
DebugLevel: viper.GetUint(params.DebugLevel),
94+
ForceDestroy: viper.IsSet(params.ForceDestroy),
95+
KeepState: viper.IsSet(params.KeepState),
96+
})
97+
},
98+
}
99+
flagSet := pflag.NewFlagSet(params.DestroyCmdName, pflag.ExitOnError)
100+
flagSet.Bool(params.ForceDestroy, false, params.ForceDestroyDesc)
101+
flagSet.Bool(params.KeepState, false, params.KeepStateDesc)
102+
c.PersistentFlags().AddFlagSet(flagSet)
103+
return c
104+
}

cmd/mapt/cmd/root.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/redhat-developer/mapt/cmd/mapt/cmd/aws"
77
"github.com/redhat-developer/mapt/cmd/mapt/cmd/azure"
88
"github.com/redhat-developer/mapt/cmd/mapt/cmd/ibmcloud"
9+
"github.com/redhat-developer/mapt/cmd/mapt/cmd/openshift"
910
"github.com/redhat-developer/mapt/cmd/mapt/cmd/params"
1011
"github.com/redhat-developer/mapt/pkg/util/logging"
1112
"github.com/spf13/cobra"
@@ -63,7 +64,8 @@ func init() {
6364
rootCmd.AddCommand(
6465
aws.GetCmd(),
6566
azure.GetCmd(),
66-
ibmcloud.GetCmd())
67+
ibmcloud.GetCmd(),
68+
openshift.GetCmd())
6769
}
6870

6971
func Execute() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +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"
31+
"github.com/redhat-developer/mapt/pkg/provider/openshift/profile"
3232
"github.com/redhat-developer/mapt/pkg/util"
3333
"github.com/redhat-developer/mapt/pkg/util/logging"
3434
resourcesUtil "github.com/redhat-developer/mapt/pkg/util/resources"
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package rhoai
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
8+
"github.com/redhat-developer/mapt/pkg/manager"
9+
mc "github.com/redhat-developer/mapt/pkg/manager/context"
10+
"github.com/redhat-developer/mapt/pkg/provider/openshift"
11+
"github.com/redhat-developer/mapt/pkg/provider/openshift/profile"
12+
"github.com/redhat-developer/mapt/pkg/util/logging"
13+
)
14+
15+
const (
16+
StackName = "stackOpenshiftRHOAI"
17+
defaultPrefix = "rhoai"
18+
)
19+
20+
type RHOAIArgs struct {
21+
KubeconfigPath string
22+
Profiles []string
23+
Prefix string
24+
}
25+
26+
type rhoaiRequest struct {
27+
mCtx *mc.Context
28+
prefix string
29+
kubeconfigPath string
30+
profiles []string
31+
}
32+
33+
func Create(mCtxArgs *mc.ContextArgs, args *RHOAIArgs) error {
34+
mCtx, err := mc.Init(mCtxArgs, openshift.Provider())
35+
if err != nil {
36+
return err
37+
}
38+
if err := profile.Validate(args.Profiles); err != nil {
39+
return err
40+
}
41+
prefix := args.Prefix
42+
if prefix == "" {
43+
prefix = defaultPrefix
44+
}
45+
r := &rhoaiRequest{
46+
mCtx: mCtx,
47+
prefix: prefix,
48+
kubeconfigPath: args.KubeconfigPath,
49+
profiles: args.Profiles,
50+
}
51+
return r.deploy()
52+
}
53+
54+
func Destroy(mCtxArgs *mc.ContextArgs) error {
55+
logging.Debug("Run openshift rhoai destroy")
56+
mCtx, err := mc.Init(mCtxArgs, openshift.Provider())
57+
if err != nil {
58+
return err
59+
}
60+
return openshift.DestroyStack(mCtx, StackName)
61+
}
62+
63+
func (r *rhoaiRequest) deploy() error {
64+
cs := manager.Stack{
65+
StackName: r.mCtx.StackNameByProject(StackName),
66+
ProjectName: r.mCtx.ProjectName(),
67+
BackedURL: r.mCtx.BackedURL(),
68+
ProviderCredentials: openshift.NoCredentials,
69+
DeployFunc: r.pulumiProgram,
70+
}
71+
_, err := manager.UpStack(r.mCtx, cs)
72+
if err != nil {
73+
return fmt.Errorf("stack creation failed: %w", err)
74+
}
75+
return nil
76+
}
77+
78+
func (r *rhoaiRequest) pulumiProgram(ctx *pulumi.Context) error {
79+
kcBytes, err := os.ReadFile(r.kubeconfigPath)
80+
if err != nil {
81+
return fmt.Errorf("reading kubeconfig from %s: %w", r.kubeconfigPath, err)
82+
}
83+
kubeconfig := pulumi.String(string(kcBytes)).ToStringOutput()
84+
85+
k8sProvider, err := profile.NewK8sProvider(ctx, "k8s-provider", kubeconfig)
86+
if err != nil {
87+
return err
88+
}
89+
90+
return profile.Deploy(ctx, r.profiles, &profile.DeployArgs{
91+
K8sProvider: k8sProvider,
92+
Kubeconfig: kubeconfig,
93+
Prefix: r.prefix,
94+
})
95+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package openshift
2+
3+
import (
4+
"context"
5+
6+
"github.com/redhat-developer/mapt/pkg/manager"
7+
mc "github.com/redhat-developer/mapt/pkg/manager/context"
8+
"github.com/redhat-developer/mapt/pkg/manager/credentials"
9+
)
10+
11+
type OpenShift struct{}
12+
13+
func (o *OpenShift) Init(_ context.Context, _ string) (string, error) {
14+
return "", nil
15+
}
16+
17+
func (o *OpenShift) DefaultHostingPlace() (*string, error) {
18+
return nil, nil
19+
}
20+
21+
func Provider() *OpenShift {
22+
return &OpenShift{}
23+
}
24+
25+
var NoCredentials = credentials.ProviderCredentials{}
26+
27+
func DestroyStack(mCtx *mc.Context, stackName string) error {
28+
return manager.DestroyStack(
29+
mCtx,
30+
manager.Stack{
31+
StackName: mCtx.StackNameByProject(stackName),
32+
ProjectName: mCtx.ProjectName(),
33+
BackedURL: mCtx.BackedURL(),
34+
ProviderCredentials: NoCredentials,
35+
})
36+
}

0 commit comments

Comments
 (0)