mirror of https://github.com/k3s-io/k3s
Add /version to server and check it in client.
Will help detect client/version skew and prevent e2e test from passing while running a version other than the one you think it's running.pull/6/head
parent
9fc52c8aaa
commit
3b8488028d
|
@ -22,6 +22,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -31,14 +32,14 @@ import (
|
||||||
kube_client "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
kube_client "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubecfg"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubecfg"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AppVersion is the current version of kubecfg.
|
|
||||||
const AppVersion = "0.1"
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
versionFlag = flag.Bool("V", false, "Print the version number.")
|
versionFlag = flag.Bool("V", false, "Print the version number.")
|
||||||
|
serverVersion = flag.Bool("server_version", false, "Print the server's version number.")
|
||||||
|
preventSkew = flag.Bool("expect_version_match", false, "Fail if server's version doesn't match own version.")
|
||||||
httpServer = flag.String("h", "", "The host to connect to.")
|
httpServer = flag.String("h", "", "The host to connect to.")
|
||||||
config = flag.String("c", "", "Path to the config file.")
|
config = flag.String("c", "", "Path to the config file.")
|
||||||
selector = flag.String("l", "", "Selector (label query) to use for listing")
|
selector = flag.String("l", "", "Selector (label query) to use for listing")
|
||||||
|
@ -107,7 +108,7 @@ func main() {
|
||||||
defer util.FlushLogs()
|
defer util.FlushLogs()
|
||||||
|
|
||||||
if *versionFlag {
|
if *versionFlag {
|
||||||
fmt.Println("Version:", AppVersion)
|
fmt.Printf("Version: %#v\n", version.Get())
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +137,30 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client := kube_client.New(masterServer, auth)
|
||||||
|
|
||||||
|
if *serverVersion {
|
||||||
|
got, err := client.ServerVersion()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Couldn't read version from server: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("Server Version: %#v\n", got)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *preventSkew {
|
||||||
|
got, err := client.ServerVersion()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Couldn't read version from server: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if c, s := version.Get(), *got; !reflect.DeepEqual(c, s) {
|
||||||
|
fmt.Printf("Server version (%#v) differs from client version (%#v)!\n", s, c)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if *proxy {
|
if *proxy {
|
||||||
glog.Info("Starting to serve on localhost:8001")
|
glog.Info("Starting to serve on localhost:8001")
|
||||||
server := kubecfg.NewProxyServer(*www, masterServer, auth)
|
server := kubecfg.NewProxyServer(*www, masterServer, auth)
|
||||||
|
@ -148,8 +173,6 @@ func main() {
|
||||||
}
|
}
|
||||||
method := flag.Arg(0)
|
method := flag.Arg(0)
|
||||||
|
|
||||||
client := kube_client.New(masterServer, auth)
|
|
||||||
|
|
||||||
matchFound := executeAPIRequest(method, client) || executeControllerRequest(method, client)
|
matchFound := executeAPIRequest(method, client) || executeControllerRequest(method, client)
|
||||||
if matchFound == false {
|
if matchFound == false {
|
||||||
glog.Fatalf("Unknown command %s", method)
|
glog.Fatalf("Unknown command %s", method)
|
||||||
|
|
|
@ -39,7 +39,7 @@ set -e
|
||||||
# Use testing config
|
# Use testing config
|
||||||
export KUBE_CONFIG_FILE="config-test.sh"
|
export KUBE_CONFIG_FILE="config-test.sh"
|
||||||
export KUBE_REPO_ROOT="$(dirname $0)/.."
|
export KUBE_REPO_ROOT="$(dirname $0)/.."
|
||||||
export CLOUDCFG="${KUBE_REPO_ROOT}/cluster/kubecfg.sh"
|
export CLOUDCFG="${KUBE_REPO_ROOT}/cluster/kubecfg.sh -expect_version_match"
|
||||||
|
|
||||||
# Build a release required by the test provider [if any]
|
# Build a release required by the test provider [if any]
|
||||||
test-build-release
|
test-build-release
|
||||||
|
|
|
@ -106,7 +106,7 @@ APISERVER_PID=$!
|
||||||
|
|
||||||
wait_for_url "http://127.0.0.1:${API_PORT}/healthz" "apiserver: "
|
wait_for_url "http://127.0.0.1:${API_PORT}/healthz" "apiserver: "
|
||||||
|
|
||||||
KUBE_CMD="${GO_OUT}/kubecfg -h http://127.0.0.1:${API_PORT}"
|
KUBE_CMD="${GO_OUT}/kubecfg -h http://127.0.0.1:${API_PORT} -expect_version_match"
|
||||||
|
|
||||||
${KUBE_CMD} list pods
|
${KUBE_CMD} list pods
|
||||||
echo "kubecfg(pods): ok"
|
echo "kubecfg(pods): ok"
|
||||||
|
|
|
@ -39,6 +39,7 @@ import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
@ -151,6 +152,7 @@ func New(storage map[string]RESTStorage, prefix string) *APIServer {
|
||||||
healthz.InstallHandler(s.mux)
|
healthz.InstallHandler(s.mux)
|
||||||
|
|
||||||
s.mux.HandleFunc("/", s.handleIndex)
|
s.mux.HandleFunc("/", s.handleIndex)
|
||||||
|
s.mux.HandleFunc("/version", s.handleVersionReq)
|
||||||
|
|
||||||
// Handle both operations and operations/* with the same handler
|
// Handle both operations and operations/* with the same handler
|
||||||
s.mux.HandleFunc(s.operationPrefix(), s.handleOperationRequest)
|
s.mux.HandleFunc(s.operationPrefix(), s.handleOperationRequest)
|
||||||
|
@ -182,6 +184,11 @@ func (server *APIServer) handleIndex(w http.ResponseWriter, req *http.Request) {
|
||||||
fmt.Fprint(w, data)
|
fmt.Fprint(w, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleVersionReq writes the server's version information.
|
||||||
|
func (server *APIServer) handleVersionReq(w http.ResponseWriter, req *http.Request) {
|
||||||
|
server.writeRawJSON(http.StatusOK, version.Get(), w)
|
||||||
|
}
|
||||||
|
|
||||||
func (server *APIServer) handleMinionReq(w http.ResponseWriter, req *http.Request) {
|
func (server *APIServer) handleMinionReq(w http.ResponseWriter, req *http.Request) {
|
||||||
minionPrefix := "/proxy/minion/"
|
minionPrefix := "/proxy/minion/"
|
||||||
if !strings.HasPrefix(req.URL.Path, minionPrefix) {
|
if !strings.HasPrefix(req.URL.Path, minionPrefix) {
|
||||||
|
@ -344,14 +351,27 @@ func (server *APIServer) notFound(w http.ResponseWriter, req *http.Request) {
|
||||||
fmt.Fprintf(w, "Not Found: %#v", req)
|
fmt.Fprintf(w, "Not Found: %#v", req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write writes an API object in wire format.
|
||||||
func (server *APIServer) write(statusCode int, object interface{}, w http.ResponseWriter) {
|
func (server *APIServer) write(statusCode int, object interface{}, w http.ResponseWriter) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(statusCode)
|
|
||||||
output, err := api.Encode(object)
|
output, err := api.Encode(object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.error(err, w)
|
server.error(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(statusCode)
|
||||||
|
w.Write(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeRawJSON writes a non-API object in JSON.
|
||||||
|
func (server *APIServer) writeRawJSON(statusCode int, object interface{}, w http.ResponseWriter) {
|
||||||
|
output, err := json.Marshal(object)
|
||||||
|
if err != nil {
|
||||||
|
server.error(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(statusCode)
|
||||||
w.Write(output)
|
w.Write(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -26,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -238,3 +240,17 @@ func (c *Client) UpdateService(svc api.Service) (result api.Service, err error)
|
||||||
func (c *Client) DeleteService(name string) error {
|
func (c *Client) DeleteService(name string) error {
|
||||||
return c.Delete().Path("services").Path(name).Do().Error()
|
return c.Delete().Path("services").Path(name).Do().Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServerVersion retrieves and parses the server's version.
|
||||||
|
func (c *Client) ServerVersion() (*version.Info, error) {
|
||||||
|
body, err := c.Get().AbsPath("/version").Do().Raw()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var info version.Info
|
||||||
|
err = json.Unmarshal(body, &info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Got '%s': %v", string(body), err)
|
||||||
|
}
|
||||||
|
return &info, nil
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -26,6 +27,7 @@ import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Move this to a common place, it's needed in multiple tests.
|
// TODO: Move this to a common place, it's needed in multiple tests.
|
||||||
|
@ -456,3 +458,30 @@ func TestDoRequestAcceptedSuccess(t *testing.T) {
|
||||||
}
|
}
|
||||||
fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil)
|
fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetServerVersion(t *testing.T) {
|
||||||
|
expect := version.Info{
|
||||||
|
Major: "foo",
|
||||||
|
Minor: "bar",
|
||||||
|
GitCommit: "baz",
|
||||||
|
}
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
output, err := json.Marshal(expect)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected encoding error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(output)
|
||||||
|
}))
|
||||||
|
client := New(server.URL, nil)
|
||||||
|
|
||||||
|
got, err := client.ServerVersion()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected encoding error: %v", err)
|
||||||
|
}
|
||||||
|
if e, a := expect, *got; !reflect.DeepEqual(e, a) {
|
||||||
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,10 +29,24 @@ import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"gopkg.in/v1/yaml"
|
"gopkg.in/v1/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetServerVersion(client *client.Client) (*version.Info, error) {
|
||||||
|
body, err := client.Get().AbsPath("/version").Do().Raw()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var info version.Info
|
||||||
|
err = json.Unmarshal(body, &info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Got '%s': %v", string(body), err)
|
||||||
|
}
|
||||||
|
return &info, nil
|
||||||
|
}
|
||||||
|
|
||||||
func promptForString(field string, r io.Reader) string {
|
func promptForString(field string, r io.Reader) string {
|
||||||
fmt.Printf("Please enter %s: ", field)
|
fmt.Printf("Please enter %s: ", field)
|
||||||
var result string
|
var result string
|
||||||
|
|
|
@ -317,9 +317,9 @@ func TestMakePorts(t *testing.T) {
|
||||||
{
|
{
|
||||||
"8080:80,8081:8081,443:444",
|
"8080:80,8081:8081,443:444",
|
||||||
[]api.Port{
|
[]api.Port{
|
||||||
api.Port{HostPort: 8080, ContainerPort: 80},
|
{HostPort: 8080, ContainerPort: 80},
|
||||||
api.Port{HostPort: 8081, ContainerPort: 8081},
|
{HostPort: 8081, ContainerPort: 8081},
|
||||||
api.Port{HostPort: 443, ContainerPort: 444},
|
{HostPort: 443, ContainerPort: 444},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,21 @@ limitations under the License.
|
||||||
|
|
||||||
package version
|
package version
|
||||||
|
|
||||||
func Get() (major, minor, gitCommit string) {
|
// Info contains versioning information.
|
||||||
return "v1beta", "1", commitFromGit
|
// TODO: Add []string of api versions supported? It's still unclear
|
||||||
|
// how we'll want to distribute that information.
|
||||||
|
type Info struct {
|
||||||
|
Major string `json:"major" yaml:"major"`
|
||||||
|
Minor string `json:"minor" yaml:"minor"`
|
||||||
|
GitCommit string `json:"gitCommit" yaml:"gitCommit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the overall codebase version. It's for detecting
|
||||||
|
// what code a binary was built from.
|
||||||
|
func Get() Info {
|
||||||
|
return Info{
|
||||||
|
Major: "0",
|
||||||
|
Minor: "1",
|
||||||
|
GitCommit: commitFromGit,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue