Skip to content
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

feat: support list cluster service reference #5477

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/user_docs/cli/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ ClusterDefinition command.
* [kbcli clusterdefinition describe](kbcli_clusterdefinition_describe.md) - Describe ClusterDefinition.
* [kbcli clusterdefinition list](kbcli_clusterdefinition_list.md) - List ClusterDefinitions.
* [kbcli clusterdefinition list-components](kbcli_clusterdefinition_list-components.md) - List cluster definition components.
* [kbcli clusterdefinition list-service-reference](kbcli_clusterdefinition_list-service-reference.md) - List cluster references declared in a cluster definition.


## [clusterversion](kbcli_clusterversion.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/user_docs/cli/kbcli_cluster_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ kbcli cluster create [NAME] [flags]
kbcli cluster create --cluster-definition pulsar --pvc type=bookies,name=ledgers,size=20Gi --pvc type=bookies,name=journal,size=20Gi

# Create a cluster with using a service reference to another KubeBlocks cluster
cluster create --cluster-definition pulsar --service-reference name=pulsarZookeeper,cluster=zookeeper,namespace=default
kbcli cluster create --cluster-definition pulsar --service-reference name=pulsarZookeeper,cluster=zookeeper,namespace=default
```

### Options
Expand Down
1 change: 1 addition & 0 deletions docs/user_docs/cli/kbcli_clusterdefinition.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ClusterDefinition command.
* [kbcli clusterdefinition describe](kbcli_clusterdefinition_describe.md) - Describe ClusterDefinition.
* [kbcli clusterdefinition list](kbcli_clusterdefinition_list.md) - List ClusterDefinitions.
* [kbcli clusterdefinition list-components](kbcli_clusterdefinition_list-components.md) - List cluster definition components.
* [kbcli clusterdefinition list-service-reference](kbcli_clusterdefinition_list-service-reference.md) - List cluster references declared in a cluster definition.

#### Go Back to [CLI Overview](cli.md) Homepage.

2 changes: 1 addition & 1 deletion internal/cli/cmd/cluster/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ var clusterCreateExample = templates.Examples(`
kbcli cluster create --cluster-definition pulsar --pvc type=bookies,name=ledgers,size=20Gi --pvc type=bookies,name=journal,size=20Gi

