mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-08-23 22:26:49 +00:00
Merge pull request #75 from skeeey/performance
add hub kubeconfig secret controller to replace mount secret directly
This commit is contained in:
@@ -28,13 +28,12 @@ spec:
|
||||
- name: bootstrap-secret
|
||||
mountPath: "/spoke/bootstrap"
|
||||
readOnly: true
|
||||
- name: hub-kubeconfig-secret
|
||||
- name: hub-kubeconfig
|
||||
mountPath: "/spoke/hub-kubeconfig"
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: bootstrap-secret
|
||||
secret:
|
||||
secretName: bootstrap-secret
|
||||
- name: hub-kubeconfig-secret
|
||||
secret:
|
||||
secretName: hub-kubeconfig-secret
|
||||
- name: hub-kubeconfig
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
|
||||
@@ -32,7 +32,6 @@ resources:
|
||||
- ./role.yaml
|
||||
- ./role_binding.yaml
|
||||
- ./deployment.yaml
|
||||
- ./secret.yaml
|
||||
|
||||
images:
|
||||
- name: quay.io/open-cluster-management/registration:latest
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: hub-kubeconfig-secret
|
||||
type: Opaque
|
||||
data:
|
||||
placeholder: YWRtaW4=
|
||||
@@ -1,6 +1,9 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -184,3 +187,18 @@ func AssertLeaseUpdated(t *testing.T, lease, lastLease *coordinationv1.Lease) {
|
||||
t.Errorf("expected lease updated, but failed")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertFileExist asserts a given file exists
|
||||
func AssertFileExist(t *testing.T, filePath string) {
|
||||
if _, err := os.Stat(filePath); err != nil {
|
||||
t.Errorf("expected file %q exits, but got error %v", filePath, err)
|
||||
}
|
||||
}
|
||||
|
||||
// AssertFileContent asserts a given file content
|
||||
func AssertFileContent(t *testing.T, filePath string, expectedContent []byte) {
|
||||
content, _ := ioutil.ReadFile(filePath)
|
||||
if !bytes.Equal(content, expectedContent) {
|
||||
t.Errorf("expect %v, but got %v", expectedContent, content)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/openshift/library-go/pkg/controller/factory"
|
||||
@@ -143,20 +142,6 @@ func (c *ClientCertForHubController) sync(ctx context.Context, syncCtx factory.S
|
||||
return nil
|
||||
}
|
||||
|
||||
// save the cluster name and agent name into secret if they are not saved yet
|
||||
newSecretConfig := map[string][]byte{}
|
||||
for k, v := range secret.Data {
|
||||
newSecretConfig[k] = v
|
||||
}
|
||||
newSecretConfig[ClusterNameFile] = []byte(c.clusterName)
|
||||
newSecretConfig[AgentNameFile] = []byte(c.agentName)
|
||||
if !reflect.DeepEqual(newSecretConfig, secret.Data) {
|
||||
secret.Data = newSecretConfig
|
||||
if err := c.saveHubKubeconfigSecret(secret); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// create a csr to request new client certificate if
|
||||
// a. there is no client certificate
|
||||
// b. client certificate exists and has less than 20% of its life remaining
|
||||
|
||||
@@ -3,7 +3,6 @@ package hubclientcert
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/informers"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
@@ -48,21 +46,8 @@ func TestSync(t *testing.T) {
|
||||
if _, ok := actual.(*certificates.CertificateSigningRequest); !ok {
|
||||
t.Errorf("expected csr was created, but failed")
|
||||
}
|
||||
expectedSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testNamespace,
|
||||
Name: testSecretName,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
ClusterNameFile: []byte(testinghelpers.TestManagedClusterName),
|
||||
AgentNameFile: []byte(testAgentName),
|
||||
},
|
||||
}
|
||||
testinghelpers.AssertActions(t, agentActions, "create")
|
||||
actualSecret := agentActions[0].(clienttesting.CreateActionImpl).Object
|
||||
if !reflect.DeepEqual(expectedSecret, actualSecret) {
|
||||
t.Errorf("expected secret %v, but got %v", expectedSecret, actualSecret)
|
||||
}
|
||||
|
||||
testinghelpers.AssertNoActions(t, agentActions)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package hubclientcert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/openshift/library-go/pkg/controller/factory"
|
||||
"github.com/openshift/library-go/pkg/operator/events"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
corev1lister "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// hubKubeconfigSecretController watches the HubKubeconfig secret, if the secret is changed, this controller creates/updates the
|
||||
// corresponding configuration files from the secret
|
||||
type hubKubeconfigSecretController struct {
|
||||
hubKubeconfigDir string
|
||||
hubKubeconfigSecretNamespace string
|
||||
hubKubeconfigSecretName string
|
||||
spokeSecretLister corev1lister.SecretLister
|
||||
}
|
||||
|
||||
// NewHubKubeconfigSecretController returns a new HubKubeconfigSecretController
|
||||
func NewHubKubeconfigSecretController(
|
||||
hubKubeconfigDir, hubKubeconfigSecretNamespace, hubKubeconfigSecretName string,
|
||||
spokeSecretInformer corev1informers.SecretInformer,
|
||||
recorder events.Recorder) factory.Controller {
|
||||
s := &hubKubeconfigSecretController{
|
||||
hubKubeconfigDir: hubKubeconfigDir,
|
||||
hubKubeconfigSecretNamespace: hubKubeconfigSecretNamespace,
|
||||
hubKubeconfigSecretName: hubKubeconfigSecretName,
|
||||
spokeSecretLister: spokeSecretInformer.Lister(),
|
||||
}
|
||||
|
||||
return factory.New().
|
||||
WithInformersQueueKeyFunc(
|
||||
func(obj runtime.Object) string {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if accessor.GetNamespace() == hubKubeconfigSecretNamespace && accessor.GetName() == hubKubeconfigSecretName {
|
||||
return accessor.GetName()
|
||||
}
|
||||
return ""
|
||||
}, spokeSecretInformer.Informer()).
|
||||
WithSync(s.sync).
|
||||
ToController("HubKubeconfigSecretController", recorder)
|
||||
}
|
||||
|
||||
func (s *hubKubeconfigSecretController) sync(ctx context.Context, syncCtx factory.SyncContext) error {
|
||||
hubKubeconfigSecretName := syncCtx.QueueKey()
|
||||
if hubKubeconfigSecretName == "" {
|
||||
return nil
|
||||
}
|
||||
klog.V(4).Infof("Reconciling Hub KubeConfig secret %q", hubKubeconfigSecretName)
|
||||
secret, err := s.spokeSecretLister.Secrets(s.hubKubeconfigSecretNamespace).Get(hubKubeconfigSecretName)
|
||||
if errors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get secret %s/%s : %w", s.hubKubeconfigSecretNamespace, s.hubKubeconfigSecretName, err)
|
||||
}
|
||||
|
||||
// if the secret is invalid, ignore it
|
||||
if !hasValidKubeconfig(secret) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(s.hubKubeconfigDir, 0700); err != nil {
|
||||
return fmt.Errorf("unable to create dir %q : %w", s.hubKubeconfigDir, err)
|
||||
}
|
||||
|
||||
// create/update configuration files from the secret
|
||||
for key, data := range secret.Data {
|
||||
configFilePath := path.Join(s.hubKubeconfigDir, key)
|
||||
if err := writeConfigFile(configFilePath, data, syncCtx.Recorder()); err != nil {
|
||||
return fmt.Errorf("unable to write config file %q: %w", configFilePath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeConfigFile creates or updates a specified file and record an event to log it.
|
||||
func writeConfigFile(filename string, data []byte, recorder events.Recorder) error {
|
||||
lastData, err := ioutil.ReadFile(filename)
|
||||
if os.IsNotExist(err) {
|
||||
if err := ioutil.WriteFile(path.Clean(filename), data, 0400); err != nil {
|
||||
return err
|
||||
}
|
||||
recorder.Event("HubKubeConfigFileCreated", fmt.Sprintf("Hub config file %q is created from hub kubeconfig secret", filename))
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(lastData, data) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path.Clean(filename), data, 0400); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
recorder.Event("HubKubeConfigFileUpdated", fmt.Sprintf("Hub config file %q is updated from hub kubeconfig secret", filename))
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package hubclientcert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
testinghelpers "github.com/open-cluster-management/registration/pkg/helpers/testing"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/rand"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
func TestHubKubeconfigSecretSync(t *testing.T) {
|
||||
testDir, err := ioutil.TempDir("", "testhubkubeconfigsecretsync")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
kubeConfigFile := testinghelpers.NewKubeconfig(nil, nil)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
queueKey string
|
||||
secret *corev1.Secret
|
||||
oldConfigData map[string][]byte
|
||||
validateFiles func(t *testing.T, fileDir string)
|
||||
}{
|
||||
{
|
||||
name: "no secret",
|
||||
queueKey: "",
|
||||
validateFiles: func(t *testing.T, hubKubeconfigDir string) {
|
||||
files, err := ioutil.ReadDir(hubKubeconfigDir)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if len(files) != 0 {
|
||||
t.Errorf("expect no files, but get %d files", len(files))
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid secret",
|
||||
queueKey: testSecretName,
|
||||
secret: testinghelpers.NewHubKubeconfigSecret(testNamespace, testSecretName, "", nil, map[string][]byte{}),
|
||||
validateFiles: func(t *testing.T, hubKubeconfigDir string) {
|
||||
files, err := ioutil.ReadDir(hubKubeconfigDir)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if len(files) != 0 {
|
||||
t.Errorf("expect no files, but get %d files", len(files))
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secret is created",
|
||||
queueKey: testSecretName,
|
||||
secret: testinghelpers.NewHubKubeconfigSecret(
|
||||
testNamespace, testSecretName, "",
|
||||
testinghelpers.NewTestCert("test", 60*time.Second),
|
||||
map[string][]byte{
|
||||
ClusterNameFile: []byte("test"),
|
||||
AgentNameFile: []byte("test"),
|
||||
KubeconfigFile: testinghelpers.NewKubeconfig(nil, nil),
|
||||
},
|
||||
),
|
||||
validateFiles: func(t *testing.T, hubKubeconfigDir string) {
|
||||
testinghelpers.AssertFileContent(t, path.Join(hubKubeconfigDir, ClusterNameFile), []byte("test"))
|
||||
testinghelpers.AssertFileContent(t, path.Join(hubKubeconfigDir, AgentNameFile), []byte("test"))
|
||||
testinghelpers.AssertFileContent(t, path.Join(hubKubeconfigDir, KubeconfigFile), kubeConfigFile)
|
||||
testinghelpers.AssertFileExist(t, path.Join(hubKubeconfigDir, TLSKeyFile))
|
||||
testinghelpers.AssertFileExist(t, path.Join(hubKubeconfigDir, TLSCertFile))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secret is updated",
|
||||
queueKey: testSecretName,
|
||||
oldConfigData: map[string][]byte{
|
||||
ClusterNameFile: []byte("test"),
|
||||
AgentNameFile: []byte("test"),
|
||||
KubeconfigFile: []byte("test"),
|
||||
},
|
||||
secret: testinghelpers.NewHubKubeconfigSecret(
|
||||
testNamespace, testSecretName, "",
|
||||
testinghelpers.NewTestCert("test", 60*time.Second),
|
||||
map[string][]byte{
|
||||
ClusterNameFile: []byte("test1"),
|
||||
AgentNameFile: []byte("test"),
|
||||
KubeconfigFile: testinghelpers.NewKubeconfig(nil, nil),
|
||||
},
|
||||
),
|
||||
validateFiles: func(t *testing.T, hubKubeconfigDir string) {
|
||||
testinghelpers.AssertFileContent(t, path.Join(hubKubeconfigDir, ClusterNameFile), []byte("test1"))
|
||||
testinghelpers.AssertFileContent(t, path.Join(hubKubeconfigDir, AgentNameFile), []byte("test"))
|
||||
testinghelpers.AssertFileContent(t, path.Join(hubKubeconfigDir, KubeconfigFile), kubeConfigFile)
|
||||
testinghelpers.AssertFileExist(t, path.Join(hubKubeconfigDir, TLSKeyFile))
|
||||
testinghelpers.AssertFileExist(t, path.Join(hubKubeconfigDir, TLSCertFile))
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
kubeClient := kubefake.NewSimpleClientset()
|
||||
kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClient, time.Minute*10)
|
||||
secretStore := kubeInformerFactory.Core().V1().Secrets().Informer().GetStore()
|
||||
if c.secret != nil {
|
||||
secretStore.Add(c.secret)
|
||||
}
|
||||
|
||||
hubKubeconfigDir := path.Join(testDir, fmt.Sprintf("/%s/hub-kubeconfig", rand.String(6)))
|
||||
if err := os.MkdirAll(hubKubeconfigDir, 0755); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
for k, v := range c.oldConfigData {
|
||||
testinghelpers.WriteFile(path.Join(hubKubeconfigDir, k), v)
|
||||
}
|
||||
|
||||
ctrl := hubKubeconfigSecretController{
|
||||
hubKubeconfigDir: hubKubeconfigDir,
|
||||
hubKubeconfigSecretName: testSecretName,
|
||||
hubKubeconfigSecretNamespace: testNamespace,
|
||||
spokeSecretLister: kubeInformerFactory.Core().V1().Secrets().Lister(),
|
||||
}
|
||||
syncErr := ctrl.sync(context.TODO(), testinghelpers.NewFakeSyncContext(t, c.queueKey))
|
||||
if syncErr != nil {
|
||||
t.Errorf("unexpected err: %v", syncErr)
|
||||
}
|
||||
|
||||
c.validateFiles(t, hubKubeconfigDir)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -128,6 +128,13 @@ func (o *SpokeAgentOptions) RunSpokeAgent(ctx context.Context, controllerContext
|
||||
)
|
||||
go spokeClusterCreatingController.Run(ctx, 1)
|
||||
|
||||
hubKubeconfigSecretController := hubclientcert.NewHubKubeconfigSecretController(
|
||||
o.HubKubeconfigDir, o.ComponentNamespace, o.HubKubeconfigSecret,
|
||||
spokeKubeInformerFactory.Core().V1().Secrets(),
|
||||
controllerContext.EventRecorder,
|
||||
)
|
||||
go hubKubeconfigSecretController.Run(ctx, 1)
|
||||
|
||||
// check if there already exists a valid client config for hub
|
||||
ok, err := o.hasValidHubClientConfig()
|
||||
if err != nil {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// deploy/spoke/namespace.yaml
|
||||
// deploy/spoke/role.yaml
|
||||
// deploy/spoke/role_binding.yaml
|
||||
// deploy/spoke/secret.yaml
|
||||
// deploy/spoke/service_account.yaml
|
||||
package bindata
|
||||
|
||||
@@ -149,16 +148,15 @@ spec:
|
||||
- name: bootstrap-secret
|
||||
mountPath: "/spoke/bootstrap"
|
||||
readOnly: true
|
||||
- name: hub-kubeconfig-secret
|
||||
- name: hub-kubeconfig
|
||||
mountPath: "/spoke/hub-kubeconfig"
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: bootstrap-secret
|
||||
secret:
|
||||
secretName: bootstrap-secret
|
||||
- name: hub-kubeconfig-secret
|
||||
secret:
|
||||
secretName: hub-kubeconfig-secret
|
||||
- name: hub-kubeconfig
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
`)
|
||||
|
||||
func deploySpokeDeploymentYamlBytes() ([]byte, error) {
|
||||
@@ -210,7 +208,6 @@ resources:
|
||||
- ./role.yaml
|
||||
- ./role_binding.yaml
|
||||
- ./deployment.yaml
|
||||
- ./secret.yaml
|
||||
|
||||
images:
|
||||
- name: quay.io/open-cluster-management/registration:latest
|
||||
@@ -315,30 +312,6 @@ func deploySpokeRole_bindingYaml() (*asset, error) {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _deploySpokeSecretYaml = []byte(`apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: hub-kubeconfig-secret
|
||||
type: Opaque
|
||||
data:
|
||||
placeholder: YWRtaW4=
|
||||
`)
|
||||
|
||||
func deploySpokeSecretYamlBytes() ([]byte, error) {
|
||||
return _deploySpokeSecretYaml, nil
|
||||
}
|
||||
|
||||
func deploySpokeSecretYaml() (*asset, error) {
|
||||
bytes, err := deploySpokeSecretYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "deploy/spoke/secret.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _deploySpokeService_accountYaml = []byte(`apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
@@ -419,7 +392,6 @@ var _bindata = map[string]func() (*asset, error){
|
||||
"deploy/spoke/namespace.yaml": deploySpokeNamespaceYaml,
|
||||
"deploy/spoke/role.yaml": deploySpokeRoleYaml,
|
||||
"deploy/spoke/role_binding.yaml": deploySpokeRole_bindingYaml,
|
||||
"deploy/spoke/secret.yaml": deploySpokeSecretYaml,
|
||||
"deploy/spoke/service_account.yaml": deploySpokeService_accountYaml,
|
||||
}
|
||||
|
||||
@@ -473,7 +445,6 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"namespace.yaml": {deploySpokeNamespaceYaml, map[string]*bintree{}},
|
||||
"role.yaml": {deploySpokeRoleYaml, map[string]*bintree{}},
|
||||
"role_binding.yaml": {deploySpokeRole_bindingYaml, map[string]*bintree{}},
|
||||
"secret.yaml": {deploySpokeSecretYaml, map[string]*bintree{}},
|
||||
"service_account.yaml": {deploySpokeService_accountYaml, map[string]*bintree{}},
|
||||
}},
|
||||
}},
|
||||
|
||||
+17
-37
@@ -162,6 +162,23 @@ var _ = ginkgo.Describe("Loopback registration [development]", func() {
|
||||
})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
sa := &corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: nsName,
|
||||
Name: "spoke-agent-sa",
|
||||
},
|
||||
}
|
||||
err = wait.Poll(1*time.Second, 5*time.Second, func() (bool, error) {
|
||||
var err error
|
||||
_, err = hubClient.CoreV1().ServiceAccounts(nsName).Create(context.TODO(), sa, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
var (
|
||||
deployment *unstructured.Unstructured
|
||||
deploymentResource = schema.GroupVersionResource{
|
||||
@@ -184,43 +201,6 @@ var _ = ginkgo.Describe("Loopback registration [development]", func() {
|
||||
})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: nsName,
|
||||
Name: "hub-kubeconfig-secret",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"placeholder": []byte("YWRtaW4="),
|
||||
},
|
||||
}
|
||||
err = wait.Poll(1*time.Second, 5*time.Second, func() (bool, error) {
|
||||
var err error
|
||||
_, err = hubClient.CoreV1().Secrets(nsName).Create(context.TODO(), secret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
sa := &corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: nsName,
|
||||
Name: "spoke-agent-sa",
|
||||
},
|
||||
}
|
||||
err = wait.Poll(1*time.Second, 5*time.Second, func() (bool, error) {
|
||||
var err error
|
||||
_, err = hubClient.CoreV1().ServiceAccounts(nsName).Create(context.TODO(), sa, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
var (
|
||||
csrs *certificatesv1beta1.CertificateSigningRequestList
|
||||
csrClient = hubClient.CertificatesV1beta1().CertificateSigningRequests()
|
||||
|
||||
@@ -69,10 +69,6 @@ var _ = ginkgo.Describe("Certificate Rotation", func() {
|
||||
return true
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
|
||||
// simulate k8s to mount the hub kubeconfig secret
|
||||
err = util.MountHubKubeConfigs(kubeClient, hubKubeconfigDir, testNamespace, hubKubeconfigSecret)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
// the agent should rotate the certificate because the certificate with a short valid time
|
||||
// the hub controller should auto approve it
|
||||
gomega.Eventually(func() bool {
|
||||
|
||||
@@ -68,9 +68,6 @@ var _ = ginkgo.Describe("Cluster Lease Update", func() {
|
||||
if _, err := util.GetFilledHubKubeConfigSecret(kubeClient, testNamespace, hubKubeconfigSecret); err != nil {
|
||||
return false
|
||||
}
|
||||
if err := util.MountHubKubeConfigs(kubeClient, hubKubeconfigDir, testNamespace, hubKubeconfigSecret); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
|
||||
@@ -123,9 +120,6 @@ var _ = ginkgo.Describe("Cluster Lease Update", func() {
|
||||
if _, err := util.GetFilledHubKubeConfigSecret(kubeClient, testNamespace, hubKubeconfigSecret); err != nil {
|
||||
return false
|
||||
}
|
||||
if err := util.MountHubKubeConfigs(kubeClient, hubKubeconfigDir, testNamespace, hubKubeconfigSecret); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
|
||||
|
||||
@@ -103,10 +103,6 @@ var _ = ginkgo.Describe("Agent Recovery", func() {
|
||||
return true
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
|
||||
// simulate k8s to mount the hub kubeconfig secret
|
||||
err = util.MountHubKubeConfigs(kubeClient, hubKubeconfigDir, testNamespace, hubKubeconfigSecret)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
// the spoke cluster should have joined condition finally
|
||||
gomega.Eventually(func() bool {
|
||||
spokeCluster, err := util.GetManagedCluster(clusterClient, managedClusterName)
|
||||
@@ -197,10 +193,6 @@ var _ = ginkgo.Describe("Agent Recovery", func() {
|
||||
return true
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
|
||||
// simulate k8s to mount the hub kubeconfig secret
|
||||
err = util.MountHubKubeConfigs(kubeClient, hubKubeconfigDir, testNamespace, hubKubeconfigSecret)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
// the spoke cluster should have joined condition finally
|
||||
gomega.Eventually(func() bool {
|
||||
spokeCluster, err := util.GetManagedCluster(clusterClient, spokeClusterName)
|
||||
|
||||
@@ -100,10 +100,6 @@ var _ = ginkgo.Describe("Joining Process", func() {
|
||||
return true
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
|
||||
// simulate k8s to mount the hub kubeconfig secret
|
||||
err = util.MountHubKubeConfigs(kubeClient, hubKubeconfigDir, testNamespace, hubKubeconfigSecret)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
// the spoke cluster should have joined condition finally
|
||||
gomega.Eventually(func() bool {
|
||||
spokeCluster, err := util.GetManagedCluster(clusterClient, managedClusterName)
|
||||
|
||||
@@ -307,41 +307,6 @@ func GetFilledHubKubeConfigSecret(kubeClient kubernetes.Interface, secretNamespa
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func MountHubKubeConfigs(kubeClient kubernetes.Interface, hubKubeConfigDir, secretNamespace, secretName string) error {
|
||||
if _, err := os.Stat(hubKubeConfigDir); os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(hubKubeConfigDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
secret, err := kubeClient.CoreV1().Secrets(secretNamespace).Get(context.TODO(), secretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path.Join(hubKubeConfigDir, "cluster-name"), secret.Data["cluster-name"], 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path.Join(hubKubeConfigDir, "agent-name"), secret.Data["agent-name"], 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path.Join(hubKubeConfigDir, "tls.crt"), secret.Data["tls.crt"], 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path.Join(hubKubeConfigDir, "tls.key"), secret.Data["tls.key"], 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path.Join(hubKubeConfigDir, "kubeconfig"), secret.Data["kubeconfig"], 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func FindUnapprovedSpokeCSR(kubeClient kubernetes.Interface, spokeClusterName string) (*certificates.CertificateSigningRequest, error) {
|
||||
csrList, err := kubeClient.CertificatesV1beta1().CertificateSigningRequests().List(context.TODO(), metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("open-cluster-management.io/cluster-name=%s", spokeClusterName),
|
||||
|
||||
Reference in New Issue
Block a user