perf tuning

mine
derailed 2019-05-01 15:45:26 -06:00
parent 5905aa80bd
commit bbc514ff76
40 changed files with 651 additions and 626 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ popeye1.go
gen.sh
cluster_info_test.go
*.test
*.log

1
go.mod
View File

@ -17,7 +17,6 @@ require (
github.com/fatih/camelcase v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.4.7
github.com/gdamore/tcell v1.1.1
github.com/go-fsnotify/fsnotify v0.0.0-20180321022601-755488143dae // indirect
github.com/gogo/protobuf v1.2.1 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/google/gofuzz v1.0.0 // indirect

24
go.sum
View File

@ -10,7 +10,6 @@ github.com/Azure/go-autorest/autorest/adal v0.1.0 h1:RSw/7EAullliqwkZvgIGDYZWQm1
github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/mocks v0.1.0 h1:Kx+AUU2Te+A3JIyYn6Dfs+cFgx5XorQKuIXrZGoq/SI=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
@ -45,10 +44,6 @@ github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/derailed/tview v0.1.4 h1:6ZtMtb5+2bbGNH7SldHGcVB8GnSTXKIQwKxWRNb6DxY=
github.com/derailed/tview v0.1.4/go.mod h1:oLBQyhVeXqeUYWDZk7/5NJVbbq/JFXm3W7oEoEtpmSc=
github.com/derailed/tview v0.1.5 h1:Gj6K73V9d+zsex208KX8YsAw68+nWVNr7oM9qfTWbXQ=
github.com/derailed/tview v0.1.5/go.mod h1:g+ZyIsV5osK+lQ6LajiGQeLW10BQLJ6aMvy8Ldt2oa0=
github.com/derailed/tview v0.1.6 h1:mmp6Yg78IgbdHapV9wFoVYrbtZbMXilCdAIHadm2uqc=
github.com/derailed/tview v0.1.6/go.mod h1:g+ZyIsV5osK+lQ6LajiGQeLW10BQLJ6aMvy8Ldt2oa0=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
@ -75,8 +70,6 @@ github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2H
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-fsnotify/fsnotify v0.0.0-20180321022601-755488143dae h1:PeVNzgTRtWGm6fVic5i21t+n5ptPGCZuMcSPVMyTWjs=
github.com/go-fsnotify/fsnotify v0.0.0-20180321022601-755488143dae/go.mod h1:BbhqyaehKPCLD83cqfRYdm177Ylm1cdGHu3txjbQSQI=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
@ -109,7 +102,6 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -119,7 +111,6 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
@ -145,11 +136,9 @@ github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.0.0-20141017032234-72f9bd7c4e0c/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@ -160,10 +149,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08 h1:5MnxBC15uMxFv5FY/J/8vzyaBiArCOkMdFT9Jsw78iY=
github.com/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08/go.mod h1:NXg0ArsFk0Y01623LgUqoqcouGDB+PwCCQlrwrG6xJ4=
@ -183,7 +170,6 @@ github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6Yf
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -226,7 +212,6 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.14.3 h1:4EGfSkR2hJDB0s3oFfrlPqjU1e4WLncergLil3nEKW0=
github.com/rs/zerolog v1.14.3/go.mod h1:3WXPzbXEEliJ+a6UFE4vhIxV8qR1EML6ngzP9ug4eYg=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
@ -245,7 +230,6 @@ github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v0.0.0-20171019201919-bdcc60b419d1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1 h1:j2hhcujLRHAg872RWAV5yaUrEjHEObwDv3aImCaNLek=
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@ -331,7 +315,6 @@ google.golang.org/api v0.3.1 h1:oJra/lMfmtm13/rgY/8i3MzjFWYXvQIAKjQ3HqofMk8=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@ -342,20 +325,16 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1 h1:TrBcJ1yqAl1G++wO39nD/qtgpsW9/1+QGrluyMGEYgM=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.0.0-20150622162204-20b71e5b60d7/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
@ -367,12 +346,10 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20190222213804-5cb15d344471 h1:MzQGt8qWQCR+39kbYRd0uQqsvSidpYqJLFeWiJ9l4OE=
k8s.io/api v0.0.0-20190222213804-5cb15d344471/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/apiextensions-apiserver v0.0.0-20190426053235-842c4571cde0 h1:blst2tV97kE1/Mxaxx3zzh6zUGpxCbGNq0CdFf9/N8s=
k8s.io/apiextensions-apiserver v0.0.0-20190426053235-842c4571cde0/go.mod h1:IPM+7P9C3mY4uik+2wHMNbydKfSZpl9Hnu0Ze0447Wg=
k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628 h1:UYfHH+KEF88OTg+GojQUwFTNxbxwmoktLwutUzR0GPg=
k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
k8s.io/apiserver v0.0.0-20190426012941-33871ad74f4b/go.mod h1:omlj40TPI/OV4YFwPP09JuOkEkKbpS5bNE2T2sPeY80=
k8s.io/apiserver v0.0.0-20190426133039-accf7b6d6716 h1:gByi/idNjfDDk+lWNRqWk2uE1/KAsJtYXRMEc2M1a1k=
k8s.io/apiserver v0.0.0-20190426133039-accf7b6d6716/go.mod h1:omlj40TPI/OV4YFwPP09JuOkEkKbpS5bNE2T2sPeY80=
k8s.io/cli-runtime v0.0.0-20190325194458-f2b4781c3ae1 h1:yIrGaL3GC1eoxtkSXoNMHKzF1QIbC0TLq07OApgVvc0=
k8s.io/cli-runtime v0.0.0-20190325194458-f2b4781c3ae1/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM=
@ -393,7 +370,6 @@ k8s.io/kubernetes v1.13.5/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/metrics v0.0.0-20190325194013-29123f6a4aa6 h1:JjAl5n2siv5gPLfvXgSoUkV6tf63/EEtvCuni1zIU8Q=
k8s.io/metrics v0.0.0-20190325194013-29123f6a4aa6/go.mod h1:a25VAbm3QT3xiVl1jtoF1ueAKQM149UdZ+L93ePfV3M=
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7 h1:8r+l4bNWjRlsFYlQJnKJ2p7s1YQPj4XyXiJVqDHRx7c=
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=

View File

@ -152,6 +152,25 @@ func (mock *MockConnection) NSDialOrDie() dynamic.NamespaceableResourceInterface
return ret0
}
func (mock *MockConnection) NodePods(_param0 string) (*v1.PodList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("NodePods", params, []reflect.Type{reflect.TypeOf((**v1.PodList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1.PodList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*v1.PodList)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockConnection) RestConfigOrDie() *rest.Config {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
@ -247,25 +266,6 @@ func (mock *MockConnection) ValidNamespaces() ([]v1.Namespace, error) {
return ret0, ret1
}
func (mock *MockConnection) ValidPods(_param0 string) ([]v1.Pod, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("ValidPods", params, []reflect.Type{reflect.TypeOf((*[]v1.Pod)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1.Pod
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1.Pod)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockConnection) VerifyWasCalledOnce() *VerifierConnection {
return &VerifierConnection{
mock: mock,
@ -449,6 +449,33 @@ func (c *Connection_NSDialOrDie_OngoingVerification) GetCapturedArguments() {
func (c *Connection_NSDialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) NodePods(_param0 string) *Connection_NodePods_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NodePods", params, verifier.timeout)
return &Connection_NodePods_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_NodePods_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_NodePods_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *Connection_NodePods_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierConnection) RestConfigOrDie() *Connection_RestConfigOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RestConfigOrDie", params, verifier.timeout)
@ -584,30 +611,3 @@ func (c *Connection_ValidNamespaces_OngoingVerification) GetCapturedArguments()
func (c *Connection_ValidNamespaces_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) ValidPods(_param0 string) *Connection_ValidPods_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ValidPods", params, verifier.timeout)
return &Connection_ValidPods_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_ValidPods_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_ValidPods_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *Connection_ValidPods_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}

View File

@ -56,7 +56,7 @@ type (
IsNamespaced(n string) bool
SupportsResource(group string) bool
ValidNamespaces() ([]v1.Namespace, error)
ValidPods(node string) ([]v1.Pod, error)
NodePods(node string) (*v1.PodList, error)
SupportsRes(grp string, versions []string) (string, bool)
ServerVersion() (*version.Info, error)
FetchNodes() (*v1.NodeList, error)
@ -102,21 +102,17 @@ func (a *APIClient) ValidNamespaces() ([]v1.Namespace, error) {
return nn.Items, nil
}
// ValidPods returns a collection of all available pods on a given node.
func (a *APIClient) ValidPods(node string) ([]v1.Pod, error) {
// NodePods returns a collection of all available pods on a given node.
func (a *APIClient) NodePods(node string) (*v1.PodList, error) {
const selFmt = "spec.nodeName=%s,status.phase!=%s,status.phase!=%s"
fieldSelector, err := fields.ParseSelector(fmt.Sprintf(selFmt, node, v1.PodSucceeded, v1.PodFailed))
if err != nil {
return nil, err
}
pods, err := a.DialOrDie().Core().Pods("").List(metav1.ListOptions{
return a.DialOrDie().Core().Pods("").List(metav1.ListOptions{
FieldSelector: fieldSelector.String(),
})
if err != nil {
return nil, err
}
return pods.Items, nil
}
// IsNamespaced check on server if given resource is namespaced

View File

@ -58,11 +58,6 @@ func (c *Cluster) UserName() string {
}
// GetNodes get all available nodes in the cluster.
func (c *Cluster) GetNodes() ([]v1.Node, error) {
list, err := c.FetchNodes()
if err != nil {
return nil, err
}
return list.Items, nil
func (c *Cluster) GetNodes() (*v1.NodeList, error) {
return c.FetchNodes()
}

View File

@ -48,17 +48,18 @@ func NewMetricsServer(c Connection) *MetricsServer {
}
// NodesMetrics retrieves metrics for a given set of nodes.
func (m *MetricsServer) NodesMetrics(nodes []v1.Node, metrics []mv1beta1.NodeMetrics, mmx NodesMetrics) {
func (m *MetricsServer) NodesMetrics(nodes Collection, metrics *mv1beta1.NodeMetricsList, mmx NodesMetrics) {
for _, n := range nodes {
mmx[n.Name] = NodeMetrics{
AvailCPU: n.Status.Allocatable.Cpu().MilliValue(),
AvailMEM: ToMB(n.Status.Allocatable.Memory().Value()),
TotalCPU: n.Status.Capacity.Cpu().MilliValue(),
TotalMEM: ToMB(n.Status.Capacity.Memory().Value()),
no := n.(v1.Node)
mmx[no.Name] = NodeMetrics{
AvailCPU: no.Status.Allocatable.Cpu().MilliValue(),
AvailMEM: ToMB(no.Status.Allocatable.Memory().Value()),
TotalCPU: no.Status.Capacity.Cpu().MilliValue(),
TotalMEM: ToMB(no.Status.Capacity.Memory().Value()),
}
}
for _, c := range metrics {
for _, c := range metrics.Items {
if mx, ok := mmx[c.Name]; ok {
mx.CurrentCPU = c.Usage.Cpu().MilliValue()
mx.CurrentMEM = ToMB(c.Usage.Memory().Value())
@ -68,19 +69,17 @@ func (m *MetricsServer) NodesMetrics(nodes []v1.Node, metrics []mv1beta1.NodeMet
}
// ClusterLoad retrieves all cluster nodes metrics.
func (m *MetricsServer) ClusterLoad(nodes []v1.Node, metrics []mv1beta1.NodeMetrics) ClusterMetrics {
nodeMetrics := make(NodesMetrics, len(nodes))
func (m *MetricsServer) ClusterLoad(nodes *v1.NodeList, metrics *mv1beta1.NodeMetricsList, mx *ClusterMetrics) {
nodeMetrics := make(NodesMetrics, len(nodes.Items))
for _, n := range nodes {
for _, n := range nodes.Items {
nodeMetrics[n.Name] = NodeMetrics{
AvailCPU: n.Status.Allocatable.Cpu().MilliValue(),
AvailMEM: ToMB(n.Status.Allocatable.Memory().Value()),
TotalCPU: n.Status.Capacity.Cpu().MilliValue(),
TotalMEM: ToMB(n.Status.Capacity.Memory().Value()),
}
}
for _, mx := range metrics {
for _, mx := range metrics.Items {
if m, ok := nodeMetrics[mx.Name]; ok {
m.CurrentCPU = mx.Usage.Cpu().MilliValue()
m.CurrentMEM = ToMB(mx.Usage.Memory().Value())
@ -96,41 +95,33 @@ func (m *MetricsServer) ClusterLoad(nodes []v1.Node, metrics []mv1beta1.NodeMetr
tmem += mx.AvailMEM
}
return ClusterMetrics{PercCPU: toPerc(cpu, tcpu), PercMEM: toPerc(mem, tmem)}
mx.PercCPU, mx.PercMEM = toPerc(cpu, tcpu), toPerc(mem, tmem)
}
// FetchNodesMetrics return all metrics for pods in a given namespace.
func (m *MetricsServer) FetchNodesMetrics() ([]mv1beta1.NodeMetrics, error) {
func (m *MetricsServer) FetchNodesMetrics() (*mv1beta1.NodeMetricsList, error) {
client, err := m.MXDial()
if err != nil {
return nil, err
}
list, err := client.Metrics().NodeMetricses().List(metav1.ListOptions{})
if err != nil {
return nil, err
}
return list.Items, nil
return client.Metrics().NodeMetricses().List(metav1.ListOptions{})
}
// FetchPodsMetrics return all metrics for pods in a given namespace.
func (m *MetricsServer) FetchPodsMetrics(ns string) ([]mv1beta1.PodMetrics, error) {
func (m *MetricsServer) FetchPodsMetrics(ns string) (*mv1beta1.PodMetricsList, error) {
client, err := m.MXDial()
if err != nil {
return nil, err
}
list, err := client.Metrics().PodMetricses(ns).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
return list.Items, nil
return client.Metrics().PodMetricses(ns).List(metav1.ListOptions{})
}
// PodsMetrics retrieves metrics for all pods in a given namespace.
func (m *MetricsServer) PodsMetrics(pods []mv1beta1.PodMetrics, mmx PodsMetrics) {
func (m *MetricsServer) PodsMetrics(pods *mv1beta1.PodMetricsList, mmx PodsMetrics) {
// Compute all pod's containers metrics.
for _, p := range pods {
for _, p := range pods.Items {
var mx PodMetrics
for _, c := range p.Containers {
mx.CurrentCPU += c.Usage.Cpu().MilliValue()

View File

@ -21,7 +21,7 @@ func TestPodsMetrics(t *testing.T) {
}
mmx := make(PodsMetrics)
m.PodsMetrics(metrics.Items, mmx)
m.PodsMetrics(&metrics, mmx)
assert.Equal(t, 2, len(mmx))
mx, ok := mmx["default/p1"]
@ -45,18 +45,16 @@ func BenchmarkPodsMetrics(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
m.PodsMetrics(metrics.Items, mmx)
m.PodsMetrics(&metrics, mmx)
}
}
func TestNodesMetrics(t *testing.T) {
m := NewMetricsServer(nil)
nodes := v1.NodeList{
Items: []v1.Node{
makeNode("n1", "32", "128Gi", "50m", "2Mi"),
makeNode("n2", "8", "4Gi", "50m", "2Mi"),
},
nodes := Collection{
makeNode("n1", "32", "128Gi", "50m", "2Mi"),
makeNode("n2", "8", "4Gi", "50m", "2Mi"),
}
metrics := v1beta1.NodeMetricsList{
@ -67,7 +65,7 @@ func TestNodesMetrics(t *testing.T) {
}
mmx := make(NodesMetrics)
m.NodesMetrics(nodes.Items, metrics.Items, mmx)
m.NodesMetrics(nodes, &metrics, mmx)
assert.Equal(t, 2, len(mmx))
mx, ok := mmx["n1"]
assert.True(t, ok)
@ -80,11 +78,9 @@ func TestNodesMetrics(t *testing.T) {
}
func BenchmarkNodesMetrics(b *testing.B) {
nodes := v1.NodeList{
Items: []v1.Node{
makeNode("n1", "100m", "4Mi", "50m", "2Mi"),
makeNode("n2", "100m", "4Mi", "50m", "2Mi"),
},
nodes := Collection{
makeNode("n1", "100m", "4Mi", "50m", "2Mi"),
makeNode("n2", "100m", "4Mi", "50m", "2Mi"),
}
metrics := v1beta1.NodeMetricsList{
@ -100,7 +96,7 @@ func BenchmarkNodesMetrics(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
m.NodesMetrics(nodes.Items, metrics.Items, mmx)
m.NodesMetrics(nodes, &metrics, mmx)
}
}
@ -121,7 +117,8 @@ func TestClusterLoad(t *testing.T) {
},
}
mx := m.ClusterLoad(nodes.Items, metrics.Items)
var mx ClusterMetrics
m.ClusterLoad(&nodes, &metrics, &mx)
assert.Equal(t, 100.0, mx.PercCPU)
assert.Equal(t, 50.0, mx.PercMEM)
}
@ -142,11 +139,11 @@ func BenchmarkClusterLoad(b *testing.B) {
}
m := NewMetricsServer(nil)
var mx ClusterMetrics
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
m.ClusterLoad(nodes.Items, metrics.Items)
m.ClusterLoad(&nodes, &metrics, &mx)
}
}

View File

@ -16,23 +16,23 @@ type (
ContextName() string
ClusterName() string
UserName() string
GetNodes() ([]v1.Node, error)
GetNodes() (*v1.NodeList, error)
}
// MetricsServer gather metrics information from pods and nodes.
MetricsServer interface {
MetricsService
ClusterLoad([]v1.Node, []mv1beta1.NodeMetrics) k8s.ClusterMetrics
NodesMetrics([]v1.Node, []mv1beta1.NodeMetrics, k8s.NodesMetrics)
PodsMetrics([]mv1beta1.PodMetrics, k8s.PodsMetrics)
ClusterLoad(*v1.NodeList, *mv1beta1.NodeMetricsList, *k8s.ClusterMetrics)
NodesMetrics(k8s.Collection, *mv1beta1.NodeMetricsList, k8s.NodesMetrics)
PodsMetrics(*mv1beta1.PodMetricsList, k8s.PodsMetrics)
}
// MetricsService calls the metrics server for metrics info.
MetricsService interface {
HasMetrics() bool
FetchNodesMetrics() ([]mv1beta1.NodeMetrics, error)
FetchPodsMetrics(ns string) ([]mv1beta1.PodMetrics, error)
FetchNodesMetrics() (*mv1beta1.NodeMetricsList, error)
FetchPodsMetrics(ns string) (*mv1beta1.PodMetricsList, error)
}
// Cluster represents a kubernetes resource.
@ -78,16 +78,16 @@ func (c *Cluster) UserName() string {
}
// Metrics gathers node level metrics and compute utilization percentages.
func (c *Cluster) Metrics(nodes []v1.Node, nmx []mv1beta1.NodeMetrics) k8s.ClusterMetrics {
return c.mx.ClusterLoad(nodes, nmx)
func (c *Cluster) Metrics(nodes *v1.NodeList, nmx *mv1beta1.NodeMetricsList, mx *k8s.ClusterMetrics) {
c.mx.ClusterLoad(nodes, nmx, mx)
}
// FetchNodesMetrics fetch all nodes metrics.
func (c *Cluster) FetchNodesMetrics() ([]mv1beta1.NodeMetrics, error) {
func (c *Cluster) FetchNodesMetrics() (*mv1beta1.NodeMetricsList, error) {
return c.mx.FetchNodesMetrics()
}
// GetNodes fetch all available nodes.
func (c *Cluster) GetNodes() ([]v1.Node, error) {
func (c *Cluster) GetNodes() (*v1.NodeList, error) {
return c.api.GetNodes()
}

View File

@ -54,34 +54,35 @@ func TestUserName(t *testing.T) {
func TestClusterMetrics(t *testing.T) {
mm, mx := NewMockClusterMeta(), NewMockMetricsServer()
m.When(mx.ClusterLoad([]v1.Node{}, []mv1beta1.NodeMetrics{})).ThenReturn(clusterMetric())
mxx := clusterMetric()
c := resource.NewClusterWithArgs(mm, mx)
assert.Equal(t, clusterMetric(), c.Metrics([]v1.Node{}, []mv1beta1.NodeMetrics{}))
c.Metrics(&v1.NodeList{}, &mv1beta1.NodeMetricsList{}, &mxx)
assert.Equal(t, clusterMetric(), mxx)
}
func TestClusterGetNodes(t *testing.T) {
mm, mx := NewMockClusterMeta(), NewMockMetricsServer()
m.When(mm.GetNodes()).ThenReturn([]v1.Node{*k8sNode()}, nil)
m.When(mx.ClusterLoad([]v1.Node{}, []mv1beta1.NodeMetrics{})).ThenReturn(clusterMetric())
m.When(mm.GetNodes()).ThenReturn(&v1.NodeList{Items: []v1.Node{*k8sNode()}}, nil)
c := resource.NewClusterWithArgs(mm, mx)
nodes, err := c.GetNodes()
assert.Nil(t, err)
assert.Equal(t, 1, len(nodes))
assert.Equal(t, 1, len(nodes.Items))
}
func TestClusterFetchNodesMetrics(t *testing.T) {
mm, mx := NewMockClusterMeta(), NewMockMetricsServer()
m.When(mm.GetNodes()).ThenReturn([]v1.Node{*k8sNode()}, nil)
m.When(mx.FetchNodesMetrics()).ThenReturn([]mv1beta1.NodeMetrics{makeMxNode("fred", "100m", "10Mi")}, nil)
m.When(mm.GetNodes()).ThenReturn(&v1.NodeList{Items: []v1.Node{*k8sNode()}}, nil)
m.When(mx.FetchNodesMetrics()).ThenReturn(&mv1beta1.NodeMetricsList{Items: []mv1beta1.NodeMetrics{makeMxNode("fred", "100m", "10Mi")}}, nil)
c := resource.NewClusterWithArgs(mm, mx)
metrics, err := c.FetchNodesMetrics()
assert.Nil(t, err)
assert.Equal(t, 1, len(metrics))
assert.Equal(t, 1, len(metrics.Items))
}
// Helpers...

View File

@ -100,7 +100,7 @@ func (r *Container) Logs(c chan<- string, ns, n, co string, lines int64, prev bo
// This call will block if nothing is in the stream!!
stream, err := req.Stream()
if err != nil {
log.Error().Msgf("Tail logs failed `%s/%s:%s -- %v", ns, n, co, err)
log.Warn().Err(err).Msgf("Stream canceled `%s/%s:%s", ns, n, co)
return cancel, err
}
@ -178,7 +178,7 @@ func (r *Container) Fields(ns string) Row {
mxs, _ := r.MetricsServer.FetchPodsMetrics(r.pod.Namespace)
var cpu, mem string
for _, mx := range mxs {
for _, mx := range mxs.Items {
if mx.Name != r.pod.Name {
continue
}

View File

@ -1,7 +1,6 @@
package resource
import (
"fmt"
"strconv"
"strings"
@ -105,11 +104,11 @@ func (r *Endpoints) toEPs(ss []v1.EndpointSubset) string {
for _, a := range s.Addresses {
if len(a.IP) != 0 {
if len(pp) == 0 {
aa = append(aa, fmt.Sprintf("%s", a.IP))
aa = append(aa, a.IP)
} else {
add := fmt.Sprintf("%s:%s", a.IP, strings.Join(pp, ","))
add := a.IP + ":" + strings.Join(pp, ",")
if len(pp) > max {
add = fmt.Sprintf("%s:%s...", a.IP, strings.Join(pp[:max], ","))
add = a.IP + ":" + strings.Join(pp[:max], ",") + "..."
}
aa = append(aa, add)
}

View File

@ -1,7 +1,6 @@
package resource
import (
"fmt"
"path"
"sort"
"strconv"
@ -36,10 +35,12 @@ const (
NAValue = "<n/a>"
)
func asPerc(f float64) string {
return fmt.Sprintf("%d%%", int(f))
// AsPerc prints a number as a percentage.
func AsPerc(f float64) string {
return strconv.Itoa(int(f)) + "%"
}
// ToPerc computes the ratio of two numbers as a percentage.
func toPerc(v1, v2 float64) float64 {
if v2 == 0 {
return 0

View File

@ -148,3 +148,28 @@ func TestToMi(t *testing.T) {
assert.Equal(t, u.e, ToMi(u.v))
}
}
func TestAsPerc(t *testing.T) {
uu := []struct {
v float64
e string
}{
{0, "0%"},
{10.5, "10%"},
{10, "10%"},
{0.05, "0%"},
}
for _, u := range uu {
assert.Equal(t, u.e, AsPerc(u.v))
}
}
func BenchmarkAsPerc(b *testing.B) {
v := 10.5
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
AsPerc(v)
}
}

View File

@ -1,7 +1,6 @@
package resource
import (
"fmt"
"strconv"
"strings"
@ -121,12 +120,12 @@ func (r *HorizontalPodAutoscalerV2Beta1) toMetrics(specs []autoscalingv2beta1.Me
if len(statuses) > i && statuses[i].Pods != nil {
current = statuses[i].Pods.CurrentAverageValue.String()
}
list = append(list, fmt.Sprintf("%s/%s", current, spec.Pods.TargetAverageValue.String()))
list = append(list, current+"/"+spec.Pods.TargetAverageValue.String())
case autoscalingv2beta1.ObjectMetricSourceType:
if len(statuses) > i && statuses[i].Object != nil {
current = statuses[i].Object.CurrentValue.String()
}
list = append(list, fmt.Sprintf("%s/%s", current, spec.Object.TargetValue.String()))
list = append(list, current+"/"+spec.Object.TargetValue.String())
case autoscalingv2beta1.ResourceMetricSourceType:
list = append(list, r.resourceMetrics(i, spec, statuses))
default:
@ -141,7 +140,7 @@ func (r *HorizontalPodAutoscalerV2Beta1) toMetrics(specs []autoscalingv2beta1.Me
ret := strings.Join(list, ", ")
if more {
return fmt.Sprintf("%s + %d more...", ret, count-max)
return ret + " + " + strconv.Itoa(count-max) + "more..."
}
return ret
@ -154,13 +153,13 @@ func (*HorizontalPodAutoscalerV2Beta1) externalMetrics(i int, spec autoscalingv2
if len(statuses) > i && statuses[i].External != nil && &statuses[i].External.CurrentAverageValue != nil {
current = statuses[i].External.CurrentAverageValue.String()
}
return fmt.Sprintf("%s/%s (avg)", current, spec.External.TargetAverageValue.String())
return current + "/" + spec.External.TargetAverageValue.String() + " (avg)"
}
if len(statuses) > i && statuses[i].External != nil {
current = statuses[i].External.CurrentValue.String()
}
return fmt.Sprintf("%s/%s", current, spec.External.TargetValue.String())
return current + "/" + spec.External.TargetValue.String()
}
func (*HorizontalPodAutoscalerV2Beta1) resourceMetrics(i int, spec autoscalingv2beta1.MetricSpec, statuses []autoscalingv2beta1.MetricStatus) string {
@ -170,16 +169,17 @@ func (*HorizontalPodAutoscalerV2Beta1) resourceMetrics(i int, spec autoscalingv2
if len(statuses) > i && statuses[i].Resource != nil {
current = statuses[i].Resource.CurrentAverageValue.String()
}
return fmt.Sprintf("%s/%s", current, spec.Resource.TargetAverageValue.String())
return current + "/" + spec.Resource.TargetAverageValue.String()
}
if len(statuses) > i && statuses[i].Resource != nil && statuses[i].Resource.CurrentAverageUtilization != nil {
current = fmt.Sprintf("%d%%", *statuses[i].Resource.CurrentAverageUtilization)
current = AsPerc(float64(*statuses[i].Resource.CurrentAverageUtilization))
}
target := "<auto>"
if spec.Resource.TargetAverageUtilization != nil {
target = fmt.Sprintf("%d%%", *spec.Resource.TargetAverageUtilization)
target = AsPerc(float64(*spec.Resource.TargetAverageUtilization))
}
return fmt.Sprintf("%s/%s", current, target)
return current + "/" + target
}

View File

@ -1,7 +1,6 @@
package resource
import (
"fmt"
"strconv"
"strings"
@ -121,12 +120,12 @@ func toMetrics(specs []autoscalingv2beta2.MetricSpec, statuses []autoscalingv2be
if len(statuses) > i && statuses[i].Pods != nil {
current = statuses[i].Pods.Current.AverageValue.String()
}
list = append(list, fmt.Sprintf("%s/%s", current, spec.Pods.Target.AverageValue.String()))
list = append(list, current+"/"+spec.Pods.Target.AverageValue.String())
case autoscalingv2beta2.ObjectMetricSourceType:
if len(statuses) > i && statuses[i].Object != nil {
current = statuses[i].Object.Current.Value.String()
}
list = append(list, fmt.Sprintf("%s/%s", current, spec.Object.Target.Value.String()))
list = append(list, current+"/"+spec.Object.Target.Value.String())
case autoscalingv2beta2.ResourceMetricSourceType:
list = append(list, resourceMetrics(i, spec, statuses))
default:
@ -141,7 +140,7 @@ func toMetrics(specs []autoscalingv2beta2.MetricSpec, statuses []autoscalingv2be
ret := strings.Join(list, ", ")
if more {
return fmt.Sprintf("%s + %d more...", ret, count-max)
return ret + " + " + strconv.Itoa(count-max) + "more..."
}
return ret
@ -154,13 +153,13 @@ func externalMetrics(i int, spec autoscalingv2beta2.MetricSpec, statuses []autos
if len(statuses) > i && statuses[i].External != nil && &statuses[i].External.Current.AverageValue != nil {
current = statuses[i].External.Current.AverageValue.String()
}
return fmt.Sprintf("%s/%s (avg)", current, spec.External.Target.AverageValue.String())
return current + "/" + spec.External.Target.AverageValue.String() + " (avg)"
}
if len(statuses) > i && statuses[i].External != nil {
current = statuses[i].External.Current.Value.String()
}
return fmt.Sprintf("%s/%s", current, spec.External.Target.Value.String())
return current + "/" + spec.External.Target.Value.String()
}
func resourceMetrics(i int, spec autoscalingv2beta2.MetricSpec, statuses []autoscalingv2beta2.MetricStatus) string {
@ -170,16 +169,17 @@ func resourceMetrics(i int, spec autoscalingv2beta2.MetricSpec, statuses []autos
if len(statuses) > i && statuses[i].Resource != nil {
current = statuses[i].Resource.Current.AverageValue.String()
}
return fmt.Sprintf("%s/%s", current, spec.Resource.Target.AverageValue.String())
return current + "/" + spec.Resource.Target.AverageValue.String()
}
if len(statuses) > i && statuses[i].Resource != nil && statuses[i].Resource.Current.AverageUtilization != nil {
current = fmt.Sprintf("%d%%", *statuses[i].Resource.Current.AverageUtilization)
current = AsPerc(float64(*statuses[i].Resource.Current.AverageUtilization))
}
target := "<auto>"
if spec.Resource.Target.AverageUtilization != nil {
target = fmt.Sprintf("%d%%", *spec.Resource.Target.AverageUtilization)
target = AsPerc(float64(*spec.Resource.Target.AverageUtilization))
}
return fmt.Sprintf("%s/%s", current, target)
return current + "/" + target
}

View File

@ -4,6 +4,7 @@ import (
"bufio"
"context"
"fmt"
"strconv"
"strings"
"time"
@ -166,10 +167,10 @@ func (*Job) toContainers(p v1.PodSpec) (string, string) {
const maxShow = 2
// Limit to 2 of each...
if len(cc) > maxShow {
cc = append(cc[:2], fmt.Sprintf("(+%d)...", len(cc)-maxShow))
cc = append(cc[:2], "(+"+strconv.Itoa(len(cc)-maxShow)+")...")
}
if len(ii) > maxShow {
ii = append(ii[:2], fmt.Sprintf("(+%d)...", len(ii)-maxShow))
ii = append(ii[:2], "(+"+strconv.Itoa(len(ii)-maxShow)+")...")
}
return strings.Join(cc, ","), strings.Join(ii, ",")
@ -177,19 +178,19 @@ func (*Job) toContainers(p v1.PodSpec) (string, string) {
func (*Job) toCompletion(spec batchv1.JobSpec, status batchv1.JobStatus) (s string) {
if spec.Completions != nil {
return fmt.Sprintf("%d/%d", status.Succeeded, *spec.Completions)
return strconv.Itoa(int(status.Succeeded)) + "/" + strconv.Itoa(int(*spec.Completions))
}
if spec.Parallelism == nil {
return fmt.Sprintf("%d/1", status.Succeeded)
return strconv.Itoa(int(status.Succeeded)) + "/1"
}
p := *spec.Parallelism
if p > 1 {
return fmt.Sprintf("%d/1 of %d", status.Succeeded, p)
return strconv.Itoa(int(status.Succeeded)) + "/1 of " + strconv.Itoa(int(p))
}
return fmt.Sprintf("%d/1", status.Succeeded)
return strconv.Itoa(int(status.Succeeded)) + "/1"
}
func (*Job) toDuration(status batchv1.JobStatus) string {

View File

@ -217,12 +217,8 @@ func (l *list) Data() TableData {
// Reconcile previous vs current state and emits delta events.
func (l *list) Reconcile() error {
var (
items Columnars
err error
)
if items, err = l.resource.List(l.namespace); err != nil {
items, err := l.resource.List(l.namespace)
if err != nil {
return err
}

View File

@ -118,17 +118,17 @@ func (mock *MockClusterMeta) FetchNodes() (*v1.NodeList, error) {
return ret0, ret1
}
func (mock *MockClusterMeta) GetNodes() ([]v1.Node, error) {
func (mock *MockClusterMeta) GetNodes() (*v1.NodeList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("GetNodes", params, []reflect.Type{reflect.TypeOf((*[]v1.Node)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1.Node
result := pegomock.GetGenericMockFrom(mock).Invoke("GetNodes", params, []reflect.Type{reflect.TypeOf((**v1.NodeList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1.NodeList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1.Node)
ret0 = result[0].(*v1.NodeList)
}
if result[1] != nil {
ret1 = result[1].(error)
@ -201,6 +201,25 @@ func (mock *MockClusterMeta) NSDialOrDie() dynamic.NamespaceableResourceInterfac
return ret0
}
func (mock *MockClusterMeta) NodePods(_param0 string) (*v1.PodList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("NodePods", params, []reflect.Type{reflect.TypeOf((**v1.PodList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1.PodList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*v1.PodList)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockClusterMeta) RestConfigOrDie() *rest.Config {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
@ -311,25 +330,6 @@ func (mock *MockClusterMeta) ValidNamespaces() ([]v1.Namespace, error) {
return ret0, ret1
}
func (mock *MockClusterMeta) ValidPods(_param0 string) ([]v1.Pod, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("ValidPods", params, []reflect.Type{reflect.TypeOf((*[]v1.Pod)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1.Pod
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1.Pod)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockClusterMeta) Version() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
@ -583,6 +583,33 @@ func (c *ClusterMeta_NSDialOrDie_OngoingVerification) GetCapturedArguments() {
func (c *ClusterMeta_NSDialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) NodePods(_param0 string) *ClusterMeta_NodePods_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NodePods", params, verifier.timeout)
return &ClusterMeta_NodePods_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_NodePods_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_NodePods_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *ClusterMeta_NodePods_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierClusterMeta) RestConfigOrDie() *ClusterMeta_RestConfigOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RestConfigOrDie", params, verifier.timeout)
@ -736,33 +763,6 @@ func (c *ClusterMeta_ValidNamespaces_OngoingVerification) GetCapturedArguments()
func (c *ClusterMeta_ValidNamespaces_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) ValidPods(_param0 string) *ClusterMeta_ValidPods_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ValidPods", params, verifier.timeout)
return &ClusterMeta_ValidPods_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_ValidPods_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_ValidPods_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *ClusterMeta_ValidPods_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierClusterMeta) Version() *ClusterMeta_Version_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Version", params, verifier.timeout)

View File

@ -152,6 +152,25 @@ func (mock *MockConnection) NSDialOrDie() dynamic.NamespaceableResourceInterface
return ret0
}
func (mock *MockConnection) NodePods(_param0 string) (*v1.PodList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("NodePods", params, []reflect.Type{reflect.TypeOf((**v1.PodList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1.PodList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*v1.PodList)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockConnection) RestConfigOrDie() *rest.Config {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
@ -247,25 +266,6 @@ func (mock *MockConnection) ValidNamespaces() ([]v1.Namespace, error) {
return ret0, ret1
}
func (mock *MockConnection) ValidPods(_param0 string) ([]v1.Pod, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("ValidPods", params, []reflect.Type{reflect.TypeOf((*[]v1.Pod)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1.Pod
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1.Pod)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockConnection) VerifyWasCalledOnce() *VerifierConnection {
return &VerifierConnection{
mock: mock,
@ -449,6 +449,33 @@ func (c *Connection_NSDialOrDie_OngoingVerification) GetCapturedArguments() {
func (c *Connection_NSDialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) NodePods(_param0 string) *Connection_NodePods_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NodePods", params, verifier.timeout)
return &Connection_NodePods_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_NodePods_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_NodePods_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *Connection_NodePods_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierConnection) RestConfigOrDie() *Connection_RestConfigOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RestConfigOrDie", params, verifier.timeout)
@ -584,30 +611,3 @@ func (c *Connection_ValidNamespaces_OngoingVerification) GetCapturedArguments()
func (c *Connection_ValidNamespaces_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) ValidPods(_param0 string) *Connection_ValidPods_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ValidPods", params, verifier.timeout)
return &Connection_ValidPods_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_ValidPods_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_ValidPods_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *Connection_ValidPods_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}

View File

@ -20,32 +20,25 @@ func NewMockMetricsServer() *MockMetricsServer {
return &MockMetricsServer{fail: pegomock.GlobalFailHandler}
}
func (mock *MockMetricsServer) ClusterLoad(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics) k8s.ClusterMetrics {
func (mock *MockMetricsServer) ClusterLoad(_param0 *v1.NodeList, _param1 *v1beta1.NodeMetricsList, _param2 *k8s.ClusterMetrics) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{_param0, _param1}
result := pegomock.GetGenericMockFrom(mock).Invoke("ClusterLoad", params, []reflect.Type{reflect.TypeOf((*k8s.ClusterMetrics)(nil)).Elem()})
var ret0 k8s.ClusterMetrics
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(k8s.ClusterMetrics)
}
}
return ret0
params := []pegomock.Param{_param0, _param1, _param2}
pegomock.GetGenericMockFrom(mock).Invoke("ClusterLoad", params, []reflect.Type{})
}
func (mock *MockMetricsServer) FetchNodesMetrics() ([]v1beta1.NodeMetrics, error) {
func (mock *MockMetricsServer) FetchNodesMetrics() (*v1beta1.NodeMetricsList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchNodesMetrics", params, []reflect.Type{reflect.TypeOf((*[]v1beta1.NodeMetrics)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1beta1.NodeMetrics
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchNodesMetrics", params, []reflect.Type{reflect.TypeOf((**v1beta1.NodeMetricsList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1beta1.NodeMetricsList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1beta1.NodeMetrics)
ret0 = result[0].(*v1beta1.NodeMetricsList)
}
if result[1] != nil {
ret1 = result[1].(error)
@ -54,17 +47,17 @@ func (mock *MockMetricsServer) FetchNodesMetrics() ([]v1beta1.NodeMetrics, error
return ret0, ret1
}
func (mock *MockMetricsServer) FetchPodsMetrics(_param0 string) ([]v1beta1.PodMetrics, error) {
func (mock *MockMetricsServer) FetchPodsMetrics(_param0 string) (*v1beta1.PodMetricsList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchPodsMetrics", params, []reflect.Type{reflect.TypeOf((*[]v1beta1.PodMetrics)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1beta1.PodMetrics
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchPodsMetrics", params, []reflect.Type{reflect.TypeOf((**v1beta1.PodMetricsList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1beta1.PodMetricsList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1beta1.PodMetrics)
ret0 = result[0].(*v1beta1.PodMetricsList)
}
if result[1] != nil {
ret1 = result[1].(error)
@ -88,7 +81,7 @@ func (mock *MockMetricsServer) HasMetrics() bool {
return ret0
}
func (mock *MockMetricsServer) NodesMetrics(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics, _param2 k8s.NodesMetrics) {
func (mock *MockMetricsServer) NodesMetrics(_param0 k8s.Collection, _param1 *v1beta1.NodeMetricsList, _param2 k8s.NodesMetrics) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
@ -96,7 +89,7 @@ func (mock *MockMetricsServer) NodesMetrics(_param0 []v1.Node, _param1 []v1beta1
pegomock.GetGenericMockFrom(mock).Invoke("NodesMetrics", params, []reflect.Type{})
}
func (mock *MockMetricsServer) PodsMetrics(_param0 []v1beta1.PodMetrics, _param1 k8s.PodsMetrics) {
func (mock *MockMetricsServer) PodsMetrics(_param0 *v1beta1.PodMetricsList, _param1 k8s.PodsMetrics) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
@ -141,8 +134,8 @@ type VerifierMetricsServer struct {
timeout time.Duration
}
func (verifier *VerifierMetricsServer) ClusterLoad(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics) *MetricsServer_ClusterLoad_OngoingVerification {
params := []pegomock.Param{_param0, _param1}
func (verifier *VerifierMetricsServer) ClusterLoad(_param0 *v1.NodeList, _param1 *v1beta1.NodeMetricsList, _param2 *k8s.ClusterMetrics) *MetricsServer_ClusterLoad_OngoingVerification {
params := []pegomock.Param{_param0, _param1, _param2}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ClusterLoad", params, verifier.timeout)
return &MetricsServer_ClusterLoad_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
@ -152,21 +145,25 @@ type MetricsServer_ClusterLoad_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetCapturedArguments() ([]v1.Node, []v1beta1.NodeMetrics) {
_param0, _param1 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1]
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetCapturedArguments() (*v1.NodeList, *v1beta1.NodeMetricsList, *k8s.ClusterMetrics) {
_param0, _param1, _param2 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1]
}
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1.Node, _param1 [][]v1beta1.NodeMetrics) {
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetAllCapturedArguments() (_param0 []*v1.NodeList, _param1 []*v1beta1.NodeMetricsList, _param2 []*k8s.ClusterMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1.Node, len(params[0]))
_param0 = make([]*v1.NodeList, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1.Node)
_param0[u] = param.(*v1.NodeList)
}
_param1 = make([][]v1beta1.NodeMetrics, len(params[1]))
_param1 = make([]*v1beta1.NodeMetricsList, len(params[1]))
for u, param := range params[1] {
_param1[u] = param.([]v1beta1.NodeMetrics)
_param1[u] = param.(*v1beta1.NodeMetricsList)
}
_param2 = make([]*k8s.ClusterMetrics, len(params[2]))
for u, param := range params[2] {
_param2[u] = param.(*k8s.ClusterMetrics)
}
}
return
@ -233,7 +230,7 @@ func (c *MetricsServer_HasMetrics_OngoingVerification) GetCapturedArguments() {
func (c *MetricsServer_HasMetrics_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierMetricsServer) NodesMetrics(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics, _param2 k8s.NodesMetrics) *MetricsServer_NodesMetrics_OngoingVerification {
func (verifier *VerifierMetricsServer) NodesMetrics(_param0 k8s.Collection, _param1 *v1beta1.NodeMetricsList, _param2 k8s.NodesMetrics) *MetricsServer_NodesMetrics_OngoingVerification {
params := []pegomock.Param{_param0, _param1, _param2}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NodesMetrics", params, verifier.timeout)
return &MetricsServer_NodesMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
@ -244,21 +241,21 @@ type MetricsServer_NodesMetrics_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetCapturedArguments() ([]v1.Node, []v1beta1.NodeMetrics, k8s.NodesMetrics) {
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetCapturedArguments() (k8s.Collection, *v1beta1.NodeMetricsList, k8s.NodesMetrics) {
_param0, _param1, _param2 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1]
}
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1.Node, _param1 [][]v1beta1.NodeMetrics, _param2 []k8s.NodesMetrics) {
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 []k8s.Collection, _param1 []*v1beta1.NodeMetricsList, _param2 []k8s.NodesMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1.Node, len(params[0]))
_param0 = make([]k8s.Collection, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1.Node)
_param0[u] = param.(k8s.Collection)
}
_param1 = make([][]v1beta1.NodeMetrics, len(params[1]))
_param1 = make([]*v1beta1.NodeMetricsList, len(params[1]))
for u, param := range params[1] {
_param1[u] = param.([]v1beta1.NodeMetrics)
_param1[u] = param.(*v1beta1.NodeMetricsList)
}
_param2 = make([]k8s.NodesMetrics, len(params[2]))
for u, param := range params[2] {
@ -268,7 +265,7 @@ func (c *MetricsServer_NodesMetrics_OngoingVerification) GetAllCapturedArguments
return
}
func (verifier *VerifierMetricsServer) PodsMetrics(_param0 []v1beta1.PodMetrics, _param1 k8s.PodsMetrics) *MetricsServer_PodsMetrics_OngoingVerification {
func (verifier *VerifierMetricsServer) PodsMetrics(_param0 *v1beta1.PodMetricsList, _param1 k8s.PodsMetrics) *MetricsServer_PodsMetrics_OngoingVerification {
params := []pegomock.Param{_param0, _param1}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PodsMetrics", params, verifier.timeout)
return &MetricsServer_PodsMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
@ -279,17 +276,17 @@ type MetricsServer_PodsMetrics_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetCapturedArguments() ([]v1beta1.PodMetrics, k8s.PodsMetrics) {
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetCapturedArguments() (*v1beta1.PodMetricsList, k8s.PodsMetrics) {
_param0, _param1 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1]
}
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1beta1.PodMetrics, _param1 []k8s.PodsMetrics) {
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 []*v1beta1.PodMetricsList, _param1 []k8s.PodsMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1beta1.PodMetrics, len(params[0]))
_param0 = make([]*v1beta1.PodMetricsList, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1beta1.PodMetrics)
_param0[u] = param.(*v1beta1.PodMetricsList)
}
_param1 = make([]k8s.PodsMetrics, len(params[1]))
for u, param := range params[1] {

View File

@ -6,8 +6,6 @@ import (
"github.com/derailed/k9s/internal/k8s"
"github.com/rs/zerolog/log"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets"
)
@ -65,21 +63,17 @@ func (r *Node) List(ns string) (Columnars, error) {
return nil, err
}
nodes := make([]v1.Node, 0, len(nn))
for _, n := range nn {
nodes = append(nodes, n.(v1.Node))
}
mx := make(k8s.NodesMetrics, len(nodes))
mx := make(k8s.NodesMetrics, len(nn))
if r.MetricsServer.HasMetrics() {
nmx, _ := r.MetricsServer.FetchNodesMetrics()
r.MetricsServer.NodesMetrics(nodes, nmx, mx)
r.MetricsServer.NodesMetrics(nn, nmx, mx)
}
cc := make(Columnars, 0, len(nodes))
for i := range nodes {
no := r.New(&nodes[i]).(*Node)
no.metrics = mx[nodes[i].Name]
cc := make(Columnars, 0, len(nn))
for i := range nn {
node := nn[i].(v1.Node)
no := r.New(&node).(*Node)
no.metrics = mx[node.Name]
cc = append(cc, no)
}
@ -114,8 +108,8 @@ func (*Node) Header(ns string) Row {
"EXTERNAL-IP",
"CPU",
"MEM",
"RCPU",
"RMEM",
// "RCPU",
// "RMEM",
"ACPU",
"AMEM",
"AGE",
@ -130,31 +124,36 @@ func (r *Node) Fields(ns string) Row {
iIP, eIP := r.getIPs(i.Status.Addresses)
iIP, eIP = missing(iIP), missing(eIP)
reqs, _, err := r.fetchReqLimit(i.Name)
if err != nil {
if !errors.IsForbidden(err) {
log.Warn().Msgf("User is not authorized to list pods on nodes: %v", err)
}
log.Error().Msgf("%#v", err)
}
// reqs, _, err := r.podsResources(i.Name)
// if err != nil {
// if !errors.IsForbidden(err) {
// log.Warn().Msgf("User is not authorized to list pods on nodes: %v", err)
// }
// log.Error().Msgf("%#v", err)
// }
rcpu, rmem := reqs["cpu"], reqs["memory"]
pcpur := toPerc(float64(rcpu.MilliValue()), float64(r.metrics.AvailCPU))
pmemr := toPerc(k8s.ToMB(rmem.Value()), float64(r.metrics.AvailMEM))
// rcpu, rmem := reqs["cpu"], reqs["memory"]
// pcpur := toPerc(float64(rcpu.MilliValue()), float64(r.metrics.AvailCPU))
// pmemr := toPerc(k8s.ToMB(rmem.Value()), float64(r.metrics.AvailMEM))
return append(ff,
i.Name,
r.status(i),
r.status(i.Status, i.Spec.Unschedulable),
r.nodeRoles(i),
i.Status.NodeInfo.KubeletVersion,
i.Status.NodeInfo.KernelVersion,
iIP,
eIP,
withPerc(ToMillicore(r.metrics.CurrentCPU), asPerc(toPerc(float64(r.metrics.CurrentCPU), float64(r.metrics.AvailCPU)))),
withPerc(ToMi(r.metrics.CurrentMEM), asPerc(toPerc(r.metrics.CurrentMEM, r.metrics.AvailMEM))),
withPerc(rcpu.String(), asPerc(pcpur)),
withPerc(rmem.String(), asPerc(pmemr)),
withPerc(
ToMillicore(r.metrics.CurrentCPU),
AsPerc(toPerc(float64(r.metrics.CurrentCPU), float64(r.metrics.AvailCPU))),
),
withPerc(
ToMi(r.metrics.CurrentMEM),
AsPerc(toPerc(r.metrics.CurrentMEM, r.metrics.AvailMEM)),
),
// withPerc(rcpu.String(), AsPerc(pcpur)),
// withPerc(rmem.String(), AsPerc(pmemr)),
ToMillicore(r.metrics.AvailCPU),
ToMi(r.metrics.AvailMEM),
toAge(i.ObjectMeta.CreationTimestamp),
@ -190,6 +189,7 @@ func (*Node) nodeRoles(node *v1.Node) string {
if len(roles) == 0 {
return MissingValue
}
return strings.Join(roles.List(), ",")
}
@ -206,31 +206,35 @@ func (*Node) getIPs(addrs []v1.NodeAddress) (iIP, eIP string) {
return
}
func (r *Node) status(i *v1.Node) string {
conditionMap := make(map[v1.NodeConditionType]*v1.NodeCondition)
NodeAllConditions := []v1.NodeConditionType{v1.NodeReady}
for n := range i.Status.Conditions {
cond := i.Status.Conditions[n]
conditionMap[cond.Type] = &cond
}
var status []string
for _, validCondition := range NodeAllConditions {
if condition, ok := conditionMap[validCondition]; ok {
if condition.Status == v1.ConditionTrue {
status = append(status, string(condition.Type))
} else {
status = append(status, "Not"+string(condition.Type))
}
}
}
if len(status) == 0 {
status = append(status, "Unknown")
}
if i.Spec.Unschedulable {
status = append(status, "SchedulingDisabled")
func (*Node) status(status v1.NodeStatus, exempt bool) string {
conditions := make(map[v1.NodeConditionType]*v1.NodeCondition)
for n := range status.Conditions {
cond := status.Conditions[n]
conditions[cond.Type] = &cond
}
return strings.Join(status, ",")
var conds []string
validConditions := []v1.NodeConditionType{v1.NodeReady}
for _, validCondition := range validConditions {
condition, ok := conditions[validCondition]
if !ok {
continue
}
neg := ""
if condition.Status != v1.ConditionTrue {
neg = "Not"
}
conds = append(conds, neg+string(condition.Type))
}
if len(conds) == 0 {
conds = append(conds, "Unknown")
}
if exempt {
conds = append(conds, "SchedulingDisabled")
}
return strings.Join(conds, ",")
}
func findNodeRoles(i *v1.Node) []string {
@ -249,12 +253,14 @@ func findNodeRoles(i *v1.Node) []string {
return roles.List()
}
func (r *Node) fetchReqLimit(name string) (req, lim v1.ResourceList, err error) {
reqs, limits := map[v1.ResourceName]resource.Quantity{}, map[v1.ResourceName]resource.Quantity{}
pods, err := r.Connection.ValidPods(name)
for _, p := range pods {
preq, plim := podRequestsAndLimits(&p)
func (r *Node) podsResources(name string) (v1.ResourceList, v1.ResourceList, error) {
reqs, limits := v1.ResourceList{}, v1.ResourceList{}
pods, err := r.Connection.NodePods(name)
if err != nil {
return reqs, limits, err
}
for _, p := range pods.Items {
preq, plim := podResources(&p)
for k, v := range preq {
if value, ok := reqs[k]; !ok {
reqs[k] = *v.Copy()
@ -276,44 +282,42 @@ func (r *Node) fetchReqLimit(name string) (req, lim v1.ResourceList, err error)
return reqs, limits, nil
}
func podRequestsAndLimits(pod *v1.Pod) (reqs, limits v1.ResourceList) {
reqs, limits = map[v1.ResourceName]resource.Quantity{}, map[v1.ResourceName]resource.Quantity{}
func podResources(pod *v1.Pod) (v1.ResourceList, v1.ResourceList) {
reqs, limits := v1.ResourceList{}, v1.ResourceList{}
for _, container := range pod.Spec.Containers {
addResourceList(reqs, container.Resources.Requests)
addResourceList(limits, container.Resources.Limits)
addResources(reqs, container.Resources.Requests)
addResources(limits, container.Resources.Limits)
}
// init containers define the minimum of any resource
for _, container := range pod.Spec.InitContainers {
maxResourceList(reqs, container.Resources.Requests)
maxResourceList(limits, container.Resources.Limits)
maxResources(reqs, container.Resources.Requests)
maxResources(limits, container.Resources.Limits)
}
return
return reqs, limits
}
// addResourceList adds the resources in newList to list
func addResourceList(list, new v1.ResourceList) {
for name, quantity := range new {
if value, ok := list[name]; !ok {
list[name] = *quantity.Copy()
} else {
// AddResources adds the resources from l2 to l1.
func addResources(l1, l2 v1.ResourceList) {
for name, quantity := range l2 {
if value, ok := l1[name]; ok {
value.Add(quantity)
list[name] = value
l1[name] = value
} else {
l1[name] = *quantity.Copy()
}
}
}
// maxResourceList sets list to the greater of list/newList for every resource
// either list
func maxResourceList(list, new v1.ResourceList) {
for name, quantity := range new {
if value, ok := list[name]; !ok {
list[name] = *quantity.Copy()
continue
} else {
// MaxResourceList sets list to the greater of l1/l2 for every resource.
func maxResources(l1, l2 v1.ResourceList) {
for name, quantity := range l2 {
if value, ok := l1[name]; ok {
if quantity.Cmp(value) > 0 {
list[name] = *quantity.Copy()
l1[name] = *quantity.Copy()
}
} else {
l1[name] = *quantity.Copy()
}
}
}

View File

@ -0,0 +1,33 @@
package resource
import (
"testing"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
)
func TestNodeStatus(t *testing.T) {
uu := []struct {
s v1.NodeStatus
e string
}{
{
v1.NodeStatus{
Conditions: []v1.NodeCondition{
{
Type: v1.NodeReady,
Status: v1.ConditionTrue,
},
},
},
"Ready",
},
}
no := NewNode(nil, nil)
for _, u := range uu {
cond := no.status(u.s, false)
assert.Equal(t, "Ready", cond)
}
}

View File

@ -66,7 +66,7 @@ func TestNodeListData(t *testing.T) {
mx := NewMockMetricsServer()
m.When(mx.HasMetrics()).ThenReturn(true)
m.When(mx.FetchNodesMetrics()).
ThenReturn([]mv1beta1.NodeMetrics{makeMxNode("fred", "100m", "100Mi")}, nil)
ThenReturn(&mv1beta1.NodeMetricsList{Items: []mv1beta1.NodeMetrics{makeMxNode("fred", "100m", "100Mi")}}, nil)
l := NewNodeListWithArgs("-", NewNodeWithArgs(mc, mr, mx))
// Make sure we mrn get deltas!
@ -81,13 +81,14 @@ func TestNodeListData(t *testing.T) {
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
row, ok := td.Rows["fred"]
assert.True(t, ok)
assert.Equal(t, 14, len(row.Deltas))
assert.Equal(t, 12, len(row.Deltas))
for _, d := range row.Deltas {
assert.Equal(t, "", d)
}
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
}
// ----------------------------------------------------------------------------
// Helpers...
func k8sNode() *v1.Node {

View File

@ -3,7 +3,6 @@ package resource
import (
"bufio"
"context"
"fmt"
"strconv"
"sync"
"time"
@ -146,7 +145,7 @@ func (r *Pod) Logs(c chan<- string, ns, n, co string, lines int64, prev bool) (c
// This call will block if nothing is in the stream!!
stream, err := req.Stream()
if err != nil {
log.Error().Msgf("Tail logs failed `%s/%s:%s -- %v", ns, n, co, err)
log.Warn().Err(err).Msgf("Stream canceled `%s/%s:%s", ns, n, co)
return cancel, err
}
@ -194,9 +193,7 @@ func (r *Pod) List(ns string) (Columnars, error) {
cc := make(Columnars, 0, len(pods))
for i := range pods {
po := r.New(&pods[i]).(*Pod)
if err == nil {
po.metrics = mx[po.Name()]
}
po.metrics = mx[po.Name()]
cc = append(cc, po)
}
@ -320,9 +317,9 @@ func (*Pod) containerPhase(st v1.PodStatus, status string) (bool, string) {
status = cs.State.Terminated.Reason
case cs.State.Terminated != nil:
if cs.State.Terminated.Signal != 0 {
status = fmt.Sprintf("Signal:%d", cs.State.Terminated.Signal)
status = "Signal:" + strconv.Itoa(int(cs.State.Terminated.Signal))
} else {
status = fmt.Sprintf("ExitCode:%d", cs.State.Terminated.ExitCode)
status = "ExitCode:" + strconv.Itoa(int(cs.State.Terminated.ExitCode))
}
case cs.Ready && cs.State.Running != nil:
running = true
@ -345,14 +342,14 @@ func (*Pod) initContainerPhase(st v1.PodStatus, initCount int, status string) (b
break
}
if cs.State.Terminated.Signal != 0 {
status = fmt.Sprintf("Init:Signal:%d", cs.State.Terminated.Signal)
status = "Init:Signal:" + strconv.Itoa(int(cs.State.Terminated.Signal))
} else {
status = fmt.Sprintf("Init:ExitCode:%d", cs.State.Terminated.ExitCode)
status = "Init:ExitCode:" + strconv.Itoa(int(cs.State.Terminated.ExitCode))
}
case cs.State.Waiting != nil && cs.State.Waiting.Reason != "" && cs.State.Waiting.Reason != "PodInitializing":
status = "Init:" + cs.State.Waiting.Reason
default:
status = fmt.Sprintf("Init:%d/%d", i, initCount)
status = "Init:" + strconv.Itoa(i) + "/" + strconv.Itoa(initCount)
}
init = true
break

View File

@ -65,7 +65,7 @@ func TestPodListData(t *testing.T) {
mx := NewMockMetricsServer()
m.When(mx.HasMetrics()).ThenReturn(true)
m.When(mx.FetchPodsMetrics("blee")).
ThenReturn([]mv1beta1.PodMetrics{makeMxPod("fred", "100m", "20Mi")}, nil)
ThenReturn(&mv1beta1.PodMetricsList{Items: []mv1beta1.PodMetrics{makeMxPod("fred", "100m", "20Mi")}}, nil)
l := NewPodListWithArgs("blee", NewPodWithArgs(mc, mr, mx))
// Make sure we mcn get deltas!

View File

@ -3,7 +3,6 @@ package views
import (
"context"
"fmt"
"runtime"
"time"
"github.com/derailed/k9s/internal/config"
@ -138,7 +137,6 @@ func (a *appView) conn() k8s.Connection {
func (a *appView) stylesUpdater() (*fsnotify.Watcher, error) {
w, err := fsnotify.NewWatcher()
if err != nil {
log.Error().Err(err).Msg("File notifier failed")
return w, err
}
@ -146,18 +144,17 @@ func (a *appView) stylesUpdater() (*fsnotify.Watcher, error) {
for {
select {
case evt := <-w.Events:
log.Debug().Msgf("Evt %#v", evt)
_ = evt
a.QueueUpdateDraw(func() {
a.refreshStyles()
})
case err := <-w.Errors:
log.Error().Err(err).Msg("Watcher failed")
// case err := <-w.Errors:
// log.Info().Err(err).Msg("Skin watcher failed")
}
}
}()
if err := w.Add(config.K9sStylesFile); err != nil {
log.Error().Err(err).Msg("Styles file watch failed")
return w, err
}
@ -200,7 +197,7 @@ func (a *appView) keyboard(evt *tcell.EventKey) *tcell.EventKey {
}
if a, ok := a.actions[key]; ok {
log.Debug().Msgf(">> AppView handled key: %s -- %d", tcell.KeyNames[key], runtime.NumGoroutine())
log.Debug().Msgf(">> AppView handled key: %s", tcell.KeyNames[key])
return a.action(evt)
}
@ -391,7 +388,7 @@ func (a *appView) nextFocus() {
func (a *appView) refreshStyles() {
var err error
if a.styles, err = config.NewStyles(); err != nil {
log.Error().Err(err).Msg("No skin file found. Loading defaults.")
log.Warn().Err(err).Msg("No skin file found. Loading defaults.")
}
a.styles.Update()

View File

@ -4,6 +4,7 @@ import (
"strings"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/k8s"
"github.com/derailed/k9s/internal/resource"
"github.com/derailed/tview"
"github.com/gdamore/tcell"
@ -88,7 +89,6 @@ func (v *clusterInfoView) infoCell(t string) *tview.TableCell {
func (v *clusterInfoView) refresh() {
var row int
v.GetCell(row, 1).SetText(v.cluster.ContextName())
row++
v.GetCell(row, 1).SetText(v.cluster.ClusterName())
@ -100,23 +100,24 @@ func (v *clusterInfoView) refresh() {
nodes, err := v.cluster.GetNodes()
if err != nil {
log.Warn().Msgf("ClusterInfo %s", err)
log.Warn().Err(err).Msg("List nodes")
return
}
mxNodes, err := v.cluster.FetchNodesMetrics()
if err != nil {
log.Warn().Msgf("ClusterInfo %s", err)
log.Warn().Err(err).Msg("List node metrics")
return
}
mx := v.cluster.Metrics(nodes, mxNodes)
var mx k8s.ClusterMetrics
v.cluster.Metrics(nodes, mxNodes, &mx)
c := v.GetCell(row, 1)
cpu := toPerc(mx.PercCPU)
cpu := resource.AsPerc(mx.PercCPU)
c.SetText(cpu + deltas(strip(c.Text), cpu))
row++
c = v.GetCell(row, 1)
mem := toPerc(mx.PercMEM)
mem := resource.AsPerc(mx.PercMEM)
c.SetText(mem + deltas(strip(c.Text), mem))
}

View File

@ -1,9 +1,5 @@
package views
import (
"github.com/rs/zerolog/log"
)
const maxBuff = 10
type buffWatcher interface {
@ -41,7 +37,6 @@ func (c *cmdBuff) String() string {
}
func (c *cmdBuff) add(r rune) {
log.Debug().Msgf("Add %s", string(r))
c.buff = append(c.buff, r)
c.fireChanged()
}

View File

@ -196,13 +196,11 @@ func (v *detailsView) refreshTitle() {
func (v *detailsView) setTitle(t string) {
v.title = t
fmat := strings.Replace(detailsTitleFmt, "[fg", "["+v.app.styles.Style.Title.FgColor, -1)
fmat = strings.Replace(fmat, ":bg:", ":"+v.app.styles.Style.Title.BgColor+":", -1)
fmat := strings.Replace(detailsTitleFmt, "[fg:bg", "["+v.app.styles.Style.Title.FgColor+":"+v.app.styles.Style.Title.BgColor, -1)
fmat = strings.Replace(fmat, "[hilite", "["+v.app.styles.Style.Title.CounterColor, 1)
title := fmt.Sprintf(fmat, v.category, t)
if !v.cmdBuff.empty() {
fmat := strings.Replace(searchFmt, "[fg", "["+v.app.styles.Style.Title.FgColor, -1)
fmat = strings.Replace(fmat, ":bg:", ":"+v.app.styles.Style.Title.BgColor+":", -1)
fmat := strings.Replace(searchFmt, "[fg:bg", "["+v.app.styles.Style.Title.FgColor+":"+v.app.styles.Style.Title.BgColor, -1)
fmat = strings.Replace(fmat, "[filter", "["+v.app.styles.Style.Title.FilterColor, 1)
title += fmt.Sprintf(fmat, v.cmdBuff.String())
}

View File

@ -1,7 +1,6 @@
package views
import (
"fmt"
"regexp"
"strconv"
"strings"
@ -10,10 +9,6 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
)
func toPerc(f float64) string {
return fmt.Sprintf("%.0f%%", f)
}
func deltas(o, n string) string {
o, n = strings.TrimSpace(o), strings.TrimSpace(n)
if o == "" || o == "n/a" {

View File

@ -34,7 +34,3 @@ func TestDeltas(t *testing.T) {
assert.Equal(t, u.e, deltas(u.s1, u.s2))
}
}
func TestToPerc(t *testing.T) {
assert.Equal(t, "50%", toPerc(50))
}

View File

@ -3,7 +3,6 @@ package views
import (
"context"
"fmt"
"runtime"
"strconv"
"time"
@ -14,10 +13,11 @@ import (
)
const (
maxBuff1 int64 = 200
refreshRate = 200 * time.Millisecond
maxCleanse = 100
logBuffSize = 100
maxBuff1 int64 = 200
refreshRate = 200 * time.Millisecond
maxCleanse = 100
logBuffSize = 100
flushTimeout = 500 * time.Millisecond
)
type logsView struct {
@ -132,7 +132,7 @@ func (v *logsView) stop() {
}
v.cancelFunc()
log.Debug().Msgf("Canceling logs... %d", runtime.NumGoroutine())
log.Debug().Msgf("Canceling logs...")
v.cancelFunc = nil
}
@ -178,7 +178,7 @@ func (v *logsView) doLoad(path, co string) error {
l.flush(index, buff, v.autoScroll)
index = 0
buff[index] = line
case <-time.After(1 * time.Second):
case <-time.After(flushTimeout):
l.flush(index, buff, v.autoScroll)
index = 0
}

View File

@ -118,17 +118,17 @@ func (mock *MockClusterMeta) FetchNodes() (*v1.NodeList, error) {
return ret0, ret1
}
func (mock *MockClusterMeta) GetNodes() ([]v1.Node, error) {
func (mock *MockClusterMeta) GetNodes() (*v1.NodeList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("GetNodes", params, []reflect.Type{reflect.TypeOf((*[]v1.Node)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1.Node
result := pegomock.GetGenericMockFrom(mock).Invoke("GetNodes", params, []reflect.Type{reflect.TypeOf((**v1.NodeList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1.NodeList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1.Node)
ret0 = result[0].(*v1.NodeList)
}
if result[1] != nil {
ret1 = result[1].(error)
@ -201,6 +201,25 @@ func (mock *MockClusterMeta) NSDialOrDie() dynamic.NamespaceableResourceInterfac
return ret0
}
func (mock *MockClusterMeta) NodePods(_param0 string) (*v1.PodList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("NodePods", params, []reflect.Type{reflect.TypeOf((**v1.PodList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1.PodList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*v1.PodList)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockClusterMeta) RestConfigOrDie() *rest.Config {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
@ -311,25 +330,6 @@ func (mock *MockClusterMeta) ValidNamespaces() ([]v1.Namespace, error) {
return ret0, ret1
}
func (mock *MockClusterMeta) ValidPods(_param0 string) ([]v1.Pod, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("ValidPods", params, []reflect.Type{reflect.TypeOf((*[]v1.Pod)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1.Pod
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1.Pod)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockClusterMeta) Version() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
@ -583,6 +583,33 @@ func (c *ClusterMeta_NSDialOrDie_OngoingVerification) GetCapturedArguments() {
func (c *ClusterMeta_NSDialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) NodePods(_param0 string) *ClusterMeta_NodePods_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NodePods", params, verifier.timeout)
return &ClusterMeta_NodePods_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_NodePods_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_NodePods_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *ClusterMeta_NodePods_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierClusterMeta) RestConfigOrDie() *ClusterMeta_RestConfigOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RestConfigOrDie", params, verifier.timeout)
@ -736,33 +763,6 @@ func (c *ClusterMeta_ValidNamespaces_OngoingVerification) GetCapturedArguments()
func (c *ClusterMeta_ValidNamespaces_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) ValidPods(_param0 string) *ClusterMeta_ValidPods_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ValidPods", params, verifier.timeout)
return &ClusterMeta_ValidPods_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_ValidPods_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_ValidPods_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *ClusterMeta_ValidPods_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierClusterMeta) Version() *ClusterMeta_Version_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Version", params, verifier.timeout)

View File

@ -20,32 +20,25 @@ func NewMockMetricsServer() *MockMetricsServer {
return &MockMetricsServer{fail: pegomock.GlobalFailHandler}
}
func (mock *MockMetricsServer) ClusterLoad(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics) k8s.ClusterMetrics {
func (mock *MockMetricsServer) ClusterLoad(_param0 *v1.NodeList, _param1 *v1beta1.NodeMetricsList, _param2 *k8s.ClusterMetrics) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{_param0, _param1}
result := pegomock.GetGenericMockFrom(mock).Invoke("ClusterLoad", params, []reflect.Type{reflect.TypeOf((*k8s.ClusterMetrics)(nil)).Elem()})
var ret0 k8s.ClusterMetrics
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(k8s.ClusterMetrics)
}
}
return ret0
params := []pegomock.Param{_param0, _param1, _param2}
pegomock.GetGenericMockFrom(mock).Invoke("ClusterLoad", params, []reflect.Type{})
}
func (mock *MockMetricsServer) FetchNodesMetrics() ([]v1beta1.NodeMetrics, error) {
func (mock *MockMetricsServer) FetchNodesMetrics() (*v1beta1.NodeMetricsList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchNodesMetrics", params, []reflect.Type{reflect.TypeOf((*[]v1beta1.NodeMetrics)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1beta1.NodeMetrics
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchNodesMetrics", params, []reflect.Type{reflect.TypeOf((**v1beta1.NodeMetricsList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1beta1.NodeMetricsList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1beta1.NodeMetrics)
ret0 = result[0].(*v1beta1.NodeMetricsList)
}
if result[1] != nil {
ret1 = result[1].(error)
@ -54,17 +47,17 @@ func (mock *MockMetricsServer) FetchNodesMetrics() ([]v1beta1.NodeMetrics, error
return ret0, ret1
}
func (mock *MockMetricsServer) FetchPodsMetrics(_param0 string) ([]v1beta1.PodMetrics, error) {
func (mock *MockMetricsServer) FetchPodsMetrics(_param0 string) (*v1beta1.PodMetricsList, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchPodsMetrics", params, []reflect.Type{reflect.TypeOf((*[]v1beta1.PodMetrics)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1beta1.PodMetrics
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchPodsMetrics", params, []reflect.Type{reflect.TypeOf((**v1beta1.PodMetricsList)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *v1beta1.PodMetricsList
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1beta1.PodMetrics)
ret0 = result[0].(*v1beta1.PodMetricsList)
}
if result[1] != nil {
ret1 = result[1].(error)
@ -88,7 +81,7 @@ func (mock *MockMetricsServer) HasMetrics() bool {
return ret0
}
func (mock *MockMetricsServer) NodesMetrics(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics, _param2 k8s.NodesMetrics) {
func (mock *MockMetricsServer) NodesMetrics(_param0 k8s.Collection, _param1 *v1beta1.NodeMetricsList, _param2 k8s.NodesMetrics) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
@ -96,7 +89,7 @@ func (mock *MockMetricsServer) NodesMetrics(_param0 []v1.Node, _param1 []v1beta1
pegomock.GetGenericMockFrom(mock).Invoke("NodesMetrics", params, []reflect.Type{})
}
func (mock *MockMetricsServer) PodsMetrics(_param0 []v1beta1.PodMetrics, _param1 k8s.PodsMetrics) {
func (mock *MockMetricsServer) PodsMetrics(_param0 *v1beta1.PodMetricsList, _param1 k8s.PodsMetrics) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
@ -141,8 +134,8 @@ type VerifierMetricsServer struct {
timeout time.Duration
}
func (verifier *VerifierMetricsServer) ClusterLoad(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics) *MetricsServer_ClusterLoad_OngoingVerification {
params := []pegomock.Param{_param0, _param1}
func (verifier *VerifierMetricsServer) ClusterLoad(_param0 *v1.NodeList, _param1 *v1beta1.NodeMetricsList, _param2 *k8s.ClusterMetrics) *MetricsServer_ClusterLoad_OngoingVerification {
params := []pegomock.Param{_param0, _param1, _param2}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ClusterLoad", params, verifier.timeout)
return &MetricsServer_ClusterLoad_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
@ -152,21 +145,25 @@ type MetricsServer_ClusterLoad_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetCapturedArguments() ([]v1.Node, []v1beta1.NodeMetrics) {
_param0, _param1 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1]
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetCapturedArguments() (*v1.NodeList, *v1beta1.NodeMetricsList, *k8s.ClusterMetrics) {
_param0, _param1, _param2 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1]
}
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1.Node, _param1 [][]v1beta1.NodeMetrics) {
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetAllCapturedArguments() (_param0 []*v1.NodeList, _param1 []*v1beta1.NodeMetricsList, _param2 []*k8s.ClusterMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1.Node, len(params[0]))
_param0 = make([]*v1.NodeList, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1.Node)
_param0[u] = param.(*v1.NodeList)
}
_param1 = make([][]v1beta1.NodeMetrics, len(params[1]))
_param1 = make([]*v1beta1.NodeMetricsList, len(params[1]))
for u, param := range params[1] {
_param1[u] = param.([]v1beta1.NodeMetrics)
_param1[u] = param.(*v1beta1.NodeMetricsList)
}
_param2 = make([]*k8s.ClusterMetrics, len(params[2]))
for u, param := range params[2] {
_param2[u] = param.(*k8s.ClusterMetrics)
}
}
return
@ -233,7 +230,7 @@ func (c *MetricsServer_HasMetrics_OngoingVerification) GetCapturedArguments() {
func (c *MetricsServer_HasMetrics_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierMetricsServer) NodesMetrics(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics, _param2 k8s.NodesMetrics) *MetricsServer_NodesMetrics_OngoingVerification {
func (verifier *VerifierMetricsServer) NodesMetrics(_param0 k8s.Collection, _param1 *v1beta1.NodeMetricsList, _param2 k8s.NodesMetrics) *MetricsServer_NodesMetrics_OngoingVerification {
params := []pegomock.Param{_param0, _param1, _param2}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NodesMetrics", params, verifier.timeout)
return &MetricsServer_NodesMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
@ -244,21 +241,21 @@ type MetricsServer_NodesMetrics_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetCapturedArguments() ([]v1.Node, []v1beta1.NodeMetrics, k8s.NodesMetrics) {
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetCapturedArguments() (k8s.Collection, *v1beta1.NodeMetricsList, k8s.NodesMetrics) {
_param0, _param1, _param2 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1]
}
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1.Node, _param1 [][]v1beta1.NodeMetrics, _param2 []k8s.NodesMetrics) {
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 []k8s.Collection, _param1 []*v1beta1.NodeMetricsList, _param2 []k8s.NodesMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1.Node, len(params[0]))
_param0 = make([]k8s.Collection, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1.Node)
_param0[u] = param.(k8s.Collection)
}
_param1 = make([][]v1beta1.NodeMetrics, len(params[1]))
_param1 = make([]*v1beta1.NodeMetricsList, len(params[1]))
for u, param := range params[1] {
_param1[u] = param.([]v1beta1.NodeMetrics)
_param1[u] = param.(*v1beta1.NodeMetricsList)
}
_param2 = make([]k8s.NodesMetrics, len(params[2]))
for u, param := range params[2] {
@ -268,7 +265,7 @@ func (c *MetricsServer_NodesMetrics_OngoingVerification) GetAllCapturedArguments
return
}
func (verifier *VerifierMetricsServer) PodsMetrics(_param0 []v1beta1.PodMetrics, _param1 k8s.PodsMetrics) *MetricsServer_PodsMetrics_OngoingVerification {
func (verifier *VerifierMetricsServer) PodsMetrics(_param0 *v1beta1.PodMetricsList, _param1 k8s.PodsMetrics) *MetricsServer_PodsMetrics_OngoingVerification {
params := []pegomock.Param{_param0, _param1}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PodsMetrics", params, verifier.timeout)
return &MetricsServer_PodsMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
@ -279,17 +276,17 @@ type MetricsServer_PodsMetrics_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetCapturedArguments() ([]v1beta1.PodMetrics, k8s.PodsMetrics) {
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetCapturedArguments() (*v1beta1.PodMetricsList, k8s.PodsMetrics) {
_param0, _param1 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1]
}
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1beta1.PodMetrics, _param1 []k8s.PodsMetrics) {
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 []*v1beta1.PodMetricsList, _param1 []k8s.PodsMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1beta1.PodMetrics, len(params[0]))
_param0 = make([]*v1beta1.PodMetricsList, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1beta1.PodMetrics)
_param0[u] = param.(*v1beta1.PodMetricsList)
}
_param1 = make([]k8s.PodsMetrics, len(params[1]))
for u, param := range params[1] {

View File

@ -1,8 +1,6 @@
package views
import (
"fmt"
"github.com/derailed/k9s/internal/k8s"
"github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell"
@ -61,8 +59,7 @@ func showPods(app *appView, ns, res, selected, labelSel, fieldSel string, b acti
list.SetLabelSelector(labelSel)
list.SetFieldSelector(fieldSel)
title := fmt.Sprintf("%s:%s Pods", res, selected)
pv := newPodView(title, app, list)
pv := newPodView("Pods", app, list)
pv.setColorerFn(podColorer)
pv.setExtraActionsFn(func(aa keyActions) {
aa[tcell.KeyEsc] = newKeyAction("Back", b, true)

View File

@ -63,8 +63,7 @@ func (v *podView) listContainers(app *appView, _, res, sel string) {
mx := k8s.NewMetricsServer(app.conn())
list := resource.NewContainerList(app.conn(), mx, po)
fmat := strings.Replace(containerFmt, "[fg", "["+v.app.styles.Style.Title.FgColor, -1)
fmat = strings.Replace(fmat, ":bg:", ":"+v.app.styles.Style.Title.BgColor+":", -1)
fmat := strings.Replace(containerFmt, "[fg:bg", "["+v.app.styles.Style.Title.FgColor+":"+v.app.styles.Style.Title.BgColor, -1)
fmat = strings.Replace(fmat, "[hilite", "["+v.app.styles.Style.Title.CounterColor, 1)
app.inject(newContainerView(

View File

@ -46,6 +46,7 @@ type (
actions keyActions
mx sync.Mutex
suspended bool
nsListAccess bool
}
)
@ -81,6 +82,21 @@ func (v *resourceView) init(ctx context.Context, ns string) {
}
v.getTV().setColorer(colorer)
v.nsListAccess = k8s.CanIAccess(v.app.conn().Config(), log.Logger, "", "list", "namespaces", "namespace.v1")
if v.nsListAccess {
nn, err := k8s.NewNamespace(v.app.conn()).List(resource.AllNamespaces)
if err != nil {
log.Warn().Err(err).Msg("List namespaces")
v.app.flash(flashErr, err.Error())
}
if v.list.Namespaced() && !v.list.AllNamespaces() {
if !config.InNSList(nn, v.list.GetNamespace()) {
v.list.SetNamespace(resource.DefaultNamespace)
}
}
}
go v.updater(ctx)
v.refresh()
if tv, ok := v.CurrentPage().Item.(*tableView); ok {
@ -94,16 +110,27 @@ func (v *resourceView) updater(ctx context.Context) {
for {
select {
case <-ctx.Done():
log.Debug().Msgf("%s watcher canceled!", v.title)
log.Debug().Msgf("%s cluster updater canceled!", v.list.GetName())
return
case <-time.After(time.Duration(15 * time.Second)):
if v.isSuspended() {
continue
}
v.app.QueueUpdate(func() {
v.app.clusterInfoView.refresh()
})
}
}
}(ctx)
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
log.Debug().Msgf("%s updater canceled!", v.list.GetName())
return
case <-time.After(time.Duration(v.app.config.K9s.RefreshRate) * time.Second):
var suspended bool
v.mx.Lock()
{
suspended = v.suspended
}
v.mx.Unlock()
if suspended == true {
if v.isSuspended() {
continue
}
v.app.QueueUpdate(func() {
@ -114,6 +141,17 @@ func (v *resourceView) updater(ctx context.Context) {
}(ctx)
}
func (v *resourceView) isSuspended() bool {
var suspended bool
v.mx.Lock()
{
suspended = v.suspended
}
v.mx.Unlock()
return suspended
}
func (v *resourceView) suspend() {
v.mx.Lock()
{
@ -184,7 +222,7 @@ func (v *resourceView) enterCmd(evt *tcell.EventKey) *tcell.EventKey {
if v.enterFn != nil {
v.enterFn(v.app, v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
} else {
v.defaultEnter(v.app, v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
v.defaultEnter(v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
}
return nil
}
@ -237,9 +275,9 @@ func (v *resourceView) dismissModal() {
v.switchPage(v.list.GetName())
}
func (v *resourceView) defaultEnter(app *appView, ns, resource, selection string) {
sel := v.getSelectedItem()
yaml, err := v.list.Resource().Describe(v.title, sel, v.app.flags)
func (v *resourceView) defaultEnter(ns, resource, selection string) {
log.Debug().Msgf("Title %s", v.title)
yaml, err := v.list.Resource().Describe(v.title, selection, v.app.flags)
if err != nil {
v.app.flash(flashErr, err.Error())
log.Warn().Msgf("Describe %v", err.Error())
@ -249,7 +287,7 @@ func (v *resourceView) defaultEnter(app *appView, ns, resource, selection string
details := v.GetPrimitive("details").(*detailsView)
{
details.setCategory("Describe")
details.setTitle(sel)
details.setTitle(selection)
details.SetTextColor(tcell.ColorAqua)
details.SetText(colorizeYAML(v.app.styles.Style, yaml))
details.ScrollToBeginning()
@ -261,7 +299,10 @@ func (v *resourceView) describeCmd(evt *tcell.EventKey) *tcell.EventKey {
if !v.rowSelected() {
return evt
}
v.defaultEnter(v.app, v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
log.Debug().Msgf("Selected Item %v-%v-%v", v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
v.defaultEnter(v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
return nil
}
@ -343,7 +384,6 @@ func (v *resourceView) refresh() {
}
v.refreshActions()
v.app.clusterInfoView.refresh()
if err := v.list.Reconcile(); err != nil {
log.Error().Err(err).Msg("Reconciliation failed")
@ -353,10 +393,8 @@ func (v *resourceView) refresh() {
if v.decorateFn != nil {
data = v.decorateFn(data)
}
v.getTV().update(data)
v.selectItem(v.selectedRow, 0)
v.app.Draw()
}
func (v *resourceView) getTV() *tableView {
@ -391,11 +429,19 @@ func (v *resourceView) selectItem(r, c int) {
}
func (v *resourceView) switchPage(p string) {
if _, ok := v.CurrentPage().Item.(*tableView); ok {
v.suspend()
}
v.SwitchToPage(p)
v.selectedNS = v.list.GetNamespace()
if h, ok := v.GetPrimitive(p).(hinter); ok {
v.app.setHints(h.hints())
}
if _, ok := v.CurrentPage().Item.(*tableView); ok {
v.resume()
}
}
func (v *resourceView) rowSelected() bool {
@ -408,31 +454,11 @@ func namespaced(n string) (string, string) {
}
func (v *resourceView) refreshActions() {
if _, ok := v.CurrentPage().Item.(*tableView); !ok {
return
}
var nn []interface{}
if k8s.CanIAccess(v.app.conn().Config(), log.Logger, "", "list", "namespaces", "namespace.v1") {
var err error
nn, err = k8s.NewNamespace(v.app.conn()).List(resource.AllNamespaces)
if err != nil {
log.Warn().Msgf("Access %v", err)
v.app.flash(flashErr, err.Error())
}
if v.list.Namespaced() && !v.list.AllNamespaces() {
if !config.InNSList(nn, v.list.GetNamespace()) {
v.list.SetNamespace(resource.DefaultNamespace)
}
}
if v.list.Access(resource.NamespaceAccess) {
v.namespaces = make(map[int]string, config.MaxFavoritesNS)
for i, n := range v.app.config.FavNamespaces() {
v.actions[tcell.Key(numKeys[i])] = newKeyAction(n, v.switchNamespaceCmd, true)
v.namespaces[i] = n
}
if v.list.Access(resource.NamespaceAccess) {
v.namespaces = make(map[int]string, config.MaxFavoritesNS)
for i, n := range v.app.config.FavNamespaces() {
v.actions[tcell.Key(numKeys[i])] = newKeyAction(n, v.switchNamespaceCmd, true)
v.namespaces[i] = n
}
}

View File

@ -3,7 +3,6 @@ package views
import (
"fmt"
"regexp"
"runtime"
"sort"
"strings"
"time"
@ -115,7 +114,6 @@ func (v *tableView) keyboard(evt *tcell.EventKey) *tcell.EventKey {
if a, ok := v.actions[key]; ok {
log.Debug().Msgf(">> TableView handled %s", tcell.KeyNames[key])
log.Debug().Msgf("Go Routine %d", runtime.NumGoroutine())
return a.action(evt)
}
@ -230,13 +228,9 @@ func (v *tableView) setColorer(f colorerFn) {
// SetActions sets up keyboard action listener.
func (v *tableView) setActions(aa keyActions) {
// v.mx.Lock()
// {
for k, a := range aa {
v.actions[k] = a
}
// }
// v.mx.Unlock()
}
// Hints options
@ -325,14 +319,12 @@ func (v *tableView) doUpdate(data resource.TableData) {
}
pads := make(maxyPad, len(data.Header))
// v.mx.Lock()
// {
computeMaxColumns(pads, v.sortCol.index, data)
// }
// v.mx.Unlock()
var row int
fg := config.AsColor(v.app.styles.Style.Table.Header.FgColor)
bg := config.AsColor(v.app.styles.Style.Table.Header.BgColor)
for col, h := range data.Header {
v.addHeaderCell(col, h, pads)
v.addHeaderCell(col, h, pads, fg, bg)
}
row++
@ -341,9 +333,9 @@ func (v *tableView) doUpdate(data resource.TableData) {
sortFn = v.sortFn
}
prim, sec := v.sortAllRows(data.Rows, sortFn)
fgColor := config.AsColor(v.app.styles.Style.Table.FgColor)
for _, pk := range prim {
for _, sk := range sec[pk] {
fgColor := config.AsColor(v.app.styles.Style.Table.FgColor)
if v.colorerFn != nil {
fgColor = v.colorerFn(data.Namespace, data.Rows[sk])
}
@ -380,12 +372,12 @@ func (v *tableView) sortAllRows(rows resource.RowEvents, sortFn sortFn) (resourc
return prim, sec
}
func (v *tableView) addHeaderCell(col int, name string, pads maxyPad) {
func (v *tableView) addHeaderCell(col int, name string, pads maxyPad, fg, bg tcell.Color) {
c := tview.NewTableCell(v.sortIndicator(col, name))
{
c.SetExpansion(1)
c.SetTextColor(config.AsColor(v.app.styles.Style.Table.Header.FgColor))
c.SetBackgroundColor(config.AsColor(v.app.styles.Style.Table.Header.BgColor))
c.SetTextColor(fg)
c.SetBackgroundColor(bg)
}
v.SetCell(0, col, c)
}
@ -442,27 +434,24 @@ func (v *tableView) resetTitle() {
}
switch v.currentNS {
case resource.NotNamespaced, "*":
fmat := strings.Replace(titleFmt, "[fg", "["+v.app.styles.Style.Title.FgColor, -1)
fmat = strings.Replace(fmat, ":bg:", ":"+v.app.styles.Style.Title.BgColor+":", -1)
fmat := strings.Replace(titleFmt, "[fg:bg", "["+v.app.styles.Style.Title.FgColor+":"+v.app.styles.Style.Title.BgColor, -1)
fmat = strings.Replace(fmat, "[count", "["+v.app.styles.Style.Title.CounterColor, 1)
title = fmt.Sprintf(fmat, v.baseTitle, rc)
default:
ns := v.currentNS
if v.currentNS == resource.AllNamespaces {
if ns == resource.AllNamespaces {
ns = resource.AllNamespace
}
fmat := strings.Replace(nsTitleFmt, "[fg", "["+v.app.styles.Style.Title.FgColor, -1)
fmat = strings.Replace(fmat, ":bg:", ":"+v.app.styles.Style.Title.BgColor+":", -1)
fmat := strings.Replace(nsTitleFmt, "[fg:bg", "["+v.app.styles.Style.Title.FgColor+":"+v.app.styles.Style.Title.BgColor, -1)
fmat = strings.Replace(fmat, "[hilite", "["+v.app.styles.Style.Title.HighlightColor, 1)
fmat = strings.Replace(fmat, "[count", "["+v.app.styles.Style.Title.CounterColor, 1)
title = fmt.Sprintf(fmat, v.baseTitle, ns, rc)
}
if !v.cmdBuff.isActive() && !v.cmdBuff.empty() {
fmat := strings.Replace(searchFmt, "[fg", "["+v.app.styles.Style.Title.FgColor, 1)
fmat := strings.Replace(searchFmt, "[fg:bg", "["+v.app.styles.Style.Title.FgColor+":"+v.app.styles.Style.Title.BgColor, -1)
fmat = strings.Replace(fmat, ":bg:", ":"+v.app.styles.Style.Title.BgColor+":", -1)
fmat = strings.Replace(fmat, "[filter", "["+v.app.styles.Style.Title.FilterColor, 1)
title += fmt.Sprintf(fmat, v.cmdBuff)
}
v.SetTitle(title)

View File

@ -1,6 +1,8 @@
package views
import (
"fmt"
"strings"
"testing"
"github.com/derailed/k9s/internal/resource"
@ -70,3 +72,26 @@ func BenchmarkTVSortRows(b *testing.B) {
v.sortRows(evts, v.defaultSort, sc, keys)
}
}
func BenchmarkTitleReplace(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
fmat := strings.Replace(nsTitleFmt, "[fg", "["+"red", -1)
fmat = strings.Replace(fmat, ":bg:", ":"+"blue"+":", -1)
fmat = strings.Replace(fmat, "[hilite", "["+"green", 1)
fmat = strings.Replace(fmat, "[count", "["+"yellow", 1)
_ = fmt.Sprintf(fmat, "Pods", "default", 10)
}
}
func BenchmarkTitleReplace1(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
fmat := strings.Replace(nsTitleFmt, "fg:bg", "red"+":"+"blue", -1)
fmat = strings.Replace(fmat, "[hilite", "["+"green", 1)
fmat = strings.Replace(fmat, "[count", "["+"yellow", 1)
_ = fmt.Sprintf(fmat, "Pods", "default", 10)
}
}