Add proxy configuration at the context level (#2675)
parent
388df15dd6
commit
b3bd60b67f
15
cmd/root.go
15
cmd/root.go
|
|
@ -128,11 +128,6 @@ func loadConfiguration() (*config.Config, error) {
|
|||
k8sCfg := client.NewConfig(k8sFlags)
|
||||
k9sCfg := config.NewConfig(k8sCfg)
|
||||
var errs error
|
||||
conn, err := client.InitConnection(k8sCfg)
|
||||
k9sCfg.SetConnection(conn)
|
||||
if err != nil {
|
||||
errs = errors.Join(errs, err)
|
||||
}
|
||||
|
||||
if err := k9sCfg.Load(config.AppConfigFile, false); err != nil {
|
||||
errs = errors.Join(errs, err)
|
||||
|
|
@ -142,14 +137,24 @@ func loadConfiguration() (*config.Config, error) {
|
|||
log.Error().Err(err).Msgf("config refine failed")
|
||||
errs = errors.Join(errs, err)
|
||||
}
|
||||
|
||||
conn, err := client.InitConnection(k8sCfg)
|
||||
|
||||
if err != nil {
|
||||
errs = errors.Join(errs, err)
|
||||
}
|
||||
|
||||
// Try to access server version if that fail. Connectivity issue?
|
||||
if !conn.CheckConnectivity() {
|
||||
errs = errors.Join(errs, fmt.Errorf("cannot connect to context: %s", k9sCfg.K9s.ActiveContextName()))
|
||||
}
|
||||
|
||||
if !conn.ConnectionOK() {
|
||||
errs = errors.Join(errs, fmt.Errorf("k8s connection failed for context: %s", k9sCfg.K9s.ActiveContextName()))
|
||||
}
|
||||
|
||||
k9sCfg.SetConnection(conn)
|
||||
|
||||
log.Info().Msg("✅ Kubernetes connectivity")
|
||||
if err := k9sCfg.Save(false); err != nil {
|
||||
log.Error().Err(err).Msg("Config save")
|
||||
|
|
|
|||
|
|
@ -286,8 +286,8 @@ func (a *APIClient) CheckConnectivity() bool {
|
|||
}
|
||||
}()
|
||||
|
||||
// Need reload to pick up any kubeconfig changes.
|
||||
cfg, err := NewConfig(a.config.flags).RESTConfig()
|
||||
cfg, err := a.config.RESTConfig()
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("restConfig load failed")
|
||||
a.connOK = false
|
||||
|
|
@ -551,9 +551,8 @@ func (a *APIClient) SwitchContext(name string) error {
|
|||
a.reset()
|
||||
ResetMetrics()
|
||||
|
||||
if !a.CheckConnectivity() {
|
||||
return fmt.Errorf("unable to connect to context %q", name)
|
||||
}
|
||||
// Need reload to pick up any kubeconfig changes.
|
||||
a.config = NewConfig(a.config.flags)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ package client
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -27,6 +29,7 @@ const (
|
|||
type Config struct {
|
||||
flags *genericclioptions.ConfigFlags
|
||||
mx sync.RWMutex
|
||||
proxy func(*http.Request) (*url.URL, error)
|
||||
}
|
||||
|
||||
// NewConfig returns a new k8s config or an error if the flags are invalid.
|
||||
|
|
@ -50,7 +53,17 @@ func (c *Config) CallTimeout() time.Duration {
|
|||
}
|
||||
|
||||
func (c *Config) RESTConfig() (*restclient.Config, error) {
|
||||
return c.clientConfig().ClientConfig()
|
||||
cfg, err := c.clientConfig().ClientConfig()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.proxy != nil {
|
||||
cfg.Proxy = c.proxy
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// Flags returns configuration flags.
|
||||
|
|
@ -179,6 +192,15 @@ func (c *Config) GetContext(n string) (*api.Context, error) {
|
|||
return nil, fmt.Errorf("getcontext - invalid context specified: %q", n)
|
||||
}
|
||||
|
||||
func (c *Config) SetProxy(proxy func(*http.Request) (*url.URL, error)) {
|
||||
c.proxy = proxy
|
||||
}
|
||||
|
||||
func (c *Config) WithProxy(proxy func(*http.Request) (*url.URL, error)) *Config {
|
||||
c.SetProxy(proxy)
|
||||
return c
|
||||
}
|
||||
|
||||
// Contexts fetch all available contexts.
|
||||
func (c *Config) Contexts() (map[string]*api.Context, error) {
|
||||
cfg, err := c.RawConfig()
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ type Context struct {
|
|||
View *View `yaml:"view"`
|
||||
FeatureGates FeatureGates `yaml:"featureGates"`
|
||||
PortForwardAddress string `yaml:"portForwardAddress"`
|
||||
Proxy *Proxy `yaml:"proxy"`
|
||||
mx sync.RWMutex
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package data
|
||||
|
||||
// Proxy tracks a context's proxy configuration.
|
||||
type Proxy struct {
|
||||
Address string `yaml:"address"`
|
||||
}
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/derailed/k9s/internal/config/json"
|
||||
|
|
@ -43,4 +45,7 @@ type KubeSettings interface {
|
|||
|
||||
// GetContext returns a given context configuration or err if not found.
|
||||
GetContext(string) (*api.Context, error)
|
||||
|
||||
// SetProxy sets the proxy for the active context, if present
|
||||
SetProxy(proxy func(*http.Request) (*url.URL, error))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,19 @@
|
|||
"readOnly": {"type": "boolean"},
|
||||
"skin": { "type": "string" },
|
||||
"portForwardAddress": { "type": "string" },
|
||||
"proxy": {
|
||||
"oneOf": [
|
||||
{ "type": "null" },
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties":
|
||||
{
|
||||
"address": {"type": "string"}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"namespace": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
|
@ -216,6 +218,27 @@ func (k *K9s) ActivateContext(n string) (*data.Context, error) {
|
|||
}
|
||||
k.setActiveConfig(cfg)
|
||||
|
||||
if cfg.Context.Proxy != nil {
|
||||
k.ks.SetProxy(func(*http.Request) (*url.URL, error) {
|
||||
log.Debug().Msgf("[Proxy]: %s", cfg.Context.Proxy.Address)
|
||||
return url.Parse(cfg.Context.Proxy.Address)
|
||||
})
|
||||
|
||||
if k.conn != nil && k.conn.Config() != nil {
|
||||
// We get on this branch when the user switches the context and k9s
|
||||
// already has an API connection object so we just set the proxy to
|
||||
// avoid recreation using client.InitConnection
|
||||
k.conn.Config().SetProxy(func(*http.Request) (*url.URL, error) {
|
||||
log.Debug().Msgf("[Proxy]: %s", cfg.Context.Proxy.Address)
|
||||
return url.Parse(cfg.Context.Proxy.Address)
|
||||
})
|
||||
|
||||
if !k.conn.CheckConnectivity() {
|
||||
return nil, fmt.Errorf("unable to connect to context %q", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
k.Validate(k.conn, k.ks)
|
||||
// If the context specifies a namespace, use it!
|
||||
if ns := ct.Namespace; ns != client.BlankNamespace {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
|
@ -106,6 +108,8 @@ func (m mockKubeSettings) ContextNames() (map[string]struct{}, error) {
|
|||
return mm, nil
|
||||
}
|
||||
|
||||
func (m mockKubeSettings) SetProxy(proxy func(*http.Request) (*url.URL, error)) {}
|
||||
|
||||
type mockConnection struct {
|
||||
ct string
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue