Skip to content

Commit

Permalink
feat: GKE connection
Browse files Browse the repository at this point in the history
  • Loading branch information
adityathebe committed Dec 3, 2024
1 parent 9266bb7 commit ad52882
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 100 deletions.
52 changes: 52 additions & 0 deletions connection/eks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package connection

import (
"fmt"

"github.com/flanksource/duty/context"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

// +kubebuilder:object:generate=true
type EKSConnection struct {
AWSConnection `json:",inline" yaml:",inline"`

Cluster string `json:"cluster"`
}

func (t *EKSConnection) Populate(ctx ConnectionContext) error {
return t.AWSConnection.Populate(ctx)
}

func (t *EKSConnection) KubernetesClient(ctx context.Context) (kubernetes.Interface, *rest.Config, error) {
awsConfig, err := t.AWSConnection.Client(ctx)
if err != nil {
return nil, nil, err
}

eksEndpoint, ca, err := eksClusterDetails(ctx, t.Cluster, awsConfig)
if err != nil {
return nil, nil, err
}

token, err := getEKSToken(ctx, t.Cluster, awsConfig)
if err != nil {
return nil, nil, fmt.Errorf("failed to get token for EKS: %w", err)
}

restConfig := &rest.Config{
Host: eksEndpoint,
BearerToken: token,
TLSClientConfig: rest.TLSClientConfig{
CAData: ca,
},
}

clientset, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return nil, nil, err
}

return clientset, restConfig, nil
}
52 changes: 9 additions & 43 deletions connection/gcp.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package connection

import (
"crypto/tls"
"net/http"

gcs "cloud.google.com/go/storage"
"golang.org/x/oauth2/google"

"github.com/flanksource/commons/utils"
"github.com/flanksource/duty/context"
"github.com/flanksource/duty/types"
"google.golang.org/api/option"
)

// +kubebuilder:object:generate=true
Expand All @@ -23,51 +19,21 @@ type GCPConnection struct {
SkipTLSVerify bool `yaml:"skipTLSVerify,omitempty" json:"skipTLSVerify,omitempty"`
}

func (conn *GCPConnection) Client(ctx context.Context) (*gcs.Client, error) {
conn = conn.Validate()
var client *gcs.Client
var err error

var clientOpts []option.ClientOption

if conn.Endpoint != "" {
clientOpts = append(clientOpts, option.WithEndpoint(conn.Endpoint))
}

if conn.SkipTLSVerify {
insecureHTTPClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}

clientOpts = append(clientOpts, option.WithHTTPClient(insecureHTTPClient))
func (g *GCPConnection) Validate() *GCPConnection {
if g == nil {
return &GCPConnection{}
}

if conn.Credentials != nil && !conn.Credentials.IsEmpty() {
credential, err := ctx.GetEnvValueFromCache(*conn.Credentials, ctx.GetNamespace())
if err != nil {
return nil, err
}
clientOpts = append(clientOpts, option.WithCredentialsJSON([]byte(credential)))
} else {
clientOpts = append(clientOpts, option.WithoutAuthentication())
}
return g
}

client, err = gcs.NewClient(ctx.Context, clientOpts...)
func (g *GCPConnection) Creds(ctx context.Context, scopes ...string) (*google.Credentials, error) {
creds, err := google.CredentialsFromJSON(ctx, []byte(g.Credentials.ValueStatic), scopes...)
if err != nil {
return nil, err
}

return client, nil
}

func (g *GCPConnection) Validate() *GCPConnection {
if g == nil {
return &GCPConnection{}
}

return g
return creds, nil
}

// HydrateConnection attempts to find the connection by name
Expand Down
45 changes: 45 additions & 0 deletions connection/gcs.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package connection

import (
"crypto/tls"
"net/http"

gcs "cloud.google.com/go/storage"
"github.com/flanksource/duty/context"
"github.com/flanksource/duty/types"
"google.golang.org/api/option"
)

// +kubebuilder:object:generate=true
Expand All @@ -18,6 +24,45 @@ func (g *GCSConnection) Validate() *GCSConnection {
return g
}

func (g *GCSConnection) Client(ctx context.Context) (*gcs.Client, error) {
g = g.Validate()
var client *gcs.Client
var err error

var clientOpts []option.ClientOption

if g.Endpoint != "" {
clientOpts = append(clientOpts, option.WithEndpoint(g.Endpoint))
}

if g.SkipTLSVerify {
insecureHTTPClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}

clientOpts = append(clientOpts, option.WithHTTPClient(insecureHTTPClient))
}

if g.Credentials != nil && !g.Credentials.IsEmpty() {
credential, err := ctx.GetEnvValueFromCache(*g.Credentials, ctx.GetNamespace())
if err != nil {
return nil, err
}
clientOpts = append(clientOpts, option.WithCredentialsJSON([]byte(credential)))
} else {
clientOpts = append(clientOpts, option.WithoutAuthentication())
}

client, err = gcs.NewClient(ctx.Context, clientOpts...)
if err != nil {
return nil, err
}

return client, nil
}

