-
Notifications
You must be signed in to change notification settings - Fork 0
/
gke.go
101 lines (87 loc) · 3.37 KB
/
gke.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package gke
import (
"context"
"fmt"
"cloud.google.com/go/container/apiv1"
gax "github.com/googleapis/gax-go/v2"
v1alpha1 "github.com/knelasevero/gkrator/api/v1alpha1"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2"
"google.golang.org/api/option"
containerpb "google.golang.org/genproto/googleapis/container/v1"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
gkratorclient "github.com/knelasevero/gkrator/pkg/clients"
)
const (
CloudPlatformRole = "https://www.googleapis.com/auth/cloud-platform"
errSpec = "cluster spec is nil"
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
errMissingSAK = "missing SecretAccessKey"
errUnableProcessJSONCredentials = "failed to process the provided JSON credentials: %w"
errUnableCreateGCPClient = "failed to create GCP client: %w"
errUnableGetCredentials = "unable to get credentials: %w"
)
type GoogleGKEClient interface {
CreateCluster(ctx context.Context, req *containerpb.CreateClusterRequest, opts ...gax.CallOption) (*containerpb.Operation, error)
CreateNodePool(ctx context.Context, req *containerpb.CreateNodePoolRequest, opts ...gax.CallOption) (*containerpb.Operation, error)
DeleteCluster(ctx context.Context, req *containerpb.DeleteClusterRequest, opts ...gax.CallOption) (*containerpb.Operation, error)
DeleteNodePool(ctx context.Context, req *containerpb.DeleteNodePoolRequest, opts ...gax.CallOption) (*containerpb.Operation, error)
Close() error
}
type GKE struct {
credentials []byte
GoogleGKEClient GoogleGKEClient
projectID string
}
// NewClient constructs a GCP Provider.
func (g *GKE) NewClient(ctx context.Context, gke v1alpha1.GoogleKubernetesEngine, kube kclient.Client, namespace string) (gkratorclient.Client, error) {
defer func() {
// closes IAMClient to prevent gRPC connection leak in case of an error.
if g.GoogleGKEClient == nil {
_ = g.GoogleGKEClient.Close()
}
}()
g.projectID = gke.Spec.ProjectID
ts, err := serviceAccountTokenSource(ctx, gke, kube, namespace)
if err != nil {
return nil, fmt.Errorf(errUnableCreateGCPClient, err)
}
// check if we can get credentials
_, err = ts.Token()
if err != nil {
return nil, fmt.Errorf(errUnableGetCredentials, err)
}
c, err := container.NewClusterManagerClient(ctx, option.WithTokenSource(ts))
if err != nil {
return nil, err
}
g.GoogleGKEClient = c
return c, nil
}
func serviceAccountTokenSource(ctx context.Context, gke v1alpha1.GoogleKubernetesEngine, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
sr := gke.Spec.Auth.SecretRef
if sr == nil {
return nil, nil
}
credentialsSecret := &v1.Secret{}
credentialsSecretName := sr.SecretAccessKey.Name
objectKey := types.NamespacedName{
Name: credentialsSecretName,
Namespace: namespace,
}
err := kube.Get(ctx, objectKey, credentialsSecret)
if err != nil {
return nil, fmt.Errorf(errFetchSAKSecret, err)
}
credentials := credentialsSecret.Data[sr.SecretAccessKey.Key]
if (credentials == nil) || (len(credentials) == 0) {
return nil, fmt.Errorf(errMissingSAK)
}
config, err := google.JWTConfigFromJSON(credentials, CloudPlatformRole)
if err != nil {
return nil, fmt.Errorf(errUnableProcessJSONCredentials, err)
}
return config.TokenSource(ctx), nil
}