parent
e43260ed05
commit
7ad07b791d
|
|
@ -1,6 +1,5 @@
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
k9s.log
|
|
||||||
.envrc
|
.envrc
|
||||||
cov.out
|
cov.out
|
||||||
execs
|
execs
|
||||||
|
|
@ -10,10 +9,8 @@ dist
|
||||||
notes
|
notes
|
||||||
vendor
|
vendor
|
||||||
go.mod1
|
go.mod1
|
||||||
popeye1.go
|
|
||||||
gen.sh
|
gen.sh
|
||||||
cluster_info_test.go
|
|
||||||
*.test
|
*.test
|
||||||
*.log
|
*.log
|
||||||
*~
|
*~
|
||||||
pod1.go
|
faas
|
||||||
|
|
|
||||||
108
README.md
108
README.md
|
|
@ -145,16 +145,16 @@ K9s uses aliases to navigate most K8s resources.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## K9s config file ($HOME/.k9s/config.yml)
|
## K9s Configuration
|
||||||
|
|
||||||
K9s keeps its configurations in a .k9s directory in your home directory.
|
K9s keeps its configurations in a .k9s directory in your home directory `$HOME/.k9s/config.yml`.
|
||||||
|
|
||||||
> NOTE: This is still in flux and will change while in pre-release stage!
|
> NOTE: This is still in flux and will change while in pre-release stage!
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# config.yml
|
# config.yml
|
||||||
k9s:
|
k9s:
|
||||||
# Indicates api-server poll intervals.
|
# Represents ui poll intervals.
|
||||||
refreshRate: 2
|
refreshRate: 2
|
||||||
# Indicates whether modification commands like delete/kill/edit are disabled. Default is false
|
# Indicates whether modification commands like delete/kill/edit are disabled. Default is false
|
||||||
readOnly: false
|
readOnly: false
|
||||||
|
|
@ -189,9 +189,9 @@ K9s uses aliases to navigate most K8s resources.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Aliases
|
## Command Aliases
|
||||||
|
|
||||||
In K9s, you can define your own command aliases (shortnames) to access your resources. In your `$HOME/.k9s` define a file called `alias.yml`. A K9s alias defines pairs of alias:gvr. A gvr represents a fully qualified Kubernetes resource identifier. Here is an example of an alias file:
|
In K9s, you can define your very own command aliases (shortnames) to access your resources. In your `$HOME/.k9s` define a file called `alias.yml`. A K9s alias defines pairs of alias:gvr. A gvr (Group/Version/Resource) represents a fully qualified Kubernetes resource identifier. Here is an example of an alias file:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# $HOME/.k9s/alias.yml
|
# $HOME/.k9s/alias.yml
|
||||||
|
|
@ -204,9 +204,44 @@ Using this alias file, you can now type pp/crb to list pods or clusterrolebindin
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## HotKey Support
|
||||||
|
|
||||||
|
Entering the command mode and typing a resource name or alias, could be cumbersome for navigating thru often used resources. We're introducing hotkeys that allows a user to define their own hotkeys to activate their favorite resource views. In order to enable hotkeys please follow these steps:
|
||||||
|
|
||||||
|
1. Create a file named `$HOME/.k9s/hotkey.yml`
|
||||||
|
2. Add the following to your `hotkey.yml`. You can use resource name/short name to specify a command ie same as typing it while in command mode.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# $HOME/.k9s/hotkey.yml
|
||||||
|
hotKey:
|
||||||
|
# Hitting Shift-0 navigates to your pod view
|
||||||
|
shift-0:
|
||||||
|
shortCut: Shift-0
|
||||||
|
description: Viewing pods
|
||||||
|
command: pods
|
||||||
|
# Hitting Shift-1 navigates to your deployments
|
||||||
|
shift-1:
|
||||||
|
shortCut: Shift-1
|
||||||
|
description: View deployments
|
||||||
|
command: dp
|
||||||
|
# Hitting Shift-2 navigates to your xray deployments
|
||||||
|
shift-2:
|
||||||
|
shortCut: Shift-4
|
||||||
|
description: Xray Deployments
|
||||||
|
command: xray deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
Not feeling so hot? Your custom hotkeys will be listed in the help view `?`. Also your hotkey file will be automatically reloaded so you can readily use your hotkeys as you define them.
|
||||||
|
|
||||||
|
You can choose any keyboard shotcuts that make sense to you, provided they are not part of the standard K9s shortcuts list.
|
||||||
|
|
||||||
|
> NOTE: This feature/configuration might change in future releases!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
|
|
||||||
K9s allows you to define your own cluster commands via plugins. K9s will look at `$HOME/.k9s/plugin.yml` to locate available plugins. A plugin is defined as follows:
|
K9s allows you to extend your command line and tooling by defining your very own cluster commands via plugins. K9s will look at `$HOME/.k9s/plugin.yml` to locate all available plugins. A plugin is defined as follows:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# $HOME/.k9s/plugin.yml
|
# $HOME/.k9s/plugin.yml
|
||||||
|
|
@ -217,7 +252,7 @@ plugin:
|
||||||
description: Pod logs
|
description: Pod logs
|
||||||
scopes:
|
scopes:
|
||||||
- po
|
- po
|
||||||
command: /usr/local/bin/kubectl
|
command: kubectl
|
||||||
background: false
|
background: false
|
||||||
args:
|
args:
|
||||||
- logs
|
- logs
|
||||||
|
|
@ -237,6 +272,8 @@ K9s does provide additional environment variables for you to customize your plug
|
||||||
|
|
||||||
* `$NAMESPACE` -- the selected resource namespace
|
* `$NAMESPACE` -- the selected resource namespace
|
||||||
* `$NAME` -- the selected resource name
|
* `$NAME` -- the selected resource name
|
||||||
|
* `$CONTAINER` -- the current container if applicable
|
||||||
|
* `$FILTER` -- the current filter if any
|
||||||
* `$KUBECONFIG` -- the KubeConfig location.
|
* `$KUBECONFIG` -- the KubeConfig location.
|
||||||
* `$CLUSTER` the active cluster name
|
* `$CLUSTER` the active cluster name
|
||||||
* `$CONTEXT` the active context name
|
* `$CONTEXT` the active context name
|
||||||
|
|
@ -244,13 +281,13 @@ K9s does provide additional environment variables for you to customize your plug
|
||||||
* `$GROUPS` the active groups
|
* `$GROUPS` the active groups
|
||||||
* `$COLX` the column at index X for the viewed resource
|
* `$COLX` the column at index X for the viewed resource
|
||||||
|
|
||||||
NOTE: This is an experimental feature! Options and layout may change in future K9s releases as this feature solidifies.
|
> NOTE: This is an experimental feature! Options and layout may change in future K9s releases as this feature solidifies.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Benchmarking
|
## Benchmark Your Applications
|
||||||
|
|
||||||
K9s integrates [Hey](https://github.com/rakyll/hey) from the brilliant and super talented [Jaana Dogan](https://github.com/rakyll) of Google fame. Hey is a CLI tool to benchmark HTTP endpoints similar to AB bench. This preliminary feature currently supports benchmarking port-forwards and services (Read the paint on this is way fresh!).
|
K9s integrates [Hey](https://github.com/rakyll/hey) from the brilliant and super talented [Jaana Dogan](https://github.com/rakyll). `Hey` is a CLI tool to benchmark HTTP endpoints similar to AB bench. This preliminary feature currently supports benchmarking port-forwards and services (Read the paint on this is way fresh!).
|
||||||
|
|
||||||
To setup a port-forward, you will need to navigate to the PodView, select a pod and a container that exposes a given port. Using `SHIFT-F` a dialog comes up to allow you to specify a local port to forward. Once acknowledged, you can navigate to the PortForward view (alias `pf`) listing out your active port-forwards. Selecting a port-forward and using `CTRL-B` will run a benchmark on that HTTP endpoint. To view the results of your benchmark runs, go to the Benchmarks view (alias `be`). You should now be able to select a benchmark and view the run stats details by pressing `<ENTER>`. NOTE: Port-forwards only last for the duration of the K9s session and will be terminated upon exit.
|
To setup a port-forward, you will need to navigate to the PodView, select a pod and a container that exposes a given port. Using `SHIFT-F` a dialog comes up to allow you to specify a local port to forward. Once acknowledged, you can navigate to the PortForward view (alias `pf`) listing out your active port-forwards. Selecting a port-forward and using `CTRL-B` will run a benchmark on that HTTP endpoint. To view the results of your benchmark runs, go to the Benchmarks view (alias `be`). You should now be able to select a benchmark and view the run stats details by pressing `<ENTER>`. NOTE: Port-forwards only last for the duration of the K9s session and will be terminated upon exit.
|
||||||
|
|
||||||
|
|
@ -272,11 +309,11 @@ benchmarks:
|
||||||
defaults:
|
defaults:
|
||||||
# One concurrent connection
|
# One concurrent connection
|
||||||
concurrency: 1
|
concurrency: 1
|
||||||
# 500 requests will be sent to an endpoint
|
# Number of requests that will be sent to an endpoint
|
||||||
requests: 500
|
requests: 500
|
||||||
containers:
|
containers:
|
||||||
# Containers section allows you to configure your http container's endpoints and benchmarking settings.
|
# Containers section allows you to configure your http container's endpoints and benchmarking settings.
|
||||||
# NOTE: the container ID syntax uses namespace/pod_name:container_name
|
# NOTE: the container ID syntax uses namespace/pod-name:container-name
|
||||||
default/nginx:nginx:
|
default/nginx:nginx:
|
||||||
# Benchmark a container named nginx using POST HTTP verb using http://localhost:port/bozo URL and headers.
|
# Benchmark a container named nginx using POST HTTP verb using http://localhost:port/bozo URL and headers.
|
||||||
concurrency: 1
|
concurrency: 1
|
||||||
|
|
@ -295,15 +332,15 @@ benchmarks:
|
||||||
# Similary you can Benchmark an HTTP service exposed either via nodeport, loadbalancer types.
|
# Similary you can Benchmark an HTTP service exposed either via nodeport, loadbalancer types.
|
||||||
# Service ID is ns/svc-name
|
# Service ID is ns/svc-name
|
||||||
default/nginx:
|
default/nginx:
|
||||||
# Hit the service with 5 concurrent sessions
|
# Set the concurrency level
|
||||||
concurrency: 5
|
concurrency: 5
|
||||||
# Issues a total of 500 requests
|
# Number of requests to be sent
|
||||||
requests: 500
|
requests: 500
|
||||||
http:
|
http:
|
||||||
method: GET
|
method: GET
|
||||||
# This setting will depend on whether service is nodeport or loadbalancer. Nodeport may require vendor port tuneling setting.
|
# This setting will depend on whether service is nodeport or loadbalancer. Nodeport may require vendor port tuneling setting.
|
||||||
# Set this to a node if nodeport or LB if applicable. IP or dns name.
|
# Set this to a node if nodeport or LB if applicable. IP or dns name.
|
||||||
host: 10.11.13.14
|
host: A.B.C.D
|
||||||
path: /bumblebeetuna
|
path: /bumblebeetuna
|
||||||
auth:
|
auth:
|
||||||
user: jean-baptiste-emmanuel
|
user: jean-baptiste-emmanuel
|
||||||
|
|
@ -312,41 +349,6 @@ benchmarks:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## HotKeys
|
|
||||||
|
|
||||||
Entering the command mode and typing a resource name or alias, could be cumbersome for navigating thru often used resources. We're introducing hotkeys that allows a user to define their own hotkeys to activate their favorite resource views. In order to enable hotkeys please follow these steps:
|
|
||||||
|
|
||||||
1. In your .k9s home directory create a file named `hotkey.yml`
|
|
||||||
2. Add the following to your `hotkey.yml`. You can use short names or resource name to specify a command ie same as typing it in command mode.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
hotKey:
|
|
||||||
shift-0:
|
|
||||||
shortCut: Shift-0
|
|
||||||
description: View pods
|
|
||||||
command: pods
|
|
||||||
shift-1:
|
|
||||||
shortCut: Shift-1
|
|
||||||
description: View deployments
|
|
||||||
command: dp
|
|
||||||
shift-2:
|
|
||||||
shortCut: Shift-2
|
|
||||||
description: View services
|
|
||||||
command: service
|
|
||||||
shift-3:
|
|
||||||
shortCut: Shift-3
|
|
||||||
description: View statefulsets
|
|
||||||
command: sts
|
|
||||||
```
|
|
||||||
|
|
||||||
Not feeling so hot? Your custom hotkeys list will be listed in the help view.`<?>`. Also your hotkey file will be automatically reloaded so you can readily use your hotkeys as you define them.
|
|
||||||
|
|
||||||
You can choose any keyboard shotcuts that make sense to you, provided they are not part of the standard K9s shortcuts list.
|
|
||||||
|
|
||||||
NOTE: This feature/configuration might change in future releases!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## K9s RBAC FU
|
## K9s RBAC FU
|
||||||
|
|
||||||
On RBAC enabled clusters, you would need to give your users/groups capabilities so that they can use K9s to explore their Kubernetes cluster. K9s needs minimally read privileges at both the cluster and namespace level to display resources and metrics.
|
On RBAC enabled clusters, you would need to give your users/groups capabilities so that they can use K9s to explore their Kubernetes cluster. K9s needs minimally read privileges at both the cluster and namespace level to display resources and metrics.
|
||||||
|
|
@ -459,7 +461,7 @@ Colors can be defined by name or uing an hex representation. Of recent, we've ad
|
||||||
> NOTE: This is very much an experimental feature at this time, more will be added/modified if this feature has legs so thread accordingly!
|
> NOTE: This is very much an experimental feature at this time, more will be added/modified if this feature has legs so thread accordingly!
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# InTheNavy Skin...
|
# Skin InTheNavy...
|
||||||
k9s:
|
k9s:
|
||||||
# General K9s styles
|
# General K9s styles
|
||||||
body:
|
body:
|
||||||
|
|
@ -589,8 +591,8 @@ to make this project a reality!
|
||||||
## Meet The Core Team!
|
## Meet The Core Team!
|
||||||
|
|
||||||
* [Fernand Galiana](https://github.com/derailed)
|
* [Fernand Galiana](https://github.com/derailed)
|
||||||
* <img src="assets/mail.png" width="16" height="auto"/> fernand@imhotep.io
|
* <img src="assets/mail.png" width="16" height="auto"/> fernand@imhotep.io
|
||||||
* <img src="assets/twitter.png" width="16" height="auto"/> [@kitesurfer](https://twitter.com/kitesurfer?lang=en)
|
* <img src="assets/twitter.png" width="16" height="auto"/> [@kitesurfer](https://twitter.com/kitesurfer?lang=en)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
5
go.mod
5
go.mod
|
|
@ -32,6 +32,7 @@ require (
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||||
github.com/atotto/clipboard v0.1.2
|
github.com/atotto/clipboard v0.1.2
|
||||||
github.com/derailed/tview v0.3.4
|
github.com/derailed/tview v0.3.4
|
||||||
|
github.com/drone/envsubst v1.0.2 // indirect
|
||||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
|
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||||
github.com/fatih/color v1.6.0
|
github.com/fatih/color v1.6.0
|
||||||
|
|
@ -41,9 +42,13 @@ require (
|
||||||
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
|
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.5
|
github.com/mattn/go-runewidth v0.0.5
|
||||||
|
github.com/openfaas/faas v0.0.0-20200207215241-6afae214e3ec // indirect
|
||||||
|
github.com/openfaas/faas-cli v0.0.0-20200124160744-30b7cec9634c
|
||||||
|
github.com/openfaas/faas-provider v0.15.0 // indirect
|
||||||
github.com/petergtz/pegomock v2.6.0+incompatible
|
github.com/petergtz/pegomock v2.6.0+incompatible
|
||||||
github.com/rakyll/hey v0.1.2
|
github.com/rakyll/hey v0.1.2
|
||||||
github.com/rs/zerolog v1.17.2
|
github.com/rs/zerolog v1.17.2
|
||||||
|
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||||
github.com/sahilm/fuzzy v0.1.0
|
github.com/sahilm/fuzzy v0.1.0
|
||||||
github.com/spf13/cobra v0.0.5
|
github.com/spf13/cobra v0.0.5
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
|
|
|
||||||
14
go.sum
14
go.sum
|
|
@ -177,6 +177,8 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ
|
||||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s=
|
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s=
|
||||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
|
github.com/drone/envsubst v1.0.2 h1:dpYLMAspQHW0a8dZpLRKe9jCNvIGZPhCPrycZzIHdqo=
|
||||||
|
github.com/drone/envsubst v1.0.2/go.mod h1:bkZbnc/2vh1M12Ecn7EYScpI4YGYU0etwLJICOWi8Z0=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs=
|
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs=
|
||||||
|
|
@ -339,9 +341,11 @@ github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1a
|
||||||
github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
|
github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
|
||||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA=
|
github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA=
|
||||||
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||||
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
|
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
|
||||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
|
@ -450,6 +454,7 @@ github.com/mindprince/gonvml v0.0.0-20171110221305-fee913ce8fb2/go.mod h1:2eu9pR
|
||||||
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
|
|
@ -497,6 +502,12 @@ github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 h1:yvQ/2
|
||||||
github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
|
github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
|
||||||
|
github.com/openfaas/faas v0.0.0-20200207215241-6afae214e3ec h1:S6wtb5ie7KeMcuEaESj0RoSmpyGfvOSuunmKEdX7wg8=
|
||||||
|
github.com/openfaas/faas v0.0.0-20200207215241-6afae214e3ec/go.mod h1:E0m2rLup0Vvxg53BKxGgaYAGcZa3Xl+vvL7vSi5yQ14=
|
||||||
|
github.com/openfaas/faas-cli v0.0.0-20200124160744-30b7cec9634c h1:9RGaDpUySgRscx5oiagwUtm9vBZti/4+QYq2GM4FegE=
|
||||||
|
github.com/openfaas/faas-cli v0.0.0-20200124160744-30b7cec9634c/go.mod h1:u/KO+e43wkagC0lqM1eaqNEWEBdg08Q1ugP/idj39MM=
|
||||||
|
github.com/openfaas/faas-provider v0.15.0 h1:3x5ma90FL7AqP4NOD6f03AY24y3xBeVF6xGLUx6Xrlc=
|
||||||
|
github.com/openfaas/faas-provider v0.15.0/go.mod h1:8Fagi2UeMfL+gZAqZWSMQg86i+w1+hBOKtwKRP5sLFI=
|
||||||
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
|
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
|
||||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
|
@ -557,6 +568,8 @@ github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvf
|
||||||
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||||
|
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||||
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
|
|
@ -631,6 +644,7 @@ github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxt
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569 h1:nSQar3Y0E3VQF/VdZ8PTAilaXpER+d7ypdABCrpwMdg=
|
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569 h1:nSQar3Y0E3VQF/VdZ8PTAilaXpER+d7ypdABCrpwMdg=
|
||||||
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
|
||||||
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df h1:shvkWr0NAZkg4nPuE3XrKP0VuBPijjk3TfX6Y6acFNg=
|
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df h1:shvkWr0NAZkg4nPuE3XrKP0VuBPijjk3TfX6Y6acFNg=
|
||||||
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15 h1:Z2sc4+v0JHV6Mn4kX1f2a5nruNjmV+Th32sugE8zwz8=
|
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15 h1:Z2sc4+v0JHV6Mn4kX1f2a5nruNjmV+Th32sugE8zwz8=
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ func (c *Container) List(ctx context.Context, _ string) ([]runtime.Object, error
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailLogs tails a given container logs
|
// TailLogs tails a given container logs
|
||||||
func (c *Container) TailLogs(ctx context.Context, logChan chan<- string, opts LogOptions) error {
|
func (c *Container) TailLogs(ctx context.Context, logChan chan<- []byte, opts LogOptions) error {
|
||||||
fac, ok := ctx.Value(internal.KeyFactory).(Factory)
|
fac, ok := ctx.Value(internal.KeyFactory).(Factory)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("Expecting an informer")
|
return errors.New("Expecting an informer")
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,11 @@ type CustomResourceDefinition struct {
|
||||||
// List returns a collection of nodes.
|
// List returns a collection of nodes.
|
||||||
func (c *CustomResourceDefinition) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
func (c *CustomResourceDefinition) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||||
strLabel, ok := ctx.Value(internal.KeyLabels).(string)
|
strLabel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||||
lsel := labels.Everything()
|
labelSel := labels.Everything()
|
||||||
if sel, e := labels.ConvertSelectorToLabelsMap(strLabel); ok && e == nil {
|
if sel, e := labels.ConvertSelectorToLabelsMap(strLabel); ok && e == nil {
|
||||||
lsel = sel.AsSelector()
|
labelSel = sel.AsSelector()
|
||||||
}
|
}
|
||||||
|
|
||||||
const gvr = "apiextensions.k8s.io/v1beta1/customresourcedefinitions"
|
const gvr = "apiextensions.k8s.io/v1beta1/customresourcedefinitions"
|
||||||
return c.Factory.List(gvr, "-", true, lsel)
|
return c.Factory.List(gvr, "-", true, labelSel)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ func (d *Deployment) Restart(path string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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<- string, 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())
|
o, err := d.Factory.Get(d.gvr.String(), opts.Path, true, labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ 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"
|
||||||
|
|
@ -61,7 +62,7 @@ func (d *DaemonSet) Restart(path string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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<- string, 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())
|
o, err := d.Factory.Get(d.gvr.String(), opts.Path, true, labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -79,7 +80,11 @@ func (d *DaemonSet) TailLogs(ctx context.Context, c chan<- string, opts LogOptio
|
||||||
return podLogs(ctx, c, ds.Spec.Selector.MatchLabels, opts)
|
return podLogs(ctx, c, ds.Spec.Selector.MatchLabels, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func podLogs(ctx context.Context, c chan<- string, 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")
|
||||||
|
|
@ -94,7 +99,7 @@ func podLogs(ctx context.Context, c chan<- string, sel map[string]string, opts L
|
||||||
}
|
}
|
||||||
|
|
||||||
ns, _ := client.Namespaced(opts.Path)
|
ns, _ := client.Namespaced(opts.Path)
|
||||||
oo, err := f.List("v1/pods", ns, true, lsel)
|
oo, err := f.List("v1/pods", ns, false, lsel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ type Generic struct {
|
||||||
func (g *Generic) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
func (g *Generic) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||||
labelSel, ok := ctx.Value(internal.KeyLabels).(string)
|
labelSel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Warn().Msgf("No label selector found in context. Listing all resources")
|
log.Debug().Msgf("No label selector found in context. Listing all resources")
|
||||||
}
|
}
|
||||||
if client.IsAllNamespace(ns) {
|
if client.IsAllNamespace(ns) {
|
||||||
ns = client.AllNamespaces
|
ns = client.AllNamespaces
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ type Job struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailLogs tail logs for all pods represented by this Job.
|
// TailLogs tail logs for all pods represented by this Job.
|
||||||
func (j *Job) TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error {
|
func (j *Job) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
||||||
o, err := j.Factory.Get(j.gvr.String(), opts.Path, true, labels.Everything())
|
o, err := j.Factory.Get(j.gvr.String(), opts.Path, true, labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -47,19 +47,26 @@ func colorize(c color.Paint, txt string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecorateLog add a log header to display po/co information along with the log message.
|
// DecorateLog add a log header to display po/co information along with the log message.
|
||||||
func (o LogOptions) DecorateLog(msg string) string {
|
func (o LogOptions) DecorateLog(bytes []byte) []byte {
|
||||||
_, n := client.Namespaced(o.Path)
|
if len(bytes) == 0 {
|
||||||
if msg == "" {
|
return bytes
|
||||||
return msg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes = bytes[:len(bytes)-1]
|
||||||
|
_, n := client.Namespaced(o.Path)
|
||||||
|
|
||||||
|
var prefix []byte
|
||||||
if o.MultiPods {
|
if o.MultiPods {
|
||||||
return colorize(o.Color, n+":"+o.Container+" ") + msg
|
prefix = []byte(colorize(o.Color, n+":"+o.Container+" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !o.SingleContainer {
|
if !o.SingleContainer {
|
||||||
return colorize(o.Color, o.Container+" ") + msg
|
prefix = []byte(colorize(o.Color, o.Container+" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg
|
if len(prefix) == 0 {
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(prefix, bytes...)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,14 +148,14 @@ func (p *Pod) Containers(path string, includeInit bool) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailLogs tails a given container logs
|
// TailLogs tails a given container logs
|
||||||
func (p *Pod) TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error {
|
func (p *Pod) TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
||||||
if !opts.HasContainer() {
|
if !opts.HasContainer() {
|
||||||
return p.logs(ctx, c, opts)
|
return p.logs(ctx, c, opts)
|
||||||
}
|
}
|
||||||
return tailLogs(ctx, p, c, opts)
|
return tailLogs(ctx, p, c, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pod) logs(ctx context.Context, c chan<- string, opts LogOptions) error {
|
func (p *Pod) logs(ctx context.Context, c chan<- []byte, opts LogOptions) error {
|
||||||
fac, ok := ctx.Value(internal.KeyFactory).(*watch.Factory)
|
fac, ok := ctx.Value(internal.KeyFactory).(*watch.Factory)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("Expecting an informer")
|
return errors.New("Expecting an informer")
|
||||||
|
|
@ -194,7 +194,7 @@ func (p *Pod) logs(ctx context.Context, c chan<- string, opts LogOptions) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tailLogs(ctx context.Context, logger Logger, c chan<- string, opts LogOptions) error {
|
func tailLogs(ctx context.Context, logger Logger, c chan<- []byte, opts LogOptions) error {
|
||||||
log.Debug().Msgf("Tailing logs for %q -- %q", opts.Path, opts.Container)
|
log.Debug().Msgf("Tailing logs for %q -- %q", opts.Path, opts.Container)
|
||||||
o := v1.PodLogOptions{
|
o := v1.PodLogOptions{
|
||||||
Container: opts.Container,
|
Container: opts.Container,
|
||||||
|
|
@ -206,11 +206,13 @@ func tailLogs(ctx context.Context, logger Logger, c chan<- string, opts LogOptio
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctxt, cancelFunc := context.WithCancel(ctx)
|
|
||||||
req.Context(ctxt)
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithCancel(ctx)
|
||||||
|
req.Context(ctx)
|
||||||
|
|
||||||
var blocked int32 = 1
|
var blocked int32 = 1
|
||||||
go logsTimeout(cancelFunc, &blocked)
|
go logsTimeout(cancel, &blocked)
|
||||||
|
|
||||||
// This call will block if nothing is in the stream!!
|
// This call will block if nothing is in the stream!!
|
||||||
stream, err := req.Stream()
|
stream, err := req.Stream()
|
||||||
|
|
@ -219,7 +221,7 @@ func tailLogs(ctx context.Context, logger Logger, c chan<- string, opts LogOptio
|
||||||
log.Error().Err(err).Msgf("Log stream failed for `%s", opts.Path)
|
log.Error().Err(err).Msgf("Log stream failed for `%s", opts.Path)
|
||||||
return fmt.Errorf("Unable to obtain log stream for %s", opts.Path)
|
return fmt.Errorf("Unable to obtain log stream for %s", opts.Path)
|
||||||
}
|
}
|
||||||
go readLogs(ctx, stream, c, opts)
|
go readLogs(stream, c, opts)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -232,7 +234,7 @@ func logsTimeout(cancel context.CancelFunc, blocked *int32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readLogs(ctx context.Context, stream io.ReadCloser, c chan<- string, opts LogOptions) {
|
func readLogs(stream io.ReadCloser, c chan<- []byte, opts LogOptions) {
|
||||||
defer func() {
|
defer func() {
|
||||||
log.Debug().Msgf(">>> Closing stream `%s", opts.Path)
|
log.Debug().Msgf(">>> Closing stream `%s", opts.Path)
|
||||||
if err := stream.Close(); err != nil {
|
if err := stream.Close(); err != nil {
|
||||||
|
|
@ -240,16 +242,18 @@ func readLogs(ctx context.Context, stream io.ReadCloser, c chan<- string, opts L
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
scanner := bufio.NewScanner(stream)
|
r := bufio.NewReader(stream)
|
||||||
for scanner.Scan() {
|
for {
|
||||||
select {
|
bytes, err := r.ReadBytes('\n')
|
||||||
case <-ctx.Done():
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Msg("Read error")
|
||||||
|
if err != io.EOF {
|
||||||
|
log.Error().Err(err).Msgf("stream reader failed")
|
||||||
|
}
|
||||||
return
|
return
|
||||||
default:
|
|
||||||
c <- opts.DecorateLog(scanner.Text())
|
|
||||||
}
|
}
|
||||||
|
c <- opts.DecorateLog(bytes)
|
||||||
}
|
}
|
||||||
log.Error().Msgf("SCAN_ERR %#v", scanner.Err())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ func (s *StatefulSet) Restart(path string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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<- string, 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())
|
o, err := s.Factory.Get(s.gvr.String(), opts.Path, true, labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ 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<- string, 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())
|
o, err := s.Factory.Get(s.gvr.String(), opts.Path, true, labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/derailed/k9s/internal"
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
@ -22,7 +23,6 @@ type Table struct {
|
||||||
func (t *Table) Get(ctx context.Context, path string) (runtime.Object, error) {
|
func (t *Table) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||||
ns, n := client.Namespaced(path)
|
ns, n := client.Namespaced(path)
|
||||||
|
|
||||||
log.Debug().Msgf("TABLE-GET %q:%q", ns, t.gvr)
|
|
||||||
a := fmt.Sprintf(gvFmt, metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName)
|
a := fmt.Sprintf(gvFmt, metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName)
|
||||||
_, codec := t.codec()
|
_, codec := t.codec()
|
||||||
|
|
||||||
|
|
@ -46,6 +46,11 @@ func (t *Table) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||||
|
|
||||||
// List all Resources in a given namespace.
|
// List all Resources in a given namespace.
|
||||||
func (t *Table) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
func (t *Table) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||||
|
labelSel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||||
|
if !ok {
|
||||||
|
log.Debug().Msgf("No label selector found in context. Listing all resources")
|
||||||
|
}
|
||||||
|
|
||||||
a := fmt.Sprintf(gvFmt, metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName)
|
a := fmt.Sprintf(gvFmt, metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName)
|
||||||
_, codec := t.codec()
|
_, codec := t.codec()
|
||||||
|
|
||||||
|
|
@ -57,7 +62,7 @@ func (t *Table) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||||
SetHeader("Accept", a).
|
SetHeader("Accept", a).
|
||||||
Namespace(ns).
|
Namespace(ns).
|
||||||
Resource(t.gvr.R()).
|
Resource(t.gvr.R()).
|
||||||
VersionedParams(&metav1beta1.TableOptions{}, codec).
|
VersionedParams(&metav1.ListOptions{LabelSelector: labelSel}, codec).
|
||||||
Do().Get()
|
Do().Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ type Accessor interface {
|
||||||
// Loggable represents resources with logs.
|
// Loggable represents resources with logs.
|
||||||
type Loggable interface {
|
type Loggable interface {
|
||||||
// TaiLogs streams resource logs.
|
// TaiLogs streams resource logs.
|
||||||
TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error
|
TailLogs(ctx context.Context, c chan<- []byte, opts LogOptions) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describer describes a resource.
|
// Describer describes a resource.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package model_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/derailed/k9s/internal/model"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClusterMetaDelta(t *testing.T) {
|
||||||
|
uu := map[string]struct {
|
||||||
|
o, n model.ClusterMeta
|
||||||
|
e bool
|
||||||
|
}{
|
||||||
|
"empty": {
|
||||||
|
o: model.NewClusterMeta(),
|
||||||
|
n: model.NewClusterMeta(),
|
||||||
|
},
|
||||||
|
"same": {
|
||||||
|
o: makeClusterMeta("fred"),
|
||||||
|
n: makeClusterMeta("fred"),
|
||||||
|
},
|
||||||
|
"diff": {
|
||||||
|
o: makeClusterMeta("fred"),
|
||||||
|
n: makeClusterMeta("freddie"),
|
||||||
|
e: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range uu {
|
||||||
|
u := uu[k]
|
||||||
|
t.Run(k, func(t *testing.T) {
|
||||||
|
assert.Equal(t, u.e, u.o.Deltas(u.n))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers...
|
||||||
|
|
||||||
|
func makeClusterMeta(cluster string) model.ClusterMeta {
|
||||||
|
m := model.NewClusterMeta()
|
||||||
|
m.Cluster = cluster
|
||||||
|
m.Cpu, m.Mem = 10, 20
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
@ -31,25 +31,23 @@ type LogsListener interface {
|
||||||
|
|
||||||
// Log represents a resource logger.
|
// Log represents a resource logger.
|
||||||
type Log struct {
|
type Log struct {
|
||||||
factory dao.Factory
|
factory dao.Factory
|
||||||
lines []string
|
lines []string
|
||||||
listeners []LogsListener
|
listeners []LogsListener
|
||||||
gvr client.GVR
|
gvr client.GVR
|
||||||
logOptions dao.LogOptions
|
logOptions dao.LogOptions
|
||||||
cancelFn context.CancelFunc
|
cancelFn context.CancelFunc
|
||||||
initialized bool
|
mx sync.RWMutex
|
||||||
mx sync.RWMutex
|
filter string
|
||||||
filter string
|
lastSent int
|
||||||
lastSent int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLog returns a new model.
|
// NewLog returns a new model.
|
||||||
func NewLog(gvr client.GVR, msg string, opts dao.LogOptions, timeOut time.Duration) *Log {
|
func NewLog(gvr client.GVR, opts dao.LogOptions, timeOut time.Duration) *Log {
|
||||||
return &Log{
|
return &Log{
|
||||||
gvr: gvr,
|
gvr: gvr,
|
||||||
logOptions: opts,
|
logOptions: opts,
|
||||||
initialized: true,
|
lines: nil,
|
||||||
lines: []string{msg},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,12 +82,11 @@ func (l *Log) Start() {
|
||||||
|
|
||||||
// Stop terminates log tailing.
|
// Stop terminates log tailing.
|
||||||
func (l *Log) Stop() {
|
func (l *Log) Stop() {
|
||||||
if l.cancelFn == nil {
|
defer log.Debug().Msgf("<<<< Logger STOPPED!")
|
||||||
return
|
if l.cancelFn != nil {
|
||||||
|
l.cancelFn()
|
||||||
|
l.cancelFn = nil
|
||||||
}
|
}
|
||||||
log.Debug().Msgf("<<<< Logger STOP!")
|
|
||||||
l.cancelFn()
|
|
||||||
l.cancelFn = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the log lines (for testing only!)
|
// Set sets the log lines (for testing only!)
|
||||||
|
|
@ -131,7 +128,7 @@ func (l *Log) load() error {
|
||||||
ctx = context.WithValue(context.Background(), internal.KeyFactory, l.factory)
|
ctx = context.WithValue(context.Background(), internal.KeyFactory, l.factory)
|
||||||
ctx, l.cancelFn = context.WithCancel(ctx)
|
ctx, l.cancelFn = context.WithCancel(ctx)
|
||||||
|
|
||||||
c := make(chan string, 10)
|
c := make(chan []byte, 10)
|
||||||
go l.updateLogs(ctx, c)
|
go l.updateLogs(ctx, c)
|
||||||
|
|
||||||
accessor, err := dao.AccessorFor(l.factory, l.gvr)
|
accessor, err := dao.AccessorFor(l.factory, l.gvr)
|
||||||
|
|
@ -163,8 +160,7 @@ func (l *Log) Append(line string) {
|
||||||
l.mx.Lock()
|
l.mx.Lock()
|
||||||
defer l.mx.Unlock()
|
defer l.mx.Unlock()
|
||||||
|
|
||||||
if l.initialized {
|
if l.lines == nil {
|
||||||
l.lines, l.initialized, l.lastSent = []string{}, false, 0
|
|
||||||
l.fireLogCleared()
|
l.fireLogCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,20 +186,20 @@ func (l *Log) Notify(timedOut bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Log) updateLogs(ctx context.Context, c <-chan string) {
|
func (l *Log) updateLogs(ctx context.Context, c <-chan []byte) {
|
||||||
defer func() {
|
defer func() {
|
||||||
log.Debug().Msgf("updateLogs view bailing out!")
|
log.Debug().Msgf("updateLogs view bailing out!")
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case line, ok := <-c:
|
case bytes, ok := <-c:
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Debug().Msgf("Closed channel detected. Bailing out...")
|
log.Debug().Msgf("Closed channel detected. Bailing out...")
|
||||||
l.Append(line)
|
l.Append(string(bytes))
|
||||||
l.Notify(false)
|
l.Notify(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l.Append(line)
|
l.Append(string(bytes))
|
||||||
var overflow bool
|
var overflow bool
|
||||||
l.mx.RLock()
|
l.mx.RLock()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
func TestLogFullBuffer(t *testing.T) {
|
func TestLogFullBuffer(t *testing.T) {
|
||||||
size := 4
|
size := 4
|
||||||
m := model.NewLog(client.NewGVR("fred"), "Blee", makeLogOpts(size), 10*time.Millisecond)
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(size), 10*time.Millisecond)
|
||||||
m.Init(makeFactory())
|
m.Init(makeFactory())
|
||||||
|
|
||||||
v := newTestView()
|
v := newTestView()
|
||||||
|
|
@ -60,7 +60,7 @@ func TestLogFilter(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) {
|
||||||
m := model.NewLog(client.NewGVR("fred"), "Blee", makeLogOpts(size), 10*time.Millisecond)
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(size), 10*time.Millisecond)
|
||||||
m.Init(makeFactory())
|
m.Init(makeFactory())
|
||||||
|
|
||||||
v := newTestView()
|
v := newTestView()
|
||||||
|
|
@ -89,7 +89,7 @@ func TestLogFilter(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogStartStop(t *testing.T) {
|
func TestLogStartStop(t *testing.T) {
|
||||||
m := model.NewLog(client.NewGVR("fred"), "Blee", makeLogOpts(4), 10*time.Millisecond)
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(4), 10*time.Millisecond)
|
||||||
m.Init(makeFactory())
|
m.Init(makeFactory())
|
||||||
|
|
||||||
v := newTestView()
|
v := newTestView()
|
||||||
|
|
@ -110,7 +110,7 @@ func TestLogStartStop(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogClear(t *testing.T) {
|
func TestLogClear(t *testing.T) {
|
||||||
m := model.NewLog(client.NewGVR("fred"), "Blee", makeLogOpts(4), 10*time.Millisecond)
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(4), 10*time.Millisecond)
|
||||||
m.Init(makeFactory())
|
m.Init(makeFactory())
|
||||||
assert.Equal(t, "fred", m.GetPath())
|
assert.Equal(t, "fred", m.GetPath())
|
||||||
assert.Equal(t, "blee", m.GetContainer())
|
assert.Equal(t, "blee", m.GetContainer())
|
||||||
|
|
@ -132,7 +132,7 @@ func TestLogClear(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogBasic(t *testing.T) {
|
func TestLogBasic(t *testing.T) {
|
||||||
m := model.NewLog(client.NewGVR("fred"), "Blee", makeLogOpts(2), 10*time.Millisecond)
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(2), 10*time.Millisecond)
|
||||||
m.Init(makeFactory())
|
m.Init(makeFactory())
|
||||||
|
|
||||||
v := newTestView()
|
v := newTestView()
|
||||||
|
|
@ -148,7 +148,7 @@ func TestLogBasic(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogAppend(t *testing.T) {
|
func TestLogAppend(t *testing.T) {
|
||||||
m := model.NewLog(client.NewGVR("fred"), "blah blah", makeLogOpts(4), 5*time.Millisecond)
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(4), 5*time.Millisecond)
|
||||||
m.Init(makeFactory())
|
m.Init(makeFactory())
|
||||||
|
|
||||||
v := newTestView()
|
v := newTestView()
|
||||||
|
|
@ -161,17 +161,17 @@ func TestLogAppend(t *testing.T) {
|
||||||
m.Append(d)
|
m.Append(d)
|
||||||
}
|
}
|
||||||
assert.Equal(t, 1, v.dataCalled)
|
assert.Equal(t, 1, v.dataCalled)
|
||||||
assert.Equal(t, []string{}, v.data)
|
assert.Equal(t, []string{"blah blah"}, v.data)
|
||||||
|
|
||||||
m.Notify(true)
|
m.Notify(true)
|
||||||
assert.Equal(t, 2, v.dataCalled)
|
assert.Equal(t, 2, v.dataCalled)
|
||||||
assert.Equal(t, 1, v.clearCalled)
|
assert.Equal(t, 0, v.clearCalled)
|
||||||
assert.Equal(t, 0, v.errCalled)
|
assert.Equal(t, 0, v.errCalled)
|
||||||
assert.Equal(t, data, v.data)
|
assert.Equal(t, append([]string{"blah blah"}, data...), v.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogTimedout(t *testing.T) {
|
func TestLogTimedout(t *testing.T) {
|
||||||
m := model.NewLog(client.NewGVR("fred"), "Blee", makeLogOpts(4), 10*time.Millisecond)
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(4), 10*time.Millisecond)
|
||||||
m.Init(makeFactory())
|
m.Init(makeFactory())
|
||||||
|
|
||||||
v := newTestView()
|
v := newTestView()
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
batchv1 "k8s.io/api/batch/v1"
|
||||||
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"
|
||||||
|
|
@ -42,7 +41,6 @@ func (Job) Header(ns string) HeaderRow {
|
||||||
|
|
||||||
// Render renders a K8s resource to screen.
|
// Render renders a K8s resource to screen.
|
||||||
func (j Job) Render(o interface{}, ns string, r *Row) error {
|
func (j Job) Render(o interface{}, ns string, r *Row) error {
|
||||||
log.Debug().Msgf("JOB RENDER %q", ns)
|
|
||||||
raw, ok := o.(*unstructured.Unstructured)
|
raw, ok := o.(*unstructured.Unstructured)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("Expected Job, but got %T", o)
|
return fmt.Errorf("Expected Job, but got %T", o)
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ func (a *App) toggleHeader(flag bool) {
|
||||||
}
|
}
|
||||||
if a.showHeader {
|
if a.showHeader {
|
||||||
flex.RemoveItemAtIndex(0)
|
flex.RemoveItemAtIndex(0)
|
||||||
flex.AddItemAtIndex(0, a.buildHeader(), 7, 1, false)
|
flex.AddItemAtIndex(0, a.buildHeader(), 8, 1, false)
|
||||||
} else {
|
} else {
|
||||||
flex.RemoveItemAtIndex(0)
|
flex.RemoveItemAtIndex(0)
|
||||||
flex.AddItemAtIndex(0, a.statusIndicator(), 1, 1, false)
|
flex.AddItemAtIndex(0, a.statusIndicator(), 1, 1, false)
|
||||||
|
|
@ -144,7 +144,6 @@ func (a *App) toggleHeader(flag bool) {
|
||||||
func (a *App) buildHeader() tview.Primitive {
|
func (a *App) buildHeader() tview.Primitive {
|
||||||
header := tview.NewFlex()
|
header := tview.NewFlex()
|
||||||
header.SetBackgroundColor(a.Styles.BgColor())
|
header.SetBackgroundColor(a.Styles.BgColor())
|
||||||
header.SetBorderPadding(0, 0, 1, 1)
|
|
||||||
header.SetDirection(tview.FlexColumn)
|
header.SetDirection(tview.FlexColumn)
|
||||||
if !a.showHeader {
|
if !a.showHeader {
|
||||||
return header
|
return header
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
logTitle = "logs"
|
logTitle = "logs"
|
||||||
logMessage = "Waiting for logs..."
|
logMessage = "[:orange:b]Waiting for logs...[::]"
|
||||||
logCoFmt = " Logs([fg:bg:]%s:[hilite:bg:b]%s[-:bg:-]) "
|
logCoFmt = " Logs([fg:bg:]%s:[hilite:bg:b]%s[-:bg:-]) "
|
||||||
logFmt = " Logs([fg:bg:]%s) "
|
logFmt = " Logs([fg:bg:]%s) "
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ func NewLog(gvr client.GVR, path, co string, prev bool) *Log {
|
||||||
l := Log{
|
l := Log{
|
||||||
Flex: tview.NewFlex(),
|
Flex: tview.NewFlex(),
|
||||||
cmdBuff: ui.NewCmdBuff('/', ui.FilterBuff),
|
cmdBuff: ui.NewCmdBuff('/', ui.FilterBuff),
|
||||||
model: model.NewLog(gvr, logMessage, buildLogOpts(path, co, prev, tailLineCount), defaultTimeout),
|
model: model.NewLog(gvr, buildLogOpts(path, co, prev, tailLineCount), defaultTimeout),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &l
|
return &l
|
||||||
|
|
@ -66,11 +66,13 @@ func (l *Log) Init(ctx context.Context) (err error) {
|
||||||
|
|
||||||
l.indicator = NewLogIndicator(l.app.Config, l.app.Styles)
|
l.indicator = NewLogIndicator(l.app.Config, l.app.Styles)
|
||||||
l.AddItem(l.indicator, 1, 1, false)
|
l.AddItem(l.indicator, 1, 1, false)
|
||||||
|
l.indicator.Refresh()
|
||||||
|
|
||||||
l.logs = NewDetails(l.app, "", "", false)
|
l.logs = NewDetails(l.app, "", "", false)
|
||||||
if err = l.logs.Init(ctx); err != nil {
|
if err = l.logs.Init(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
l.logs.SetText(logMessage)
|
||||||
l.logs.SetWrap(false)
|
l.logs.SetWrap(false)
|
||||||
l.logs.SetMaxBuffer(l.app.Config.K9s.LogBufferSize)
|
l.logs.SetMaxBuffer(l.app.Config.K9s.LogBufferSize)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue