Skip to content

Commit

Permalink
Refine "antctl mc deploy" command (#5080)
Browse files Browse the repository at this point in the history
There is a bug that when user deploys Antrea Multi-cluster via
`antctl mc` on EKS clusters, user can't create ClusterSet and
ClusterClaims with an error like below:
```
Internal error occurred: failed calling webhook "vclusterclaim.kb.io":
failed to call webhook: ... x509: certificate signed by unknown
authority
```

It is caused by a slow deployment when using `antctl mc deploy`, that
antrea-mc-controller is running but the validation webhook
configuration is not created yet, and the `cabundle` in the webhook
configuration won't be updated. It turns out `GetAPIGroupResources` is
a time-consuming step and it is also unnecessary to be called every
time in a loop, so this commit moves it out to the caller with a few
other refinements to fix the issue.

Signed-off-by: Lan Luo <[email protected]>
  • Loading branch information
luolanzone authored Jun 20, 2023
1 parent 1ca159f commit c920779
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 12 deletions.
29 changes: 18 additions & 11 deletions pkg/antctl/raw/multicluster/deploy/deploy_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const (
)

var httpGet = http.Get
var getAPIGroupResources = getAPIGroupResourcesWrapper

func generateManifests(role string, version string) ([]string, error) {
var manifests []string
Expand Down Expand Up @@ -82,9 +83,10 @@ func generateManifests(role string, version string) ([]string, error) {
return manifests, nil
}

func createResources(cmd *cobra.Command, k8sClient kubernetes.Interface, dynamicClient dynamic.Interface, content []byte) error {
func createResources(cmd *cobra.Command, apiGroupResources []*restmapper.APIGroupResources, dynamicClient dynamic.Interface, content []byte) error {
var err error
decoder := yamlutil.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(content)), 100)
unstructuredObjs := map[dynamic.ResourceInterface]*unstructured.Unstructured{}
for {
var rawObj runtime.RawExtension
if err = decoder.Decode(&rawObj); err != nil {
Expand All @@ -101,25 +103,21 @@ func createResources(cmd *cobra.Command, k8sClient kubernetes.Interface, dynamic
}

unstructuredObj := &unstructured.Unstructured{Object: unstructuredMap}

gr, err := restmapper.GetAPIGroupResources(k8sClient.Discovery())
if err != nil {
return err
}

mapper := restmapper.NewDiscoveryRESTMapper(gr)
mapper := restmapper.NewDiscoveryRESTMapper(apiGroupResources)
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return err
}

var dri dynamic.ResourceInterface
if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
dri = dynamicClient.Resource(mapping.Resource).Namespace(unstructuredObj.GetNamespace())
} else {
dri = dynamicClient.Resource(mapping.Resource)
}
unstructuredObjs[dri] = unstructuredObj
}

for dri, unstructuredObj := range unstructuredObjs {
if _, err := dri.Create(context.TODO(), unstructuredObj, metav1.CreateOptions{}); err != nil {
if !kerrors.IsAlreadyExists(err) {
return err
Expand Down Expand Up @@ -149,12 +147,17 @@ func deploy(cmd *cobra.Command, role string, version string, namespace string, f
return err
}

apiGroupResources, err := getAPIGroupResources(k8sClient)
if err != nil {
return err
}

if filename != "" {
content, err := os.ReadFile(filename)
if err != nil {
return err
}
if err := createResources(cmd, k8sClient, dynamicClient, content); err != nil {
if err := createResources(cmd, apiGroupResources, dynamicClient, content); err != nil {
return err
}
} else {
Expand All @@ -180,11 +183,15 @@ func deploy(cmd *cobra.Command, role string, version string, namespace string, f
if role == memberRole && strings.Contains(manifest, "member") && namespace != common.DefaultMemberNamespace {
content = strings.ReplaceAll(content, common.DefaultMemberNamespace, namespace)
}
if err := createResources(cmd, k8sClient, dynamicClient, []byte(content)); err != nil {
if err := createResources(cmd, apiGroupResources, dynamicClient, []byte(content)); err != nil {
return err
}
}
}
fmt.Fprintf(cmd.OutOrStdout(), "Antrea Multi-cluster successfully deployed\n")
return nil
}

func getAPIGroupResourcesWrapper(k8sClient kubernetes.Interface) ([]*restmapper.APIGroupResources, error) {
return restmapper.GetAPIGroupResources(k8sClient.Discovery())
}
11 changes: 10 additions & 1 deletion pkg/antctl/raw/multicluster/deploy/deploy_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import (
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
dynamicfake "k8s.io/client-go/dynamic/fake"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/restmapper"

mcscheme "antrea.io/antrea/pkg/antctl/raw/multicluster/scheme"
)
Expand Down Expand Up @@ -98,13 +100,14 @@ func TestGenerateManifests(t *testing.T) {
func TestCreateResources(t *testing.T) {
fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(mcscheme.Scheme)
fakeClient := fake.NewSimpleClientset()
apiGroupResources, _ := restmapper.GetAPIGroupResources(fakeClient.Discovery())
cmd := &cobra.Command{}
file := filepath.Join("..", "..", "..", "..", "..", "multicluster", "build", "yamls", "antrea-multicluster-leader-global.yml")
content, err := os.ReadFile(file)
if err != nil {
t.Errorf("Failed to open the file %s", file)
}
err = createResources(cmd, fakeClient, fakeDynamicClient, content)
err = createResources(cmd, apiGroupResources, fakeDynamicClient, content)
if err != nil {
assert.Contains(t, err.Error(), "no matches for kind \"CustomResourceDefinition\"")
}
Expand Down Expand Up @@ -135,6 +138,8 @@ kind: Config`)
kubeconfig := ""
cmd := &cobra.Command{}
cmd.Flags().StringVarP(&kubeconfig, "kubeconfig", "k", fakeKubeconfig.Name(), "path of kubeconfig")
fakeClient := fake.NewSimpleClientset()

tests := []struct {
name string
body string
Expand All @@ -156,8 +161,12 @@ kind: Config`)
httpGet = func(url string) (resp *http.Response, err error) {
return &http.Response{Body: io.NopCloser(strings.NewReader(tt.body))}, tt.err
}
getAPIGroupResources = func(k8sClient kubernetes.Interface) ([]*restmapper.APIGroupResources, error) {
return restmapper.GetAPIGroupResources(fakeClient.Discovery())
}
defer func() {
httpGet = http.Get
getAPIGroupResources = getAPIGroupResourcesWrapper
}()
gotErr := deploy(cmd, "leader", "latest", "kube-system", "")
if tt.expectedErr != "" {
Expand Down

0 comments on commit c920779

Please sign in to comment.