// HydrateConnection attempts to find the connection by name
// and populate the endpoint and credentials.
func (g *GCSConnection) HydrateConnection(ctx ConnectionContext) error {
Expand Down
116 changes: 116 additions & 0 deletions connection/gke.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package connection

import (
"crypto/tls"
"encoding/base64"
"fmt"
"net/http"

"github.com/flanksource/duty/context"
container "google.golang.org/api/container/v1"
"google.golang.org/api/option"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

// +kubebuilder:object:generate=true
type GKEConnection struct {
GCPConnection `json:",inline" yaml:",inline"`

ProjectID string `json:"projectID"`
Zone string `json:"zone"`
Cluster string `json:"cluster"`
}

func (t *GKEConnection) Populate(ctx ConnectionContext) error {
return t.GCPConnection.HydrateConnection(ctx)
}

func (t *GKEConnection) Validate() *GKEConnection {
if t == nil {
return &GKEConnection{}
}

return t
}

func (t *GKEConnection) Client(ctx context.Context) (*container.Service, error) {
t = t.Validate()

var clientOpts []option.ClientOption

if t.Endpoint != "" {
clientOpts = append(clientOpts, option.WithEndpoint(t.Endpoint))
}

if t.SkipTLSVerify {
insecureHTTPClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}

clientOpts = append(clientOpts, option.WithHTTPClient(insecureHTTPClient))
}

if t.Credentials != nil && !t.Credentials.IsEmpty() {
credential, err := ctx.GetEnvValueFromCache(*t.Credentials, ctx.GetNamespace())
if err != nil {
return nil, err
}
clientOpts = append(clientOpts, option.WithCredentialsJSON([]byte(credential)))
} else {
clientOpts = append(clientOpts, option.WithoutAuthentication())
}

svc, err := container.NewService(ctx, clientOpts...)
if err != nil {
return nil, err
}

return svc, nil
}

func (t *GKEConnection) KubernetesClient(ctx context.Context) (kubernetes.Interface, *rest.Config, error) {
containerService, err := t.Client(ctx)
if err != nil {
return nil, nil, err
}

clusterName := fmt.Sprintf("projects/%s/locations/%s/clusters/%s", t.ProjectID, t.Zone, t.Cluster)
cluster, err := containerService.Projects.Locations.Clusters.Get(clusterName).Context(ctx).Do()
if err != nil {
return nil, nil, fmt.Errorf("failed to get cluster: %w", err)
}

creds, err := t.GCPConnection.Creds(ctx, container.CloudPlatformScope)
if err != nil {
return nil, nil, err
}

tokenSource := creds.TokenSource
token, err := tokenSource.Token()
if err != nil {
return nil, nil, err
}

ca, err := base64.URLEncoding.DecodeString(cluster.MasterAuth.ClusterCaCertificate)
if err != nil {
return nil, nil, fmt.Errorf("unable to presign URL: %v", err)
}

restConfig := &rest.Config{
Host: "https://" + cluster.Endpoint,
BearerToken: token.AccessToken,
TLSClientConfig: rest.TLSClientConfig{
CAData: ca,
},
}

clientset, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return nil, nil, err
}

return clientset, restConfig, nil
}
59 changes: 3 additions & 56 deletions connection/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,6 @@ func (t *KubeconfigConnection) Populate(ctx context.Context) (kubernetes.Interfa
return nil, nil, nil
}

// +kubebuilder:object:generate=true
type EKSConnection struct {
AWSConnection `json:",inline" yaml:",inline"`

Cluster string `json:"cluster"`
}

// +kubebuilder:object:generate=true
type GKEConnection struct {
GCPConnection `json:",inline" yaml:",inline"`

Cluster string `json:"cluster"`
}

// +kubebuilder:object:generate=true
type KubernetesConnection struct {
KubeconfigConnection `json:",inline"`
Expand All @@ -94,58 +80,19 @@ func (t *KubernetesConnection) Populate(ctx context.Context) (kubernetes.Interfa
}

if t.GKE != nil {
if err := t.GKE.GCPConnection.HydrateConnection(ctx); err != nil {
if err := t.GKE.Populate(ctx); err != nil {
return nil, nil, err
}

gClient, err := t.GKE.GCPConnection.Client(ctx)
if err != nil {
return nil, nil, err
}

fmt.Println("location", gClient)

// get the gcloud access token

// get the kubeconfig

// Set the token
return t.GKE.KubernetesClient(ctx)
}

if t.EKS != nil {
if err := t.EKS.Populate(ctx); err != nil {
return nil, nil, err
}

awsConfig, err := t.EKS.AWSConnection.Client(ctx)
if err != nil {
return nil, nil, err
}

eksEndpoint, ca, err := eksClusterDetails(ctx, t.EKS.Cluster, awsConfig)
if err != nil {
return nil, nil, err
}

token, err := getEKSToken(ctx, t.EKS.Cluster, awsConfig)
if err != nil {
return nil, nil, fmt.Errorf("failed to get token for EKS: %w", err)
}

restConfig := &rest.Config{
Host: eksEndpoint,
BearerToken: token,
TLSClientConfig: rest.TLSClientConfig{
CAData: ca,
},
}

clientset, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return nil, nil, err
}

return clientset, restConfig, nil
return t.EKS.KubernetesClient(ctx)
}

return nil, nil, nil
Expand Down
Loading

0 comments on commit ad52882

Please sign in to comment.