diff --git a/cmd/mapt/cmd/aws/hosts/fedora.go b/cmd/mapt/cmd/aws/hosts/fedora.go index c35866f4..43bff4b7 100644 --- a/cmd/mapt/cmd/aws/hosts/fedora.go +++ b/cmd/mapt/cmd/aws/hosts/fedora.go @@ -66,14 +66,14 @@ func getFedoraCreate() *cobra.Command { CPUs: viper.GetInt32(params.CPUs), MemoryGib: viper.GetInt32(params.Memory), Arch: util.If(viper.GetString(params.LinuxArch) == "arm64", instancetypes.Arm64, instancetypes.Amd64), - NestedVirt: viper.GetBool(profileSNC) || viper.GetBool(params.NestedVirt), + NestedVirt: viper.GetBool(params.ProfileSNC) || viper.GetBool(params.NestedVirt), } // Run create if err := fedora.Create( &fedora.Request{ Prefix: "main", - Version: viper.GetString(rhelVersion), + Version: viper.GetString(fedoraVersion), Arch: viper.GetString(params.LinuxArch), VMType: viper.GetStringSlice(vmTypes), InstanceRequest: instanceRequest, diff --git a/cmd/mapt/cmd/aws/hosts/rhel.go b/cmd/mapt/cmd/aws/hosts/rhel.go index 23910e74..962f1b75 100644 --- a/cmd/mapt/cmd/aws/hosts/rhel.go +++ b/cmd/mapt/cmd/aws/hosts/rhel.go @@ -16,16 +16,6 @@ import ( const ( cmdRHEL = "rhel" cmdRHELDesc = "manage rhel dedicated host" - - rhelVersion string = "version" - rhelVersionDesc string = "version for the RHEL OS" - rhelVersionDefault string = "9.4" - subsUsername string = "rh-subscription-username" - subsUsernameDesc string = "username to register the subscription" - subsUserpass string = "rh-subscription-password" - subsUserpassDesc string = "password to register the subscription" - profileSNC string = "snc" - profileSNCDesc string = "if this flag is set the RHEL will be setup with SNC profile. Setting up all requirements to run https://github.com/crc-org/snc" ) func GetRHELCmd() *cobra.Command { @@ -73,20 +63,20 @@ func getRHELCreate() *cobra.Command { CPUs: viper.GetInt32(params.CPUs), MemoryGib: viper.GetInt32(params.Memory), Arch: util.If(viper.GetString(params.LinuxArch) == "arm64", instancetypes.Arm64, instancetypes.Amd64), - NestedVirt: viper.GetBool(profileSNC) || viper.GetBool(params.NestedVirt), + NestedVirt: viper.GetBool(params.ProfileSNC) || viper.GetBool(params.NestedVirt), } // Run create if err := rhel.Create( &rhel.Request{ Prefix: "main", - Version: viper.GetString(rhelVersion), + Version: viper.GetString(params.RhelVersion), Arch: viper.GetString(params.LinuxArch), InstanceRequest: instanceRequest, VMType: viper.GetStringSlice(vmTypes), - SubsUsername: viper.GetString(subsUsername), - SubsUserpass: viper.GetString(subsUserpass), - ProfileSNC: viper.IsSet(profileSNC), + SubsUsername: viper.GetString(params.SubsUsername), + SubsUserpass: viper.GetString(params.SubsUserpass), + ProfileSNC: viper.IsSet(params.ProfileSNC), Spot: viper.IsSet(spot), Airgap: viper.IsSet(airgap), SetupGHActionsRunner: viper.IsSet(params.InstallGHActionsRunner), @@ -99,14 +89,14 @@ func getRHELCreate() *cobra.Command { flagSet := pflag.NewFlagSet(params.CreateCmdName, pflag.ExitOnError) flagSet.StringP(params.ConnectionDetailsOutput, "", "", params.ConnectionDetailsOutputDesc) flagSet.StringToStringP(params.Tags, "", nil, params.TagsDesc) - flagSet.StringP(rhelVersion, "", rhelVersionDefault, rhelVersionDesc) + flagSet.StringP(params.RhelVersion, "", params.RhelVersionDefault, params.RhelVersionDesc) flagSet.StringP(params.LinuxArch, "", params.LinuxArchDefault, params.LinuxArchDesc) flagSet.StringSliceP(vmTypes, "", []string{}, vmTypesDescription) - flagSet.StringP(subsUsername, "", "", subsUsernameDesc) - flagSet.StringP(subsUserpass, "", "", subsUserpassDesc) + flagSet.StringP(params.SubsUsername, "", "", params.SubsUsernameDesc) + flagSet.StringP(params.SubsUserpass, "", "", params.SubsUserpassDesc) flagSet.Bool(airgap, false, airgapDesc) flagSet.Bool(spot, false, spotDesc) - flagSet.Bool(profileSNC, false, profileSNCDesc) + flagSet.Bool(params.ProfileSNC, false, params.ProfileSNCDesc) flagSet.AddFlagSet(params.GetGHActionsFlagset()) flagSet.AddFlagSet(params.GetCpusAndMemoryFlagset()) c.PersistentFlags().AddFlagSet(flagSet) diff --git a/cmd/mapt/cmd/azure/hosts/constants.go b/cmd/mapt/cmd/azure/hosts/constants.go index a93bbb56..d60abf95 100644 --- a/cmd/mapt/cmd/azure/hosts/constants.go +++ b/cmd/mapt/cmd/azure/hosts/constants.go @@ -14,4 +14,9 @@ const ( paramSpotTolerance = "spot-eviction-tolerance" paramSpotToleranceDesc = "if spot is enable we can define the minimum tolerance level of eviction. Allowed value are: lowest, low, medium, high or highest" defaultSpotTolerance = "lowest" + paramLinuxVersion = "version" + paramLinuxVersionDesc = "linux version. Version should be formated as X.Y (Major.minor)" + defaultUbuntuVersion = "24.04" + defaultRHELVersion = "9.4" + defaultFedoraVersion = "40.0" ) diff --git a/cmd/mapt/cmd/azure/hosts/linux.go b/cmd/mapt/cmd/azure/hosts/linux.go index 21f13c8e..692f14db 100644 --- a/cmd/mapt/cmd/azure/hosts/linux.go +++ b/cmd/mapt/cmd/azure/hosts/linux.go @@ -20,27 +20,14 @@ import ( const ( cmdUbuntu = "ubuntu" cmdUbuntuDesc = "ubuntu operations" - cmdRHEL = "rhel" - cmdRHELDesc = "RHEL operations" cmdFedora = "fedora" cmdFedoraDesc = "fedora operations" - defaultVMSize = "Standard_D8as_v5" - - paramLinuxVersion = "version" - paramLinuxVersionDesc = "linux version. Version should be formated as X.Y (Major.minor)" - defaultUbuntuVersion = "24.04" - defaultRHELVersion = "9.4" - defaultFedoraVersion = "40.0" ) func GetUbuntuCmd() *cobra.Command { return getLinuxCmd(cmdUbuntu, cmdUbuntuDesc, azureLinux.Ubuntu, defaultUbuntuVersion) } -func GetRHELCmd() *cobra.Command { - return getLinuxCmd(cmdRHEL, cmdRHELDesc, azureLinux.RHEL, defaultRHELVersion) -} - func GetFedoraCmd() *cobra.Command { return getLinuxCmd(cmdFedora, cmdFedoraDesc, azureLinux.Fedora, defaultFedoraVersion) } diff --git a/cmd/mapt/cmd/azure/hosts/rhel.go b/cmd/mapt/cmd/azure/hosts/rhel.go new file mode 100644 index 00000000..c470bf72 --- /dev/null +++ b/cmd/mapt/cmd/azure/hosts/rhel.go @@ -0,0 +1,141 @@ +package hosts + +import ( + "fmt" + + azparams "github.com/redhat-developer/mapt/cmd/mapt/cmd/azure/constants" + params "github.com/redhat-developer/mapt/cmd/mapt/cmd/constants" + maptContext "github.com/redhat-developer/mapt/pkg/manager/context" + azureRHEL "github.com/redhat-developer/mapt/pkg/provider/azure/action/rhel" + "github.com/redhat-developer/mapt/pkg/provider/util/instancetypes" + "github.com/redhat-developer/mapt/pkg/util" + + spotAzure "github.com/redhat-developer/mapt/pkg/spot/azure" + "github.com/redhat-developer/mapt/pkg/util/ghactions" + "github.com/redhat-developer/mapt/pkg/util/logging" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" +) + +const ( + cmdRHEL = "rhel" + cmdRHELDesc = "RHEL operations" +) + +func GetRHELCmd() *cobra.Command { + c := &cobra.Command{ + Use: cmdRHEL, + Short: cmdRHELDesc, + RunE: func(cmd *cobra.Command, args []string) error { + if err := viper.BindPFlags(cmd.Flags()); err != nil { + return err + } + return nil + }, + } + c.AddCommand(getCreateRHEL(), getDestroyRHEL()) + return c +} + +func getCreateRHEL() *cobra.Command { + c := &cobra.Command{ + Use: params.CreateCmdName, + Short: params.CreateCmdName, + RunE: func(cmd *cobra.Command, args []string) error { + if err := viper.BindPFlags(cmd.Flags()); err != nil { + return err + } + // Initialize context + maptContext.Init( + viper.GetString(params.ProjectName), + viper.GetString(params.BackedURL), + viper.GetString(params.ConnectionDetailsOutput), + viper.GetStringMapString(params.Tags)) + + // ParseEvictionRate + var spotToleranceValue = spotAzure.DefaultEvictionRate + if viper.IsSet(paramSpotTolerance) { + var ok bool + spotToleranceValue, ok = spotAzure.ParseEvictionRate( + viper.GetString(paramSpotTolerance)) + if !ok { + return fmt.Errorf("%s is not a valid spot tolerance value", viper.GetString(azparams.ParamSpotTolerance)) + } + } + instanceRequest := &instancetypes.AzureInstanceRequest{ + CPUs: viper.GetInt32(params.CPUs), + MemoryGib: viper.GetInt32(params.Memory), + Arch: util.If(viper.GetString(params.LinuxArch) == "arm64", instancetypes.Arm64, instancetypes.Amd64), + NestedVirt: viper.GetBool(params.NestedVirt), + } + + // Initialize gh actions runner if needed + if viper.IsSet(params.InstallGHActionsRunner) { + err := ghactions.InitGHRunnerArgs(viper.GetString(params.GHActionsRunnerToken), + viper.GetString(params.GHActionsRunnerName), + viper.GetString(params.GHActionsRunnerRepo)) + if err != nil { + logging.Error(err) + } + } + + if err := azureRHEL.Create( + &azureRHEL.Request{ + Prefix: viper.GetString(params.ProjectName), + Location: viper.GetString(paramLocation), + VMSizes: viper.GetStringSlice(paramVMSize), + InstanceRequest: instanceRequest, + Version: viper.GetString(paramLinuxVersion), + Arch: viper.GetString(params.LinuxArch), + SubsUsername: viper.GetString(params.SubsUsername), + SubsUserpass: viper.GetString(params.SubsUserpass), + ProfileSNC: viper.IsSet(params.ProfileSNC), + Username: viper.GetString(paramUsername), + Spot: viper.IsSet(paramSpot), + SpotTolerance: spotToleranceValue, + SetupGHActionsRunner: viper.IsSet(params.InstallGHActionsRunner)}); err != nil { + logging.Error(err) + } + return nil + }, + } + flagSet := pflag.NewFlagSet(params.CreateCmdName, pflag.ExitOnError) + flagSet.StringP(params.ConnectionDetailsOutput, "", "", params.ConnectionDetailsOutputDesc) + flagSet.StringToStringP(params.Tags, "", nil, params.TagsDesc) + flagSet.StringP(paramLocation, "", defaultLocation, paramLocationDesc) + flagSet.StringP(params.LinuxArch, "", params.LinuxArchDefault, params.LinuxArchDesc) + flagSet.StringSliceP(paramVMSize, "", []string{}, paramVMSizeDesc) + flagSet.StringP(paramLinuxVersion, "", defaultRHELVersion, paramLinuxVersionDesc) + flagSet.StringP(paramUsername, "", defaultUsername, paramUsernameDesc) + flagSet.StringP(params.SubsUsername, "", "", params.SubsUsernameDesc) + flagSet.StringP(params.SubsUserpass, "", "", params.SubsUserpassDesc) + flagSet.Bool(paramSpot, false, paramSpotDesc) + flagSet.StringP(paramSpotTolerance, "", defaultSpotTolerance, paramSpotToleranceDesc) + flagSet.AddFlagSet(params.GetGHActionsFlagset()) + flagSet.AddFlagSet(params.GetCpusAndMemoryFlagset()) + c.PersistentFlags().AddFlagSet(flagSet) + return c +} + +func getDestroyRHEL() *cobra.Command { + return &cobra.Command{ + Use: params.DestroyCmdName, + Short: params.DestroyCmdName, + RunE: func(cmd *cobra.Command, args []string) error { + if err := viper.BindPFlags(cmd.Flags()); err != nil { + return err + } + // Initialize context + maptContext.Init( + viper.GetString(params.ProjectName), + viper.GetString(params.BackedURL), + viper.GetString(params.ConnectionDetailsOutput), + viper.GetStringMapString(params.Tags)) + if err := azureRHEL.Destroy(); err != nil { + logging.Error(err) + } + return nil + }, + } +} diff --git a/cmd/mapt/cmd/constants/constants.go b/cmd/mapt/cmd/constants/constants.go index be14f3ba..e4e27f50 100644 --- a/cmd/mapt/cmd/constants/constants.go +++ b/cmd/mapt/cmd/constants/constants.go @@ -54,6 +54,17 @@ const ( GHActionsRunnerToken string = "ghactions-runner-token" GHActionsRunnerName string = "ghactions-runner-name" GHActionsRunnerRepo string = "ghactions-runner-repo" + + //RHEL + SubsUsername string = "rh-subscription-username" + SubsUsernameDesc string = "username to register the subscription" + SubsUserpass string = "rh-subscription-password" + SubsUserpassDesc string = "password to register the subscription" + ProfileSNC string = "snc" + ProfileSNCDesc string = "if this flag is set the RHEL will be setup with SNC profile. Setting up all requirements to run https://github.com/crc-org/snc" + RhelVersion string = "version" + RhelVersionDesc string = "version for the RHEL OS" + RhelVersionDefault string = "9.4" ) func GetGHActionsFlagset() *pflag.FlagSet { diff --git a/pkg/provider/aws/action/fedora/fedora.go b/pkg/provider/aws/action/fedora/fedora.go index 642077ce..1b208c81 100644 --- a/pkg/provider/aws/action/fedora/fedora.go +++ b/pkg/provider/aws/action/fedora/fedora.go @@ -277,8 +277,6 @@ func (r *Request) getUserdata() (pulumi.StringPtrInput, error) { amiUserDefault, r.SetupGHActionsRunner, ghactions.GetActionRunnerSnippetLinux()}, - resourcesUtil.GetResourceName( - r.Prefix, awsFedoraDedicatedID, "userdata"), templateConfig) return pulumi.String(base64.StdEncoding.EncodeToString([]byte(userdata))), err } diff --git a/pkg/provider/aws/action/mac/mac-machine.go b/pkg/provider/aws/action/mac/mac-machine.go index 26015103..cf1443f7 100644 --- a/pkg/provider/aws/action/mac/mac-machine.go +++ b/pkg/provider/aws/action/mac/mac-machine.go @@ -391,7 +391,6 @@ func (r *MacRequest) getBootstrapScript(ctx *pulumi.Context) ( authorizedKey, r.SetupGHActionsRunner, ghactions.GetActionRunnerSnippetMacos()}, - resourcesUtil.GetResourceName(r.Prefix, awsMacMachineID, "mac-bootstrap"), string(BootstrapScript[:])) }).(pulumi.StringOutput) return postscript, password, ukp, nil diff --git a/pkg/provider/aws/action/rhel/rhel.go b/pkg/provider/aws/action/rhel/rhel.go index bfff9085..6eff570d 100644 --- a/pkg/provider/aws/action/rhel/rhel.go +++ b/pkg/provider/aws/action/rhel/rhel.go @@ -1,8 +1,6 @@ package rhel import ( - _ "embed" - "encoding/base64" "fmt" "os" @@ -24,9 +22,8 @@ import ( "github.com/redhat-developer/mapt/pkg/provider/util/command" "github.com/redhat-developer/mapt/pkg/provider/util/instancetypes" "github.com/redhat-developer/mapt/pkg/provider/util/output" + targetRHEL "github.com/redhat-developer/mapt/pkg/targets/rhel" "github.com/redhat-developer/mapt/pkg/util" - "github.com/redhat-developer/mapt/pkg/util/file" - "github.com/redhat-developer/mapt/pkg/util/ghactions" "github.com/redhat-developer/mapt/pkg/util/logging" resourcesUtil "github.com/redhat-developer/mapt/pkg/util/resources" ) @@ -60,20 +57,6 @@ type Request struct { spotPrice float64 } -type userDataValues struct { - SubscriptionUsername string - SubscriptionPassword string - Username string - InstallActionsRunner bool - ActionsRunnerSnippet string -} - -//go:embed cloud-config-base -var CloudConfigBase []byte - -//go:embed cloud-config-snc -var CloudConfigSNC []byte - // Create orchestrate 2 stacks: // If spot is enable it will run best spot option to get the best option to spin the machine // Then it will run the stack for windows dedicated host @@ -210,7 +193,9 @@ func (r *Request) deploy(ctx *pulumi.Context) error { return err } // Compute - userDataB64, err := r.getUserdata() + userDataB64, err := targetRHEL.GetUserdata(r.ProfileSNC, + r.SubsUsername, r.SubsUserpass, amiUserDefault, + r.SetupGHActionsRunner) if err != nil { return err } @@ -220,7 +205,7 @@ func (r *Request) deploy(ctx *pulumi.Context) error { VPC: vpc, Subnet: targetSubnet, AMI: ami, - UserDataAsBase64: userDataB64, + UserDataAsBase64: pulumi.String(userDataB64), KeyResources: keyResources, SecurityGroups: securityGroups, InstaceTypes: util.If(len(r.VMType) > 0, @@ -283,21 +268,3 @@ func (r *Request) securityGroups(ctx *pulumi.Context, }) return pulumi.StringArray(sgs[:]), nil } - -func (r *Request) getUserdata() (pulumi.StringPtrInput, error) { - templateConfig := string(CloudConfigBase[:]) - if r.ProfileSNC { - templateConfig = string(CloudConfigSNC[:]) - } - userdata, err := file.Template( - userDataValues{ - r.SubsUsername, - r.SubsUserpass, - amiUserDefault, - r.SetupGHActionsRunner, - ghactions.GetActionRunnerSnippetLinux()}, - resourcesUtil.GetResourceName( - r.Prefix, awsRHELDedicatedID, "userdata"), - templateConfig) - return pulumi.String(base64.StdEncoding.EncodeToString([]byte(userdata))), err -} diff --git a/pkg/provider/aws/action/windows/windows.go b/pkg/provider/aws/action/windows/windows.go index b98e5572..1b059cc7 100644 --- a/pkg/provider/aws/action/windows/windows.go +++ b/pkg/provider/aws/action/windows/windows.go @@ -324,7 +324,6 @@ func (r *Request) getUserdata(ctx *pulumi.Context, func(args []interface{}) (string, error) { password := args[0].(string) authorizedKey := args[1].(string) - tmplName := resourcesUtil.GetResourceName(r.Prefix, awsWindowsDedicatedID, "userdatas") udv := userDataValues{ r.AMIUser, password, @@ -333,7 +332,7 @@ func (r *Request) getUserdata(ctx *pulumi.Context, ghactions.GetActionRunnerSnippetWin(), ghactions.GetToken(), } - userdata, err := file.Template(udv, tmplName, string(BootstrapScript[:])) + userdata, err := file.Template(udv, string(BootstrapScript[:])) if err != nil { return "", err } diff --git a/pkg/provider/azure/action/linux/linux.go b/pkg/provider/azure/action/linux/linux.go index ce428ebc..48e47ffc 100644 --- a/pkg/provider/azure/action/linux/linux.go +++ b/pkg/provider/azure/action/linux/linux.go @@ -34,16 +34,18 @@ const ( ) type LinuxRequest struct { - Prefix string - Location string - VMSizes []string - Arch string - InstanceRequest instancetypes.InstanceRequest - OSType OSType - Version string - Username string - Spot bool - SpotTolerance spotAzure.EvictionRate + Prefix string + Location string + VMSizes []string + Arch string + InstanceRequest instancetypes.InstanceRequest + OSType OSType + Version string + Username string + Spot bool + SpotTolerance spotAzure.EvictionRate + Userdata string + ReadinessCommand string } func Create(r *LinuxRequest) (err error) { @@ -134,6 +136,7 @@ func (r *LinuxRequest) deployer(ctx *pulumi.Context) error { AdminUsername: r.Username, PrivateKey: privateKey, SpotPrice: spotPrice, + Userdata: r.Userdata, } vm, err := vmr.Create(ctx) if err != nil { @@ -149,8 +152,14 @@ func (r *LinuxRequest) deployer(ctx *pulumi.Context) error { User: pulumi.String(r.Username), DialErrorLimit: pulumi.Int(-1), }, - Create: pulumi.String(command.CommandPing), - Update: pulumi.String(command.CommandPing), + Create: pulumi.String(util.If( + len(r.ReadinessCommand) == 0, + command.CommandPing, + r.ReadinessCommand)), + Update: pulumi.String(util.If( + len(r.ReadinessCommand) == 0, + command.CommandPing, + r.ReadinessCommand)), }, pulumi.Timeouts( &pulumi.CustomTimeouts{ diff --git a/pkg/provider/azure/action/rhel/rhel.go b/pkg/provider/azure/action/rhel/rhel.go new file mode 100644 index 00000000..b0965236 --- /dev/null +++ b/pkg/provider/azure/action/rhel/rhel.go @@ -0,0 +1,68 @@ +package rhel + +import ( + "fmt" + + azureLinux "github.com/redhat-developer/mapt/pkg/provider/azure/action/linux" + "github.com/redhat-developer/mapt/pkg/provider/util/command" + "github.com/redhat-developer/mapt/pkg/provider/util/instancetypes" + spotAzure "github.com/redhat-developer/mapt/pkg/spot/azure" + targetRHEL "github.com/redhat-developer/mapt/pkg/targets/rhel" + "github.com/redhat-developer/mapt/pkg/util/logging" +) + +type Request struct { + Prefix string + Location string + VMSizes []string + Arch string + InstanceRequest instancetypes.InstanceRequest + Version string + SubsUsername string + SubsUserpass string + ProfileSNC bool + Username string + Spot bool + SpotTolerance spotAzure.EvictionRate + // setup as github actions runner + SetupGHActionsRunner bool +} + +func Create(r *Request) (err error) { + if len(r.VMSizes) == 0 { + vmSizes, err := r.InstanceRequest.GetMachineTypes() + if err != nil { + logging.Debugf("Unable to fetch desired instance type: %v", err) + } + if len(vmSizes) > 0 { + r.VMSizes = append(r.VMSizes, vmSizes...) + } + } + logging.Debug("Creating RHEL Server") + userDataB64, err := targetRHEL.GetUserdata(r.ProfileSNC, + r.SubsUsername, r.SubsUserpass, r.Username, + r.SetupGHActionsRunner) + if err != nil { + return fmt.Errorf("error creating RHEL Server on Azure: %v", err) + } + azureLinuxRequest := + &azureLinux.LinuxRequest{ + Prefix: r.Prefix, + Location: r.Location, + VMSizes: r.VMSizes, + InstanceRequest: r.InstanceRequest, + Version: r.Version, + Arch: r.Arch, + OSType: azureLinux.RHEL, + Username: r.Username, + Spot: r.Spot, + SpotTolerance: r.SpotTolerance, + Userdata: userDataB64, + // As RHEL now is set with cloud init this is the ReadinessCommand to check + ReadinessCommand: command.CommandCloudInitWait} + return azureLinux.Create(azureLinuxRequest) +} + +func Destroy() error { + return azureLinux.Destroy() +} diff --git a/pkg/provider/azure/action/windows/windows.go b/pkg/provider/azure/action/windows/windows.go index 1d49c856..816c60c9 100644 --- a/pkg/provider/azure/action/windows/windows.go +++ b/pkg/provider/azure/action/windows/windows.go @@ -303,7 +303,7 @@ func (r *WindowsRequest) uploadScript(ctx *pulumi.Context, r.SetupGHActionsRunner, ghactions.GetActionRunnerSnippetWin(), } - ciSetupScript, err := file.Template(data, "ciSetupScript", string(RHQPCISetupScript)) + ciSetupScript, err := file.Template(data, string(RHQPCISetupScript)) if err != nil { return nil, err } diff --git a/pkg/provider/azure/module/virtual-machine/virtual-machine.go b/pkg/provider/azure/module/virtual-machine/virtual-machine.go index 325d3986..3b3de21e 100644 --- a/pkg/provider/azure/module/virtual-machine/virtual-machine.go +++ b/pkg/provider/azure/module/virtual-machine/virtual-machine.go @@ -35,6 +35,8 @@ type VirtualMachineRequest struct { // Linux required PrivateKey *tls.PrivateKey AdminPasswd *random.RandomPassword + // Linux optional + Userdata string } // Create virtual machine based on request + export to context @@ -79,8 +81,7 @@ func (r *VirtualMachineRequest) Create(ctx *pulumi.Context) (*compute.VirtualMac }, }, OsProfile: r.osProfile(), - - Tags: maptContext.ResourceTags(), + Tags: maptContext.ResourceTags(), } if r.SpotPrice != nil { vmArgs.Priority = pulumi.String(prioritySpot) @@ -88,6 +89,9 @@ func (r *VirtualMachineRequest) Create(ctx *pulumi.Context) (*compute.VirtualMac MaxPrice: pulumi.Float64(*r.SpotPrice), } } + if len(r.Userdata) > 0 { + vmArgs.UserData = pulumi.String(r.Userdata) + } return compute.NewVirtualMachine(ctx, resourcesUtil.GetResourceName(r.Prefix, r.ComponentID, "vm"), vmArgs) @@ -103,6 +107,7 @@ func (r *VirtualMachineRequest) osProfile() compute.OSProfileArgs { } if r.PrivateKey != nil { osProfile.LinuxConfiguration = &compute.LinuxConfigurationArgs{ + PatchSettings: compute.LinuxPatchSettingsArgs{}, DisablePasswordAuthentication: pulumi.Bool(true), Ssh: &compute.SshConfigurationArgs{ PublicKeys: compute.SshPublicKeyTypeArray{ diff --git a/pkg/provider/util/windows/windows.go b/pkg/provider/util/windows/windows.go index e792de17..64f352bf 100644 --- a/pkg/provider/util/windows/windows.go +++ b/pkg/provider/util/windows/windows.go @@ -3,7 +3,6 @@ package windows import ( _ "embed" "encoding/base64" - "fmt" "github.com/pulumi/pulumi-random/sdk/v4/go/random" "github.com/pulumi/pulumi-tls/sdk/v5/go/tls" @@ -37,7 +36,6 @@ func GetUserdata(ctx *pulumi.Context, resourceID string, password, authorizedKey, hostname}, - fmt.Sprintf("%s-%s", "windows-userdata", resourceID), string(userdataTemplate[:])) if err != nil { return "", err diff --git a/pkg/provider/aws/action/rhel/cloud-config-base b/pkg/targets/rhel/cloud-config-base similarity index 100% rename from pkg/provider/aws/action/rhel/cloud-config-base rename to pkg/targets/rhel/cloud-config-base diff --git a/pkg/provider/aws/action/rhel/cloud-config-snc b/pkg/targets/rhel/cloud-config-snc similarity index 100% rename from pkg/provider/aws/action/rhel/cloud-config-snc rename to pkg/targets/rhel/cloud-config-snc diff --git a/pkg/targets/rhel/rhel.go b/pkg/targets/rhel/rhel.go new file mode 100644 index 00000000..c8a7bd41 --- /dev/null +++ b/pkg/targets/rhel/rhel.go @@ -0,0 +1,41 @@ +package rhel + +import ( + _ "embed" + "encoding/base64" + + "github.com/redhat-developer/mapt/pkg/util/file" + "github.com/redhat-developer/mapt/pkg/util/ghactions" +) + +type userDataValues struct { + SubscriptionUsername string + SubscriptionPassword string + Username string + InstallActionsRunner bool + ActionsRunnerSnippet string +} + +//go:embed cloud-config-base +var CloudConfigBase []byte + +//go:embed cloud-config-snc +var CloudConfigSNC []byte + +func GetUserdata(sncProfile bool, subsUsername, subsPassword string, + username string, ghActionRunner bool) (string, error) { + templateConfig := string(CloudConfigBase[:]) + if sncProfile { + templateConfig = string(CloudConfigSNC[:]) + } + userdata, err := file.Template( + userDataValues{ + subsUsername, + subsPassword, + username, + ghActionRunner, + ghactions.GetActionRunnerSnippetLinux()}, + templateConfig) + // return pulumi.String(base64.StdEncoding.EncodeToString([]byte(userdata))), err + return base64.StdEncoding.EncodeToString([]byte(userdata)), err +} diff --git a/pkg/util/file/file.go b/pkg/util/file/file.go index 1900c664..19f47aae 100644 --- a/pkg/util/file/file.go +++ b/pkg/util/file/file.go @@ -18,8 +18,8 @@ func WriteTempFile(content string) (string, error) { return tmpFile.Name(), err } -func Template(data any, templateName, templateContent string) (string, error) { - tmpl, err := template.New(templateName).Parse(templateContent) +func Template(data any, templateContent string) (string, error) { + tmpl, err := template.New("tpl").Parse(templateContent) if err != nil { return "", err } diff --git a/tkn/infra-aws-fedora.yaml b/tkn/infra-aws-fedora.yaml index 1c451737..dd820c9b 100644 --- a/tkn/infra-aws-fedora.yaml +++ b/tkn/infra-aws-fedora.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: infra-aws-fedora labels: - app.kubernetes.io/version: "0.7.0-dev" + app.kubernetes.io/version: "pr-309" annotations: tekton.dev/pipelines.minVersion: "0.24.x" tekton.dev/categories: infrastructure @@ -121,7 +121,7 @@ spec: steps: - name: provisioner - image: quay.io/redhat-developer/mapt:v0.7.0-dev + image: quay.io/redhat-developer/mapt:vpr-309 imagePullPolicy: Always script: | #!/bin/sh diff --git a/tkn/infra-aws-mac.yaml b/tkn/infra-aws-mac.yaml index 2a33c7c1..c5042689 100644 --- a/tkn/infra-aws-mac.yaml +++ b/tkn/infra-aws-mac.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: infra-aws-mac labels: - app.kubernetes.io/version: "0.7.0-dev" + app.kubernetes.io/version: "pr-309" annotations: tekton.dev/pipelines.minVersion: "0.24.x" tekton.dev/categories: infrastructure @@ -126,7 +126,7 @@ spec: steps: - name: provisioner - image: quay.io/redhat-developer/mapt:v0.7.0-dev + image: quay.io/redhat-developer/mapt:vpr-309 imagePullPolicy: Always script: | #!/bin/sh diff --git a/tkn/infra-aws-rhel.yaml b/tkn/infra-aws-rhel.yaml index 982499a9..8ba19809 100644 --- a/tkn/infra-aws-rhel.yaml +++ b/tkn/infra-aws-rhel.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: infra-aws-rhel labels: - app.kubernetes.io/version: "0.7.0-dev" + app.kubernetes.io/version: "pr-309" annotations: tekton.dev/pipelines.minVersion: "0.24.x" tekton.dev/categories: infrastructure @@ -144,7 +144,7 @@ spec: steps: - name: provisioner - image: quay.io/redhat-developer/mapt:v0.7.0-dev + image: quay.io/redhat-developer/mapt:vpr-309 imagePullPolicy: Always script: | #!/bin/sh diff --git a/tkn/infra-aws-windows-server.yaml b/tkn/infra-aws-windows-server.yaml index 2fad252d..0fe0e50f 100644 --- a/tkn/infra-aws-windows-server.yaml +++ b/tkn/infra-aws-windows-server.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: infra-aws-windows-server labels: - app.kubernetes.io/version: "0.7.0-dev" + app.kubernetes.io/version: "pr-309" annotations: tekton.dev/pipelines.minVersion: "0.24.x" tekton.dev/categories: infrastructure @@ -112,7 +112,7 @@ spec: steps: - name: provisioner - image: quay.io/redhat-developer/mapt:v0.7.0-dev + image: quay.io/redhat-developer/mapt:vpr-309 imagePullPolicy: Always script: | #!/bin/sh diff --git a/tkn/infra-azure-aks.yaml b/tkn/infra-azure-aks.yaml deleted file mode 100644 index 2a594d92..00000000 --- a/tkn/infra-azure-aks.yaml +++ /dev/null @@ -1,146 +0,0 @@ ---- -apiVersion: tekton.dev/v1beta1 -kind: Task -metadata: - name: infra-azure-aks - labels: - app.kubernetes.io/version: "0.7.0-dev" - annotations: - tekton.dev/pipelines.minVersion: "0.44.x" - tekton.dev/categories: infrastructure - tekton.dev/tags: infrastructure, azure - tekton.dev/displayName: "azure manager" - tekton.dev/platforms: "linux/amd64" -spec: - description: | - This task will provision / decomission azure aks cluster - - The output will give required information to connect within the remote provisioned cluster - - workspaces: - - name: az-credentials - description: | - ocp secret holding the azure credentials. Secret should be accessible to this task. - - To be a valid secret it should contains the following fields: - * tenant_id - * subscription_id - * client_id - * client_secret - * storage_account (optional if we use remote az storage) - * storage_key (optional if we use remote az storage) - mountPath: /opt/credentials - - params: - # mapt params - - name: project-name - description: identifier for project. - - name: backed-url - description: external az storage (i.e azblob://existing-storage). - - name: operation - description: operation to execute within the infrastructure. Current values (create, destroy) - default: create - - # AKS params - - name: k8s-version - description: AKS K8s cluster version (default "1.30") - default: '1.30' - - name: only-system-pool - description: if we do not need bunch of resources we can run only the systempool. More info https://learn.microsoft.com/es-es/azure/aks/use-system-pools?tabs=azure-cli#system-and-user-node-pools. (default false) - default: 'false' - - name: enable-app-routing - description: enable application routing add-on with NGINX. (default false) - default: 'false' - - # VM type params for pools - - name: spot - description: in case spot is set to true it 'ill check for best spot price and create the VM on the target region - default: 'true' - - name: spot-eviction-tolerance - description: 'if spot is enable we can define the minimum tolerance level of eviction. Allowed value are: lowest, low, medium, high or highest' - default: 'lowest' - - - # Metadata params - - name: tags - description: tags for the resources created on the providers - default: "''" - - # Control params - - name: remove-lock - description: in case a previous run fails the stack can be locked. This value allows to control if remove lock - default: 'true' - - results: - - name: kubeconfig - description: kubeconfig file - - steps: - - name: provisioner - image: quay.io/redhat-developer/mapt:v0.7.0-dev - imagePullPolicy: Always - script: | - #!/bin/sh - - # Added verbosity - set -xuo - - # Credentials - export ARM_TENANT_ID=$(cat /opt/credentials/tenant_id) - export ARM_SUBSCRIPTION_ID=$(cat /opt/credentials/subscription_id) - export ARM_CLIENT_ID=$(cat /opt/credentials/client_id) - export ARM_CLIENT_SECRET=$(cat /opt/credentials/client_secret) - if ! [ -f /opt/credentials/storage_account ]; then - export AZURE_STORAGE_ACCOUNT=$(cat /opt/credentials/storage_account) - fi - if ! [ -f /opt/credentials/storage_key ]; then - export AZURE_STORAGE_KEY=$(cat /opt/credentials/storage_key) - fi - - # Output folder - mkdir -p aks-kubeconfig - - # Remove lock - if [[ $(params.remove-lock) == "true" ]]; then - rm -rf ${workspace_path}/.pulumi/locks/* - fi - - # Run mapt - cmd="mapt azure aks $(params.operation) " - cmd="$cmd --project-name $(params.project-name) " - cmd="$cmd --backed-url $(params.backed-url) " - if [[ $(params.operation) == "create" ]]; then - cmd="$cmd --conn-details-output aks-kubeconfig " - cmd="$cmd --version $(params.k8s-version) " - if [[ $(params.only-system-pool) == "true" ]]; then - cmd="$cmd --only-system-pool " - fi - if [[ $(params.enable-app-routing) == "true" ]]; then - cmd="$cmd --enable-app-routing " - fi - if [[ $(params.spot) == "true" ]]; then - cmd="$cmd --spot " - cmd="$cmd --spot-eviction-tolerance $(params.spot-eviction-tolerance) " - fi - if [[ $(params.tags) != "" ]]; then - cmd="$cmd --tags $(params.tags) " - fi - fi - eval "${cmd}" - - create_exit_code=$? - - # set task results - cat "aks-kubeconfig/kubeconfig" | tee $(results.kubeconfig.path) - - if [[ ${create_exit_code} -ne 0 ]]; then - exit 1 - fi - - resources: - requests: - memory: "200Mi" - cpu: "100m" - limits: - memory: "600Mi" - cpu: "300m" diff --git a/tkn/infra-azure-fedora.yaml b/tkn/infra-azure-fedora.yaml index e20bb158..d8113374 100644 --- a/tkn/infra-azure-fedora.yaml +++ b/tkn/infra-azure-fedora.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: infra-azure-rhel labels: - app.kubernetes.io/version: "0.7.0-dev" + app.kubernetes.io/version: "pr-309" annotations: tekton.dev/pipelines.minVersion: "0.44.x" tekton.dev/categories: infrastructure @@ -97,7 +97,7 @@ spec: steps: - name: provisioner - image: quay.io/redhat-developer/mapt:v0.7.0-dev + image: quay.io/redhat-developer/mapt:vpr-309 imagePullPolicy: Always script: | #!/bin/sh diff --git a/tkn/infra-azure-rhel.yaml b/tkn/infra-azure-rhel.yaml index 160a8308..87282728 100644 --- a/tkn/infra-azure-rhel.yaml +++ b/tkn/infra-azure-rhel.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: infra-azure-rhel labels: - app.kubernetes.io/version: "0.7.0-dev" + app.kubernetes.io/version: "pr-309" annotations: tekton.dev/pipelines.minVersion: "0.44.x" tekton.dev/categories: infrastructure @@ -32,6 +32,22 @@ spec: * storage_account (optional if we use remote az storage) * storage_key (optional if we use remote az storage) mountPath: /opt/credentials + - name: rh-account-secret + optional: true + description: | + ocp secret holding the credentials for a valid rh user to subscribe VM. Secret should be accessible to this task. + + Sample format for valid Secret + --- + apiVersion: v1 + kind: Secret + metadata: + name: credentials-${configname} + type: Opaque + data: + user: ${user} + password: ${password} + mountPath: /opt/rh-account-secret params: # mapt params @@ -76,6 +92,10 @@ spec: - name: version description: this task will spin a RHEL image. This param will set the version for it. Default 9.4. default: '9.4' + - name: profile-snc + description: | + This param will setup RHEL with SNC profile. Setting up all requirements to run https://github.com/crc-org/snc + default: 'false' # Metadata params - name: tags @@ -97,7 +117,7 @@ spec: steps: - name: provisioner - image: quay.io/redhat-developer/mapt:v0.7.0-dev + image: quay.io/redhat-developer/mapt:vpr-309 imagePullPolicy: Always script: | #!/bin/sh @@ -150,6 +170,11 @@ spec: cmd="$cmd --spot " cmd="$cmd --spot-eviction-tolerance $(params.spot-eviction-tolerance) " fi + cmd="$cmd --rh-subscription-username $(cat /opt/rh-account-secret/user) " + cmd="$cmd --rh-subscription-password $(cat /opt/rh-account-secret/password) " + if [[ $(params.profile-snc) == "true" ]]; then + cmd="$cmd --snc " + fi if [[ $(params.tags) != "" ]]; then cmd="$cmd --tags $(params.tags) " fi diff --git a/tkn/infra-azure-windows-desktop.yaml b/tkn/infra-azure-windows-desktop.yaml index f7532486..72368087 100644 --- a/tkn/infra-azure-windows-desktop.yaml +++ b/tkn/infra-azure-windows-desktop.yaml @@ -4,7 +4,7 @@ kind: Task metadata: name: infra-azure-windows-desktop labels: - app.kubernetes.io/version: "0.7.0-dev" + app.kubernetes.io/version: "pr-309" annotations: tekton.dev/pipelines.minVersion: "0.24.x" tekton.dev/categories: infrastructure @@ -98,7 +98,7 @@ spec: steps: - name: provisioner - image: quay.io/redhat-developer/mapt:v0.7.0-dev + image: quay.io/redhat-developer/mapt:vpr-309 imagePullPolicy: Always script: | #!/bin/sh diff --git a/tkn/template/infra-azure-rhel.yaml b/tkn/template/infra-azure-rhel.yaml index 6cbc95f6..f48e74b2 100644 --- a/tkn/template/infra-azure-rhel.yaml +++ b/tkn/template/infra-azure-rhel.yaml @@ -32,6 +32,22 @@ spec: * storage_account (optional if we use remote az storage) * storage_key (optional if we use remote az storage) mountPath: /opt/credentials + - name: rh-account-secret + optional: true + description: | + ocp secret holding the credentials for a valid rh user to subscribe VM. Secret should be accessible to this task. + + Sample format for valid Secret + --- + apiVersion: v1 + kind: Secret + metadata: + name: credentials-${configname} + type: Opaque + data: + user: ${user} + password: ${password} + mountPath: /opt/rh-account-secret params: # mapt params @@ -76,6 +92,10 @@ spec: - name: version description: this task will spin a RHEL image. This param will set the version for it. Default 9.4. default: '9.4' + - name: profile-snc + description: | + This param will setup RHEL with SNC profile. Setting up all requirements to run https://github.com/crc-org/snc + default: 'false' # Metadata params - name: tags @@ -150,6 +170,11 @@ spec: cmd="$cmd --spot " cmd="$cmd --spot-eviction-tolerance $(params.spot-eviction-tolerance) " fi + cmd="$cmd --rh-subscription-username $(cat /opt/rh-account-secret/user) " + cmd="$cmd --rh-subscription-password $(cat /opt/rh-account-secret/password) " + if [[ $(params.profile-snc) == "true" ]]; then + cmd="$cmd --snc " + fi if [[ $(params.tags) != "" ]]; then cmd="$cmd --tags $(params.tags) " fi