Skip to content

Commit

Permalink
antctl command for multicluster feature
Browse files Browse the repository at this point in the history
Signed-off-by: zbangqi <zbangqi@vmware.com>
  • Loading branch information
zbangqi committed Mar 18, 2022
1 parent cbca3ff commit ed591c2
Show file tree
Hide file tree
Showing 9 changed files with 517 additions and 28 deletions.
2 changes: 1 addition & 1 deletion pkg/antctl/command_definition_test.go
Expand Up @@ -31,6 +31,7 @@ import (

"antrea.io/antrea/pkg/agent/apiserver/handlers/agentinfo"
"antrea.io/antrea/pkg/agent/apiserver/handlers/podinterface"
"antrea.io/antrea/pkg/antctl/output"
"antrea.io/antrea/pkg/antctl/runtime"
"antrea.io/antrea/pkg/antctl/transform/addressgroup"
"antrea.io/antrea/pkg/antctl/transform/appliedtogroup"
Expand All @@ -39,7 +40,6 @@ import (
"antrea.io/antrea/pkg/antctl/transform/networkpolicy"
cpv1beta "antrea.io/antrea/pkg/apis/controlplane/v1beta2"
"antrea.io/antrea/pkg/apis/crd/v1beta1"
"antrea.io/antrea/pkg/antctl/output"
)

type Foobar struct {
Expand Down
11 changes: 11 additions & 0 deletions pkg/antctl/raw/helper.go
Expand Up @@ -24,8 +24,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"

agentapiserver "antrea.io/antrea/pkg/agent/apiserver"
multiclusterscheme "antrea.io/antrea/pkg/antctl/raw/multicluster/scheme"
"antrea.io/antrea/pkg/antctl/runtime"
"antrea.io/antrea/pkg/apis"
clusterinformationv1beta1 "antrea.io/antrea/pkg/apis/crd/v1beta1"
Expand Down Expand Up @@ -146,3 +148,12 @@ func CreateControllerClientCfg(k8sClientset kubernetes.Interface, antreaClientse
cfg.Host = fmt.Sprintf("https://%s", net.JoinHostPort(nodeIP, fmt.Sprint(controllerInfo.APIPort)))
return cfg, nil
}

func AddSchemeToClientCfg(kubeconfig *rest.Config) (client.Client, error) {
k8sClient, err := client.New(kubeconfig, client.Options{Scheme: multiclusterscheme.Scheme})
if err != nil {
return nil, err
}

return k8sClient, nil
}
2 changes: 2 additions & 0 deletions pkg/antctl/raw/multicluster/commands.go
Expand Up @@ -26,5 +26,7 @@ var GetCmd = &cobra.Command{
}

func init() {
GetCmd.AddCommand(get.NewClusterSetCommand())
GetCmd.AddCommand(get.NewResourceImportCommand())
GetCmd.AddCommand(get.NewResourceExportCommand())
}
168 changes: 168 additions & 0 deletions pkg/antctl/raw/multicluster/get/clusterset.go
@@ -0,0 +1,168 @@
// Copyright 2022 Antrea Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package get

import (
"context"
"fmt"
"os"
"strings"

"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

multiclusterv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1"
antcltOutput "antrea.io/antrea/pkg/antctl/output"
"antrea.io/antrea/pkg/antctl/raw"
"antrea.io/antrea/pkg/antctl/transform/clusterset"
)

var cmdClusterSet *cobra.Command

type clusterSetOptions struct {
namespace string
outputFormat string
allNamespaces bool
}

var optionsClusterSet *clusterSetOptions

var clusterSetExamples = strings.Trim(`
Gel all ClusterSets in default Namesapce
$ antctl mc get clusterset
Get all ClusterSets in all Namespaces
$ antctl mc get clusterset -A
Get all ClusterSets in the specified Namespace
$ antctl mc get clusterset -n <NAMESPACE>
Get all ClusterSets and print them in JSON format
$ antctl mc get clusterset -o json
Get the specified ClusterSet
$ antctl mc get clusterset <CLUSTERSETID>
`, "\n")

func (o *clusterSetOptions) validateAndComplete() {
if o.allNamespaces {
o.namespace = metav1.NamespaceAll
return
}
if o.namespace == "" {
o.namespace = metav1.NamespaceDefault
return
}
}

func NewClusterSetCommand() *cobra.Command {
cmdClusterSet = &cobra.Command{
Use: "clusterset",
Aliases: []string{
"clustersets",
},
Short: "Print Multi-cluster ClusterSets",
Args: cobra.MaximumNArgs(1),
Example: clusterSetExamples,
RunE: runEClusterSet,
}
o := &clusterSetOptions{}
optionsClusterSet = o
cmdClusterSet.Flags().StringVarP(&o.namespace, "namespace", "n", "", "Namespace of ClusterSets")
cmdClusterSet.Flags().StringVarP(&o.outputFormat, "output", "o", "", "Output format. Supported formats: json|yaml")
cmdClusterSet.Flags().BoolVarP(&o.allNamespaces, "all-namespaces", "A", false, "If present, list ClusterSets across all namespaces")

return cmdClusterSet
}

func runEClusterSet(cmd *cobra.Command, args []string) error {
optionsClusterSet.validateAndComplete()

kubeconfig, err := raw.ResolveKubeconfig(cmd)
if err != nil {
return err
}

argsNum := len(args)
singleResource := false
if argsNum > 0 {
singleResource = true
}

k8sClient, err := raw.AddSchemeToClientCfg(kubeconfig)
if err != nil {
return err
}

var clusterSets []multiclusterv1alpha1.ClusterSet
if singleResource {
clusterSetName := args[0]
clusterSet := multiclusterv1alpha1.ClusterSet{}
err = k8sClient.Get(context.TODO(), types.NamespacedName{
Namespace: optionsClusterSet.namespace,
Name: clusterSetName,
}, &clusterSet)
if err != nil {
return err
}
gvks, unversioned, err := k8sClient.Scheme().ObjectKinds(&clusterSet)
if err != nil {
return err
}
if !unversioned && len(gvks) == 1 {
clusterSet.SetGroupVersionKind(gvks[0])
}
clusterSets = append(clusterSets, clusterSet)
} else {
clusterSetList := &multiclusterv1alpha1.ClusterSetList{}
err = k8sClient.List(context.TODO(), clusterSetList, &client.ListOptions{Namespace: optionsClusterSet.namespace})
if err != nil {
return err
}
clusterSets = clusterSetList.Items
}

if len(clusterSets) == 0 {
if optionsClusterSet.namespace != "" {
fmt.Fprintf(cmd.ErrOrStderr(), "No resource found in Namespace %s\n", optionsClusterSet.namespace)
} else {
fmt.Fprintln(cmd.ErrOrStderr(), "No resources found")
}
return nil
}

switch optionsClusterSet.outputFormat {
case "json":
err := antcltOutput.JsonOutput(clusterSets, os.Stdout)
if err != nil {
return err
}
case "yaml":
err := antcltOutput.YamlOutput(clusterSets, os.Stdout)
if err != nil {
return err
}
default:
clusterSetsNum := len(clusterSets)
for i, singleclusterset := range clusterSets {
err := output(singleclusterset, true, optionsResourceExport.outputFormat, clusterset.Transform)
if err != nil {
return err
}
if i != clusterSetsNum-1 {
fmt.Print("\n")
}
}
}
return nil
}
155 changes: 155 additions & 0 deletions pkg/antctl/raw/multicluster/get/resourceexport.go
@@ -0,0 +1,155 @@
// Copyright 2022 Antrea Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package get

import (
"context"
"fmt"
"strings"

"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

multiclusterv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1"
"antrea.io/antrea/pkg/antctl/raw"
"antrea.io/antrea/pkg/antctl/transform/resourceexport"
)

var cmdResourceExport *cobra.Command

type resourceExportOptions struct {
namespace string
outputFormat string
allNamespaces bool
clusterID string
}

var optionsResourceExport *resourceExportOptions

var resourceExportExamples = strings.Trim(`
Gel all ResourceExports of ClusterSet in default Namesapce
$ antctl mc get resourceexport
Get all ResourceExports of ClusterSet in all Namespaces
$ antctl mc get resourceexport -A
Get all ResourceExports in the specified Namespace
$ antctl mc get resourceexport -n <NAMESPACE>
Get all ResourceExports and print them in JSON format
$ antctl mc get resourceexport -o json
Get the specified ResourceExport
$ antctl mc get resourceexport <RESOURCEEXPORT> -n <NAMESPACE>
`, "\n")

func (o *resourceExportOptions) validateAndComplete() {
if o.allNamespaces {
o.namespace = metav1.NamespaceAll
return
}
if o.namespace == "" {
o.namespace = metav1.NamespaceDefault
return
}
}

func NewResourceExportCommand() *cobra.Command {
cmdResourceExport = &cobra.Command{
Use: "resourceexport",
Aliases: []string{
"resourceexports",
"re",
},
Short: "Print Multi-cluster ResourceExports",
Args: cobra.MaximumNArgs(1),
Example: resourceExportExamples,
RunE: runEResourceExport,
}
o := &resourceExportOptions{}
optionsResourceExport = o
cmdResourceExport.Flags().StringVarP(&o.namespace, "namespace", "n", "", "Namespace of ResourceExport")
cmdResourceExport.Flags().StringVarP(&o.outputFormat, "output", "o", "", "Output format. Supported formats: json|yaml")
cmdResourceExport.Flags().BoolVarP(&o.allNamespaces, "all-namespaces", "A", false, "If present, list ResourceExport across all namespaces")
cmdResourceExport.Flags().StringVarP(&o.clusterID, "cluster-id", "", "", "List of the ResourceExport of specific clusterID")

return cmdResourceExport
}

func runEResourceExport(cmd *cobra.Command, args []string) error {
optionsResourceExport.validateAndComplete()

kubeconfig, err := raw.ResolveKubeconfig(cmd)
if err != nil {
return err
}

argsNum := len(args)
singleResource := false
if argsNum > 0 {
singleResource = true
}
var resExports []multiclusterv1alpha1.ResourceExport
k8sClient, err := raw.AddSchemeToClientCfg(kubeconfig)
if err != nil {
return err
}

if singleResource {
resourceExportName := args[0]
resourceExport := multiclusterv1alpha1.ResourceExport{}
err = k8sClient.Get(context.TODO(), types.NamespacedName{
Namespace: optionsResourceExport.namespace,
Name: resourceExportName,
}, &resourceExport)
if err != nil {
return err
}
gvks, unversioned, err := k8sClient.Scheme().ObjectKinds(&resourceExport)
if err != nil {
return err
}
if !unversioned && len(gvks) == 1 {
resourceExport.SetGroupVersionKind(gvks[0])
}
resExports = append(resExports, resourceExport)
} else {
var labels map[string]string
if optionsResourceExport.clusterID != "" {
labels = map[string]string{"sourceClusterID": optionsResourceExport.clusterID}
}
selector := metav1.LabelSelector{MatchLabels: labels}
labelSelector, _ := metav1.LabelSelectorAsSelector(&selector)
resourceExportList := &multiclusterv1alpha1.ResourceExportList{}
err = k8sClient.List(context.TODO(), resourceExportList, &client.ListOptions{
Namespace: optionsResourceExport.namespace,
LabelSelector: labelSelector,
})
if err != nil {
return err
}
resExports = resourceExportList.Items
}

if len(resExports) == 0 {
if optionsResourceExport.namespace != "" {
fmt.Fprintf(cmd.ErrOrStderr(), "No resources found in Namespace %s\n", optionsResourceExport.namespace)
} else {
fmt.Fprintln(cmd.ErrOrStderr(), "No resources found")
}
return nil
}

return output(resExports, false, optionsResourceExport.outputFormat, resourceexport.Transform)

}

0 comments on commit ed591c2

Please sign in to comment.