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 Feb 16, 2022
1 parent 70fac83 commit 8d268ea
Show file tree
Hide file tree
Showing 6 changed files with 597 additions and 0 deletions.
28 changes: 28 additions & 0 deletions pkg/antctl/antctl.go
Expand Up @@ -23,8 +23,12 @@ import (
"antrea.io/antrea/pkg/agent/apiserver/handlers/podinterface"
"antrea.io/antrea/pkg/agent/openflow"
fallbackversion "antrea.io/antrea/pkg/antctl/fallback/version"
"antrea.io/antrea/pkg/antctl/raw/clusterset"
"antrea.io/antrea/pkg/antctl/raw/featuregates"
"antrea.io/antrea/pkg/antctl/raw/proxy"
"antrea.io/antrea/pkg/antctl/raw/resourceexport"
"antrea.io/antrea/pkg/antctl/raw/serviceexport"
"antrea.io/antrea/pkg/antctl/raw/serviceimport"
"antrea.io/antrea/pkg/antctl/raw/supportbundle"
"antrea.io/antrea/pkg/antctl/raw/traceflow"
"antrea.io/antrea/pkg/antctl/transform/addressgroup"
Expand Down Expand Up @@ -531,6 +535,30 @@ var CommandList = &commandList{
supportController: true,
commandGroup: get,
},
{
cobraCommand: clusterset.Command,
supportAgent: true,
supportController: true,
commandGroup: get,
},
{
cobraCommand: resourceexport.Command,
supportAgent: true,
supportController: true,
commandGroup: get,
},
{
cobraCommand: serviceexport.Command,
supportAgent: true,
supportController: true,
commandGroup: get,
},
{
cobraCommand: serviceimport.Command,
supportAgent: true,
supportController: true,
commandGroup: get,
},
},
codec: scheme.Codecs,
}
Expand Down
144 changes: 144 additions & 0 deletions pkg/antctl/raw/clusterset/command.go
@@ -0,0 +1,144 @@
// 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 clusterset

import (
"bytes"
"context"
"encoding/json"
"fmt"
"sort"
"strings"

"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"

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

var (
Command *cobra.Command
option = &struct {
namespace string
outputFormat string
}{}
)

func init() {
Command = &cobra.Command{
Use: "clusterset",
Aliases: []string{"clustersets"},
Short: "Print Multi-cluster ClusterSets",
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 0 {
_ = runE(cmd, args[0])
} else {
_ = runE(cmd, "")
}
},
}
Command.Flags().StringVarP(&option.namespace, "namespace", "n", "", "Namespace of the ClusterSet")
Command.Flags().StringVarP(&option.outputFormat, "output", "o", "", "Output format. Supported formats: json|yaml")
}

func runE(cmd *cobra.Command, clustersetName string) error {
kubeconfig, err := raw.ResolveKubeconfig(cmd)
if err != nil {
return err
}
kubeconfig.GroupVersion = &schema.GroupVersion{Group: "", Version: ""}
restconfigTmpl := rest.CopyConfig(kubeconfig)
raw.SetupKubeconfig(restconfigTmpl)
if server, err := Command.Flags().GetString("server"); err != nil {
kubeconfig.Host = server
}

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

clusterSetList := &multiclusterv1alpha1.ClusterSetList{}
if option.namespace == "" {
err = k8sClient.List(context.Background(), clusterSetList, &client.ListOptions{Namespace: metav1.NamespaceAll})
} else {
err = k8sClient.List(context.Background(), clusterSetList, &client.ListOptions{Namespace: option.namespace})
}
if err != nil {
return err
}

var clusterSets []multiclusterv1alpha1.ClusterSet

if clustersetName != "" {
for _, clusterSet := range clusterSetList.Items {
if clusterSet.Name == clustersetName {
clusterSets = append(clusterSets, clusterSet)
break
}
}
} else {
clusterSets = clusterSetList.Items
}
switch option.outputFormat {
case "json":
bytesJSON, err := json.Marshal(clusterSets)
if err != nil {
return err
}
var prettyJSON bytes.Buffer
err = json.Indent(&prettyJSON, bytesJSON, "", " ")
if err != nil {
return err
}
fmt.Println(prettyJSON.String())
case "yaml":
yamlOutput, err := yaml.Marshal(clusterSets)
if err != nil {
return err
}
fmt.Println(string(yamlOutput))
default:
fmt.Println(output(clusterSets))
}

return nil
}

