/
testuser.go
115 lines (100 loc) · 2.99 KB
/
testuser.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package testuser
import (
"bytes"
"context"
"encoding/base64"
"html/template"
"time"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
cr "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/giantswarm/clustertest/pkg/client"
"github.com/giantswarm/clustertest/pkg/logger"
"github.com/giantswarm/clustertest/pkg/wait"
)
// Create handles the creation of a ServiceAccount with cluster-admin permission within the cluster
// and generated a new Kubernetes client that authenticates as that account.
func Create(ctx context.Context, kubeClient *client.Client) (*client.Client, error) {
// default namespace is created by controllers after a while
err := waitForNamespace(ctx, kubeClient)
if err != nil {
return nil, err
}
existing, err := doesUserExist(ctx, kubeClient)
if err != nil {
return nil, err
}
if !existing {
// ServiceAccount
if err := kubeClient.Create(ctx, &serviceAccount); err != nil {
return nil, err
}
// Secret
if err := kubeClient.Create(ctx, &secret); err != nil {
return nil, err
}
// ClusterRoleBinding
if err := kubeClient.Create(ctx, &clusterRoleBinding); err != nil {
return nil, err
}
}
var ca string
var token string
err = wait.For(
func() (bool, error) {
var populatedSecret corev1.Secret
err := kubeClient.Get(ctx, types.NamespacedName{Name: secret.ObjectMeta.Name, Namespace: secret.ObjectMeta.Namespace}, &populatedSecret)
if err != nil {
return false, err
}
ca = base64.StdEncoding.EncodeToString(populatedSecret.Data["ca.crt"])
token = string(populatedSecret.Data["token"])
return (ca != "" && token != ""), nil
},
wait.WithTimeout(5*time.Minute),
wait.WithInterval(1*time.Second),
)
if err != nil {
return nil, err
}
t := template.Must(template.New("kubeconfig").Parse(kubeConfigTemplate))
var buf bytes.Buffer
err = t.Execute(&buf, templateVars{
Endpoint: kubeClient.GetAPIServerEndpoint(),
AccountName: accountName,
CA: ca,
Token: token,
})
if err != nil {
return nil, err
}
return client.NewFromRawKubeconfig(buf.String())
}
func waitForNamespace(ctx context.Context, kubeClient *client.Client) error {
err := wait.For(
func() (bool, error) {
var namespace corev1.Namespace
err := kubeClient.Get(ctx, types.NamespacedName{Name: serviceAccount.Namespace}, &namespace)
if err != nil {
logger.Log("Waiting for %s namespace. Error: %v", serviceAccount.Namespace, err)
return false, nil
}
logger.Log("Namespace %s exists", serviceAccount.Namespace)
return true, nil
},
wait.WithTimeout(5*time.Minute),
wait.WithInterval(5*time.Second),
)
return err
}
func doesUserExist(ctx context.Context, kubeClient *client.Client) (bool, error) {
var existingAccount corev1.ServiceAccount
err := kubeClient.Get(ctx, cr.ObjectKeyFromObject(&serviceAccount), &existingAccount)
if err != nil && !errors.IsNotFound(err) {
return false, err
} else if errors.IsNotFound(err) {
return false, nil
}
return true, nil
}