Skip to content

Commit

Permalink
#29 - implement support GCP provider for Cluster API
Browse files Browse the repository at this point in the history
  • Loading branch information
apanasiuk-el committed Nov 21, 2024
1 parent 8597c60 commit 57d810c
Show file tree
Hide file tree
Showing 11 changed files with 461 additions and 63 deletions.
34 changes: 34 additions & 0 deletions cmd/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"rmk/config"
"rmk/providers/aws_provider"
"rmk/providers/azure_provider"
"rmk/providers/google_provider"
"rmk/util"
)

Expand Down Expand Up @@ -58,6 +59,11 @@ func (cc *ClusterCommands) clusterCTL(args ...string) *util.SpecCMD {
"EXP_MACHINE_POOL=true",
"EXP_CLUSTER_RESOURCE_SET=false",
}
case google_provider.GoogleClusterProvider:
envs = []string{
"GCP_B64ENCODED_CREDENTIALS=",
"EXP_CAPG_GKE=true",
}
}

return &util.SpecCMD{
Expand Down Expand Up @@ -295,6 +301,15 @@ func (cc *ClusterCommands) switchKubeContext() error {
return err
}

if err := cc.mergeKubeConfigs(clusterContext); err != nil {
return err
}
case google_provider.GoogleClusterProvider:
clusterContext, err := cc.getGCPClusterContext()
if err != nil {
return err
}

if err := cc.mergeKubeConfigs(clusterContext); err != nil {
return err
}
Expand All @@ -321,6 +336,9 @@ func (cc *ClusterCommands) provisionDestroyTargetCluster() error {
return err
}
case azure_provider.AzureClusterProvider:
// Pre-provision hook for Azure
case google_provider.GoogleClusterProvider:
// Pre-provision hook for GCP
}

cc.SpecCMD = cc.prepareHelmfile("--log-level", "error", "-l", "cluster="+cc.Conf.ClusterProvider, "sync")
Expand All @@ -344,6 +362,15 @@ func (cc *ClusterCommands) provisionDestroyTargetCluster() error {
return err
}

if err := cc.mergeKubeConfigs(clusterContext); err != nil {
return err
}
case google_provider.GoogleClusterProvider:
clusterContext, err := cc.getGCPClusterContext()
if err != nil {
return err
}

if err := cc.mergeKubeConfigs(clusterContext); err != nil {
return err
}
Expand All @@ -360,6 +387,9 @@ func (cc *ClusterCommands) provisionDestroyTargetCluster() error {
return err
}
case azure_provider.AzureClusterProvider:
// Pre-destroy hook for Azure
case google_provider.GoogleClusterProvider:
// Pre-destroy hook for GCP
}

kubeConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
Expand Down Expand Up @@ -423,6 +453,8 @@ func CAPIInitAction(conf *config.Config) cli.AfterFunc {
return cc.applyAWSClusterIdentity()
case azure_provider.AzureClusterProvider:
return cc.applyAzureClusterIdentity()
case google_provider.GoogleClusterProvider:
return cc.applyGCPClusterIdentitySecret()
}

return nil
Expand Down Expand Up @@ -453,6 +485,8 @@ func CAPIUpdateAction(conf *config.Config) cli.ActionFunc {
return cc.applyAWSClusterIdentity()
case azure_provider.AzureClusterProvider:
return cc.applyAzureClusterIdentity()
case google_provider.GoogleClusterProvider:
return cc.applyGCPClusterIdentitySecret()
}

return nil
Expand Down
87 changes: 87 additions & 0 deletions cmd/cluster_capg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package cmd

import (
"os"
"path/filepath"

corev1 "k8s.io/api/core/v1"
v1 "k8s.io/client-go/applyconfigurations/core/v1"

"rmk/providers/google_provider"
)

const (
gcpClusterIdentityName = "gcp-cluster-identity"
gcpClusterIdentityNamespace = "capg-system"
gcpClusterIdentitySecret = "gcp-cluster-identity-secret"
gcpFlagsCategory = "GCP authentication"
)

var gcpClusterIdentitySecretType = corev1.SecretTypeOpaque

type GCPClusterIdentityConfig struct {
*v1.SecretApplyConfiguration
ManifestFiles []string
ManifestFilesDir string
}

