parent
e43260ed05
commit
7ad07b791d
|
|
@ -1,6 +1,5 @@
|
|||
.vscode
|
||||
.idea
|
||||
k9s.log
|
||||
.envrc
|
||||
cov.out
|
||||
execs
|
||||
|
|
@ -10,10 +9,8 @@ dist
|
|||
notes
|
||||
vendor
|
||||
go.mod1
|
||||
popeye1.go
|
||||
gen.sh
|
||||
cluster_info_test.go
|
||||
*.test
|
||||
*.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!
|
||||
|
||||
```yaml
|
||||
# config.yml
|
||||
k9s:
|
||||
# Indicates api-server poll intervals.
|
||||
# Represents ui poll intervals.
|
||||
refreshRate: 2
|
||||
# Indicates whether modification commands like delete/kill/edit are disabled. Default is 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
|
||||
# $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
|
||||
|
||||
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
|
||||
# $HOME/.k9s/plugin.yml
|
||||
|
|
@ -217,7 +252,7 @@ plugin:
|
|||
description: Pod logs
|
||||
scopes:
|
||||
- po
|
||||
command: /usr/local/bin/kubectl
|
||||
command: kubectl
|
||||
background: false
|
||||
args:
|
||||
- logs
|
||||
|
|
@ -237,6 +272,8 @@ K9s does provide additional environment variables for you to customize your plug
|
|||
|
||||
* `$NAMESPACE` -- the selected resource namespace
|
||||
* `$NAME` -- the selected resource name
|
||||
* `$CONTAINER` -- the current container if applicable
|
||||
* `$FILTER` -- the current filter if any
|
||||
* `$KUBECONFIG` -- the KubeConfig location.
|
||||
* `$CLUSTER` the active cluster 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
|
||||
* `$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.
|
||||
|
||||
|
|
@ -272,11 +309,11 @@ benchmarks:
|
|||
defaults:
|
||||
# One concurrent connection
|
||||
concurrency: 1
|
||||
# 500 requests will be sent to an endpoint
|
||||
# Number of requests that will be sent to an endpoint
|
||||
requests: 500
|
||||
containers:
|
||||
# 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:
|
||||
# Benchmark a container named nginx using POST HTTP verb using http://localhost:port/bozo URL and headers.
|
||||
concurrency: 1
|
||||
|
|
@ -295,15 +332,15 @@ benchmarks:
|
|||
# Similary you can Benchmark an HTTP service exposed either via nodeport, loadbalancer types.
|
||||
# Service ID is ns/svc-name
|
||||
default/nginx:
|
||||
# Hit the service with 5 concurrent sessions
|
||||
# Set the concurrency level
|
||||
concurrency: 5
|
||||
# Issues a total of 500 requests
|
||||
# Number of requests to be sent
|
||||
requests: 500
|
||||
http:
|
||||
method: GET
|
||||
# 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.
|
||||
host: 10.11.13.14
|
||||
host: A.B.C.D
|
||||
path: /bumblebeetuna
|
||||
auth:
|
||||
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
|
||||
|
||||
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!
|
||||
|
||||
```yaml
|
||||
# InTheNavy Skin...
|
||||
# Skin InTheNavy...
|
||||
k9s:
|
||||
# General K9s styles
|
||||
body:
|
||||
|
|
@ -589,8 +591,8 @@ to make this project a reality!
|
|||
## Meet The Core Team!
|
||||
|
||||
* [Fernand Galiana](https://github.com/derailed)
|
||||
* <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/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)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
5
go.mod
5
go.mod
|
|
@ -32,6 +32,7 @@ require (
|
|||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/atotto/clipboard v0.1.2
|
||||
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/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/fatih/color v1.6.0
|
||||
|
|
@ -41,9 +42,13 @@ require (
|
|||
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
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/rakyll/hey v0.1.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/spf13/cobra v0.0.5
|
||||
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/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
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/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=
|
||||
|
|
@ -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/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
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/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/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/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
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/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
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-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
||||
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/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/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/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
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 v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
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/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
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.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/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/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
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
|
||||
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)
|
||||
if !ok {
|
||||
return errors.New("Expecting an informer")
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ type CustomResourceDefinition struct {
|
|||
// List returns a collection of nodes.
|
||||
func (c *CustomResourceDefinition) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||
strLabel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||
lsel := labels.Everything()
|
||||
labelSel := labels.Everything()
|
||||
if sel, e := labels.ConvertSelectorToLabelsMap(strLabel); ok && e == nil {
|
||||
lsel = sel.AsSelector()
|
||||
labelSel = sel.AsSelector()
|
||||
}
|
||||
|
||||
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.
|
||||
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())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"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.
|
||||
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())
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
if !ok {
|
||||
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)
|
||||
oo, err := f.List("v1/pods", ns, true, lsel)
|
||||
oo, err := f.List("v1/pods", ns, false, lsel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ type Generic struct {
|
|||
func (g *Generic) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
labelSel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||
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) {
|
||||
ns = client.AllNamespaces
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ type Job struct {
|
|||
}
|
||||
|
||||
// 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())
|
||||
if err != nil {
|
||||
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.
|
||||
func (o LogOptions) DecorateLog(msg string) string {
|
||||
_, n := client.Namespaced(o.Path)
|
||||
if msg == "" {
|
||||
return msg
|
||||
func (o LogOptions) DecorateLog(bytes []byte) []byte {
|
||||
if len(bytes) == 0 {
|
||||
return bytes
|
||||
}
|
||||
|
||||
bytes = bytes[:len(bytes)-1]
|
||||
_, n := client.Namespaced(o.Path)
|
||||
|
||||
var prefix []byte
|
||||
if o.MultiPods {
|
||||
return colorize(o.Color, n+":"+o.Container+" ") + msg
|
||||
prefix = []byte(colorize(o.Color, n+":"+o.Container+" "))
|
||||
}
|
||||
|
||||
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
|
||||
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() {
|
||||
return p.logs(ctx, 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)
|
||||
if !ok {
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
o := v1.PodLogOptions{
|
||||
Container: opts.Container,
|
||||
|
|
@ -206,11 +206,13 @@ func tailLogs(ctx context.Context, logger Logger, c chan<- string, opts LogOptio
|
|||
if err != nil {
|
||||
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
|
||||
go logsTimeout(cancelFunc, &blocked)
|
||||
go logsTimeout(cancel, &blocked)
|
||||
|
||||
// This call will block if nothing is in the 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)
|
||||
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
|
||||
}
|
||||
|
|
@ -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() {
|
||||
log.Debug().Msgf(">>> Closing stream `%s", opts.Path)
|
||||
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)
|
||||
for scanner.Scan() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
r := bufio.NewReader(stream)
|
||||
for {
|
||||
bytes, err := r.ReadBytes('\n')
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("Read error")
|
||||
if err != io.EOF {
|
||||
log.Error().Err(err).Msgf("stream reader failed")
|
||||
}
|
||||
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.
|
||||
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())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ type Service struct {
|
|||
}
|
||||
|
||||
// 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())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
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) {
|
||||
ns, n := client.Namespaced(path)
|
||||
|
||||
log.Debug().Msgf("TABLE-GET %q:%q", ns, t.gvr)
|
||||
a := fmt.Sprintf(gvFmt, metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName)
|
||||
_, 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.
|
||||
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)
|
||||
_, codec := t.codec()
|
||||
|
||||
|
|
@ -57,7 +62,7 @@ func (t *Table) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
|||
SetHeader("Accept", a).
|
||||
Namespace(ns).
|
||||
Resource(t.gvr.R()).
|
||||
VersionedParams(&metav1beta1.TableOptions{}, codec).
|
||||
VersionedParams(&metav1.ListOptions{LabelSelector: labelSel}, codec).
|
||||
Do().Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ type Accessor interface {
|
|||
// Loggable represents resources with logs.
|
||||
type Loggable interface {
|
||||
// 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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
type Log struct {
|
||||
factory dao.Factory
|
||||
lines []string
|
||||
listeners []LogsListener
|
||||
gvr client.GVR
|
||||
logOptions dao.LogOptions
|
||||
cancelFn context.CancelFunc
|
||||
initialized bool
|
||||
mx sync.RWMutex
|
||||
filter string
|
||||
lastSent int
|
||||
factory dao.Factory
|
||||
lines []string
|
||||
listeners []LogsListener
|
||||
gvr client.GVR
|
||||
logOptions dao.LogOptions
|
||||
cancelFn context.CancelFunc
|
||||
mx sync.RWMutex
|
||||
filter string
|
||||
lastSent int
|
||||
}
|
||||
|
||||
// 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{
|
||||
gvr: gvr,
|
||||
logOptions: opts,
|
||||
initialized: true,
|
||||
lines: []string{msg},
|
||||
gvr: gvr,
|
||||
logOptions: opts,
|
||||
lines: nil,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,12 +82,11 @@ func (l *Log) Start() {
|
|||
|
||||
// Stop terminates log tailing.
|
||||
func (l *Log) Stop() {
|
||||
if l.cancelFn == nil {
|
||||
return
|
||||
defer log.Debug().Msgf("<<<< Logger STOPPED!")
|
||||
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!)
|
||||
|
|
@ -131,7 +128,7 @@ func (l *Log) load() error {
|
|||
ctx = context.WithValue(context.Background(), internal.KeyFactory, l.factory)
|
||||
ctx, l.cancelFn = context.WithCancel(ctx)
|
||||
|
||||
c := make(chan string, 10)
|
||||
c := make(chan []byte, 10)
|
||||
go l.updateLogs(ctx, c)
|
||||
|
||||
accessor, err := dao.AccessorFor(l.factory, l.gvr)
|
||||
|
|
@ -163,8 +160,7 @@ func (l *Log) Append(line string) {
|
|||
l.mx.Lock()
|
||||
defer l.mx.Unlock()
|
||||
|
||||
if l.initialized {
|
||||
l.lines, l.initialized, l.lastSent = []string{}, false, 0
|
||||
if l.lines == nil {
|
||||
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() {
|
||||
log.Debug().Msgf("updateLogs view bailing out!")
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case line, ok := <-c:
|
||||
case bytes, ok := <-c:
|
||||
if !ok {
|
||||
log.Debug().Msgf("Closed channel detected. Bailing out...")
|
||||
l.Append(line)
|
||||
l.Append(string(bytes))
|
||||
l.Notify(false)
|
||||
return
|
||||
}
|
||||
l.Append(line)
|
||||
l.Append(string(bytes))
|
||||
var overflow bool
|
||||
l.mx.RLock()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import (
|
|||
|
||||
func TestLogFullBuffer(t *testing.T) {
|
||||
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())
|
||||
|
||||
v := newTestView()
|
||||
|
|
@ -60,7 +60,7 @@ func TestLogFilter(t *testing.T) {
|
|||
for k := range uu {
|
||||
u := uu[k]
|
||||
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())
|
||||
|
||||
v := newTestView()
|
||||
|
|
@ -89,7 +89,7 @@ func TestLogFilter(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())
|
||||
|
||||
v := newTestView()
|
||||
|
|
@ -110,7 +110,7 @@ func TestLogStartStop(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())
|
||||
assert.Equal(t, "fred", m.GetPath())
|
||||
assert.Equal(t, "blee", m.GetContainer())
|
||||
|
|
@ -132,7 +132,7 @@ func TestLogClear(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())
|
||||
|
||||
v := newTestView()
|
||||
|
|
@ -148,7 +148,7 @@ func TestLogBasic(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())
|
||||
|
||||
v := newTestView()
|
||||
|
|
@ -161,17 +161,17 @@ func TestLogAppend(t *testing.T) {
|
|||
m.Append(d)
|
||||
}
|
||||
assert.Equal(t, 1, v.dataCalled)
|
||||
assert.Equal(t, []string{}, v.data)
|
||||
assert.Equal(t, []string{"blah blah"}, v.data)
|
||||
|
||||
m.Notify(true)
|
||||
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, data, v.data)
|
||||
assert.Equal(t, append([]string{"blah blah"}, data...), v.data)
|
||||
}
|
||||
|
||||
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())
|
||||
|
||||
v := newTestView()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"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.
|
||||
func (j Job) Render(o interface{}, ns string, r *Row) error {
|
||||
log.Debug().Msgf("JOB RENDER %q", ns)
|
||||
raw, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("Expected Job, but got %T", o)
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ func (a *App) toggleHeader(flag bool) {
|
|||
}
|
||||
if a.showHeader {
|
||||
flex.RemoveItemAtIndex(0)
|
||||
flex.AddItemAtIndex(0, a.buildHeader(), 7, 1, false)
|
||||
flex.AddItemAtIndex(0, a.buildHeader(), 8, 1, false)
|
||||
} else {
|
||||
flex.RemoveItemAtIndex(0)
|
||||
flex.AddItemAtIndex(0, a.statusIndicator(), 1, 1, false)
|
||||
|
|
@ -144,7 +144,6 @@ func (a *App) toggleHeader(flag bool) {
|
|||
func (a *App) buildHeader() tview.Primitive {
|
||||
header := tview.NewFlex()
|
||||
header.SetBackgroundColor(a.Styles.BgColor())
|
||||
header.SetBorderPadding(0, 0, 1, 1)
|
||||
header.SetDirection(tview.FlexColumn)
|
||||
if !a.showHeader {
|
||||
return header
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import (
|
|||
|
||||
const (
|
||||
logTitle = "logs"
|
||||
logMessage = "Waiting for logs..."
|
||||
logMessage = "[:orange:b]Waiting for logs...[::]"
|
||||
logCoFmt = " Logs([fg:bg:]%s:[hilite:bg:b]%s[-:bg:-]) "
|
||||
logFmt = " Logs([fg:bg:]%s) "
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ func NewLog(gvr client.GVR, path, co string, prev bool) *Log {
|
|||
l := Log{
|
||||
Flex: tview.NewFlex(),
|
||||
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
|
||||
|
|
@ -66,11 +66,13 @@ func (l *Log) Init(ctx context.Context) (err error) {
|
|||
|
||||
l.indicator = NewLogIndicator(l.app.Config, l.app.Styles)
|
||||
l.AddItem(l.indicator, 1, 1, false)
|
||||
l.indicator.Refresh()
|
||||
|
||||
l.logs = NewDetails(l.app, "", "", false)
|
||||
if err = l.logs.Init(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
l.logs.SetText(logMessage)
|
||||
l.logs.SetWrap(false)
|
||||
l.logs.SetMaxBuffer(l.app.Config.K9s.LogBufferSize)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue