Skip to content

Commit

Permalink
Add [antctl mc] command
Browse files Browse the repository at this point in the history
Signed-off-by: hjiajing <[email protected]>
  • Loading branch information
hjiajing committed Feb 22, 2022
1 parent e23cf3b commit cc281ca
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 1 deletion.
7 changes: 7 additions & 0 deletions pkg/antctl/antctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"antrea.io/antrea/pkg/agent/openflow"
fallbackversion "antrea.io/antrea/pkg/antctl/fallback/version"
"antrea.io/antrea/pkg/antctl/raw/featuregates"
"antrea.io/antrea/pkg/antctl/raw/multicluster"
"antrea.io/antrea/pkg/antctl/raw/proxy"
"antrea.io/antrea/pkg/antctl/raw/supportbundle"
"antrea.io/antrea/pkg/antctl/raw/traceflow"
Expand Down Expand Up @@ -531,6 +532,12 @@ var CommandList = &commandList{
supportController: true,
commandGroup: get,
},
{
cobraCommand: multicluster.GetCmd,
supportAgent: false,
supportController: false,
commandGroup: mc,
},
},
codec: scheme.Codecs,
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/antctl/command_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const (
flat commandGroup = iota
get
query
mc
)

var groupCommands = map[commandGroup]*cobra.Command{
Expand All @@ -89,6 +90,11 @@ var groupCommands = map[commandGroup]*cobra.Command{
Short: "Execute a user-provided query",
Long: "Execute a user-provided query",
},
mc: {
Use: "mc",
Short: "Sub-commands of multiple cluster",
Long: "Sub-commands of multiple cluster",
},
}

type endpointResponder interface {
Expand Down
2 changes: 1 addition & 1 deletion pkg/antctl/command_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (cl *commandList) applyToRootCommand(root *cobra.Command, client AntctlClie

for _, cmd := range cl.rawCommands {
if (runtime.Mode == runtime.ModeAgent && cmd.supportAgent) ||
(runtime.Mode == runtime.ModeController && cmd.supportController) {
(runtime.Mode == runtime.ModeController && cmd.supportController) || cmd.commandGroup == mc {
if groupCommand, ok := groupCommands[cmd.commandGroup]; ok {
groupCommand.AddCommand(cmd.cobraCommand)
} else {
Expand Down
26 changes: 26 additions & 0 deletions pkg/antctl/raw/multicluster/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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 multicluster

import "github.com/spf13/cobra"

var GetCmd *cobra.Command

func init() {
GetCmd = &cobra.Command{
Use: "get",
Short: "List or query resources of multiple cluster",
}
}
179 changes: 179 additions & 0 deletions pkg/antctl/raw/multicluster/resourceimport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// 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 multicluster

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

"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
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"

multiclusterv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1"
antreamcscheme "antrea.io/antrea/multicluster/pkg/client/clientset/versioned/scheme"
"antrea.io/antrea/pkg/antctl/raw"
)

var command *cobra.Command

type resourceImportOptions struct {
namespace string
outputFormat string
allNamespace bool
}

var options *resourceImportOptions

var resourceImportExample = strings.Trim(`
Gel all resource imports of cluster set in default namesapce
$ antctl get resourceimport
Get all resource imports of cluster set in all namespace
$ antctl get resoruceimport -A
Get all resource imports of specified namespace
$ antctl get resourceimport -n <NAMESPACE>
Get all resource imports and print json format
$ antctl get resourceimport -o json
`, "\n")

func (o *resourceImportOptions) validateAndComplete() error {
if o.allNamespace {
o.namespace = metav1.NamespaceAll
} else if o.namespace == "" {
o.namespace = metav1.NamespaceDefault
}

return nil
}

func init() {
command = &cobra.Command{
Use: "resourceimport",
Aliases: []string{
"resourceimports",
"ri",
},
Short: "Print Multi-Cluster resource imports",
Args: cobra.MaximumNArgs(1),
Example: resourceImportExample,
RunE: runE,
}
o := &resourceImportOptions{}
options = o
command.Flags().StringVarP(&o.namespace, "namespace", "n", "", "namespace of resource import")
command.Flags().StringVarP(&o.outputFormat, "output", "o", "", "Output format. Supported formats: json|yaml")
command.Flags().BoolVarP(&o.allNamespace, "all-namespace", "A", false, "Get resource of all namespace or not")

GetCmd.AddCommand(command)
}

func runE(cmd *cobra.Command, args []string) error {
options.validateAndComplete()
kubeconfig, err := raw.ResolveKubeconfig(cmd)
if err != nil {
return err
}
kubeconfig.GroupVersion = &schema.GroupVersion{Group: "", Version: ""}
restconfigTmpl := rest.CopyConfig(kubeconfig)
raw.SetupKubeconfig(restconfigTmpl)

scheme := k8sruntime.NewScheme()
err = mcsscheme.AddToScheme(scheme)
if err != nil {
return err
}
err = antreamcscheme.AddToScheme(scheme)
if err != nil {
return err
}
err = k8sscheme.AddToScheme(scheme)
if err != nil {
return err
}
k8sClient, err := client.New(kubeconfig, client.Options{Scheme: scheme})
if err != nil {
return err
}

var res []multiclusterv1alpha1.ResourceImport
resourceImportList := &multiclusterv1alpha1.ResourceImportList{}
err = k8sClient.List(context.TODO(), resourceImportList, &client.ListOptions{Namespace: options.namespace})

for _, ri := range resourceImportList.Items {
if len(args) > 0 && ri.Name == args[0] {
res = append(res, ri)
break
} else if len(args) == 0 {
res = append(res, ri)
}
}
if len(res) == 0 {
if len(args) == 0 {
fmt.Println("No resource found")
return nil
}
return fmt.Errorf("Error from server (NotFound): resourceimport %s not found.", args[0])
}

switch options.outputFormat {
case "json":
byteJson, err := json.Marshal(res)
if err != nil {
return err
}
var prettyJson bytes.Buffer
err = json.Indent(&prettyJson, byteJson, "", " ")
if err != nil {
return err
}

fmt.Println(prettyJson.String())
case "yaml":
yamlOutput, err := yaml.Marshal(res)
if err != nil {
return err
}
fmt.Println(string(yamlOutput))
default:
fmt.Print(output(res))
}

return nil
}

func output(resourceImports []multiclusterv1alpha1.ResourceImport) string {
var output strings.Builder
formatter := "%-25s%-50s%-25s\n"
output.Write([]byte(fmt.Sprintf(formatter, "NAMESPACE", "NAME", "KIND")))
sort.SliceStable(resourceImports, func(i, j int) bool {
return strings.Compare(resourceImports[i].Namespace, resourceImports[j].Namespace) == 1
})

for _, ri := range resourceImports {
fmt.Fprintf(&output, formatter, ri.Namespace, ri.Name, ri.Kind)
}

return output.String()
}

0 comments on commit cc281ca

Please sign in to comment.