func NewGCPClusterIdentityConfig(gcp *google_provider.GCPConfigure) *GCPClusterIdentityConfig {
gcpcc := &GCPClusterIdentityConfig{
SecretApplyConfiguration: v1.Secret(gcpClusterIdentitySecret, gcpClusterIdentityNamespace),
ManifestFilesDir: filepath.Join("/tmp", gcpClusterIdentityName),
}

gcpcc.SecretApplyConfiguration.Type = &gcpClusterIdentitySecretType
gcpcc.SecretApplyConfiguration.Data = map[string][]byte{"credentials": gcp.AppCredentials.JSON()}

return gcpcc
}

func (gic *GCPClusterIdentityConfig) createGCPClusterIdentitySecretManifestFiles() error {
if err := os.MkdirAll(gic.ManifestFilesDir, 0775); err != nil {
return err
}

fileSecret, err := createManifestFile(gic.SecretApplyConfiguration, gic.ManifestFilesDir, gcpClusterIdentitySecret)
if err != nil {
return err
}

gic.ManifestFiles = append(gic.ManifestFiles, fileSecret)

return nil
}

func (cc *ClusterCommands) applyGCPClusterIdentitySecret() error {
var kubectlArgs = []string{"apply"}

gcp := google_provider.NewGCPConfigure(cc.Ctx.Context, cc.Conf.GCPConfigure.AppCredentialsPath)
if err := gcp.ReadSACredentials(); err != nil {
return err
}

gic := NewGCPClusterIdentityConfig(gcp)
if err := gic.createGCPClusterIdentitySecretManifestFiles(); err != nil {
return err
}

for _, val := range gic.ManifestFiles {
kubectlArgs = append(kubectlArgs, "-f", val)
}

cc.SpecCMD = cc.kubectl(kubectlArgs...)
if err := releaseRunner(cc).runCMD(); err != nil {
if err := os.RemoveAll(gic.ManifestFilesDir); err != nil {
return err
}

return err
}

return os.RemoveAll(gic.ManifestFilesDir)
}

func (cc *ClusterCommands) getGCPClusterContext() ([]byte, error) {
return google_provider.NewGCPConfigure(cc.Ctx.Context, cc.Conf.GCPConfigure.AppCredentialsPath).
GetGCPClusterContext(cc.Conf.Name)
}
41 changes: 41 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"rmk/git_handler"
"rmk/providers/aws_provider"
"rmk/providers/azure_provider"
"rmk/providers/google_provider"
"rmk/util"
)

Expand Down Expand Up @@ -345,6 +346,30 @@ func initAzureProfile(c *cli.Context, conf *config.Config, gitSpec *git_handler.
return nil
}

func initGCPProfile(c *cli.Context, conf *config.Config, gitSpec *git_handler.GitSpec) error {
gcp := google_provider.NewGCPConfigure(c.Context,
util.GetHomePath(google_provider.GoogleHomeDir, google_provider.GooglePrefix+gitSpec.ID+".json"))

if c.IsSet("google-application-credentials") {
gcp.AppCredentialsPath = c.String("google-application-credentials")
if err := gcp.ReadSACredentials(); err != nil {
return err
}

if err := gcp.CopySACredentials(gitSpec.ID); err != nil {
return err
}
} else {
if err := gcp.ReadSACredentials(); err != nil {
return err
}
}

conf.GCPConfigure = gcp

return nil
}

