mirror of
https://github.com/alibaba/higress.git
synced 2026-02-21 14:30:54 +08:00
192 lines
5.0 KiB
Go
192 lines
5.0 KiB
Go
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package hgctl
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/alibaba/higress/hgctl/pkg/kubernetes"
|
|
"github.com/alibaba/higress/pkg/cmd/options"
|
|
"github.com/alibaba/higress/pkg/cmd/version"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
"gopkg.in/yaml.v2"
|
|
v1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
|
)
|
|
|
|
const (
|
|
higressCoreContainerName = "higress-core"
|
|
higressGatewayContainerName = "higress-gateway"
|
|
)
|
|
|
|
func newVersionCommand() *cobra.Command {
|
|
var (
|
|
output string
|
|
client bool
|
|
)
|
|
|
|
versionCommand := &cobra.Command{
|
|
Use: "version",
|
|
Aliases: []string{"versions", "v"},
|
|
Short: "Show version",
|
|
Example: ` # Show versions of both client and server.
|
|
hgctl version
|
|
|
|
# Show versions of both client and server in JSON format.
|
|
hgctl version --output=json
|
|
|
|
# Show version of client without server.
|
|
hgctl version --client
|
|
`,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
cmdutil.CheckErr(versions(cmd.OutOrStdout(), output, client))
|
|
},
|
|
}
|
|
|
|
flags := versionCommand.Flags()
|
|
options.AddKubeConfigFlags(flags)
|
|
|
|
versionCommand.PersistentFlags().StringVarP(&output, "output", "o", yamlOutput, "One of 'yaml' or 'json'")
|
|
|
|
versionCommand.PersistentFlags().BoolVarP(&client, "client", "r", false, "If true, only log client version.")
|
|
|
|
return versionCommand
|
|
}
|
|
|
|
type VersionInfo struct {
|
|
ClientVersion string `json:"client" yaml:"client"`
|
|
ServerVersions []*ServerVersion `json:"server,omitempty" yaml:"server"`
|
|
}
|
|
|
|
type ServerVersion struct {
|
|
types.NamespacedName `yaml:"namespacedName"`
|
|
version.Info `yaml:"versionInfo"`
|
|
}
|
|
|
|
func Get() VersionInfo {
|
|
return VersionInfo{
|
|
ClientVersion: version.Get().HigressVersion,
|
|
ServerVersions: make([]*ServerVersion, 0),
|
|
}
|
|
}
|
|
|
|
func retrieveVersion(w io.Writer, v *VersionInfo, containerName string, cmd string, labelSelector string, c kubernetes.CLIClient, f versionFunc) error {
|
|
pods, err := c.PodsForSelector(metav1.NamespaceAll, labelSelector)
|
|
if err != nil {
|
|
return errors.Wrap(err, "list Higress pods failed")
|
|
}
|
|
|
|
for _, pod := range pods.Items {
|
|
if pod.Status.Phase != v1.PodRunning {
|
|
|
|
fmt.Fprintf(w, "WARN: pod %s/%s is not running, skipping it.", pod.Namespace, pod.Name)
|
|
continue
|
|
}
|
|
|
|
nn := types.NamespacedName{
|
|
Namespace: pod.Namespace,
|
|
Name: pod.Name,
|
|
}
|
|
stdout, _, err := c.PodExec(nn, containerName, cmd)
|
|
if err != nil {
|
|
return fmt.Errorf("pod exec on %s/%s failed: %w", nn.Namespace, nn.Name, err)
|
|
}
|
|
|
|
info, err := f(stdout)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v.ServerVersions = append(v.ServerVersions, &ServerVersion{
|
|
NamespacedName: nn,
|
|
Info: *info,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type versionFunc func(string) (*version.Info, error)
|
|
|
|
func versions(w io.Writer, output string, client bool) error {
|
|
v := Get()
|
|
|
|
if client {
|
|
fmt.Fprintf(w, "clientVersion: %s", v.ClientVersion)
|
|
return nil
|
|
}
|
|
|
|
c, err := kubernetes.NewCLIClient(options.DefaultConfigFlags.ToRawKubeConfigLoader())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to build kubernetes client: %w", err)
|
|
}
|
|
|
|
if err := retrieveVersion(w, &v, higressCoreContainerName, "higress version -ojson", "app=higress-controller", c, func(s string) (*version.Info, error) {
|
|
info := &version.Info{}
|
|
if err := json.Unmarshal([]byte(s), info); err != nil {
|
|
return nil, fmt.Errorf("unmarshall pod exec result failed: %w", err)
|
|
}
|
|
info.Type = "higress-controller"
|
|
return info, nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := retrieveVersion(w, &v, higressGatewayContainerName, "envoy --version", "app=higress-gateway", c, func(s string) (*version.Info, error) {
|
|
if len(strings.Split(s, ":")) != 2 {
|
|
return nil, nil
|
|
}
|
|
proxyVersion := strings.TrimSpace(strings.Split(s, ":")[1])
|
|
return &version.Info{
|
|
GatewayVersion: proxyVersion,
|
|
Type: "higress-gateway",
|
|
}, nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
sort.Slice(v.ServerVersions, func(i, j int) bool {
|
|
if v.ServerVersions[i].Namespace == v.ServerVersions[j].Namespace {
|
|
return v.ServerVersions[i].Name < v.ServerVersions[j].Name
|
|
}
|
|
|
|
return v.ServerVersions[i].Namespace < v.ServerVersions[j].Namespace
|
|
})
|
|
|
|
var out []byte
|
|
switch output {
|
|
case yamlOutput:
|
|
out, err = yaml.Marshal(v)
|
|
case jsonOutput:
|
|
out, err = json.MarshalIndent(v, "", " ")
|
|
default:
|
|
out, err = json.MarshalIndent(v, "", " ")
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintln(w, string(out))
|
|
|
|
return nil
|
|
}
|