Skip to content

Commit

Permalink
add output option: json (#288)
Browse files Browse the repository at this point in the history
* add output option: json

Signed-off-by: ycyaoxdu <[email protected]>

* disable WaitCRDReady print output while --wait not set

Signed-off-by: ycyaoxdu <[email protected]>

* e2e: delete finalizers before clean hub, set larger timeout

Signed-off-by: ycyaoxdu <[email protected]>

Signed-off-by: ycyaoxdu <[email protected]>
  • Loading branch information
ycyaoxdu authored Nov 30, 2022
1 parent bc8c82e commit 3185bd5
Show file tree
Hide file tree
Showing 16 changed files with 131 additions and 30 deletions.
1 change: 1 addition & 0 deletions pkg/cmd/get/token/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func NewCmd(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, stream

cmd.Flags().StringVar(&o.outputFile, "output-file", "", "The generated resources will be copied in the specified file")
cmd.Flags().BoolVar(&o.useBootstrapToken, "use-bootstrap-token", false, "If set then the bootstrap token will used instead of a service account token")
cmd.Flags().StringVarP(&o.output, "output", "o", "text", "output should be json or text")

return cmd
}
16 changes: 14 additions & 2 deletions pkg/cmd/get/token/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ package token
import (
"context"
"fmt"
"os"

"github.com/spf13/cobra"
"github.com/stolostron/applier/pkg/apply"
"github.com/stolostron/applier/pkg/asset"
"k8s.io/apimachinery/pkg/api/errors"
"open-cluster-management.io/clusteradm/pkg/cmd/init/scenario"
"open-cluster-management.io/clusteradm/pkg/helpers"
clusteradmjson "open-cluster-management.io/clusteradm/pkg/helpers/json"
)

func (o *Options) complete(cmd *cobra.Command, args []string) (err error) {
Expand Down Expand Up @@ -129,7 +131,17 @@ func (o *Options) writeResult(token, host string, output []string) error {
fmt.Println("token doesn't exist")
return apply.WriteOutput(o.outputFile, output)
}
fmt.Printf("token=%s\n", token)
fmt.Printf("please log on spoke and run:\n%s join --hub-token %s --hub-apiserver %s --cluster-name <cluster_name>\n", helpers.GetExampleHeader(), token, host)
if o.output == "json" {
err := clusteradmjson.WriteJsonOutput(os.Stdout, clusteradmjson.HubInfo{
HubToken: token,
HubApiserver: host,
})
if err != nil {
return err
}
} else {
fmt.Printf("token=%s\n", token)
fmt.Printf("please log on spoke and run:\n%s join --hub-token %s --hub-apiserver %s --cluster-name <cluster_name>\n", helpers.GetExampleHeader(), token, host)
}
return apply.WriteOutput(o.outputFile, output)
}
2 changes: 2 additions & 0 deletions pkg/cmd/get/token/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type Options struct {
outputFile string
//If true the bootstrap token will be used instead of the service account token
useBootstrapToken bool
//output format
output string
}

//Values: The values used in the template
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/init/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ package init
import (
"fmt"

"open-cluster-management.io/clusteradm/pkg/helpers"

"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
genericclioptionsclusteradm "open-cluster-management.io/clusteradm/pkg/genericclioptions"
"open-cluster-management.io/clusteradm/pkg/helpers"
)

var example = `
Expand Down Expand Up @@ -56,5 +55,6 @@ func NewCmd(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, stream
"If set, the generated join command be saved to the prescribed file.")
cmd.Flags().BoolVar(&o.wait, "wait", false,
"If set, the command will initialize the OCM control plan in foreground.")
cmd.Flags().StringVarP(&o.output, "output", "o", "text", "output foramt, should be json or text")
return cmd
}
30 changes: 23 additions & 7 deletions pkg/cmd/init/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"open-cluster-management.io/clusteradm/pkg/cmd/init/preflight"
"open-cluster-management.io/clusteradm/pkg/cmd/init/scenario"
"open-cluster-management.io/clusteradm/pkg/helpers"
clusteradmjson "open-cluster-management.io/clusteradm/pkg/helpers/json"
version "open-cluster-management.io/clusteradm/pkg/helpers/version"
helperwait "open-cluster-management.io/clusteradm/pkg/helpers/wait"
)
Expand Down Expand Up @@ -75,6 +76,11 @@ func (o *Options) validate() error {
return fmt.Errorf("registry should not be empty")
}

// If --wait is set, some information during initialize process will print to output, the output would not keep
// machine readable, so this behavior should be disabled
if o.wait && o.output != "text" {
return fmt.Errorf("output should be text if --wait is set")
}
return nil
}

Expand Down Expand Up @@ -128,7 +134,7 @@ func (o *Options) run() error {
output = append(output, out...)

if !o.ClusteradmFlags.DryRun {
if err := helperwait.WaitUntilCRDReady(apiExtensionsClient, "clustermanagers.operator.open-cluster-management.io"); err != nil {
if err := helperwait.WaitUntilCRDReady(apiExtensionsClient, "clustermanagers.operator.open-cluster-management.io", o.wait); err != nil {
return err
}
}
Expand Down Expand Up @@ -192,12 +198,22 @@ func (o *Options) run() error {
}
}

fmt.Printf("The multicluster hub control plane has been initialized successfully!\n\n"+
"You can now register cluster(s) to the hub control plane. Log onto those cluster(s) and run the following command:\n\n"+
" %s --cluster-name <cluster_name>\n\n"+
"Replace <cluster_name> with a cluster name of your choice. For example, cluster1.\n\n",
cmd,
)
if o.output == "json" {
err := clusteradmjson.WriteJsonOutput(os.Stdout, clusteradmjson.HubInfo{
HubToken: token,
HubApiserver: restConfig.Host,
})
if err != nil {
return err
}
} else {
fmt.Printf("The multicluster hub control plane has been initialized successfully!\n\n"+
"You can now register cluster(s) to the hub control plane. Log onto those cluster(s) and run the following command:\n\n"+
" %s --cluster-name <cluster_name>\n\n"+
"Replace <cluster_name> with a cluster name of your choice. For example, cluster1.\n\n",
cmd,
)
}

return apply.WriteOutput(o.outputFile, output)
}
2 changes: 2 additions & 0 deletions pkg/cmd/init/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type Options struct {
outputJoinCommandFile string
//If set, the command will hold until the OCM control plane initialized
wait bool
//
output string
}

type BundleVersion struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/join/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func (o *Options) run() error {
output = append(output, out...)

if !o.ClusteradmFlags.DryRun {
if err := wait.WaitUntilCRDReady(apiExtensionsClient, "klusterlets.operator.open-cluster-management.io"); err != nil {
if err := wait.WaitUntilCRDReady(apiExtensionsClient, "klusterlets.operator.open-cluster-management.io", o.wait); err != nil {
return err
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/unjoin/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (o *Options) run() error {
}
err = klusterletClient.OperatorV1().Klusterlets().Delete(context.Background(), "klusterlet", metav1.DeleteOptions{})
if errors.IsNotFound(err) {
fmt.Fprintf(o.Streams.Out, "klusterlet is cleaned up already")
fmt.Fprintf(o.Streams.Out, "klusterlet is cleaned up already\n")
return nil
}
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/upgrade/clustermanager/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ func (o *Options) run() error {
}
output = append(output, out...)

if o.wait && !o.ClusteradmFlags.DryRun {
if err := wait.WaitUntilCRDReady(apiExtensionsClient, "clustermanagers.operator.open-cluster-management.io"); err != nil {
if !o.ClusteradmFlags.DryRun {
if err := wait.WaitUntilCRDReady(apiExtensionsClient, "clustermanagers.operator.open-cluster-management.io", o.wait); err != nil {
return err
}
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/upgrade/klusterlet/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ func (o *Options) run() error {
}
output = append(output, out...)

if o.wait && !o.ClusteradmFlags.DryRun {
if err := wait.WaitUntilCRDReady(apiExtensionsClient, "clustermanagers.operator.open-cluster-management.io"); err != nil {
if !o.ClusteradmFlags.DryRun {
if err := wait.WaitUntilCRDReady(apiExtensionsClient, "clustermanagers.operator.open-cluster-management.io", o.wait); err != nil {
return err
}
}
Expand Down
12 changes: 8 additions & 4 deletions pkg/helpers/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,12 @@ func getClusterInfoKubeConfig(kubeClient kubernetes.Interface) (*clientcmdapiv1.
}

//WaitCRDToBeReady waits if a crd is ready
func WaitCRDToBeReady(apiExtensionsClient apiextensionsclient.Interface, name string, b wait.Backoff) error {
func WaitCRDToBeReady(apiExtensionsClient apiextensionsclient.Interface, name string, b wait.Backoff, wait bool) error {
errGet := retry.OnError(b, func(err error) bool {
if err != nil {
fmt.Printf("Wait for %s crd to be ready\n", name)
if wait {
fmt.Printf("Wait for %s crd to be ready\n", name)
}
return true
}
return false
Expand All @@ -129,8 +131,10 @@ func WaitCRDToBeReady(apiExtensionsClient apiextensionsclient.Interface, name st
name,
metav1.GetOptions{})
if established := apiextensionshelpers.IsCRDConditionTrue(crd, apiextensionsv1.Established); !established {
fmt.Printf("Wait for %s crd to be established\n", name)
return fmt.Errorf("Wait for %s crd to be established", name)
if wait {
fmt.Printf("Wait for %s crd to be established\n", name)
}
return fmt.Errorf("Wait for %s crd to be established", name)
}

return err
Expand Down
32 changes: 32 additions & 0 deletions pkg/helpers/json/json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright Contributors to the Open Cluster Management project
package json

import (
"bytes"
"encoding/json"
"fmt"
"io"
)

type HubInfo struct {
HubToken string `json:"hub-token"`
HubApiserver string `json:"hub-apiserver"`
}

func WriteJsonOutput(w io.Writer, val interface{}) error {
b, err := json.Marshal(val)
if err != nil {
return err
}
var out bytes.Buffer
err = json.Indent(&out, b, "", " ")
if err != nil {
return err
}
_, err = out.WriteTo(w)
if err != nil {
return err
}
fmt.Fprintln(w)
return nil
}
15 changes: 8 additions & 7 deletions pkg/helpers/wait/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ import (
"open-cluster-management.io/clusteradm/pkg/helpers/printer"
)

func WaitUntilCRDReady(apiExtensionsClient apiextensionsclient.Interface, crdName string) error {
func WaitUntilCRDReady(apiExtensionsClient apiextensionsclient.Interface, crdName string, wait bool) error {
b := retry.DefaultBackoff
b.Duration = 200 * time.Millisecond

crdSpinner := printer.NewSpinner("Waiting for CRD to be ready...", time.Second)
crdSpinner.FinalMSG = "CRD successfully registered.\n"
crdSpinner.Start()
defer crdSpinner.Stop()
return helpers.WaitCRDToBeReady(
apiExtensionsClient, crdName, b)
if wait {
crdSpinner := printer.NewSpinner("Waiting for CRD to be ready...", time.Second)
crdSpinner.FinalMSG = "CRD successfully registered.\n"
crdSpinner.Start()
defer crdSpinner.Stop()
}
return helpers.WaitCRDToBeReady(apiExtensionsClient, crdName, b, wait)
}

func WaitUntilRegistrationOperatorReady(f util.Factory, timeout int64) error {
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/e2e-test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ start-cluster:
.PHONY: start-cluster

test-e2e: clean-e2e ensure-kubebuilder-tools start-cluster deps install
go test -v ./test/e2e/clusteradm --timeout 1800s
go test -v ./test/e2e/clusteradm --timeout 3600s
.PHONY: test-e2e

test-only:
go test -v ./test/e2e/clusteradm --timeout 1800s
go test -v ./test/e2e/clusteradm --timeout 3600s
.PHONY: test-e2e
26 changes: 26 additions & 0 deletions test/e2e/util/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clusterclient "open-cluster-management.io/api/client/cluster/clientset/versioned"
)

// WaitNamespaceDeleted receive a kubeconfigpath, a context name and a namespace name,
Expand Down Expand Up @@ -56,6 +57,31 @@ func DeleteClusterCSRs(kubeconfigpath string, ctx string) error {
})
}

func DeleteClusterFinalizers(kubeconfigpath string, ctx string) error {
restcfg, err := buildConfigFromFlags(ctx, kubeconfigpath)
if err != nil {
return fmt.Errorf("error occurred while build rest config: %s", err)
}

clientset, err := clusterclient.NewForConfig(restcfg)
if err != nil {
return err
}

clusterList, err := clientset.ClusterV1().ManagedClusters().List(context.TODO(), metav1.ListOptions{})
if err != nil {
return err
}
for _, mcl := range clusterList.Items {
mcl.Finalizers = []string{}
_, err := clientset.ClusterV1().ManagedClusters().Update(context.TODO(), &mcl, metav1.UpdateOptions{})
if err != nil {
return err
}
}
return nil
}

func WaitCRDDeleted(kubeconfigpath string, ctx string, name string) error {
restcfg, err := buildConfigFromFlags(ctx, kubeconfigpath)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ func initE2E() (*TestE2eConfig, error) {
return err
}

// delete cluster finalizers
err = DeleteClusterFinalizers(e2eConf.Kubeconfigpath, e2eConf.Cluster().Hub().Context())
if err != nil {
return err
}
err = e2eConf.Clusteradm().Clean(
"--context", e2eConf.Cluster().Hub().Context(),
"--purge-operator=false",
Expand Down

0 comments on commit 3185bd5

Please sign in to comment.