func configDeleteAction(conf *config.Config) cli.ActionFunc {
return func(c *cli.Context) error {
if err := util.ValidateNArg(c, 0); err != nil {
Expand Down Expand Up @@ -378,6 +403,11 @@ func configDeleteAction(conf *config.Config) cli.ActionFunc {
azure_provider.AzurePrefix+conf.Name+".json")); err != nil {
return err
}
case c.String("cluster-provider") == google_provider.GoogleClusterProvider:
if err := os.RemoveAll(util.GetHomePath(google_provider.GoogleHomeDir,
google_provider.GooglePrefix+conf.Name+".json")); err != nil {
return err
}
}

if err := os.RemoveAll(c.String("config")); err != nil {
Expand Down Expand Up @@ -419,21 +449,32 @@ func configInitAction(conf *config.Config, gitSpec *git_handler.GitSpec) cli.Act
switch conf.ClusterProvider {
case aws_provider.AWSClusterProvider:
conf.AzureConfigure = nil
conf.GCPConfigure = nil
if err := initAWSProfile(c, conf, gitSpec); err != nil {
return err
}

conf.SopsAgeKeys = util.GetHomePath(util.RMKDir, util.SopsRootName, conf.Tenant+"-"+util.SopsRootName+"-"+aws_provider.AWSClusterProvider)
case azure_provider.AzureClusterProvider:
conf.AwsConfigure = nil
conf.GCPConfigure = nil
if err := initAzureProfile(c, conf, gitSpec); err != nil {
return err
}

conf.SopsAgeKeys = util.GetHomePath(util.RMKDir, util.SopsRootName, conf.Tenant+"-"+util.SopsRootName+"-"+azure_provider.AzureClusterProvider)
case google_provider.GoogleClusterProvider:
conf.AwsConfigure = nil
conf.AzureConfigure = nil
if err := initGCPProfile(c, conf, gitSpec); err != nil {
return err
}

conf.SopsAgeKeys = util.GetHomePath(util.RMKDir, util.SopsRootName, conf.Tenant+"-"+util.SopsRootName+"-"+google_provider.GoogleClusterProvider)
case util.LocalClusterProvider:
conf.AwsConfigure = nil
conf.AzureConfigure = nil
conf.GCPConfigure = nil
conf.SopsAgeKeys = util.GetHomePath(util.RMKDir, util.SopsRootName, conf.Tenant+"-"+util.SopsRootName+"-"+util.LocalClusterProvider)
}

Expand Down
25 changes: 16 additions & 9 deletions cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ func flagsConfig() []cli.Flag {
Aliases: []string{"azt"},
EnvVars: []string{"RMK_AZURE_TENANT_ID", "AZURE_TENANT_ID"},
},
altsrc.NewStringFlag(
&cli.StringFlag{
Name: "cluster-provider",
Usage: "select cluster provider to provision clusters",
Aliases: []string{"cp"},
EnvVars: []string{"RMK_CLUSTER_PROVIDER"},
Value: util.LocalClusterProvider,
},
),
&cli.StringFlag{
Name: "config",
Hidden: true,
Expand All @@ -95,15 +104,13 @@ func flagsConfig() []cli.Flag {
EnvVars: []string{"RMK_GITHUB_TOKEN"},
},
),
altsrc.NewStringFlag(
&cli.StringFlag{
Name: "cluster-provider",
Usage: "select cluster provider to provision clusters",
Aliases: []string{"cp"},
EnvVars: []string{"RMK_CLUSTER_PROVIDER"},
Value: util.LocalClusterProvider,
},
),
&cli.StringFlag{
Category: gcpFlagsCategory,
Name: "google-application-credentials",
Usage: "GCP service account credentials file path in JSON format",
Aliases: []string{"gac"},
EnvVars: []string{"RMK_GOOGLE_APPLICATION_CREDENTIALS", "GOOGLE_APPLICATION_CREDENTIALS"},
},
altsrc.NewBoolFlag(
&cli.BoolFlag{
Name: "progress-bar",
Expand Down
6 changes: 6 additions & 0 deletions cmd/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"rmk/notification"
"rmk/providers/aws_provider"
"rmk/providers/azure_provider"
"rmk/providers/google_provider"
"rmk/util"
)

Expand Down Expand Up @@ -164,6 +165,11 @@ func (rc *ReleaseCommands) prepareHelmfile(args ...string) *util.SpecCMD {
envs = append(envs,
"AZURE_SUBSCRIPTION_ID="+rc.Conf.AzureConfigure.SubscriptionID,
)
case google_provider.GoogleClusterProvider:
envs = append(envs,
"GCP_PROJECT_ID="+rc.Conf.GCPConfigure.ProjectID,
"GOOGLE_APPLICATION_CREDENTIALS="+rc.Conf.GCPConfigure.AppCredentialsPath,
)
}

for _, val := range rc.Conf.HooksMapping {
Expand Down
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"rmk/git_handler"
"rmk/providers/aws_provider"
"rmk/providers/azure_provider"
"rmk/providers/google_provider"
"rmk/util"
)

Expand All @@ -39,6 +40,7 @@ type Config struct {
AWSMFATokenExpiration string `yaml:"aws-mfa-token-expiration,omitempty"`
*aws_provider.AwsConfigure `yaml:"aws,omitempty"`
*azure_provider.AzureConfigure `yaml:"azure,omitempty"`
*google_provider.GCPConfigure `yaml:"gcp,omitempty"`
ProgressBar bool `yaml:"progress-bar"`
ProjectFile `yaml:"project-file"`
}
Expand Down
Loading

0 comments on commit 57d810c

Please sign in to comment.