func output(clusterSets []multiclusterv1alpha1.ClusterSet) string {
var output strings.Builder
formatter := "%-25s%-25s%-25s%-28s%-20s%-10s\n"
output.Write([]byte(fmt.Sprintf(formatter, "CLUSTERID", "NAMESPACE", "CLUSTERSETID", "TYPE", "STATUS", "REASON")))
sort.SliceStable(clusterSets, func(i, j int) bool {
return strings.Compare(clusterSets[i].Namespace, clusterSets[j].Namespace) == 1
})
for _, clusterSet := range clusterSets {
sort.SliceStable(clusterSet.Status.ClusterStatuses, func(i, j int) bool {
return strings.Compare(clusterSet.Status.ClusterStatuses[i].ClusterID, clusterSet.Status.ClusterStatuses[j].ClusterID) == 1
})
for _, r := range clusterSet.Status.ClusterStatuses {
for _, condition := range r.Conditions {
fmt.Fprintf(&output, formatter, r.ClusterID, clusterSet.Namespace, clusterSet.Name, condition.Type, condition.Status, condition.Reason)
}
}
}
return output.String()
}
28 changes: 28 additions & 0 deletions pkg/antctl/raw/helper.go
Expand Up @@ -22,9 +22,14 @@ import (

"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
k8sscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
mcsscheme "sigs.k8s.io/mcs-api/pkg/client/clientset/versioned/scheme"

antreamcscheme "antrea.io/antrea/multicluster/pkg/client/clientset/versioned/scheme"
agentapiserver "antrea.io/antrea/pkg/agent/apiserver"
"antrea.io/antrea/pkg/antctl/runtime"
"antrea.io/antrea/pkg/apis"
Expand Down Expand Up @@ -146,3 +151,26 @@ 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) {
var err error
scheme := k8sruntime.NewScheme()
err = mcsscheme.AddToScheme(scheme)
if err != nil {
return nil, err
}
err = antreamcscheme.AddToScheme(scheme)
if err != nil {
return nil, err
}
err = k8sscheme.AddToScheme(scheme)
if err != nil {
return nil, err
}

k8sClient, err := client.New(kubeconfig, client.Options{Scheme: scheme})
if err != nil {
return nil, err
}
return k8sClient, nil
}
127 changes: 127 additions & 0 deletions pkg/antctl/raw/resourceexport/command.go
@@ -0,0 +1,127 @@
// 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 resourceexport

import (
"bytes"
"context"
"encoding/json"
"fmt"
"strings"

"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"

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

var (
Command *cobra.Command
option = &struct {
outputFormat string
}{}
)

func init() {
Command = &cobra.Command{
Use: "resourceexport",
Aliases: []string{"resourceexports"},
Short: "Print Multi-cluster ResourceExports",
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 0 {
_ = runE(cmd, args[0])
} else {
_ = runE(cmd, "")
}
},
}
Command.Flags().StringVarP(&option.outputFormat, "output", "o", "", "Output format. Supported formats: json|yaml")

}

func runE(cmd *cobra.Command, ClusterID string) error {
kubeconfig, err := raw.ResolveKubeconfig(cmd)
if err != nil {
return err
}
kubeconfig.GroupVersion = &schema.GroupVersion{Group: "", Version: ""}

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

res := &multiclusterv1alpha1.ResourceExportList{}

err = k8sClient.List(context.TODO(), res, &client.ListOptions{Namespace: metav1.NamespaceAll})

if err != nil {
return err
}

var resExports []multiclusterv1alpha1.ResourceExport

if ClusterID != "" {
for _, r := range res.Items {
if r.Labels["sourceClusterID"] == ClusterID {
resExports = append(resExports, r)
}
}
} else {
resExports = res.Items
}

switch option.outputFormat {
case "json":
bytesJSON, err := json.Marshal(resExports)
if err != nil {
return err
}
var prettyJSON bytes.Buffer
err = json.Indent(&prettyJSON, bytesJSON, "", " ")
if err != nil {
return err
}
fmt.Println(prettyJSON.String())
case "yaml":
yamlOutput, err := yaml.Marshal(resExports)
if err != nil {
return err
}
fmt.Println(string(yamlOutput))
default:
fmt.Println(output(resExports))
}

return nil
}

func output(resExports []multiclusterv1alpha1.ResourceExport) string {
var output strings.Builder
formatter := "%-50s%-50s%-50s\n"
output.Write([]byte(fmt.Sprintf(formatter, "CLUSTERID", "NAMESPACE", "NAME")))
for _, r := range resExports {
fmt.Fprintf(&output, formatter, r.Labels["sourceClusterID"], r.Namespace, r.Name)
}
return output.String()
}

0 comments on commit 8d268ea

Please sign in to comment.