Permalink
Browse files

Use client-go to retrieve cluster version

Use functionality in client-go to retrieve version from Open API
schema instead of trying to construct the call manually.

Fixes #503

Signed-off-by: bryanl <bryanliles@gmail.com>
  • Loading branch information...
bryanl committed May 8, 2018
1 parent 9bd5b3a commit 8dfed4281f8c3b847d73776edca6a8822d940e1f
@@ -43,6 +43,7 @@ ks param set guestbook replicas 2 --env=dev
### Options
```
--as-string Force value to be interpreted as string
--env string Specify environment to set parameters for
-h, --help help for set
```
@@ -42,7 +42,7 @@ const (
func init() {
RootCmd.AddCommand(applyCmd)
applyClientConfig = client.NewDefaultClientConfig()
applyClientConfig = client.NewDefaultClientConfig(ka)
applyClientConfig.BindClientGoFlags(applyCmd)
bindJsonnetFlags(applyCmd, "apply")
@@ -39,7 +39,7 @@ var (
func init() {
RootCmd.AddCommand(deleteCmd)
deleteClientConfig = client.NewDefaultClientConfig()
deleteClientConfig = client.NewDefaultClientConfig(ka)
deleteClientConfig.BindClientGoFlags(deleteCmd)
bindJsonnetFlags(deleteCmd, "delete")
@@ -47,7 +47,7 @@ var (
func init() {
RootCmd.AddCommand(envCmd)
envClientConfig = client.NewDefaultClientConfig()
envClientConfig = client.NewDefaultClientConfig(ka)
envClientConfig.BindClientGoFlags(envCmd)
envCmd.AddCommand(envAddCmd)
@@ -51,7 +51,7 @@ var envAddCmd = &cobra.Command{
return err
}
if specFlag == "" {
specFlag = envClientConfig.GetAPISpec(server)
specFlag = envClientConfig.GetAPISpec()
}
isOverride := viper.GetBool(vEnvAddOverride)
@@ -43,7 +43,7 @@ var (
func init() {
RootCmd.AddCommand(initCmd)
initClientConfig = client.NewDefaultClientConfig()
initClientConfig = client.NewDefaultClientConfig(ka)
initClientConfig.BindClientGoFlags(initCmd)
initCmd.Flags().String(flagDir, "", "Ksonnet application directory")
@@ -90,7 +90,7 @@ var initCmd = &cobra.Command{
specFlag := viper.GetString(vInitAPISpec)
if specFlag == "" {
specFlag = initClientConfig.GetAPISpec(server)
specFlag = initClientConfig.GetAPISpec()
}
m := map[string]interface{}{
@@ -45,7 +45,7 @@ func Test_initCmd(t *testing.T) {
actions.OptionEnvName: "env-name",
actions.OptionRootPath: root,
actions.OptionServer: "http://127.0.0.1",
actions.OptionSpecFlag: "version:v1.7.0",
actions.OptionSpecFlag: "version:v1.8.0",
actions.OptionNamespace: "new-namespace",
actions.OptionSkipDefaultRegistries: false,
},
@@ -38,7 +38,7 @@ func init() {
RootCmd.AddCommand(validateCmd)
addEnvCmdFlags(validateCmd)
bindJsonnetFlags(validateCmd, "validate")
validateClientConfig = client.NewDefaultClientConfig()
validateClientConfig = client.NewDefaultClientConfig(ka)
validateClientConfig.BindClientGoFlags(validateCmd)
viper.BindPFlag(vValidateComponent, validateCmd.Flag(flagComponent))
@@ -16,17 +16,9 @@
package client
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"path"
"reflect"
"time"
"github.com/ksonnet/ksonnet/pkg/app"
str "github.com/ksonnet/ksonnet/pkg/util/strings"
@@ -40,7 +32,7 @@ import (
)
const (
defaultVersion = "version:v1.7.0"
defaultVersion = "version:v1.8.0"
)
// Config is a wrapper around client-go's ClientConfig
@@ -49,122 +41,65 @@ type Config struct {
LoadingRules *clientcmd.ClientConfigLoadingRules
Config clientcmd.ClientConfig
discoveryClient func() (discovery.DiscoveryInterface, error)
}
func defaultDiscoveryClient(config clientcmd.ClientConfig) func() (discovery.DiscoveryInterface, error) {
return func() (discovery.DiscoveryInterface, error) {
c, err := config.ClientConfig()
if err != nil {
return nil, errors.Wrap(err, "retrive client config")
}
return discovery.NewDiscoveryClientForConfig(c)
}
}
// NewClientConfig initializes a new client.Config with the provided loading rules and overrides.
func NewClientConfig(a app.App, overrides clientcmd.ConfigOverrides, loadingRules clientcmd.ClientConfigLoadingRules) *Config {
config := clientcmd.NewInteractiveDeferredLoadingClientConfig(&loadingRules, &overrides, os.Stdin)
return &Config{
Overrides: &overrides,
LoadingRules: &loadingRules,
Config: config,
Overrides: &overrides,
LoadingRules: &loadingRules,
Config: config,
discoveryClient: defaultDiscoveryClient(config),
}
}
// NewDefaultClientConfig initializes a new ClientConfig with default loading rules and no overrides.
func NewDefaultClientConfig() *Config {
func NewDefaultClientConfig(a app.App) *Config {
overrides := clientcmd.ConfigOverrides{}
loadingRules := *clientcmd.NewDefaultClientConfigLoadingRules()
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
config := clientcmd.NewInteractiveDeferredLoadingClientConfig(&loadingRules, &overrides, os.Stdin)
return &Config{
Overrides: &overrides,
LoadingRules: &loadingRules,
Config: config,
}
return NewClientConfig(a, overrides, loadingRules)
}
// InitClient initializes a new ClientConfig given the specified environment
// spec and returns the ClientPool, DiscoveryInterface, and namespace.
func InitClient(a app.App, env string) (dynamic.ClientPool, discovery.DiscoveryInterface, string, error) {
clientConfig := NewDefaultClientConfig()
clientConfig := NewDefaultClientConfig(a)
return clientConfig.RestClient(a, &env)
}
// GetAPISpec reads the kubernetes API version from this client's swagger.json.
// We anticipate the swagger.json to be located at <server>/swagger.json.
// If no swagger is found, or we are unable to authenticate to the server, we
// will default to version:v1.7.0.
func (c *Config) GetAPISpec(server string) string {
type Info struct {
Version string `json:"version"`
}
type Spec struct {
Info Info `json:"info"`
}
u, err := url.Parse(server)
u.Path = path.Join(u.Path, "swagger.json")
url := u.String()
client := http.Client{
Timeout: time.Second * 2,
}
restConfig, err := c.Config.ClientConfig()
// GetAPISpec reads the kubernetes API version from this client's Open API schema.
// If there is an error retrieving the schema, return the default version.
func (c *Config) GetAPISpec() string {
dc, err := c.discoveryClient()
if err != nil {
log.Debugf("Failed to retrieve REST config:\n%v", err)
}
if len(restConfig.TLSClientConfig.CAData) > 0 {
log.Info("Configuring TLS (from data) for retrieving cluster swagger.json")
client.Transport = buildTransportFromData(restConfig.TLSClientConfig.CAData)
}
if restConfig.TLSClientConfig.CAFile != "" {
log.Info("Configuring TLS (from file) for retrieving cluster swagger.json")
transport, err := buildTransportFromFile(restConfig.TLSClientConfig.CAFile)
if err != nil {
log.Debugf("Failed to read CA file: %v", err)
return defaultVersion
}
client.Transport = transport
}
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
log.Debugf("Failed to create request at %s\n%s", url, err.Error())
log.WithError(err).Debug("Failed to create discovery client")
return defaultVersion
}
res, err := client.Do(req)
openAPIDoc, err := dc.OpenAPISchema()
if err != nil {
log.Debugf("Failed to open swagger at %s\n%s", url, err.Error())
log.WithError(err).Debug("Failed to retrieve OpenAPI schema")
return defaultVersion
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Debugf("Failed to read swagger at %s\n%s", url, err.Error())
return defaultVersion
}
spec := Spec{}
err = json.Unmarshal(body, &spec)
if err != nil {
log.Debugf("Failed to parse swagger at %s\n%s", url, err.Error())
return defaultVersion
}
return fmt.Sprintf("version:%s", spec.Info.Version)
}
func buildTransportFromData(data []byte) *http.Transport {
tlsConfig := &tls.Config{RootCAs: x509.NewCertPool()}
tlsConfig.RootCAs.AppendCertsFromPEM(data)
return &http.Transport{TLSClientConfig: tlsConfig}
}
func buildTransportFromFile(file string) (*http.Transport, error) {
data, err := ioutil.ReadFile(file)
if err != nil {
return nil, errors.Wrap(err, "unable to ready CA file")
}
return buildTransportFromData(data), nil
return fmt.Sprintf("version:%s", openAPIDoc.Info.Version)
}
// Namespace returns the namespace for the provided ClientConfig.
Oops, something went wrong.

0 comments on commit 8dfed42

Please sign in to comment.