-
Notifications
You must be signed in to change notification settings - Fork 370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Antctl for multicluster #3287
Antctl for multicluster #3287
Conversation
@bangqipropel please checkout latest code from main and make sure you have correct sign-off info in your commits. |
@luolanzone Doing it now, VM stuck suddenly, will push the new one after this |
e769498
to
062627d
Compare
Codecov Report
@@ Coverage Diff @@
## main #3287 +/- ##
===========================================
- Coverage 65.57% 55.03% -10.54%
===========================================
Files 268 374 +106
Lines 26780 41323 +14543
===========================================
+ Hits 17560 22743 +5183
- Misses 7315 16189 +8874
- Partials 1905 2391 +486
Flags with carried forward coverage won't be shown. Click here to find out more.
|
10378d7
to
6d79091
Compare
pkg/antctl/raw/clusterset/command.go
Outdated
"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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please reorganize the import section, all Antrea package should be placed in last section, you can refer to other files. the CI build also failed due to this. https://github.com/antrea-io/antrea/runs/5120537819?check_suite_focus=true, you can run make golangci-lint
to double check your fix.
pkg/antctl/raw/clusterset/command.go
Outdated
} | ||
}, | ||
} | ||
Command.Flags().StringVarP(&option.namespace, "namespace", "n", "", "source of the Traceflow: Namespace/Pod, Pod, or IP") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the comment of this option is incorrect.
formatter := "%-50s%-50s%-50s\n" | ||
output.Write([]byte(fmt.Sprintf(formatter, "NAME", "NAMESPACE", "ClusterID"))) | ||
for _, r := range resExports { | ||
fmt.Fprintf(&output, formatter, r.Name, r.Namespace, r.Labels["sourceClusterID"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better to place Namespace
before Name
like kubectl do. is there is way to guarantee the order of output? I mean it's better to put ClusterID in first column and list all ResourceExport together from one cluster.
pkg/antctl/raw/clusterset/command.go
Outdated
func output(clusterSets []multiclusterv1alpha1.ClusterSet) string { | ||
var output strings.Builder | ||
formatter := "%-15s%-15s%-18s%-10s%-30s%-50s%-10s\n" | ||
output.Write([]byte(fmt.Sprintf(formatter, "ClusterID", "NAMESPACE", "Type", "Status", "LastTransitionTime", "Message", "Reason"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please make sure all column name are upper case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried locally, the format doesn't look good:
ClusterID NAMESPACE Type Status LastTransitionTime Message Reason
test-cluster-westdocs Ready True 2022-02-07 18:05:49 +0800 CST Connected
test-cluster-westdocs ImportsResources True 2022-02-07 18:05:49 +0800 CST Local cluster is the elected leader of member: test-cluster-westElectedLeader
test-cluster-northdocs Ready False 2022-02-09 12:36:37 +0800 CST No MemberClusterAnnounce update after 2022-02-09 04:36:18.960999439 +0000 UTC m=+153058.719069367Disconnected
test-cluster-northdocs ImportsResources False 2022-02-09 12:36:37 +0800 CST No MemberClusterAnnounce update after 2022-02-09 04:36:18.960999439 +0000 UTC m=+153058.719069367Disconnected
test-cluster-eastdocs Ready False 2022-02-09 12:36:37 +0800 CST No MemberClusterAnnounce update after 2022-02-09 04:36:18.960981033 +0000 UTC m=+153058.719050945Disconnected
test-cluster-eastdocs ImportsResources False 2022-02-09 12:36:37 +0800 CST No MemberClusterAnnounce update after 2022-02-09 04:36:18.960981033 +0000 UTC m=+153058.719050945Disconnected
test-cluster-northkube-system Ready True 2022-01-21 15:02:02 +0800 CST
test-cluster-northkube-system IsElectedLeader True 2022-01-21 15:02:04 +0800 CST This leader cluster is an elected leader for local cluster
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bangqipropel I think you can remove message
column.
8f7f77b
to
3035a9b
Compare
pkg/antctl/raw/clusterset/command.go
Outdated
Command = &cobra.Command{ | ||
Use: "clusterset", | ||
Aliases: []string{"clustersets"}, | ||
Short: "Print multicluster clustersets", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/multicluster/Multi-cluster
pkg/antctl/raw/clusterset/command.go
Outdated
err = runE(cmd, "") | ||
} | ||
if err != nil { | ||
fmt.Println(fmt.Errorf("please input the correct numbers of argumrnts here")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why you need fmt.Errorf
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/argumrnts/arguments/
s/please/Please/
Please fix all same issue in other file.
pkg/antctl/raw/clusterset/command.go
Outdated
} | ||
}, | ||
} | ||
Command.Flags().StringVarP(&option.namespace, "namespace", "n", "", "namespace of the clusterset") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/namespace of/Namespace of/
pkg/antctl/raw/clusterset/command.go
Outdated
scheme := runtime.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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can wrap this as a method considering it's duplicated in each file.
pkg/antctl/raw/clusterset/command.go
Outdated
err = k8sClient.List(context.Background(), clusterSetList, &client.ListOptions{Namespace: option.namespace}) | ||
} | ||
if err != nil { | ||
return fmt.Errorf("failed to list Clustersets: %w", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/Clustersets/ClusterSets/
pkg/antctl/raw/clusterset/command.go
Outdated
output.Write([]byte(fmt.Sprintf(formatter, "CLUSTERID", "NAMESPACE", "TYPE", "STATUS", "LASTTRANSACTIONTIME", "MESSAGE", "REASON"))) | ||
for _, clusterSet := range clusterSets { | ||
for _, r := range clusterSet.Status.ClusterStatuses { | ||
for _, condition := range r.Conditions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the basic information in ClusterSet spec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a column named 'ClUSTERSETID', otherwise the output only shows the overall status and user is unable to tell which ClusterSet it belongs to:
CLUSTERID NAMESPACE TYPE STATUS REASON
test-cluster-east docs Ready Unknown NeverConnected
test-cluster-east docs ImportsResources False NeverConnected
test-cluster-west docs Ready True Connected
test-cluster-west docs ImportsResources True ElectedLeader
test-cluster-north docs Ready Unknown NeverConnected
test-cluster-north docs ImportsResources False NeverConnected
@aravindakidambi any suggestion here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we do some thing like this:
(1) Command to show summary of the ClusterSet
(2) Command to show details of a ClusterSet, customer needs to provide a cluster-set-id to see the details
The above command seems more like (2) for me
For (1), we should just have these columns
CLUSTERSETID TOTAL_CLUSTERS NUM_READY_CLUSTERS OVERALL_CONDITION REASON
test-clusterset-1 4 3 Ready=True
test-cluster-2 2 0 Ready=Unknown NoReadyCluster
"k8s.io/client-go/rest" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please fix import issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
err = runE(cmd, "") | ||
} | ||
if err != nil { | ||
fmt.Println(fmt.Errorf("please input the correct numbers of argumrnts here")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
Command = &cobra.Command{ | ||
Use: "resourceexport", | ||
Aliases: []string{"resourceexports"}, | ||
Short: "Print multicluster resourceexports", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
formatter := "%-50s%-50s%-50s\n" | ||
output.Write([]byte(fmt.Sprintf(formatter, "NAME", "NAMESPACE", "CLUSTERID"))) | ||
for _, r := range resExports { | ||
fmt.Fprintf(&output, formatter, r.Namespace, r.Name, r.Labels["sourceClusterID"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as we discussed offline, it's better to move ClusterID as first column.
3035a9b
to
bb6581d
Compare
#3287 (comment) @luolanzone May I know what this means? We want the information from clusterset.spec? I thought we have already can see if it is leader or member from condition.Type? |
bb6581d
to
302a72d
Compare
pkg/antctl/raw/clusterset/command.go
Outdated
"github.com/spf13/cobra" | ||
"gopkg.in/yaml.v2" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/client-go/rest" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you still have the import issue, please merge these two sections as below:
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pkg/antctl/raw/clusterset/command.go
Outdated
}, | ||
} | ||
Command.Flags().StringVarP(&option.namespace, "namespace", "n", "", "Namespace of the clusterset") | ||
Command.Flags().StringVarP(&option.outputFormat, "output", "o", "", "Output format. Supported formats: yaml") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
according to following code, json is also supported. this should be 'json|yaml'
pkg/antctl/raw/clusterset/command.go
Outdated
} | ||
}, | ||
} | ||
Command.Flags().StringVarP(&option.namespace, "namespace", "n", "", "Namespace of the clusterset") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/clusterset/ClusterSet/
pkg/antctl/raw/clusterset/command.go
Outdated
Command = &cobra.Command{ | ||
Use: "clusterset", | ||
Aliases: []string{"clustersets"}, | ||
Short: "Print Multi-cluster clustersets", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/clustersets/ClusterSets/
all CRDs name should be started with upper case: eg: resourceexports -> ResourceExports, please update corresponding name in all other files.
pkg/antctl/raw/clusterset/command.go
Outdated
if option.outputFormat == "" { | ||
fmt.Println(output(clusterSets)) | ||
} else if option.outputFormat == "json" { | ||
bytesJSON, _ := json.Marshal(clusterSets) | ||
var prettyJSON bytes.Buffer | ||
err = json.Indent(&prettyJSON, bytesJSON, "", " ") | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Println(prettyJSON.String()) | ||
} else if option.outputFormat == "yaml" { | ||
yamlOutput, _ := yaml.Marshal(clusterSets) | ||
fmt.Println(string(yamlOutput)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better to use 'switch' to organize the code.
pkg/antctl/raw/clusterset/command.go
Outdated
output.Write([]byte(fmt.Sprintf(formatter, "CLUSTERID", "NAMESPACE", "TYPE", "STATUS", "LASTTRANSACTIONTIME", "MESSAGE", "REASON"))) | ||
for _, clusterSet := range clusterSets { | ||
for _, r := range clusterSet.Status.ClusterStatuses { | ||
for _, condition := range r.Conditions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a column named 'ClUSTERSETID', otherwise the output only shows the overall status and user is unable to tell which ClusterSet it belongs to:
CLUSTERID NAMESPACE TYPE STATUS REASON
test-cluster-east docs Ready Unknown NeverConnected
test-cluster-east docs ImportsResources False NeverConnected
test-cluster-west docs Ready True Connected
test-cluster-west docs ImportsResources True ElectedLeader
test-cluster-north docs Ready Unknown NeverConnected
test-cluster-north docs ImportsResources False NeverConnected
@aravindakidambi any suggestion here?
"k8s.io/client-go/rest" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
func output(resExports []multiclusterv1alpha1.ResourceExport) string { | ||
var output strings.Builder | ||
formatter := "%-50s%-50s%-50s\n" | ||
output.Write([]byte(fmt.Sprintf(formatter, "CLUSTERID", "NAME", "NAMESPACE"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the sequence is wrong, it's inconsistent with output, it should be "NAMESPACE", "NAME"
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest to support -o for all commands.
#3287 (comment) I think for this table output itself is good, but do we still need the yaml/json output for the non-specify Cluster-id command? It seems too big difference between the table output and the json/yaml output for the non-specify Cluster-ID command. @luolanzone @aravindakidambi |
302a72d
to
c9b6fd7
Compare
pkg/antctl/antctl.go
Outdated
supportAgent: true, | ||
supportController: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we only support to run it out-of-cluster, right? if so, both of them should be false
.
pkg/antctl/raw/clusterset/command.go
Outdated
} else { | ||
_ = runE(cmd, "") | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it is better to put clusterID argument in options struct and use flags to get it .
func output(resImports []k8smcsv1alpha1.ServiceImport) string { | ||
var output strings.Builder | ||
formatter := "%-50s%-50s%-50s\n" | ||
output.Write([]byte(fmt.Sprintf(formatter, "NAMESPACE", "NAME", "ClusterID"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CLUSTERID maybe better.
8d268ea
to
c933fcc
Compare
This pull request introduces 1 alert when merging c933fcc into 3f30d84 - view on LGTM.com new alerts:
|
@bangqipropel please check and fix build error: https://github.com/antrea-io/antrea/runs/5297062280?check_suite_focus=true |
pkg/antctl/raw/clusterset/command.go
Outdated
Args: cobra.MaximumNArgs(1), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if len(args) != 0 { | ||
_ = runE(cmd, args[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to handle returned error, otherwise, it will do nothing when there is an error returned by runE
and user will be unable to know what's going on. please fix it in all new added commands
var seviceExportMap map[string][]k8smcsv1alpha1.ServiceExport | ||
seviceExportMap = make(map[string][]k8smcsv1alpha1.ServiceExport) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seviceExportMap := make(map[string][]k8smcsv1alpha1.ServiceExport)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/seviceExportMap/serviceExportMap/
please fix all for this typo.
|
||
clusterClaimList := &multiclusterv1alpha1.ClusterClaimList{} | ||
|
||
err = k8sClient.List(context.Background(), clusterClaimList, &client.ListOptions{Namespace: metav1.NamespaceAll}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
err
is not handled.
|
||
err = k8sClient.List(context.Background(), clusterClaimList, &client.ListOptions{Namespace: metav1.NamespaceAll}) | ||
|
||
clusterID := clusterClaimList.Items[0].Value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's better to check the length of clusterClaimList first, there might be no ClusterClaim at all or two ClusterClaims, one is for ClusterSet, another is for local cluster, please check the guide doc https://github.com/antrea-io/antrea/blob/main/docs/multicluster/getting-started.md.
better to wrap the logic into a function to do following check:
- when there is only no ClusterClaim, skip the cluster.
- when there are two clusterclaims, make sure you get the value from the one with name
id.k8s.io
, otherwise, you are getting ClusterSet ID. - when there are more than two ClusterClaims, skip it.
} | ||
|
||
results := res.Items | ||
if ClusterID != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's quite confusing to use two variables with similar names. you can change the parameter var as 'targetClusterID'.
results := res.Items | ||
if ClusterID != "" { | ||
if clusterID == ClusterID { | ||
resExports := results |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's your purpose to add a new var? I suppose you can use results
directly.
btw, you are handling ServiceExport,not ResourceExport, you can name it as svcExports if needed.
Args: cobra.MaximumNArgs(1), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if len(args) != 0 { | ||
_ = runE(cmd, args[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
res := &k8smcsv1alpha1.ServiceImportList{} | ||
|
||
err = k8sClient.List(context.TODO(), res, &client.ListOptions{Namespace: metav1.NamespaceAll}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the blank line here.
278bd14
to
ad0e219
Compare
@luolanzone @hjiajing @aravindakidambi this can be reivewed, thanks! |
cmd/antctl/main.go
Outdated
@@ -26,6 +26,7 @@ import ( | |||
"k8s.io/component-base/logs" | |||
|
|||
"antrea.io/antrea/pkg/antctl" | |||
_ "antrea.io/antrea/pkg/antctl/raw/multicluster/get" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of leveraging the obscure side effect of importing and adding the package of one subcommand here while other subcommands are initialized in another fashion, it would be better to make the multicluster.GetCmd
initialized in its own package and the initialization should be done automatically when importing the command. Otherwise it would lead to an unmanageable maintenance effort to its consumer: "If you want to use A, you should also import B, C, etc.
I would suggest to move init
function to pkg/antctl/raw/multicluster/commands.go
:
var GetCmd = &cobra.Command{
Use: "get",
Short: "Display one or many resources in a ClusterSet",
}
func init() {
GetCmd.AddCommand(get.NewClusterSetCommand())
GetCmd.AddCommand(get.NewResourceExportCommand())
GetCmd.AddCommand(get.NewResourceImportCommand())
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please summarize the added commands and their examples in the PR description?
pkg/antctl/raw/helper.go
Outdated
|
||
func AddSchemeToClientCfg(kubeconfig *rest.Config) (client.Client, error) { | ||
var err error | ||
scheme := k8sruntime.NewScheme() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's more common to declare a global schema and initialize it in init
function, then all consumers can share the schema.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tnqn editing on other comments, but for this one, I know the meaning, but init()
cannot throw out an error, at first we wanted to throw out error on this, so do we think it is not that important to throw out an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initializing a schema is a static routine which has no external dependency, it either throws error because of a programming error which should be identified during development or never throw error. In many code it's wrapped with utilruntime.Must()
to ensure it never fails.
utilruntime.Must(AddToScheme(scheme)) |
|
||
if len(clusterSets) == 0 { | ||
if optionsClusterSet.namespace != "" { | ||
fmt.Printf("No resource found in Namespace %s\n", optionsClusterSet.namespace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this information normally goes to stderr to make user able to distinguish it from valid output easily.
fmt.Fprintln(cmd.ErrOrStderr(), "No resources found")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you mean for the allNamespace? if yes, changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean both cases, the point is outputing non-data message to stderr, not mixed to stdout.
default: | ||
clusterSetsNum := len(clusterSets) | ||
for i, singleclusterset := range clusterSets { | ||
err := output(singleclusterset, true, optionsResourceExport.outputFormat, clusterset.Transform) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the above two conditions duplicated with what output
has done?
Get all ClusterSets and print them in JSON format | ||
$ antctl mc get clusterset -o json | ||
Get the specified ClusterSet | ||
$ antctl mc get clusterset <clusterSetID> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use uppercase for all placeholders consistently
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed
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, "clusterid", "", "", "List of the ResourceExport of specific clusterID") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cmdResourceExport.Flags().StringVarP(&o.clusterID, "clusterid", "", "", "List of the ResourceExport of specific clusterID") | |
cmdResourceExport.Flags().StringVarP(&o.clusterID, "cluster-id", "", "", "List of the ResourceExport of specific clusterID") |
To follow same convention that multi words are connected with "-" to make it easier to remember the writing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed
|
||
if len(resExports) == 0 { | ||
if optionsResourceExport.namespace != "" { | ||
fmt.Printf("No resource found in Namespace %s\n", optionsResourceExport.namespace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
) | ||
|
||
type Response struct { | ||
ClusterID string `json:"clusterid" yaml:"clusterid"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the convention is using lowerCamelCase for field names in json and yaml output
return result, nil | ||
} | ||
|
||
func objectTransform(o interface{}, r interface{}, c interface{}) (interface{}, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why it uses interface{}
as the types and do another conversion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
var _ common.TableOutput = new(Response) | ||
|
||
func (r Response) GetTableHeader() []string { | ||
return []string{"CLUSTERID", "NAMESPACE", "CLUSTERSETID", "TYPE", "STATUS", "REASON"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The convention is "CLUSTER-ID", "CLUSTER-SET-ID"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
) | ||
|
||
type Response struct { | ||
ClusterID string `json:"clusterid" yaml:"clusterid"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ed591c2
to
ab786bc
Compare
@tnqn can this be reviewed again? thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall, some nits
pkg/antctl/raw/helper.go
Outdated
@@ -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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this is function is not very necessary now as it's actually oneline function after reducing the redundance, and AddSchemeToClientCfg
sounds it will only mutate the client config but it actually creates a client:
func AddSchemeToClientCfg(kubeconfig *rest.Config) (client.Client, error) {
return client.New(kubeconfig, client.Options{Scheme: multiclusterscheme.Scheme})
}
Maybe we could just call client.New(kubeconfig, client.Options{Scheme: multiclusterscheme.Scheme})
in its caller?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it done?
return nil | ||
} | ||
|
||
switch optionsClusterSet.outputFormat { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it could reuse what output
function has done and move some logic to clusterset.Transform
so this file doesn't have format related code, e.g.
return output(clusterSets, singleResource, optionsResourceExport.outputFormat, resourceexport.Transform)
func Transform(r interface{}, single bool) (interface{}, error) {
if single {
return objectTransform(r)
}
return listTransform(r)
}
func listTransform(l interface{}) (interface{}, error) {
clusterSets := l.([]multiclusterv1alpha1.ClusterSet)
...
}
func objectTransform(o interface{}) (interface{}, error) {
clusterSet := o.(multiclusterv1alpha1.ClusterSet)
...
}
func clusterTransform(clusterSet multiclusterv1alpha1.ClusterSet,
status multiclusterv1alpha1.ClusterStatus,
condition multiclusterv1alpha1.ClusterCondition) (interface{}, error) {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tnqn Hi Quan, I tried some ways, but the blockers for me is here: we don't want to change the function TableOutputForGetCommands
, but we want to output the table output result one by one, so the "tableHeader" will always output once, but Jianjun wanted to output them multiple times here: #3287 (comment)
So the only left way seems to be also ouput the yaml and json format one-by-one, but this seems a little weird for me, because if we do this, the json and yaml output for clusterset will be totally different to other kind of resources,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
var optionsResourceExport *resourceExportOptions | ||
|
||
var resourceExportExamples = strings.Trim(` | ||
Gel all ResourceExports of ClusterSet in default Namesapce |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/Gel/Get/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
} | ||
|
||
func (r Response) GetTableRow(maxColumnLength int) []string { | ||
return []string{r.ClusterID, r.Namespace, r.Name} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it include kind? otherwise it would not straightforward to know what's this resource?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ab786bc
to
d65aa10
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM except one nit, and PR needs rebasing
pkg/antctl/raw/helper.go
Outdated
@@ -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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it done?
return nil | ||
} | ||
|
||
switch optionsClusterSet.outputFormat { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
d65aa10
to
8805d50
Compare
@bangqipropel could you remove the first commit that has been merged via #3341 from this one and make the commit message more specific like #3341 (comment).
|
8805d50
to
6511a6a
Compare
|
Add subcommands to get two more antrea multicluster resources, ClusterSet and ResourceExport. We could list or get mc resource by antctl mc get <Resource>. Example: ➜ antctl mc get resourceexport -A CLUSTER-ID NAMESPACE NAME KIND cluster-a leader-ns cluster-a-testns-stale-busybus-service Service cluster-a leader-ns cluster-a-testns-stale-nginx-service Service cluster-a1 leader-nsforholdingalotof cluster-b-testns-stale-nginx-service Service ➜ antctl mc get clusterset -A CLUSTER-ID NAMESPACE CLUSTER-SET-ID TYPE STATUS REASON cluster-a leader-ns test-clusterset IsElectedLeader True <NONE> cluster-a leader-ns test-clusterset Ready True <NONE> CLUSTER-ID NAMESPACE CLUSTER-SET-ID TYPE STATUS REASON cluster-a1 leader-nsforholdingalotof test-clusterset1 IsElectedLeader True <NONE> cluster-a1 leader-nsforholdingalotof test-clusterset1 Ready True <NONE> In the future, other resources like serviceimport or serviceexport could be added to the sub-command if necessary. Signed-off-by: zbangqi <[email protected]>
6511a6a
to
bae9741
Compare
/skip-all |
I will edit the commit message when merging it, please format the body (wrap the body at 72 characters) in the future. For more details, check this guide and links it refer to: https://github.com/antrea-io/antrea/blob/main/CONTRIBUTING.md#getting-reviewers |
@tnqn Thanks, I am checking this file now |
antctl multicluster command for clusterset & clustersets, resourceexport
For command lines for ClusterSets, we have
For command lines for ResourceExport, we have