mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 01:06:27 +00:00
Merge pull request #39858 from alejandroEsc/ae/issue/39427
Automatic merge from submit-queue addressing issue #39427 adding a flag --output to 'kubectl version' **What this PR does / why we need it**: Addressing Issue https://github.com/kubernetes/kubernetes/issues/39427 we all **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #39427 **Release note**: ``` kubectl version has new flag --output (=json or yaml) allowing result of the command to be parsed in either json format or yaml. ```
This commit is contained in:
commit
c01baaf54f
@ -303,3 +303,100 @@ kube::test::if_supports_resource() {
|
|||||||
done
|
done
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
kube::test::version::object_to_file() {
|
||||||
|
name=$1
|
||||||
|
flags=${2:-""}
|
||||||
|
file=$3
|
||||||
|
kubectl version $flags | grep "$name Version:" | sed -e s/"$name Version: version.Info{"/'/' -e s/'}'/'/' -e s/', '/','/g -e s/':'/'=/g' -e s/'"'/""/g | tr , '\n' > "${file}"
|
||||||
|
}
|
||||||
|
|
||||||
|
kube::test::version::json_object_to_file() {
|
||||||
|
flags=$1
|
||||||
|
file=$2
|
||||||
|
kubectl version $flags --output json | sed -e s/'\"'/''/g -e s/'}'/''/g -e s/'{'/''/g -e s/'clientVersion:'/'clientVersion:,'/ -e s/'serverVersion:'/'serverVersion:,'/ | tr , '\n' > "${file}"
|
||||||
|
}
|
||||||
|
|
||||||
|
kube::test::version::json_client_server_object_to_file() {
|
||||||
|
flags=$1
|
||||||
|
name=$2
|
||||||
|
file=$3
|
||||||
|
kubectl version $flags --output json | jq -r ".${name}" | sed -e s/'\"'/''/g -e s/'}'/''/g -e s/'{'/''/g -e /^$/d -e s/','/''/g -e s/':'/'='/g > "${file}"
|
||||||
|
}
|
||||||
|
|
||||||
|
kube::test::version::yaml_object_to_file() {
|
||||||
|
flags=$1
|
||||||
|
file=$2
|
||||||
|
kubectl version $flags --output yaml | sed -e s/' '/''/g -e s/'\"'/''/g -e /^$/d > "${file}"
|
||||||
|
}
|
||||||
|
|
||||||
|
kube::test::version::diff_assert() {
|
||||||
|
local original=$1
|
||||||
|
local comparator=${2:-"eq"}
|
||||||
|
local latest=$3
|
||||||
|
local diff_msg=${4:-""}
|
||||||
|
local res=""
|
||||||
|
|
||||||
|
if [ ! -f $original ]; then
|
||||||
|
echo ${bold}${red}
|
||||||
|
echo "FAIL! ${diff_msg}"
|
||||||
|
echo "the file '${original}' does not exit"
|
||||||
|
echo ${reset}${red}
|
||||||
|
caller
|
||||||
|
echo ${reset}
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f $latest ]; then
|
||||||
|
echo ${bold}${red}
|
||||||
|
echo "FAIL! ${diff_msg}"
|
||||||
|
echo "the file '${latest}' does not exit"
|
||||||
|
echo ${reset}${red}
|
||||||
|
caller
|
||||||
|
echo ${reset}
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sort ${original} > "${original}.sorted"
|
||||||
|
sort ${latest} > "${latest}.sorted"
|
||||||
|
|
||||||
|
if [ "$comparator" == "eq" ]; then
|
||||||
|
if [ "$(diff -iwB ${original}.sorted ${latest}.sorted)" == "" ] ; then
|
||||||
|
echo -n ${green}
|
||||||
|
echo "Successful: ${diff_msg}"
|
||||||
|
echo -n ${reset}
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo ${bold}${red}
|
||||||
|
echo "FAIL! ${diff_msg}"
|
||||||
|
echo " Expected: "
|
||||||
|
echo "$(cat ${original})"
|
||||||
|
echo " Got: "
|
||||||
|
echo "$(cat ${latest})"
|
||||||
|
echo ${reset}${red}
|
||||||
|
caller
|
||||||
|
echo ${reset}
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ ! -z "$(diff -iwB ${original}.sorted ${latest}.sorted)" ] ; then
|
||||||
|
echo -n ${green}
|
||||||
|
echo "Successful: ${diff_msg}"
|
||||||
|
echo -n ${reset}
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo ${bold}${red}
|
||||||
|
echo "FAIL! ${diff_msg}"
|
||||||
|
echo " Expected: "
|
||||||
|
echo "$(cat ${original})"
|
||||||
|
echo " Got: "
|
||||||
|
echo "$(cat ${latest})"
|
||||||
|
echo ${reset}${red}
|
||||||
|
caller
|
||||||
|
echo ${reset}
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -223,6 +223,48 @@ setup() {
|
|||||||
kube::log::status "Setup complete"
|
kube::log::status "Setup complete"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Kubectl version (--short, --client, --output) #
|
||||||
|
########################################################
|
||||||
|
run_kubectl_version_tests() {
|
||||||
|
kube::log::status "Testing kubectl version"
|
||||||
|
TEMP="${KUBE_TEMP}"
|
||||||
|
|
||||||
|
# create version files, one for the client, one for the server.
|
||||||
|
# these are the files we will use to ensure that the remainder output is correct
|
||||||
|
kube::test::version::object_to_file "Client" "" "${TEMP}/client_version_test"
|
||||||
|
kube::test::version::object_to_file "Server" "" "${TEMP}/server_version_test"
|
||||||
|
|
||||||
|
kube::log::status "Testing kubectl version: check client only output matches expected output"
|
||||||
|
kube::test::version::object_to_file "Client" "--client" "${TEMP}/client_only_version_test"
|
||||||
|
kube::test::version::object_to_file "Client" "--client" "${TEMP}/server_client_only_version_test"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/client_version_test" "eq" "${TEMP}/client_only_version_test" "the flag '--client' shows correct client info"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/server_version_test" "ne" "${TEMP}/server_client_only_version_test" "the flag '--client' correctly has no server version info"
|
||||||
|
|
||||||
|
kube::log::status "Testing kubectl version: verify json output"
|
||||||
|
kube::test::version::json_client_server_object_to_file "" "clientVersion" "${TEMP}/client_json_version_test"
|
||||||
|
kube::test::version::json_client_server_object_to_file "" "serverVersion" "${TEMP}/server_json_version_test"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/client_version_test" "eq" "${TEMP}/client_json_version_test" "--output json has correct client info"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/server_version_test" "eq" "${TEMP}/server_json_version_test" "--output json has correct server info"
|
||||||
|
|
||||||
|
kube::log::status "Testing kubectl version: verify json output using additional --client flag does not contain serverVersion"
|
||||||
|
kube::test::version::json_client_server_object_to_file "--client" "clientVersion" "${TEMP}/client_only_json_version_test"
|
||||||
|
kube::test::version::json_client_server_object_to_file "--client" "serverVersion" "${TEMP}/server_client_only_json_version_test"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/client_version_test" "eq" "${TEMP}/client_only_json_version_test" "--client --output json has correct client info"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/server_version_test" "ne" "${TEMP}/server_client_only_json_version_test" "--client --output json has no server info"
|
||||||
|
|
||||||
|
kube::log::status "Testing kubectl version: compare json output using additional --short flag"
|
||||||
|
kube::test::version::json_client_server_object_to_file "--short" "clientVersion" "${TEMP}/client_short_json_version_test"
|
||||||
|
kube::test::version::json_client_server_object_to_file "--short" "serverVersion" "${TEMP}/server_short_json_version_test"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/client_version_test" "eq" "${TEMP}/client_short_json_version_test" "--short --output client json info is equal to non short result"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/server_version_test" "eq" "${TEMP}/server_short_json_version_test" "--short --output server json info is equal to non short result"
|
||||||
|
|
||||||
|
kube::log::status "Testing kubectl version: compare json output with yaml output"
|
||||||
|
kube::test::version::json_object_to_file "" "${TEMP}/client_server_json_version_test"
|
||||||
|
kube::test::version::yaml_object_to_file "" "${TEMP}/client_server_yaml_version_test"
|
||||||
|
kube::test::version::diff_assert "${TEMP}/client_server_json_version_test" "eq" "${TEMP}/client_server_yaml_version_test" "--output json/yaml has identical information"
|
||||||
|
}
|
||||||
|
|
||||||
# Runs all pod related tests.
|
# Runs all pod related tests.
|
||||||
run_pod_tests() {
|
run_pod_tests() {
|
||||||
kube::log::status "Testing kubectl(v1:pods)"
|
kube::log::status "Testing kubectl(v1:pods)"
|
||||||
@ -2819,6 +2861,11 @@ runTests() {
|
|||||||
kubectl get "${kube_flags[@]}" -f hack/testdata/kubernetes-service.yaml
|
kubectl get "${kube_flags[@]}" -f hack/testdata/kubernetes-service.yaml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# Kubectl version #
|
||||||
|
#########################
|
||||||
|
run_kubectl_version_tests
|
||||||
|
|
||||||
# Passing no arguments to create is an error
|
# Passing no arguments to create is an error
|
||||||
! kubectl create
|
! kubectl create
|
||||||
|
|
||||||
|
@ -133,6 +133,7 @@ go_library(
|
|||||||
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/yaml",
|
"//vendor:k8s.io/apimachinery/pkg/util/yaml",
|
||||||
|
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||||
"//vendor:k8s.io/apiserver/pkg/util/flag",
|
"//vendor:k8s.io/apiserver/pkg/util/flag",
|
||||||
"//vendor:k8s.io/client-go/discovery",
|
"//vendor:k8s.io/client-go/discovery",
|
||||||
|
@ -17,17 +17,26 @@ limitations under the License.
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
apimachineryversion "k8s.io/apimachinery/pkg/version"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/util/i18n"
|
"k8s.io/kubernetes/pkg/util/i18n"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Version struct {
|
||||||
|
ClientVersion *apimachineryversion.Info `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"`
|
||||||
|
ServerVersion *apimachineryversion.Info `json:"serverVersion,omitempty" yaml:"serverVersion,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version_example = templates.Examples(`
|
version_example = templates.Examples(`
|
||||||
# Print the client and server versions for the current context
|
# Print the client and server versions for the current context
|
||||||
@ -47,36 +56,75 @@ func NewCmdVersion(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
}
|
}
|
||||||
cmd.Flags().BoolP("client", "c", false, "Client version only (no server required).")
|
cmd.Flags().BoolP("client", "c", false, "Client version only (no server required).")
|
||||||
cmd.Flags().BoolP("short", "", false, "Print just the version number.")
|
cmd.Flags().BoolP("short", "", false, "Print just the version number.")
|
||||||
|
cmd.Flags().String("output", "", "output format, options available are yaml and json")
|
||||||
cmd.Flags().MarkShorthandDeprecated("client", "please use --client instead.")
|
cmd.Flags().MarkShorthandDeprecated("client", "please use --client instead.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunVersion(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
|
func RunVersion(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
|
||||||
v := fmt.Sprintf("%#v", version.Get())
|
var serverVersion *apimachineryversion.Info = nil
|
||||||
if cmdutil.GetFlagBool(cmd, "short") {
|
var serverErr error = nil
|
||||||
v = version.Get().GitVersion
|
vo := Version{nil, nil}
|
||||||
|
|
||||||
|
clientVersion := version.Get()
|
||||||
|
vo.ClientVersion = &clientVersion
|
||||||
|
|
||||||
|
if !cmdutil.GetFlagBool(cmd, "client") {
|
||||||
|
serverVersion, serverErr = retrieveServerVersion(f)
|
||||||
|
vo.ServerVersion = serverVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(out, "Client Version: %s\n", v)
|
switch of := cmdutil.GetFlagString(cmd, "output"); of {
|
||||||
if cmdutil.GetFlagBool(cmd, "client") {
|
case "":
|
||||||
return nil
|
if cmdutil.GetFlagBool(cmd, "short") {
|
||||||
|
fmt.Fprintf(out, "Client Version: %s\n", clientVersion.GitVersion)
|
||||||
|
|
||||||
|
if serverVersion != nil {
|
||||||
|
fmt.Fprintf(out, "Server Version: %s\n", serverVersion.GitVersion)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(out, "Client Version: %s\n", fmt.Sprintf("%#v", clientVersion))
|
||||||
|
|
||||||
|
if serverVersion != nil {
|
||||||
|
fmt.Fprintf(out, "Server Version: %s\n", fmt.Sprintf("%#v", *serverVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "yaml":
|
||||||
|
y, err := yaml.Marshal(&vo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(out, string(y))
|
||||||
|
case "json":
|
||||||
|
y, err := json.Marshal(&vo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintln(out, string(y))
|
||||||
|
default:
|
||||||
|
return errors.New("invalid output format: " + of)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
discoveryclient, err := f.DiscoveryClient()
|
if serverErr != nil {
|
||||||
if err != nil {
|
return serverErr
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverVersion, err := discoveryclient.ServerVersion()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
v = fmt.Sprintf("%#v", *serverVersion)
|
|
||||||
if cmdutil.GetFlagBool(cmd, "short") {
|
|
||||||
v = serverVersion.GitVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(out, "Server Version: %s\n", v)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func retrieveServerVersion(f cmdutil.Factory) (*apimachineryversion.Info, error) {
|
||||||
|
discoveryClient, err := f.DiscoveryClient()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
serverVersion, err := discoveryClient.ServerVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverVersion, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user