mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
Feat: vela cluster export config (#5336)
Signed-off-by: Somefive <yd219913@alibaba-inc.com> Signed-off-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
@@ -108,7 +108,7 @@ func NewCommandWithIOStreams(ioStream util.IOStreams) *cobra.Command {
|
||||
|
||||
// Workflows
|
||||
NewWorkflowCommand(commandArgs, ioStream),
|
||||
ClusterCommandGroup(commandArgs, ioStream),
|
||||
ClusterCommandGroup(f, commandArgs, ioStream),
|
||||
|
||||
// Debug
|
||||
NewDebugCommand(commandArgs, ioStream),
|
||||
|
||||
@@ -24,15 +24,22 @@ import (
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/fatih/color"
|
||||
"github.com/kubevela/pkg/util/runtime"
|
||||
"github.com/kubevela/pkg/util/slices"
|
||||
prismclusterv1alpha1 "github.com/kubevela/prism/pkg/apis/cluster/v1alpha1"
|
||||
clustergatewayapi "github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
|
||||
"github.com/oam-dev/cluster-gateway/pkg/config"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/kubectl/pkg/util/i18n"
|
||||
"k8s.io/kubectl/pkg/util/templates"
|
||||
"k8s.io/utils/pointer"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
prismclusterv1alpha1 "github.com/kubevela/prism/pkg/apis/cluster/v1alpha1"
|
||||
"github.com/oam-dev/cluster-gateway/pkg/config"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
velacmd "github.com/oam-dev/kubevela/pkg/cmd"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
@@ -58,7 +65,7 @@ const (
|
||||
)
|
||||
|
||||
// ClusterCommandGroup create a group of cluster command
|
||||
func ClusterCommandGroup(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
func ClusterCommandGroup(f velacmd.Factory, c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "cluster",
|
||||
Short: "Manage Kubernetes Clusters",
|
||||
@@ -88,6 +95,7 @@ func ClusterCommandGroup(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comm
|
||||
NewClusterProbeCommand(&c),
|
||||
NewClusterLabelCommandGroup(&c),
|
||||
NewClusterAliasCommand(&c),
|
||||
NewClusterExportConfigCommand(f, ioStreams),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
@@ -429,3 +437,85 @@ func NewClusterDelLabelsCommand(c *common.Args) *cobra.Command {
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewClusterExportConfigCommand create command to export multi-cluster config
|
||||
func NewClusterExportConfigCommand(f velacmd.Factory, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
var labelSelector string
|
||||
cmd := &cobra.Command{
|
||||
Use: "export-config",
|
||||
Short: i18n.T("Export multi-cluster kubeconfig"),
|
||||
Long: templates.LongDesc(i18n.T(`
|
||||
Export multi-cluster kubeconfig
|
||||
|
||||
Load existing cluster kubeconfig and list clusters registered in
|
||||
KubeVela. Export the proxy access of these clusters to KubeConfig
|
||||
and print it out.
|
||||
`)),
|
||||
Example: templates.Examples(i18n.T(`
|
||||
# Export all clusters to kubeconfig
|
||||
vela cluster export-config
|
||||
|
||||
# Export clusters with specified kubeconfig
|
||||
KUBECONFIG=./my-hub-cluster.kubeconfig vela cluster export-config
|
||||
|
||||
# Export clusters with specified labels
|
||||
vela cluster export-config -l gpu-cluster=true
|
||||
|
||||
# Export clusters to kubeconfig and save in file
|
||||
vela cluster export-config > my-vela.kubeconfig
|
||||
|
||||
# Use the exported kubeconfig in kubectl
|
||||
KUBECONFIG=my-vela.kubeconfig kubectl get namespaces --cluster c2
|
||||
`)),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg := runtime.Must(clientcmd.NewDefaultClientConfigLoadingRules().Load())
|
||||
ctx, ok := cfg.Contexts[cfg.CurrentContext]
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot find current context %s in given config", cfg.CurrentContext)
|
||||
}
|
||||
baseCluster, ok := cfg.Clusters[ctx.Cluster]
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot find base cluster %s in given config", ctx.Cluster)
|
||||
}
|
||||
selector, err := labels.Parse(labelSelector)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid selector %s: %w", labelSelector, err)
|
||||
}
|
||||
clusters, err := prismclusterv1alpha1.NewClusterClient(f.Client()).List(cmd.Context(), client.MatchingLabelsSelector{Selector: selector})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load clusters: %w", err)
|
||||
}
|
||||
clusterNames := slices.Filter(
|
||||
slices.Map(clusters.Items, func(cluster prismclusterv1alpha1.Cluster) string { return cluster.Name }),
|
||||
func(s string) bool { return s != prismclusterv1alpha1.ClusterLocalName })
|
||||
|
||||
if len(clusterNames) == 0 {
|
||||
return fmt.Errorf("no cluster found")
|
||||
}
|
||||
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%d cluster loaded: [%s]\n", len(clusterNames), strings.Join(clusterNames, ", "))
|
||||
|
||||
delete(cfg.Clusters, ctx.Cluster)
|
||||
ctx.Cluster = types.ClusterLocalName
|
||||
cfg.Clusters[types.ClusterLocalName] = baseCluster.DeepCopy()
|
||||
for _, clusterName := range clusterNames {
|
||||
cls := baseCluster.DeepCopy()
|
||||
cls.LocationOfOrigin = ""
|
||||
cls.Server = strings.Join([]string{cls.Server, "apis",
|
||||
clustergatewayapi.SchemeGroupVersion.Group,
|
||||
clustergatewayapi.SchemeGroupVersion.Version,
|
||||
"clustergateways", clusterName, "proxy"}, "/")
|
||||
cfg.Clusters[clusterName] = cls
|
||||
}
|
||||
bs, err := clientcmd.Write(*cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal generated kubeconfig: %w", err)
|
||||
}
|
||||
_, _ = ioStreams.Out.Write(bs)
|
||||
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "kubeconfig generated.\n")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&labelSelector, "selector", "l", labelSelector, "LabelSelector for select clusters to export.")
|
||||
|
||||
return velacmd.NewCommandBuilder(f, cmd).WithResponsiveWriter().Build()
|
||||
}
|
||||
|
||||
@@ -202,6 +202,12 @@ var _ = Describe("Test multicluster scenario", func() {
|
||||
Expect(err).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Test vela cluster export-config", func() {
|
||||
out, err := execCommand("cluster", "export-config")
|
||||
Expect(err).Should(Succeed())
|
||||
Expect(out).Should(ContainSubstring("name: " + WorkerClusterName))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
Context("Test multi-cluster Application", func() {
|
||||
|
||||
Reference in New Issue
Block a user