# Create a cluster with using a service reference to another KubeBlocks cluster
cluster create --cluster-definition pulsar --service-reference name=pulsarZookeeper,cluster=zookeeper,namespace=default
kbcli cluster create --cluster-definition pulsar --service-reference name=pulsarZookeeper,cluster=zookeeper,namespace=default
`)

const (
Expand Down
1 change: 1 addition & 0 deletions internal/cli/cmd/clusterdefinition/clusterdefinition.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func NewClusterDefinitionCmd(f cmdutil.Factory, streams genericiooptions.IOStrea
cmd.AddCommand(NewListCmd(f, streams))
cmd.AddCommand(NewListComponentsCmd(f, streams))
cmd.AddCommand(NewDescribeCmd(f, streams))
cmd.AddCommand(NewListServiceReferenceCmd(f, streams))
return cmd
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ var _ = Describe("clusterdefinition list components", func() {
GroupVersion: schema.GroupVersion{Group: types.AppsAPIGroup, Version: types.AppsAPIVersion},
Resp: &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, testing.FakeResourceNotFound(types.ClusterDefGVR(), clusterdefinitionName+"-no-exist"))},
}
Expect(run(o)).Should(HaveOccurred())
Expect(listComponents(o)).Should(HaveOccurred())

})

Expand Down
4 changes: 2 additions & 2 deletions internal/cli/cmd/clusterdefinition/list_components.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func NewListComponentsCmd(f cmdutil.Factory, streams genericiooptions.IOStreams)
Run: func(cmd *cobra.Command, args []string) {
util.CheckErr(validate(args))
o.Names = args
util.CheckErr(run(o))
util.CheckErr(listComponents(o))
},
}
return cmd
Expand All @@ -67,7 +67,7 @@ func validate(args []string) error {
return nil
}

func run(o *list.ListOptions) error {
func listComponents(o *list.ListOptions) error {
o.Print = false

r, err := o.Run()
Expand Down
101 changes: 101 additions & 0 deletions internal/cli/cmd/clusterdefinition/list_service_reference.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
Copyright (C) 2022-2023 ApeCloud Co., Ltd

This file is part of KubeBlocks project

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package clusterdefinition

import (
"fmt"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericiooptions"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/templates"

"github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
"github.com/apecloud/kubeblocks/internal/cli/list"
"github.com/apecloud/kubeblocks/internal/cli/printer"
"github.com/apecloud/kubeblocks/internal/cli/types"
"github.com/apecloud/kubeblocks/internal/cli/util"
)

var (
listServiceRefExample = templates.Examples(`
# List cluster references name declared in a cluster definition.
kbcli clusterdefinition list-service-reference apecloud-mysql`)
)

func NewListServiceReferenceCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
o := list.NewListOptions(f, streams, types.ClusterDefGVR())
o.AllNamespaces = true
cmd := &cobra.Command{
Use: "list-service-reference",
Short: "List cluster references declared in a cluster definition.",
Example: listServiceRefExample,
Aliases: []string{"ls-sr"},
ValidArgsFunction: util.ResourceNameCompletionFunc(f, o.GVR),
Run: func(cmd *cobra.Command, args []string) {
util.CheckErr(validate(args))
o.Names = args
util.CheckErr(listServiceRef(o))
},
}
return cmd
}

func listServiceRef(o *list.ListOptions) error {
o.Print = false

r, err := o.Run()
if err != nil {
return err
}
infos, err := r.Infos()
if err != nil {
return err
}

p := printer.NewTablePrinter(o.Out)
p.SetHeader("CLUSTER-DEFINITION", "NAME", "COMPONENT", "SERVICE-KIND", "SERVICE-VERSION")
p.SortBy(1, 2)
for _, info := range infos {
var cd v1alpha1.ClusterDefinition
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(info.Object.(*unstructured.Unstructured).Object, &cd); err != nil {
return err
}
for _, comp := range cd.Spec.ComponentDefs {
if comp.ServiceRefDeclarations == nil {
continue
}
for _, serviceDec := range comp.ServiceRefDeclarations {
for _, ref := range serviceDec.ServiceRefDeclarationSpecs {
p.AddRow(cd.Name, serviceDec.Name, comp.Name, ref.ServiceKind, ref.ServiceVersion)
}
}
}
}

if p.Tbl.Length() == 0 {
fmt.Printf("No service references are declared in cluster definition %s", o.Names)
} else {
p.Print()
}
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
Copyright (C) 2022-2023 ApeCloud Co., Ltd

This file is part of KubeBlocks project

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package clusterdefinition

import (
"bytes"
"fmt"
"net/http"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericiooptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/kubernetes/scheme"
clientfake "k8s.io/client-go/rest/fake"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"

appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
"github.com/apecloud/kubeblocks/internal/cli/testing"
"github.com/apecloud/kubeblocks/internal/cli/types"
)

var _ = Describe("clusterdefinition list components", func() {
var (
cmd *cobra.Command
streams genericiooptions.IOStreams
out *bytes.Buffer
tf *cmdtesting.TestFactory
)
const (
namespace = testing.Namespace
clusterdefinitionName = testing.ClusterDefName
)

mockClient := func(data runtime.Object) *cmdtesting.TestFactory {
tf := testing.NewTestFactory(namespace)
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &clientfake.RESTClient{
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
GroupVersion: schema.GroupVersion{Group: types.AppsAPIGroup, Version: types.AppsAPIVersion},
Resp: &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, data)},
}
tf.Client = tf.UnstructuredClient
tf.FakeDynamicClient = testing.FakeDynamicClient(data)
return tf
}

BeforeEach(func() {
_ = appsv1alpha1.AddToScheme(scheme.Scheme)
clusterDef := testing.FakeClusterDef()
tf = mockClient(clusterDef)
streams, _, out, _ = genericiooptions.NewTestIOStreams()
cmd = NewListServiceReferenceCmd(tf, streams)
})

It("create list-service-reference cmd", func() {
cmd := NewListServiceReferenceCmd(tf, streams)
Expect(cmd).ShouldNot(BeNil())
})

It("list-service", func() {
cmd.Run(cmd, []string{clusterdefinitionName})
expected := `CLUSTER-DEFINITION NAME COMPONENT SERVICE-KIND SERVICE-VERSION
fake-cluster-definition fake-serviceRef fake-component-type mysql 8.0.\d{1,2}$
`
Expect(expected).Should(Equal(out.String()))
fmt.Println(out.String())
})

})