refactor pf and benchmarks
parent
2822ac702e
commit
7a977f31c7
1
go.mod
1
go.mod
|
|
@ -29,6 +29,7 @@ replace (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
fyne.io/fyne v1.2.2 // indirect
|
fyne.io/fyne v1.2.2 // indirect
|
||||||
|
github.com/GeertJohan/gomatrix v0.0.0-20190924221747-74328b69a02f // indirect
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||||
github.com/alexellis/go-execute v0.0.0-20200124154445-8697e4e28c5e // indirect
|
github.com/alexellis/go-execute v0.0.0-20200124154445-8697e4e28c5e // indirect
|
||||||
github.com/alexellis/hmac v0.0.0-20180624211220-5c52ab81c0de // indirect
|
github.com/alexellis/hmac v0.0.0-20180624211220-5c52ab81c0de // indirect
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -29,6 +29,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
|
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||||
|
github.com/GeertJohan/gomatrix v0.0.0-20190924221747-74328b69a02f h1:O4XncXE6+qNjZIvermf2/Z4esEl8K1zFVPbl3l14mjM=
|
||||||
|
github.com/GeertJohan/gomatrix v0.0.0-20190924221747-74328b69a02f/go.mod h1:HqtsgfzGADJzbZ+MbYAJ+PJnxIxBwBvYjyqd2wWw0j0=
|
||||||
github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14=
|
github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14=
|
||||||
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA=
|
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA=
|
||||||
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
|
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
|
||||||
|
|
@ -389,6 +391,8 @@ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
|
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
|
||||||
|
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||||
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
|
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigCurrentContext(t *testing.T) {
|
func TestConfigCurrentContext(t *testing.T) {
|
||||||
name, kubeConfig := "blee", "./assets/config"
|
name, kubeConfig := "blee", "./testdata/config"
|
||||||
uu := []struct {
|
uu := []struct {
|
||||||
flags *genericclioptions.ConfigFlags
|
flags *genericclioptions.ConfigFlags
|
||||||
context string
|
context string
|
||||||
|
|
@ -36,7 +36,7 @@ func TestConfigCurrentContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigCurrentCluster(t *testing.T) {
|
func TestConfigCurrentCluster(t *testing.T) {
|
||||||
name, kubeConfig := "blee", "./assets/config"
|
name, kubeConfig := "blee", "./testdata/config"
|
||||||
uu := []struct {
|
uu := []struct {
|
||||||
flags *genericclioptions.ConfigFlags
|
flags *genericclioptions.ConfigFlags
|
||||||
cluster string
|
cluster string
|
||||||
|
|
@ -54,7 +54,7 @@ func TestConfigCurrentCluster(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigCurrentUser(t *testing.T) {
|
func TestConfigCurrentUser(t *testing.T) {
|
||||||
name, kubeConfig := "blee", "./assets/config"
|
name, kubeConfig := "blee", "./testdata/config"
|
||||||
uu := []struct {
|
uu := []struct {
|
||||||
flags *genericclioptions.ConfigFlags
|
flags *genericclioptions.ConfigFlags
|
||||||
user string
|
user string
|
||||||
|
|
@ -72,7 +72,7 @@ func TestConfigCurrentUser(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigCurrentNamespace(t *testing.T) {
|
func TestConfigCurrentNamespace(t *testing.T) {
|
||||||
name, kubeConfig := "blee", "./assets/config"
|
name, kubeConfig := "blee", "./testdata/config"
|
||||||
uu := []struct {
|
uu := []struct {
|
||||||
flags *genericclioptions.ConfigFlags
|
flags *genericclioptions.ConfigFlags
|
||||||
namespace string
|
namespace string
|
||||||
|
|
@ -91,7 +91,7 @@ func TestConfigCurrentNamespace(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigGetContext(t *testing.T) {
|
func TestConfigGetContext(t *testing.T) {
|
||||||
kubeConfig := "./assets/config"
|
kubeConfig := "./testdata/config"
|
||||||
uu := []struct {
|
uu := []struct {
|
||||||
flags *genericclioptions.ConfigFlags
|
flags *genericclioptions.ConfigFlags
|
||||||
cluster string
|
cluster string
|
||||||
|
|
@ -114,7 +114,7 @@ func TestConfigGetContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigSwitchContext(t *testing.T) {
|
func TestConfigSwitchContext(t *testing.T) {
|
||||||
cluster, kubeConfig := "duh", "./assets/config"
|
cluster, kubeConfig := "duh", "./testdata/config"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
ClusterName: &cluster,
|
ClusterName: &cluster,
|
||||||
|
|
@ -129,7 +129,7 @@ func TestConfigSwitchContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigClusterNameFromContext(t *testing.T) {
|
func TestConfigClusterNameFromContext(t *testing.T) {
|
||||||
cluster, kubeConfig := "duh", "./assets/config"
|
cluster, kubeConfig := "duh", "./testdata/config"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
ClusterName: &cluster,
|
ClusterName: &cluster,
|
||||||
|
|
@ -142,7 +142,7 @@ func TestConfigClusterNameFromContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigAccess(t *testing.T) {
|
func TestConfigAccess(t *testing.T) {
|
||||||
cluster, kubeConfig := "duh", "./assets/config"
|
cluster, kubeConfig := "duh", "./testdata/config"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
ClusterName: &cluster,
|
ClusterName: &cluster,
|
||||||
|
|
@ -155,7 +155,7 @@ func TestConfigAccess(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigContexts(t *testing.T) {
|
func TestConfigContexts(t *testing.T) {
|
||||||
cluster, kubeConfig := "duh", "./assets/config"
|
cluster, kubeConfig := "duh", "./testdata/config"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
ClusterName: &cluster,
|
ClusterName: &cluster,
|
||||||
|
|
@ -168,7 +168,7 @@ func TestConfigContexts(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigContextNames(t *testing.T) {
|
func TestConfigContextNames(t *testing.T) {
|
||||||
cluster, kubeConfig := "duh", "./assets/config"
|
cluster, kubeConfig := "duh", "./testdata/config"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
ClusterName: &cluster,
|
ClusterName: &cluster,
|
||||||
|
|
@ -181,7 +181,7 @@ func TestConfigContextNames(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigClusterNames(t *testing.T) {
|
func TestConfigClusterNames(t *testing.T) {
|
||||||
cluster, kubeConfig := "duh", "./assets/config"
|
cluster, kubeConfig := "duh", "./testdata/config"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
ClusterName: &cluster,
|
ClusterName: &cluster,
|
||||||
|
|
@ -194,7 +194,7 @@ func TestConfigClusterNames(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigDelContext(t *testing.T) {
|
func TestConfigDelContext(t *testing.T) {
|
||||||
cluster, kubeConfig := "duh", "./assets/config.1"
|
cluster, kubeConfig := "duh", "./testdata/config.1"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
ClusterName: &cluster,
|
ClusterName: &cluster,
|
||||||
|
|
@ -209,7 +209,7 @@ func TestConfigDelContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigRestConfig(t *testing.T) {
|
func TestConfigRestConfig(t *testing.T) {
|
||||||
kubeConfig := "./assets/config"
|
kubeConfig := "./testdata/config"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
}
|
}
|
||||||
|
|
@ -221,7 +221,7 @@ func TestConfigRestConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigBadConfig(t *testing.T) {
|
func TestConfigBadConfig(t *testing.T) {
|
||||||
kubeConfig := "./assets/bork_config"
|
kubeConfig := "./testdata/bork_config"
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
}
|
}
|
||||||
|
|
@ -232,7 +232,7 @@ func TestConfigBadConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNamespaceNames(t *testing.T) {
|
func TestNamespaceNames(t *testing.T) {
|
||||||
kubeConfig := "./assets/config"
|
kubeConfig := "./testdata/config"
|
||||||
|
|
||||||
flags := genericclioptions.ConfigFlags{
|
flags := genericclioptions.ConfigFlags{
|
||||||
KubeConfig: &kubeConfig,
|
KubeConfig: &kubeConfig,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
// PortTunnel represents a host tunnel port mapper.
|
||||||
|
type PortTunnel struct {
|
||||||
|
Address, LocalPort, ContainerPort string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortMap returns a port mapping.
|
||||||
|
func (t PortTunnel) PortMap() string {
|
||||||
|
return t.LocalPort + ":" + t.ContainerPort
|
||||||
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ func TestAliasDefine(t *testing.T) {
|
||||||
func TestAliasesLoad(t *testing.T) {
|
func TestAliasesLoad(t *testing.T) {
|
||||||
a := config.NewAliases()
|
a := config.NewAliases()
|
||||||
|
|
||||||
assert.Nil(t, a.LoadAliases("test_assets/alias.yml"))
|
assert.Nil(t, a.LoadAliases("testdata/alias.yml"))
|
||||||
assert.Equal(t, 2, len(a.Alias))
|
assert.Equal(t, 2, len(a.Alias))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,3 +105,15 @@ func (s *Bench) load(path string) error {
|
||||||
|
|
||||||
return yaml.Unmarshal(f, &s)
|
return yaml.Unmarshal(f, &s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultBenchSpec returns a default bench spec.
|
||||||
|
func DefaultBenchSpec() BenchConfig {
|
||||||
|
return BenchConfig{
|
||||||
|
C: DefaultC,
|
||||||
|
N: DefaultN,
|
||||||
|
HTTP: HTTP{
|
||||||
|
Method: DefaultMethod,
|
||||||
|
Path: "/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,14 @@ func TestBenchLoad(t *testing.T) {
|
||||||
coCount int
|
coCount int
|
||||||
}{
|
}{
|
||||||
"goodConfig": {
|
"goodConfig": {
|
||||||
"test_assets/b_good.yml",
|
"testdata/b_good.yml",
|
||||||
2,
|
2,
|
||||||
1000,
|
1000,
|
||||||
2,
|
2,
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
"malformed": {
|
"malformed": {
|
||||||
"test_assets/b_toast.yml",
|
"testdata/b_toast.yml",
|
||||||
1,
|
1,
|
||||||
200,
|
200,
|
||||||
0,
|
0,
|
||||||
|
|
@ -100,7 +100,7 @@ func TestBenchServiceLoad(t *testing.T) {
|
||||||
for k := range uu {
|
for k := range uu {
|
||||||
u := uu[k]
|
u := uu[k]
|
||||||
t.Run(k, func(t *testing.T) {
|
t.Run(k, func(t *testing.T) {
|
||||||
b, err := NewBench("test_assets/b_good.yml")
|
b, err := NewBench("testdata/b_good.yml")
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, len(b.Benchmarks.Services))
|
assert.Equal(t, 2, len(b.Benchmarks.Services))
|
||||||
|
|
@ -119,16 +119,16 @@ func TestBenchServiceLoad(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBenchReLoad(t *testing.T) {
|
func TestBenchReLoad(t *testing.T) {
|
||||||
b, err := NewBench("test_assets/b_containers.yml")
|
b, err := NewBench("testdata/b_containers.yml")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 2, b.Benchmarks.Defaults.C)
|
assert.Equal(t, 2, b.Benchmarks.Defaults.C)
|
||||||
assert.Nil(t, b.Reload("test_assets/b_containers_1.yml"))
|
assert.Nil(t, b.Reload("testdata/b_containers_1.yml"))
|
||||||
assert.Equal(t, 20, b.Benchmarks.Defaults.C)
|
assert.Equal(t, 20, b.Benchmarks.Defaults.C)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBenchLoadToast(t *testing.T) {
|
func TestBenchLoadToast(t *testing.T) {
|
||||||
_, err := NewBench("test_assets/toast.yml")
|
_, err := NewBench("testdata/toast.yml")
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ func TestBenchContainerLoad(t *testing.T) {
|
||||||
for k := range uu {
|
for k := range uu {
|
||||||
u := uu[k]
|
u := uu[k]
|
||||||
t.Run(k, func(t *testing.T) {
|
t.Run(k, func(t *testing.T) {
|
||||||
b, err := NewBench("test_assets/b_containers.yml")
|
b, err := NewBench("testdata/b_containers.yml")
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, len(b.Benchmarks.Services))
|
assert.Equal(t, 2, len(b.Benchmarks.Services))
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigRefine(t *testing.T) {
|
func TestConfigRefine(t *testing.T) {
|
||||||
cfgFile, ctx, cluster, ns := "test_assets/kubeconfig-test.yml", "test", "c1", "ns1"
|
cfgFile, ctx, cluster, ns := "testdata/kubeconfig-test.yml", "test", "c1", "ns1"
|
||||||
uu := map[string]struct {
|
uu := map[string]struct {
|
||||||
flags *genericclioptions.ConfigFlags
|
flags *genericclioptions.ConfigFlags
|
||||||
issue bool
|
issue bool
|
||||||
|
|
@ -85,7 +85,7 @@ func TestConfigValidate(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
cfg.SetConnection(mc)
|
cfg.SetConnection(mc)
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
cfg.Validate()
|
cfg.Validate()
|
||||||
// mc.VerifyWasCalledOnce().ValidNamespaces()
|
// mc.VerifyWasCalledOnce().ValidNamespaces()
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ func TestConfigValidate(t *testing.T) {
|
||||||
func TestConfigLoad(t *testing.T) {
|
func TestConfigLoad(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
|
|
||||||
assert.Equal(t, 2, cfg.K9s.RefreshRate)
|
assert.Equal(t, 2, cfg.K9s.RefreshRate)
|
||||||
assert.Equal(t, 200, cfg.K9s.LogBufferSize)
|
assert.Equal(t, 200, cfg.K9s.LogBufferSize)
|
||||||
|
|
@ -119,7 +119,7 @@ func TestConfigCurrentCluster(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
|
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
assert.NotNil(t, cfg.CurrentCluster())
|
assert.NotNil(t, cfg.CurrentCluster())
|
||||||
assert.Equal(t, "kube-system", cfg.CurrentCluster().Namespace.Active)
|
assert.Equal(t, "kube-system", cfg.CurrentCluster().Namespace.Active)
|
||||||
assert.Equal(t, "ctx", cfg.CurrentCluster().View.Active)
|
assert.Equal(t, "ctx", cfg.CurrentCluster().View.Active)
|
||||||
|
|
@ -129,7 +129,7 @@ func TestConfigActiveNamespace(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
|
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
assert.Equal(t, "kube-system", cfg.ActiveNamespace())
|
assert.Equal(t, "kube-system", cfg.ActiveNamespace())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ func TestConfigSetActiveNamespace(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
|
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
assert.Nil(t, cfg.SetActiveNamespace("default"))
|
assert.Nil(t, cfg.SetActiveNamespace("default"))
|
||||||
assert.Equal(t, "default", cfg.ActiveNamespace())
|
assert.Equal(t, "default", cfg.ActiveNamespace())
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +151,7 @@ func TestConfigActiveView(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
|
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
assert.Equal(t, "ctx", cfg.ActiveView())
|
assert.Equal(t, "ctx", cfg.ActiveView())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,7 +164,7 @@ func TestConfigSetActiveView(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
|
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
cfg.SetActiveView("po")
|
cfg.SetActiveView("po")
|
||||||
assert.Equal(t, "po", cfg.ActiveView())
|
assert.Equal(t, "po", cfg.ActiveView())
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ func TestConfigFavNamespaces(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
|
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
expectedNS := []string{"default", "kube-public", "istio-system", "all", "kube-system"}
|
expectedNS := []string{"default", "kube-public", "istio-system", "all", "kube-system"}
|
||||||
assert.Equal(t, expectedNS, cfg.FavNamespaces())
|
assert.Equal(t, expectedNS, cfg.FavNamespaces())
|
||||||
}
|
}
|
||||||
|
|
@ -181,13 +181,13 @@ func TestConfigFavNamespaces(t *testing.T) {
|
||||||
func TestConfigLoadOldCfg(t *testing.T) {
|
func TestConfigLoadOldCfg(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s_old.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s_old.yml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigLoadCrap(t *testing.T) {
|
func TestConfigLoadCrap(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
assert.NotNil(t, cfg.Load("test_assets/k9s_not_there.yml"))
|
assert.NotNil(t, cfg.Load("testdata/k9s_not_there.yml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigSaveFile(t *testing.T) {
|
func TestConfigSaveFile(t *testing.T) {
|
||||||
|
|
@ -203,7 +203,7 @@ func TestConfigSaveFile(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
cfg.SetConnection(mc)
|
cfg.SetConnection(mc)
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
cfg.K9s.RefreshRate = 100
|
cfg.K9s.RefreshRate = 100
|
||||||
cfg.K9s.ReadOnly = true
|
cfg.K9s.ReadOnly = true
|
||||||
cfg.K9s.LogBufferSize = 500
|
cfg.K9s.LogBufferSize = 500
|
||||||
|
|
@ -233,7 +233,7 @@ func TestConfigReset(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
cfg.SetConnection(mc)
|
cfg.SetConnection(mc)
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
cfg.Reset()
|
cfg.Reset()
|
||||||
cfg.Validate()
|
cfg.Validate()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
func TestHotKeyLoad(t *testing.T) {
|
func TestHotKeyLoad(t *testing.T) {
|
||||||
h := config.NewHotKeys()
|
h := config.NewHotKeys()
|
||||||
assert.Nil(t, h.LoadHotKeys("test_assets/hot_key.yml"))
|
assert.Nil(t, h.LoadHotKeys("testdata/hot_key.yml"))
|
||||||
|
|
||||||
assert.Equal(t, 1, len(h.HotKey))
|
assert.Equal(t, 1, len(h.HotKey))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ func TestK9sActiveClusterBlank(t *testing.T) {
|
||||||
func TestK9sActiveCluster(t *testing.T) {
|
func TestK9sActiveCluster(t *testing.T) {
|
||||||
mk := NewMockKubeSettings()
|
mk := NewMockKubeSettings()
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
|
||||||
|
|
||||||
cl := cfg.K9s.ActiveCluster()
|
cl := cfg.K9s.ActiveCluster()
|
||||||
assert.NotNil(t, cl)
|
assert.NotNil(t, cl)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
func TestPluginLoad(t *testing.T) {
|
func TestPluginLoad(t *testing.T) {
|
||||||
p := config.NewPlugins()
|
p := config.NewPlugins()
|
||||||
assert.Nil(t, p.LoadPlugins("test_assets/plugin.yml"))
|
assert.Nil(t, p.LoadPlugins("testdata/plugin.yml"))
|
||||||
|
|
||||||
assert.Equal(t, 1, len(p.Plugin))
|
assert.Equal(t, 1, len(p.Plugin))
|
||||||
k, ok := p.Plugin["blah"]
|
k, ok := p.Plugin["blah"]
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func TestAsColor(t *testing.T) {
|
||||||
|
|
||||||
func TestSkinNone(t *testing.T) {
|
func TestSkinNone(t *testing.T) {
|
||||||
s := config.NewStyles()
|
s := config.NewStyles()
|
||||||
assert.Nil(t, s.Load("test_assets/empty_skin.yml"))
|
assert.Nil(t, s.Load("testdata/empty_skin.yml"))
|
||||||
s.Update()
|
s.Update()
|
||||||
|
|
||||||
assert.Equal(t, "cadetblue", s.Body().FgColor)
|
assert.Equal(t, "cadetblue", s.Body().FgColor)
|
||||||
|
|
@ -40,7 +40,7 @@ func TestSkinNone(t *testing.T) {
|
||||||
|
|
||||||
func TestSkin(t *testing.T) {
|
func TestSkin(t *testing.T) {
|
||||||
s := config.NewStyles()
|
s := config.NewStyles()
|
||||||
assert.Nil(t, s.Load("test_assets/black_and_wtf.yml"))
|
assert.Nil(t, s.Load("testdata/black_and_wtf.yml"))
|
||||||
s.Update()
|
s.Update()
|
||||||
|
|
||||||
assert.Equal(t, "white", s.Body().FgColor)
|
assert.Equal(t, "white", s.Body().FgColor)
|
||||||
|
|
@ -53,10 +53,10 @@ func TestSkin(t *testing.T) {
|
||||||
|
|
||||||
func TestSkinNotExits(t *testing.T) {
|
func TestSkinNotExits(t *testing.T) {
|
||||||
s := config.NewStyles()
|
s := config.NewStyles()
|
||||||
assert.NotNil(t, s.Load("test_assets/blee.yml"))
|
assert.NotNil(t, s.Load("testdata/blee.yml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSkinBoarked(t *testing.T) {
|
func TestSkinBoarked(t *testing.T) {
|
||||||
s := config.NewStyles()
|
s := config.NewStyles()
|
||||||
assert.NotNil(t, s.Load("test_assets/skin_boarked.yml"))
|
assert.NotNil(t, s.Load("testdata/skin_boarked.yml"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@ func TestBenchmarkList(t *testing.T) {
|
||||||
a := dao.Benchmark{}
|
a := dao.Benchmark{}
|
||||||
a.Init(makeFactory(), client.NewGVR("benchmarks"))
|
a.Init(makeFactory(), client.NewGVR("benchmarks"))
|
||||||
|
|
||||||
ctx := context.WithValue(context.Background(), internal.KeyDir, "test_assets/bench")
|
ctx := context.WithValue(context.Background(), internal.KeyDir, "testdata/bench")
|
||||||
oo, err := a.List(ctx, "-")
|
oo, err := a.List(ctx, "-")
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(oo))
|
assert.Equal(t, 1, len(oo))
|
||||||
assert.Equal(t, "test_assets/bench/default_fred_1577308050814961000.txt", oo[0].(render.BenchInfo).Path)
|
assert.Equal(t, "testdata/bench/default_fred_1577308050814961000.txt", oo[0].(render.BenchInfo).Path)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ func TestCruiserSlice(t *testing.T) {
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
func loadJSON(t assert.TestingT, n string) *unstructured.Unstructured {
|
func loadJSON(t assert.TestingT, n string) *unstructured.Unstructured {
|
||||||
raw, err := ioutil.ReadFile(fmt.Sprintf("test_assets/%s.json", n))
|
raw, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.json", n))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var o unstructured.Unstructured
|
var o unstructured.Unstructured
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ var (
|
||||||
_ Loggable = (*Deployment)(nil)
|
_ Loggable = (*Deployment)(nil)
|
||||||
_ Restartable = (*Deployment)(nil)
|
_ Restartable = (*Deployment)(nil)
|
||||||
_ Scalable = (*Deployment)(nil)
|
_ Scalable = (*Deployment)(nil)
|
||||||
|
_ Controller = (*Deployment)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Deployment represents a deployment K8s resource.
|
// Deployment represents a deployment K8s resource.
|
||||||
|
|
@ -51,12 +52,7 @@ func (d *Deployment) Scale(path string, replicas int32) error {
|
||||||
|
|
||||||
// Restart a Deployment rollout.
|
// Restart a Deployment rollout.
|
||||||
func (d *Deployment) Restart(path string) error {
|
func (d *Deployment) Restart(path string) error {
|
||||||
o, err := d.Factory.Get(d.gvr.String(), path, true, labels.Everything())
|
dp, err := d.GetInstance(path)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var ds appsv1.Deployment
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &ds)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -69,30 +65,50 @@ func (d *Deployment) Restart(path string) error {
|
||||||
if !auth {
|
if !auth {
|
||||||
return fmt.Errorf("user is not authorized to restart a deployment")
|
return fmt.Errorf("user is not authorized to restart a deployment")
|
||||||
}
|
}
|
||||||
update, err := polymorphichelpers.ObjectRestarterFn(&ds)
|
update, err := polymorphichelpers.ObjectRestarterFn(dp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = d.Client().DialOrDie().AppsV1().Deployments(ds.Namespace).Patch(ds.Name, types.StrategicMergePatchType, update)
|
|
||||||
|
|
||||||
|
_, err = d.Client().DialOrDie().AppsV1().Deployments(dp.Namespace).Patch(dp.Name, types.StrategicMergePatchType, update)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailLogs tail logs for all pods represented by this Deployment.
|
// TailLogs tail logs for all pods represented by this Deployment.
|
||||||
func (d *Deployment) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
func (d *Deployment) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
||||||
o, err := d.Factory.Get(d.gvr.String(), opts.Path, true, labels.Everything())
|
dp, err := d.GetInstance(opts.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var dp appsv1.Deployment
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &dp)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("expecting Deployment resource")
|
|
||||||
}
|
|
||||||
if dp.Spec.Selector == nil || len(dp.Spec.Selector.MatchLabels) == 0 {
|
if dp.Spec.Selector == nil || len(dp.Spec.Selector.MatchLabels) == 0 {
|
||||||
return fmt.Errorf("No valid selector found on Deployment %s", opts.Path)
|
return fmt.Errorf("No valid selector found on Deployment %s", opts.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return podLogs(ctx, c, dp.Spec.Selector.MatchLabels, opts)
|
return podLogs(ctx, c, dp.Spec.Selector.MatchLabels, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pod returns a pod victim by name.
|
||||||
|
func (d *Deployment) Pod(fqn string) (string, error) {
|
||||||
|
dp, err := d.GetInstance(fqn)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return podFromSelector(d.Factory, dp.Namespace, dp.Spec.Selector.MatchLabels)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstance returns a deployment instance.
|
||||||
|
func (d *Deployment) GetInstance(fqn string) (*appsv1.Deployment, error) {
|
||||||
|
o, err := d.Factory.Get(d.gvr.String(), fqn, false, labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var dp appsv1.Deployment
|
||||||
|
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &dp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("expecting Deployment resource")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dp, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,10 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal"
|
"github.com/derailed/k9s/internal"
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/watch"
|
"github.com/derailed/k9s/internal/watch"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
@ -26,6 +24,7 @@ var (
|
||||||
_ Nuker = (*DaemonSet)(nil)
|
_ Nuker = (*DaemonSet)(nil)
|
||||||
_ Loggable = (*DaemonSet)(nil)
|
_ Loggable = (*DaemonSet)(nil)
|
||||||
_ Restartable = (*DaemonSet)(nil)
|
_ Restartable = (*DaemonSet)(nil)
|
||||||
|
_ Controller = (*DaemonSet)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// DaemonSet represents a K8s daemonset.
|
// DaemonSet represents a K8s daemonset.
|
||||||
|
|
@ -35,12 +34,7 @@ type DaemonSet struct {
|
||||||
|
|
||||||
// Restart a DaemonSet rollout.
|
// Restart a DaemonSet rollout.
|
||||||
func (d *DaemonSet) Restart(path string) error {
|
func (d *DaemonSet) Restart(path string) error {
|
||||||
o, err := d.Factory.Get(d.gvr.String(), path, true, labels.Everything())
|
ds, err := d.GetInstance(path)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var ds appsv1.DaemonSet
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &ds)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -52,26 +46,21 @@ func (d *DaemonSet) Restart(path string) error {
|
||||||
if !auth {
|
if !auth {
|
||||||
return fmt.Errorf("user is not authorized to restart a daemonset")
|
return fmt.Errorf("user is not authorized to restart a daemonset")
|
||||||
}
|
}
|
||||||
update, err := polymorphichelpers.ObjectRestarterFn(&ds)
|
update, err := polymorphichelpers.ObjectRestarterFn(ds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = d.Client().DialOrDie().AppsV1().DaemonSets(ds.Namespace).Patch(ds.Name, types.StrategicMergePatchType, update)
|
|
||||||
|
|
||||||
|
_, err = d.Client().DialOrDie().AppsV1().DaemonSets(ds.Namespace).Patch(ds.Name, types.StrategicMergePatchType, update)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailLogs tail logs for all pods represented by this DaemonSet.
|
// TailLogs tail logs for all pods represented by this DaemonSet.
|
||||||
func (d *DaemonSet) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
func (d *DaemonSet) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
||||||
o, err := d.Factory.Get(d.gvr.String(), opts.Path, true, labels.Everything())
|
ds, err := d.GetInstance(opts.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var ds appsv1.DaemonSet
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &ds)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("expecting daemonset resource")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ds.Spec.Selector == nil || len(ds.Spec.Selector.MatchLabels) == 0 {
|
if ds.Spec.Selector == nil || len(ds.Spec.Selector.MatchLabels) == 0 {
|
||||||
return fmt.Errorf("no valid selector found on daemonset %q", opts.Path)
|
return fmt.Errorf("no valid selector found on daemonset %q", opts.Path)
|
||||||
|
|
@ -81,10 +70,6 @@ func (d *DaemonSet) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptio
|
||||||
}
|
}
|
||||||
|
|
||||||
func podLogs(ctx context.Context, c chan<- []byte, sel map[string]string, opts LogOptions) error {
|
func podLogs(ctx context.Context, c chan<- []byte, sel map[string]string, opts LogOptions) error {
|
||||||
defer func(t time.Time) {
|
|
||||||
log.Debug().Msgf("POD LOGS %v", time.Since(t))
|
|
||||||
}(time.Now())
|
|
||||||
|
|
||||||
f, ok := ctx.Value(internal.KeyFactory).(*watch.Factory)
|
f, ok := ctx.Value(internal.KeyFactory).(*watch.Factory)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("expecting a context factory")
|
return errors.New("expecting a context factory")
|
||||||
|
|
@ -116,7 +101,6 @@ func podLogs(ctx context.Context, c chan<- []byte, sel map[string]string, opts L
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debug().Msgf("TAILING logs on pod %q", pod.Name)
|
|
||||||
opts.Path = client.FQN(pod.Namespace, pod.Name)
|
opts.Path = client.FQN(pod.Namespace, pod.Name)
|
||||||
if err := po.TailLogs(ctx, c, opts); err != nil {
|
if err := po.TailLogs(ctx, c, opts); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -125,6 +109,32 @@ func podLogs(ctx context.Context, c chan<- []byte, sel map[string]string, opts L
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pod returns a pod victim by name.
|
||||||
|
func (d *DaemonSet) Pod(fqn string) (string, error) {
|
||||||
|
ds, err := d.GetInstance(fqn)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return podFromSelector(d.Factory, ds.Namespace, ds.Spec.Selector.MatchLabels)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstance returns a daemonset instance.
|
||||||
|
func (d *DaemonSet) GetInstance(fqn string) (*appsv1.DaemonSet, error) {
|
||||||
|
o, err := d.Factory.Get(d.gvr.String(), fqn, false, labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ds appsv1.DaemonSet
|
||||||
|
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &ds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("expecting DaemonSet resource")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ds, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,10 @@ import (
|
||||||
const defaultTimeout = 1 * time.Second
|
const defaultTimeout = 1 * time.Second
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ Accessor = (*Pod)(nil)
|
_ Accessor = (*Pod)(nil)
|
||||||
_ Nuker = (*Pod)(nil)
|
_ Nuker = (*Pod)(nil)
|
||||||
_ Loggable = (*Pod)(nil)
|
_ Loggable = (*Pod)(nil)
|
||||||
|
_ Controller = (*Pod)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pod represents a pod resource.
|
// Pod represents a pod resource.
|
||||||
|
|
@ -122,13 +123,7 @@ func (p *Pod) Logs(path string, opts *v1.PodLogOptions) (*restclient.Request, er
|
||||||
|
|
||||||
// Containers returns all container names on pod
|
// Containers returns all container names on pod
|
||||||
func (p *Pod) Containers(path string, includeInit bool) ([]string, error) {
|
func (p *Pod) Containers(path string, includeInit bool) ([]string, error) {
|
||||||
o, err := p.Factory.Get(p.gvr.String(), path, true, labels.Everything())
|
pod, err := p.GetInstance(path)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var pod v1.Pod
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &pod)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -147,6 +142,27 @@ func (p *Pod) Containers(path string, includeInit bool) ([]string, error) {
|
||||||
return cc, nil
|
return cc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pod returns a pod victim by name.
|
||||||
|
func (p *Pod) Pod(fqn string) (string, error) {
|
||||||
|
return fqn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstance returns a pod instance.
|
||||||
|
func (p *Pod) GetInstance(fqn string) (*v1.Pod, error) {
|
||||||
|
o, err := p.Factory.Get(p.gvr.String(), fqn, false, labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pod v1.Pod
|
||||||
|
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &pod)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pod, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TailLogs tails a given container logs
|
// TailLogs tails a given container logs
|
||||||
func (p *Pod) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
func (p *Pod) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
||||||
if !opts.HasContainer() {
|
if !opts.HasContainer() {
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,14 @@ package dao
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal"
|
"github.com/derailed/k9s/internal"
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/config"
|
"github.com/derailed/k9s/internal/config"
|
||||||
"github.com/derailed/k9s/internal/render"
|
"github.com/derailed/k9s/internal/render"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,21 +42,26 @@ func (p *PortForward) Delete(path string, cascade, force bool) error {
|
||||||
|
|
||||||
// List returns a collection of screen dumps.
|
// List returns a collection of screen dumps.
|
||||||
func (p *PortForward) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
func (p *PortForward) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||||
config, ok := ctx.Value(internal.KeyBenchCfg).(*config.Bench)
|
benchFile, ok := ctx.Value(internal.KeyBenchCfg).(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("no benchconfig found in context")
|
return nil, fmt.Errorf("no bench file found in context")
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := config.NewBench(benchFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug().Msgf("No custom benchmark config file found")
|
||||||
}
|
}
|
||||||
|
|
||||||
cc := config.Benchmarks.Containers
|
cc := config.Benchmarks.Containers
|
||||||
oo := make([]runtime.Object, 0, len(p.Factory.Forwarders()))
|
oo := make([]runtime.Object, 0, len(p.Factory.Forwarders()))
|
||||||
for _, f := range p.Factory.Forwarders() {
|
for k, f := range p.Factory.Forwarders() {
|
||||||
cfg := render.BenchCfg{
|
cfg := render.BenchCfg{
|
||||||
C: config.Benchmarks.Defaults.C,
|
C: config.Benchmarks.Defaults.C,
|
||||||
N: config.Benchmarks.Defaults.N,
|
N: config.Benchmarks.Defaults.N,
|
||||||
}
|
}
|
||||||
if config, ok := cc[containerID(f.Path(), f.Container())]; ok {
|
if cust, ok := cc[PodToKey(k)]; ok {
|
||||||
cfg.C, cfg.N = config.C, config.N
|
cfg.C, cfg.N = cust.C, cust.N
|
||||||
cfg.Host, cfg.Path = config.HTTP.Host, config.HTTP.Path
|
cfg.Host, cfg.Path = cust.HTTP.Host, cust.HTTP.Path
|
||||||
}
|
}
|
||||||
oo = append(oo, render.ForwardRes{
|
oo = append(oo, render.ForwardRes{
|
||||||
Forwarder: f,
|
Forwarder: f,
|
||||||
|
|
@ -68,10 +75,31 @@ func (p *PortForward) List(ctx context.Context, _ string) ([]runtime.Object, err
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
// ContainerID computes container ID based on ns/po/co.
|
var podNameRX = regexp.MustCompile(`\A(.+)\-(\w{10})\-(\w{5})\z`)
|
||||||
func containerID(path, co string) string {
|
|
||||||
ns, n := client.Namespaced(path)
|
|
||||||
po := strings.Split(n, "-")[0]
|
|
||||||
|
|
||||||
return ns + "/" + po + ":" + co
|
// PodToKey converts a pod path to a generic bench config key
|
||||||
|
func PodToKey(path string) string {
|
||||||
|
tokens := strings.Split(path, ":")
|
||||||
|
ns, po := client.Namespaced(tokens[0])
|
||||||
|
sections := podNameRX.FindStringSubmatch(po)
|
||||||
|
if len(sections) >= 1 {
|
||||||
|
po = sections[1]
|
||||||
|
}
|
||||||
|
return client.FQN(ns, po) + ":" + tokens[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// BenchConfigFor returns a custom bench spec if defined otherwise returns the default one.
|
||||||
|
func BenchConfigFor(benchFile, path string) config.BenchConfig {
|
||||||
|
def := config.DefaultBenchSpec()
|
||||||
|
cust, err := config.NewBench(benchFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug().Msgf("No custom benchmark config file found")
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
if b, ok := cust.Benchmarks.Containers[PodToKey(path)]; ok {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
def.C, def.N = cust.Benchmarks.Defaults.C, cust.Benchmarks.Defaults.N
|
||||||
|
return def
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package dao_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/derailed/k9s/internal/config"
|
||||||
|
"github.com/derailed/k9s/internal/dao"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBenchForConfig(t *testing.T) {
|
||||||
|
uu := map[string]struct {
|
||||||
|
file, key string
|
||||||
|
spec config.BenchConfig
|
||||||
|
}{
|
||||||
|
"no_file": {file: "", key: "", spec: config.DefaultBenchSpec()},
|
||||||
|
"spec": {file: "testdata/benchspec.yml", key: "default/nginx-123-456:nginx", spec: config.BenchConfig{
|
||||||
|
C: 2,
|
||||||
|
N: 3000,
|
||||||
|
HTTP: config.HTTP{
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range uu {
|
||||||
|
u := uu[k]
|
||||||
|
t.Run(k, func(t *testing.T) {
|
||||||
|
assert.NotNil(t, u.spec, dao.BenchConfigFor(u.file, u.key))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,14 +23,9 @@ import (
|
||||||
|
|
||||||
const localhost = "localhost"
|
const localhost = "localhost"
|
||||||
|
|
||||||
// Tunnel represents a host tunnel port mapper.
|
|
||||||
type Tunnel struct {
|
|
||||||
Address, LocalPort, ContainerPort string
|
|
||||||
}
|
|
||||||
|
|
||||||
// PortForwarder tracks a port forward stream.
|
// PortForwarder tracks a port forward stream.
|
||||||
type PortForwarder struct {
|
type PortForwarder struct {
|
||||||
client.Connection
|
Factory
|
||||||
genericclioptions.IOStreams
|
genericclioptions.IOStreams
|
||||||
|
|
||||||
stopChan, readyChan chan struct{}
|
stopChan, readyChan chan struct{}
|
||||||
|
|
@ -42,11 +37,11 @@ type PortForwarder struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPortForwarder returns a new port forward streamer.
|
// NewPortForwarder returns a new port forward streamer.
|
||||||
func NewPortForwarder(c client.Connection) *PortForwarder {
|
func NewPortForwarder(f Factory) *PortForwarder {
|
||||||
return &PortForwarder{
|
return &PortForwarder{
|
||||||
Connection: c,
|
Factory: f,
|
||||||
stopChan: make(chan struct{}),
|
stopChan: make(chan struct{}),
|
||||||
readyChan: make(chan struct{}),
|
readyChan: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +67,12 @@ func (p *PortForwarder) Ports() []string {
|
||||||
|
|
||||||
// Path returns the pod resource path.
|
// Path returns the pod resource path.
|
||||||
func (p *PortForwarder) Path() string {
|
func (p *PortForwarder) Path() string {
|
||||||
return p.path + ":" + p.container
|
return PortForwardID(p.path, p.container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortForwardID computes port-forward identifier.
|
||||||
|
func PortForwardID(path, co string) string {
|
||||||
|
return path + ":" + co
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container returns the targetes container.
|
// Container returns the targetes container.
|
||||||
|
|
@ -92,13 +92,23 @@ func (p *PortForwarder) FQN() string {
|
||||||
return p.path + ":" + p.container
|
return p.path + ":" + p.container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasPortMapping checks if port mapping is defined for this fwd.
|
||||||
|
func (p *PortForwarder) HasPortMapping(m string) bool {
|
||||||
|
for _, mapping := range p.ports {
|
||||||
|
if mapping == m {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Start initiates a port forward session for a given pod and ports.
|
// Start initiates a port forward session for a given pod and ports.
|
||||||
func (p *PortForwarder) Start(path, co string, t Tunnel) (*portforward.PortForwarder, error) {
|
func (p *PortForwarder) Start(path, co string, t client.PortTunnel) (*portforward.PortForwarder, error) {
|
||||||
fwds := []string{t.LocalPort + ":" + t.ContainerPort}
|
fwds := []string{t.PortMap()}
|
||||||
p.path, p.container, p.ports, p.age = path, co, fwds, time.Now()
|
p.path, p.container, p.ports, p.age = path, co, fwds, time.Now()
|
||||||
|
|
||||||
ns, n := client.Namespaced(path)
|
ns, n := client.Namespaced(path)
|
||||||
auth, err := p.CanI(ns, "v1/pods", []string{client.GetVerb})
|
auth, err := p.Client().CanI(ns, "v1/pods", []string{client.GetVerb})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -106,8 +116,9 @@ func (p *PortForwarder) Start(path, co string, t Tunnel) (*portforward.PortForwa
|
||||||
return nil, fmt.Errorf("user is not authorized to get pods")
|
return nil, fmt.Errorf("user is not authorized to get pods")
|
||||||
}
|
}
|
||||||
|
|
||||||
// BOZO!! Use the factory!
|
var res Pod
|
||||||
pod, err := p.DialOrDie().CoreV1().Pods(ns).Get(n, metav1.GetOptions{})
|
res.Init(p, client.NewGVR("v1/pods"))
|
||||||
|
pod, err := res.GetInstance(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +126,7 @@ func (p *PortForwarder) Start(path, co string, t Tunnel) (*portforward.PortForwa
|
||||||
return nil, fmt.Errorf("unable to forward port because pod is not running. Current status=%v", pod.Status.Phase)
|
return nil, fmt.Errorf("unable to forward port because pod is not running. Current status=%v", pod.Status.Phase)
|
||||||
}
|
}
|
||||||
|
|
||||||
auth, err = p.CanI(ns, "v1/pods:portforward", []string{client.UpdateVerb})
|
auth, err = p.Client().CanI(ns, "v1/pods:portforward", []string{client.UpdateVerb})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +134,7 @@ func (p *PortForwarder) Start(path, co string, t Tunnel) (*portforward.PortForwa
|
||||||
return nil, fmt.Errorf("user is not authorized to update portforward")
|
return nil, fmt.Errorf("user is not authorized to update portforward")
|
||||||
}
|
}
|
||||||
|
|
||||||
rcfg := p.RestConfigOrDie()
|
rcfg := p.Client().RestConfigOrDie()
|
||||||
rcfg.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"}
|
rcfg.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"}
|
||||||
rcfg.APIPath = "/api"
|
rcfg.APIPath = "/api"
|
||||||
codec, _ := codec()
|
codec, _ := codec()
|
||||||
|
|
@ -143,7 +154,7 @@ func (p *PortForwarder) Start(path, co string, t Tunnel) (*portforward.PortForwa
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PortForwarder) forwardPorts(method string, url *url.URL, address string, ports []string) (*portforward.PortForwarder, error) {
|
func (p *PortForwarder) forwardPorts(method string, url *url.URL, address string, ports []string) (*portforward.PortForwarder, error) {
|
||||||
cfg, err := p.Config().RESTConfig()
|
cfg, err := p.Client().Config().RESTConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ func TestExtractString(t *testing.T) {
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
func load(t *testing.T, n string) *unstructured.Unstructured {
|
func load(t *testing.T, n string) *unstructured.Unstructured {
|
||||||
raw, err := ioutil.ReadFile(fmt.Sprintf("assets/%s.json", n))
|
raw, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.json", n))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var o unstructured.Unstructured
|
var o unstructured.Unstructured
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ var (
|
||||||
_ Loggable = (*StatefulSet)(nil)
|
_ Loggable = (*StatefulSet)(nil)
|
||||||
_ Restartable = (*StatefulSet)(nil)
|
_ Restartable = (*StatefulSet)(nil)
|
||||||
_ Scalable = (*StatefulSet)(nil)
|
_ Scalable = (*StatefulSet)(nil)
|
||||||
|
_ Controller = (*StatefulSet)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// StatefulSet represents a K8s sts.
|
// StatefulSet represents a K8s sts.
|
||||||
|
|
@ -51,12 +52,7 @@ func (s *StatefulSet) Scale(path string, replicas int32) error {
|
||||||
|
|
||||||
// Restart a StatefulSet rollout.
|
// Restart a StatefulSet rollout.
|
||||||
func (s *StatefulSet) Restart(path string) error {
|
func (s *StatefulSet) Restart(path string) error {
|
||||||
o, err := s.Factory.Get(s.gvr.String(), path, true, labels.Everything())
|
sts, err := s.getStatefulSet(path)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var ds appsv1.StatefulSet
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &ds)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -70,24 +66,18 @@ func (s *StatefulSet) Restart(path string) error {
|
||||||
return fmt.Errorf("user is not authorized to update statefulsets")
|
return fmt.Errorf("user is not authorized to update statefulsets")
|
||||||
}
|
}
|
||||||
|
|
||||||
update, err := polymorphichelpers.ObjectRestarterFn(&ds)
|
update, err := polymorphichelpers.ObjectRestarterFn(sts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = s.Client().DialOrDie().AppsV1().StatefulSets(ds.Namespace).Patch(ds.Name, types.StrategicMergePatchType, update)
|
|
||||||
|
|
||||||
|
_, err = s.Client().DialOrDie().AppsV1().StatefulSets(sts.Namespace).Patch(sts.Name, types.StrategicMergePatchType, update)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailLogs tail logs for all pods represented by this StatefulSet.
|
// TailLogs tail logs for all pods represented by this StatefulSet.
|
||||||
func (s *StatefulSet) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
func (s *StatefulSet) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
||||||
o, err := s.Factory.Get(s.gvr.String(), opts.Path, true, labels.Everything())
|
sts, err := s.getStatefulSet(opts.Path)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var sts appsv1.StatefulSet
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &sts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("expecting StatefulSet resource")
|
return errors.New("expecting StatefulSet resource")
|
||||||
}
|
}
|
||||||
|
|
@ -97,3 +87,28 @@ func (s *StatefulSet) TailLogs(ctx context.Context, c chan<- []byte, opts LogOpt
|
||||||
|
|
||||||
return podLogs(ctx, c, sts.Spec.Selector.MatchLabels, opts)
|
return podLogs(ctx, c, sts.Spec.Selector.MatchLabels, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pod returns a pod victim by name.
|
||||||
|
func (s *StatefulSet) Pod(fqn string) (string, error) {
|
||||||
|
sts, err := s.getStatefulSet(fqn)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return podFromSelector(s.Factory, sts.Namespace, sts.Spec.Selector.MatchLabels)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StatefulSet) getStatefulSet(fqn string) (*appsv1.StatefulSet, error) {
|
||||||
|
o, err := s.Factory.Get(s.gvr.String(), fqn, false, labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var sts appsv1.StatefulSet
|
||||||
|
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &sts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("expecting Service resource")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &sts, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/derailed/k9s/internal/client"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
|
@ -12,8 +13,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ Accessor = (*Service)(nil)
|
_ Accessor = (*Service)(nil)
|
||||||
_ Loggable = (*Service)(nil)
|
_ Loggable = (*Service)(nil)
|
||||||
|
_ Controller = (*Service)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Service represents a k8s service.
|
// Service represents a k8s service.
|
||||||
|
|
@ -23,19 +25,61 @@ type Service struct {
|
||||||
|
|
||||||
// TailLogs tail logs for all pods represented by this Service.
|
// TailLogs tail logs for all pods represented by this Service.
|
||||||
func (s *Service) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
func (s *Service) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
||||||
o, err := s.Factory.Get(s.gvr.String(), opts.Path, true, labels.Everything())
|
svc, err := s.GetInstance(opts.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var svc v1.Service
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &svc)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("expecting Service resource")
|
|
||||||
}
|
|
||||||
|
|
||||||
if svc.Spec.Selector == nil || len(svc.Spec.Selector) == 0 {
|
if svc.Spec.Selector == nil || len(svc.Spec.Selector) == 0 {
|
||||||
return fmt.Errorf("no valid selector found on Service %s", opts.Path)
|
return fmt.Errorf("no valid selector found on Service %s", opts.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return podLogs(ctx, c, svc.Spec.Selector, opts)
|
return podLogs(ctx, c, svc.Spec.Selector, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pod returns a pod victim by name.
|
||||||
|
func (s *Service) Pod(fqn string) (string, error) {
|
||||||
|
svc, err := s.GetInstance(fqn)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return podFromSelector(s.Factory, svc.Namespace, svc.Spec.Selector)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstance returns a service instance.
|
||||||
|
func (s *Service) GetInstance(fqn string) (*v1.Service, error) {
|
||||||
|
o, err := s.Factory.Get(s.gvr.String(), fqn, false, labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var svc v1.Service
|
||||||
|
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &svc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("expecting Service resource")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &svc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Helpers...
|
||||||
|
|
||||||
|
func podFromSelector(f Factory, ns string, sel map[string]string) (string, error) {
|
||||||
|
oo, err := f.List("v1/pods", ns, true, labels.Set(sel).AsSelector())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(oo) == 0 {
|
||||||
|
return "", fmt.Errorf("no matching pods for %v", sel)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pod v1.Pod
|
||||||
|
err = runtime.DefaultUnstructuredConverter.FromUnstructured(oo[0].(*unstructured.Unstructured).Object, &pod)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.FQN(pod.Namespace, pod.Name), nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
benchmarks:
|
||||||
|
defaults:
|
||||||
|
concurrency: 2
|
||||||
|
requests: 500
|
||||||
|
containers:
|
||||||
|
default/nginx:nginx:
|
||||||
|
concurrency: 2
|
||||||
|
requests: 3000
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
path: /
|
||||||
|
services:
|
||||||
|
default/nginx:
|
||||||
|
concurrency: 1
|
||||||
|
requests: 666
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
host: 192.168.64.1
|
||||||
|
path: /
|
||||||
|
|
@ -91,6 +91,12 @@ type Scalable interface {
|
||||||
Scale(path string, replicas int32) error
|
Scale(path string, replicas int32) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Controller represents a pod controller.
|
||||||
|
type Controller interface {
|
||||||
|
// Pod returns a pod instance matching the selector.
|
||||||
|
Pod(path string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
// Nuker represents a resource deleter.
|
// Nuker represents a resource deleter.
|
||||||
type Nuker interface {
|
type Nuker interface {
|
||||||
// Delete removes a resource from the api server.
|
// Delete removes a resource from the api server.
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,6 @@ func TestTableMeta(t *testing.T) {
|
||||||
accessor dao.Accessor
|
accessor dao.Accessor
|
||||||
renderer Renderer
|
renderer Renderer
|
||||||
}{
|
}{
|
||||||
// BOZO!!
|
|
||||||
// "full": {
|
|
||||||
// gvr: "v1/pods",
|
|
||||||
// accessor: &pd,
|
|
||||||
// renderer: &render.Pod{},
|
|
||||||
// },
|
|
||||||
"generic": {
|
"generic": {
|
||||||
gvr: "containers",
|
gvr: "containers",
|
||||||
accessor: &dao.Container{},
|
accessor: &dao.Container{},
|
||||||
|
|
@ -144,7 +138,7 @@ func TestTableGenericHydrate(t *testing.T) {
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
func mustLoad(n string) *unstructured.Unstructured {
|
func mustLoad(n string) *unstructured.Unstructured {
|
||||||
raw, err := ioutil.ReadFile(fmt.Sprintf("test_assets/%s.json", n))
|
raw, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.json", n))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +150,7 @@ func mustLoad(n string) *unstructured.Unstructured {
|
||||||
}
|
}
|
||||||
|
|
||||||
func load(t *testing.T, n string) *unstructured.Unstructured {
|
func load(t *testing.T, n string) *unstructured.Unstructured {
|
||||||
raw, err := ioutil.ReadFile(fmt.Sprintf("test_assets/%s.json", n))
|
raw, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.json", n))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
var o unstructured.Unstructured
|
var o unstructured.Unstructured
|
||||||
err = json.Unmarshal(raw, &o)
|
err = json.Unmarshal(raw, &o)
|
||||||
|
|
@ -165,7 +159,7 @@ func load(t *testing.T, n string) *unstructured.Unstructured {
|
||||||
}
|
}
|
||||||
|
|
||||||
func raw(t *testing.T, n string) []byte {
|
func raw(t *testing.T, n string) []byte {
|
||||||
raw, err := ioutil.ReadFile(fmt.Sprintf("test_assets/%s.json", n))
|
raw, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.json", n))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
return raw
|
return raw
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ func makeTableFactory() tableFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustLoad(n string) *unstructured.Unstructured {
|
func mustLoad(n string) *unstructured.Unstructured {
|
||||||
raw, err := ioutil.ReadFile(fmt.Sprintf("test_assets/%s.json", n))
|
raw, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.json", n))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,19 +18,19 @@ func TestAugmentRow(t *testing.T) {
|
||||||
e Fields
|
e Fields
|
||||||
}{
|
}{
|
||||||
"cool": {
|
"cool": {
|
||||||
"assets/b1.txt",
|
"testdata/b1.txt",
|
||||||
Fields{"pass", "3.3544", "29.8116", "100", "0"},
|
Fields{"pass", "3.3544", "29.8116", "100", "0"},
|
||||||
},
|
},
|
||||||
"2XX": {
|
"2XX": {
|
||||||
"assets/b4.txt",
|
"testdata/b4.txt",
|
||||||
Fields{"pass", "3.3544", "29.8116", "160", "0"},
|
Fields{"pass", "3.3544", "29.8116", "160", "0"},
|
||||||
},
|
},
|
||||||
"4XX/5XX": {
|
"4XX/5XX": {
|
||||||
"assets/b2.txt",
|
"testdata/b2.txt",
|
||||||
Fields{"pass", "3.3544", "29.8116", "100", "12"},
|
Fields{"pass", "3.3544", "29.8116", "100", "12"},
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"assets/b3.txt",
|
"testdata/b3.txt",
|
||||||
Fields{"fail", "2.3688", "35.4606", "0", "0"},
|
Fields{"fail", "2.3688", "35.4606", "0", "0"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
func load(t assert.TestingT, n string) *unstructured.Unstructured {
|
func load(t assert.TestingT, n string) *unstructured.Unstructured {
|
||||||
raw, err := ioutil.ReadFile(fmt.Sprintf("assets/%s.json", n))
|
raw, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.json", n))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var o unstructured.Unstructured
|
var o unstructured.Unstructured
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ type synchronizer interface {
|
||||||
|
|
||||||
// Configurator represents an application configurationa.
|
// Configurator represents an application configurationa.
|
||||||
type Configurator struct {
|
type Configurator struct {
|
||||||
skinFile string
|
skinFile string
|
||||||
Config *config.Config
|
Config *config.Config
|
||||||
Styles *config.Styles
|
Styles *config.Styles
|
||||||
Bench *config.Bench
|
BenchFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasSkin returns true if a skin file was located.
|
// HasSkin returns true if a skin file was located.
|
||||||
|
|
@ -67,21 +67,15 @@ func (c *Configurator) StylesUpdater(ctx context.Context, s synchronizer) error
|
||||||
return w.Add(c.skinFile)
|
return w.Add(c.skinFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitBench load benchmark configuration if any.
|
|
||||||
func (c *Configurator) InitBench(cluster string) {
|
|
||||||
var err error
|
|
||||||
if c.Bench, err = config.NewBench(BenchConfig(cluster)); err != nil {
|
|
||||||
log.Info().Msg("No benchmark config file found, using defaults.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BenchConfig location of the benchmarks configuration file.
|
// BenchConfig location of the benchmarks configuration file.
|
||||||
func BenchConfig(cluster string) string {
|
func BenchConfig(context string) string {
|
||||||
return filepath.Join(config.K9sHome, config.K9sBench+"-"+cluster+".yml")
|
return filepath.Join(config.K9sHome, config.K9sBench+"-"+context+".yml")
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshStyles load for skin configuration changes.
|
// RefreshStyles load for skin configuration changes.
|
||||||
func (c *Configurator) RefreshStyles(context string) {
|
func (c *Configurator) RefreshStyles(context string) {
|
||||||
|
c.BenchFile = BenchConfig(context)
|
||||||
|
|
||||||
clusterSkins := filepath.Join(config.K9sHome, fmt.Sprintf("%s_skin.yml", context))
|
clusterSkins := filepath.Join(config.K9sHome, fmt.Sprintf("%s_skin.yml", context))
|
||||||
if c.Styles == nil {
|
if c.Styles == nil {
|
||||||
c.Styles = config.NewStyles()
|
c.Styles = config.NewStyles()
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ func TestBenchConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfiguratorRefreshStyle(t *testing.T) {
|
func TestConfiguratorRefreshStyle(t *testing.T) {
|
||||||
config.K9sStylesFile = filepath.Join("..", "config", "test_assets", "black_and_wtf.yml")
|
config.K9sStylesFile = filepath.Join("..", "config", "testdata", "black_and_wtf.yml")
|
||||||
|
|
||||||
cfg := ui.Configurator{}
|
cfg := ui.Configurator{}
|
||||||
cfg.RefreshStyles("")
|
cfg.RefreshStyles("")
|
||||||
|
|
@ -26,15 +26,3 @@ func TestConfiguratorRefreshStyle(t *testing.T) {
|
||||||
assert.Equal(t, tcell.ColorGhostWhite, render.StdColor)
|
assert.Equal(t, tcell.ColorGhostWhite, render.StdColor)
|
||||||
assert.Equal(t, tcell.ColorWhiteSmoke, render.ErrColor)
|
assert.Equal(t, tcell.ColorWhiteSmoke, render.ErrColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitBench(t *testing.T) {
|
|
||||||
config.K9sHome = filepath.Join("..", "config", "test_assets")
|
|
||||||
|
|
||||||
cfg := ui.Configurator{}
|
|
||||||
cfg.InitBench("fred")
|
|
||||||
|
|
||||||
assert.NotNil(t, cfg.Bench)
|
|
||||||
assert.Equal(t, 2, cfg.Bench.Benchmarks.Defaults.C)
|
|
||||||
assert.Equal(t, 1000, cfg.Bench.Benchmarks.Defaults.N)
|
|
||||||
assert.Equal(t, 2, len(cfg.Bench.Benchmarks.Services))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package dialog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/config"
|
|
||||||
"github.com/derailed/k9s/internal/dao"
|
|
||||||
"github.com/derailed/k9s/internal/ui"
|
|
||||||
"github.com/derailed/tview"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPortForwards(t *testing.T) {
|
|
||||||
p := ui.NewPages()
|
|
||||||
|
|
||||||
cbFunc := func(path, co string, t dao.Tunnel) {}
|
|
||||||
ShowPortForwards(p, config.NewStyles(), "fred", []string{"8080"}, cbFunc)
|
|
||||||
|
|
||||||
d := p.GetPrimitive(portForwardKey).(*tview.ModalForm)
|
|
||||||
assert.NotNil(t, d)
|
|
||||||
|
|
||||||
DismissPortForwards(p)
|
|
||||||
assert.Nil(t, p.GetPrimitive(portForwardKey))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractPort(t *testing.T) {
|
|
||||||
uu := map[string]struct {
|
|
||||||
port, e string
|
|
||||||
}{
|
|
||||||
"full": {
|
|
||||||
"fred:8000", "8000",
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"8000", "8000",
|
|
||||||
},
|
|
||||||
"protocol": {
|
|
||||||
"dns:53╱UDP", "53",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k := range uu {
|
|
||||||
u := uu[k]
|
|
||||||
t.Run(k, func(t *testing.T) {
|
|
||||||
assert.Equal(t, u.e, extractPort(u.port))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,7 +16,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
menuIndexFmt = " [key:-:b]<%d> [fg:-:d]%s "
|
menuIndexFmt = " [key:-:b]<%d> [fg:-:d]%s "
|
||||||
maxRows = 7
|
maxRows = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
var menuRX = regexp.MustCompile(`\d`)
|
var menuRX = regexp.MustCompile(`\d`)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExitStatus indicates UI exit conditions.
|
// // ExitStatus indicates UI exit conditions.
|
||||||
var ExitStatus = ""
|
var ExitStatus = ""
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -50,7 +50,6 @@ func NewApp(cfg *config.Config) *App {
|
||||||
Content: NewPageStack(),
|
Content: NewPageStack(),
|
||||||
}
|
}
|
||||||
a.Config = cfg
|
a.Config = cfg
|
||||||
a.InitBench(cfg.K9s.CurrentCluster)
|
|
||||||
|
|
||||||
a.Views()["statusIndicator"] = ui.NewStatusIndicator(a.App, a.Styles)
|
a.Views()["statusIndicator"] = ui.NewStatusIndicator(a.App, a.Styles)
|
||||||
a.Views()["clusterInfo"] = NewClusterInfo(&a)
|
a.Views()["clusterInfo"] = NewClusterInfo(&a)
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,6 @@ func (b *Browser) TableDataChanged(data render.TableData) {
|
||||||
b.app.QueueUpdateDraw(func() {
|
b.app.QueueUpdateDraw(func() {
|
||||||
b.refreshActions()
|
b.refreshActions()
|
||||||
b.Update(data)
|
b.Update(data)
|
||||||
b.App().ClearStatus(false)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/dao"
|
|
||||||
"github.com/derailed/k9s/internal/render"
|
"github.com/derailed/k9s/internal/render"
|
||||||
"github.com/derailed/k9s/internal/ui"
|
"github.com/derailed/k9s/internal/ui"
|
||||||
"github.com/derailed/k9s/internal/ui/dialog"
|
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"k8s.io/client-go/tools/portforward"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -114,23 +111,11 @@ func (c *Container) portFwdCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Debug().Msgf("CONTAINER-PORTS %#v", ports)
|
log.Debug().Msgf("CONTAINER-PORTS %#v", ports)
|
||||||
dialog.ShowPortForwards(c.App().Content.Pages, c.App().Styles, c.GetTable().Path, ports, c.portForward)
|
ShowPortForwards(c, c.GetTable().Path, ports, startFwdCB)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) portForward(path, co string, t dao.Tunnel) {
|
|
||||||
pf := dao.NewPortForwarder(c.App().Conn())
|
|
||||||
fw, err := pf.Start(path, co, t)
|
|
||||||
if err != nil {
|
|
||||||
c.App().Flash().Err(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug().Msgf(">>> Starting port forward %q %#v", path, t)
|
|
||||||
go runForward(c.App(), pf, fw)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) isForwardable(path string) ([]string, bool) {
|
func (c *Container) isForwardable(path string) ([]string, bool) {
|
||||||
state := c.GetTable().GetSelectedCell(3)
|
state := c.GetTable().GetSelectedCell(3)
|
||||||
if state != "Running" {
|
if state != "Running" {
|
||||||
|
|
@ -155,24 +140,3 @@ func (c *Container) isForwardable(path string) ([]string, bool) {
|
||||||
|
|
||||||
return pp, true
|
return pp, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Helpers...
|
|
||||||
|
|
||||||
func runForward(a *App, pf *dao.PortForwarder, f *portforward.PortForwarder) {
|
|
||||||
a.QueueUpdateDraw(func() {
|
|
||||||
a.factory.AddForwarder(pf)
|
|
||||||
a.Flash().Infof("PortForward activated %s:%s", pf.Path(), pf.Ports()[0])
|
|
||||||
dialog.DismissPortForwards(a.Content.Pages)
|
|
||||||
})
|
|
||||||
|
|
||||||
pf.SetActive(true)
|
|
||||||
if err := f.ForwardPorts(); err != nil {
|
|
||||||
a.Flash().Err(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
a.QueueUpdateDraw(func() {
|
|
||||||
a.factory.DeleteForwarder(pf.FQN())
|
|
||||||
pf.SetActive(false)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,10 @@ package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
|
"github.com/derailed/k9s/internal/dao"
|
||||||
"github.com/derailed/k9s/internal/render"
|
"github.com/derailed/k9s/internal/render"
|
||||||
"github.com/derailed/k9s/internal/ui"
|
"github.com/derailed/k9s/internal/ui"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const scaleDialogKey = "scale"
|
const scaleDialogKey = "scale"
|
||||||
|
|
@ -21,8 +18,15 @@ type Deploy struct {
|
||||||
// NewDeploy returns a new deployment view.
|
// NewDeploy returns a new deployment view.
|
||||||
func NewDeploy(gvr client.GVR) ResourceViewer {
|
func NewDeploy(gvr client.GVR) ResourceViewer {
|
||||||
d := Deploy{
|
d := Deploy{
|
||||||
ResourceViewer: NewRestartExtender(
|
ResourceViewer: NewPortForwardExtender(
|
||||||
NewScaleExtender(NewLogsExtender(NewBrowser(gvr), nil)),
|
NewRestartExtender(
|
||||||
|
NewScaleExtender(
|
||||||
|
NewLogsExtender(
|
||||||
|
NewBrowser(gvr),
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
d.SetBindKeysFn(d.bindKeys)
|
d.SetBindKeysFn(d.bindKeys)
|
||||||
|
|
@ -41,21 +45,19 @@ func (d *Deploy) bindKeys(aa ui.KeyActions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Deploy) showPods(app *App, model ui.Tabular, gvr, path string) {
|
func (d *Deploy) showPods(app *App, model ui.Tabular, gvr, path string) {
|
||||||
o, err := app.factory.Get(d.GVR(), path, true, labels.Everything())
|
var res dao.Deployment
|
||||||
|
res.Init(app.factory, client.NewGVR(d.GVR()))
|
||||||
|
|
||||||
|
dp, err := res.GetInstance(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.Flash().Err(err)
|
app.Flash().Err(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var dp appsv1.Deployment
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &dp)
|
|
||||||
if err != nil {
|
|
||||||
app.Flash().Err(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
showPodsFromSelector(app, path, dp.Spec.Selector)
|
showPodsFromSelector(app, path, dp.Spec.Selector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
func showPodsFromSelector(app *App, path string, sel *metav1.LabelSelector) {
|
func showPodsFromSelector(app *App, path string, sel *metav1.LabelSelector) {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,5 @@ func TestDeploy(t *testing.T) {
|
||||||
|
|
||||||
assert.Nil(t, v.Init(makeCtx()))
|
assert.Nil(t, v.Init(makeCtx()))
|
||||||
assert.Equal(t, "Deployments", v.Name())
|
assert.Equal(t, "Deployments", v.Name())
|
||||||
assert.Equal(t, 10, len(v.Hints()))
|
assert.Equal(t, 11, len(v.Hints()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,9 @@ package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
|
"github.com/derailed/k9s/internal/dao"
|
||||||
"github.com/derailed/k9s/internal/render"
|
"github.com/derailed/k9s/internal/render"
|
||||||
"github.com/derailed/k9s/internal/ui"
|
"github.com/derailed/k9s/internal/ui"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DaemonSet represents a daemon set custom viewer.
|
// DaemonSet represents a daemon set custom viewer.
|
||||||
|
|
@ -18,8 +15,10 @@ type DaemonSet struct {
|
||||||
// NewDaemonSet returns a new viewer.
|
// NewDaemonSet returns a new viewer.
|
||||||
func NewDaemonSet(gvr client.GVR) ResourceViewer {
|
func NewDaemonSet(gvr client.GVR) ResourceViewer {
|
||||||
d := DaemonSet{
|
d := DaemonSet{
|
||||||
ResourceViewer: NewRestartExtender(
|
ResourceViewer: NewPortForwardExtender(
|
||||||
NewLogsExtender(NewBrowser(gvr), nil),
|
NewRestartExtender(
|
||||||
|
NewLogsExtender(NewBrowser(gvr), nil),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
d.SetBindKeysFn(d.bindKeys)
|
d.SetBindKeysFn(d.bindKeys)
|
||||||
|
|
@ -40,14 +39,10 @@ func (d *DaemonSet) bindKeys(aa ui.KeyActions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DaemonSet) showPods(app *App, model ui.Tabular, _, path string) {
|
func (d *DaemonSet) showPods(app *App, model ui.Tabular, _, path string) {
|
||||||
o, err := app.factory.Get(d.GVR(), path, true, labels.Everything())
|
var res dao.DaemonSet
|
||||||
if err != nil {
|
res.Init(app.factory, client.NewGVR(d.GVR()))
|
||||||
d.App().Flash().Err(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var ds appsv1.DaemonSet
|
ds, err := res.GetInstance(path)
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &ds)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.App().Flash().Err(err)
|
d.App().Flash().Err(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,5 @@ func TestDaemonSet(t *testing.T) {
|
||||||
|
|
||||||
assert.Nil(t, v.Init(makeCtx()))
|
assert.Nil(t, v.Init(makeCtx()))
|
||||||
assert.Equal(t, "DaemonSets", v.Name())
|
assert.Equal(t, "DaemonSets", v.Name())
|
||||||
assert.Equal(t, 11, len(v.Hints()))
|
assert.Equal(t, 12, len(v.Hints()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -235,11 +235,11 @@ func (h *Help) showGeneral() model.MenuHints {
|
||||||
Description: "Clear command",
|
Description: "Clear command",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Mnemonic: "Ctrl-h",
|
Mnemonic: "t",
|
||||||
Description: "Toggle Header",
|
Description: "Toggle Header",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Mnemonic: ":q",
|
Mnemonic: "q",
|
||||||
Description: "Quit",
|
Description: "Quit",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue