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:
Somefive
2023-01-16 18:03:38 +08:00
committed by GitHub
parent 9dc102021e
commit b342ab0f86
3 changed files with 101 additions and 5 deletions

View File

@@ -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),

View File

@@ -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()
}

View File

@@ -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() {