mirror of https://github.com/portainer/portainer
fix(gke): port metrics to the backend EE-5447 (#9041)
parent
e996d29d52
commit
704d70c99b
22
api/go.mod
22
api/go.mod
|
@ -51,13 +51,15 @@ require (
|
||||||
go.etcd.io/bbolt v1.3.7
|
go.etcd.io/bbolt v1.3.7
|
||||||
golang.org/x/crypto v0.7.0
|
golang.org/x/crypto v0.7.0
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||||
|
golang.org/x/mod v0.9.0
|
||||||
golang.org/x/oauth2 v0.6.0
|
golang.org/x/oauth2 v0.6.0
|
||||||
golang.org/x/sync v0.1.0
|
golang.org/x/sync v0.1.0
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
k8s.io/api v0.26.1
|
k8s.io/api v0.27.4
|
||||||
k8s.io/apimachinery v0.26.1
|
k8s.io/apimachinery v0.27.4
|
||||||
k8s.io/client-go v0.26.1
|
k8s.io/client-go v0.27.4
|
||||||
|
k8s.io/metrics v0.27.4
|
||||||
software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78
|
software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -90,8 +92,8 @@ require (
|
||||||
github.com/go-git/gcfg v1.5.0 // indirect
|
github.com/go-git/gcfg v1.5.0 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.1.0 // indirect
|
github.com/go-git/go-billy/v5 v5.1.0 // indirect
|
||||||
github.com/go-logr/logr v1.2.3 // indirect
|
github.com/go-logr/logr v1.2.3 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
github.com/go-openapi/jsonreference v0.20.1 // indirect
|
||||||
github.com/go-openapi/swag v0.22.3 // indirect
|
github.com/go-openapi/swag v0.22.3 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
@ -101,6 +103,7 @@ require (
|
||||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/imdario/mergo v0.3.15 // indirect
|
github.com/imdario/mergo v0.3.15 // indirect
|
||||||
|
@ -141,7 +144,6 @@ require (
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
golang.org/x/mod v0.9.0 // indirect
|
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/net v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.7.0 // indirect
|
golang.org/x/sys v0.7.0 // indirect
|
||||||
golang.org/x/term v0.6.0 // indirect
|
golang.org/x/term v0.6.0 // indirect
|
||||||
|
@ -153,10 +155,10 @@ require (
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
k8s.io/klog/v2 v2.80.1 // indirect
|
k8s.io/klog/v2 v2.90.1 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
|
||||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
|
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
54
api/go.sum
54
api/go.sum
|
@ -96,7 +96,6 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
|
||||||
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
||||||
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||||
|
@ -137,12 +136,10 @@ github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjR
|
||||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
@ -152,6 +149,7 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
|
github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
|
||||||
github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
|
github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||||
|
@ -195,9 +193,12 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
|
@ -258,8 +259,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
|
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
|
||||||
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
|
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
|
@ -291,8 +290,8 @@ github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
|
github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
|
||||||
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
|
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
|
@ -330,7 +329,7 @@ github.com/portainer/portainer/third_party/digest v0.0.0-20221201002639-8fd0efa3
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
|
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
|
||||||
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||||
|
@ -530,7 +529,6 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
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 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
@ -555,20 +553,22 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||||
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ=
|
k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs=
|
||||||
k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg=
|
k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y=
|
||||||
k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ=
|
k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs=
|
||||||
k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74=
|
k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
|
||||||
k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU=
|
k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
|
||||||
k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE=
|
k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
|
||||||
k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
|
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
|
||||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
|
||||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
|
||||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs=
|
k8s.io/metrics v0.27.4 h1:2s04bods7rA507iouGbxD55YrKNlFjLYzm30noOl9Sk=
|
||||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/metrics v0.27.4/go.mod h1:kRvfhFC7wCQEFvu6H92uiV7v05z3Ty/vtluYT5D2Xpk=
|
||||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
|
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
|
||||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
|
|
|
@ -53,6 +53,10 @@ func NewHandler(bouncer security.BouncerService, authorizationService *authoriza
|
||||||
endpointRouter.Use(h.kubeClient)
|
endpointRouter.Use(h.kubeClient)
|
||||||
|
|
||||||
endpointRouter.PathPrefix("/nodes_limits").Handler(httperror.LoggerHandler(h.getKubernetesNodesLimits)).Methods(http.MethodGet)
|
endpointRouter.PathPrefix("/nodes_limits").Handler(httperror.LoggerHandler(h.getKubernetesNodesLimits)).Methods(http.MethodGet)
|
||||||
|
endpointRouter.Path("/metrics/nodes").Handler(httperror.LoggerHandler(h.getKubernetesMetricsForAllNodes)).Methods(http.MethodGet)
|
||||||
|
endpointRouter.Path("/metrics/nodes/{name}").Handler(httperror.LoggerHandler(h.getKubernetesMetricsForNode)).Methods(http.MethodGet)
|
||||||
|
endpointRouter.Path("/metrics/pods/namespace/{namespace}").Handler(httperror.LoggerHandler(h.getKubernetesMetricsForAllPods)).Methods(http.MethodGet)
|
||||||
|
endpointRouter.Path("/metrics/pods/namespace/{namespace}/{name}").Handler(httperror.LoggerHandler(h.getKubernetesMetricsForPod)).Methods(http.MethodGet)
|
||||||
endpointRouter.Handle("/ingresscontrollers", httperror.LoggerHandler(h.getKubernetesIngressControllers)).Methods(http.MethodGet)
|
endpointRouter.Handle("/ingresscontrollers", httperror.LoggerHandler(h.getKubernetesIngressControllers)).Methods(http.MethodGet)
|
||||||
endpointRouter.Handle("/ingresscontrollers", httperror.LoggerHandler(h.updateKubernetesIngressControllers)).Methods(http.MethodPut)
|
endpointRouter.Handle("/ingresscontrollers", httperror.LoggerHandler(h.updateKubernetesIngressControllers)).Methods(http.MethodPut)
|
||||||
endpointRouter.Handle("/ingresses/delete", httperror.LoggerHandler(h.deleteKubernetesIngresses)).Methods(http.MethodPost)
|
endpointRouter.Handle("/ingresses/delete", httperror.LoggerHandler(h.deleteKubernetesIngresses)).Methods(http.MethodPost)
|
||||||
|
|
|
@ -0,0 +1,247 @@
|
||||||
|
package kubernetes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @id getKubernetesMetricsForAllNodes
|
||||||
|
// @summary Get a list of nodes with their live metrics
|
||||||
|
// @description Get a list of nodes with their live metrics
|
||||||
|
// @description **Access policy**: authenticated
|
||||||
|
// @tags kubernetes
|
||||||
|
// @security ApiKeyAuth
|
||||||
|
// @security jwt
|
||||||
|
// @accept json
|
||||||
|
// @produce json
|
||||||
|
// @param id path int true "Environment (Endpoint) identifier"
|
||||||
|
// @success 200 {object} v1beta1.NodeMetricsList "Success"
|
||||||
|
// @failure 400 "Invalid request"
|
||||||
|
// @failure 500 "Server error"
|
||||||
|
// @router /kubernetes/{id}/metrics/nodes [get]
|
||||||
|
func (handler *Handler) getKubernetesMetricsForAllNodes(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||||
|
endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
|
||||||
|
if err != nil {
|
||||||
|
return httperror.BadRequest(
|
||||||
|
"Invalid environment identifier route variable",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
|
||||||
|
if handler.DataStore.IsErrObjectNotFound(err) {
|
||||||
|
return httperror.NotFound("Unable to find an environment with the specified identifier inside the database", err)
|
||||||
|
} else if err != nil {
|
||||||
|
return httperror.InternalServerError("Unable to find an environment with the specified identifier inside the database", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := handler.KubernetesClientFactory.CreateRemoteMetricsClient(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return httperror.InternalServerError(
|
||||||
|
"failed to create metrics KubeClient",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics, err := cli.MetricsV1beta1().NodeMetricses().List(r.Context(), v1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return httperror.InternalServerError(
|
||||||
|
"Failed to fetch metrics",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.JSON(w, metrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @id getKubernetesMetricsForNode
|
||||||
|
// @summary Get live metrics for a node
|
||||||
|
// @description Get live metrics for a node
|
||||||
|
// @description **Access policy**: authenticated
|
||||||
|
// @tags kubernetes
|
||||||
|
// @security ApiKeyAuth
|
||||||
|
// @security jwt
|
||||||
|
// @accept json
|
||||||
|
// @produce json
|
||||||
|
// @param id path int true "Environment (Endpoint) identifier"
|
||||||
|
// @param name path string true "Node identifier"
|
||||||
|
// @success 200 {object} v1beta1.NodeMetrics "Success"
|
||||||
|
// @failure 400 "Invalid request"
|
||||||
|
// @failure 500 "Server error"
|
||||||
|
// @router /kubernetes/{id}/metrics/nodes/{name} [get]
|
||||||
|
func (handler *Handler) getKubernetesMetricsForNode(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||||
|
endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
|
||||||
|
if err != nil {
|
||||||
|
return httperror.BadRequest(
|
||||||
|
"Invalid environment identifier route variable",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
|
||||||
|
if handler.DataStore.IsErrObjectNotFound(err) {
|
||||||
|
return httperror.NotFound("Unable to find an environment with the specified identifier inside the database", err)
|
||||||
|
} else if err != nil {
|
||||||
|
return httperror.InternalServerError("Unable to find an environment with the specified identifier inside the database", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := handler.KubernetesClientFactory.CreateRemoteMetricsClient(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return httperror.InternalServerError(
|
||||||
|
"failed to create metrics KubeClient",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeName, err := request.RetrieveRouteVariableValue(r, "name")
|
||||||
|
if err != nil {
|
||||||
|
return httperror.BadRequest(
|
||||||
|
"Invalid node identifier route variable",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics, err := cli.MetricsV1beta1().NodeMetricses().Get(
|
||||||
|
r.Context(),
|
||||||
|
nodeName,
|
||||||
|
v1.GetOptions{},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return httperror.InternalServerError(
|
||||||
|
"Failed to fetch metrics",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.JSON(w, metrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @id getKubernetesMetricsForAllPods
|
||||||
|
// @summary Get a list of pods with their live metrics
|
||||||
|
// @description Get a list of pods with their live metrics
|
||||||
|
// @description **Access policy**: authenticated
|
||||||
|
// @tags kubernetes
|
||||||
|
// @security ApiKeyAuth
|
||||||
|
// @security jwt
|
||||||
|
// @accept json
|
||||||
|
// @produce json
|
||||||
|
// @param id path int true "Environment (Endpoint) identifier"
|
||||||
|
// @param namespace path string true "Namespace"
|
||||||
|
// @success 200 {object} v1beta1.PodMetricsList "Success"
|
||||||
|
// @failure 400 "Invalid request"
|
||||||
|
// @failure 500 "Server error"
|
||||||
|
// @router /kubernetes/{id}/metrics/pods/{namespace} [get]
|
||||||
|
func (handler *Handler) getKubernetesMetricsForAllPods(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||||
|
endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
|
||||||
|
if err != nil {
|
||||||
|
return httperror.BadRequest(
|
||||||
|
"Invalid environment identifier route variable",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
|
||||||
|
if handler.DataStore.IsErrObjectNotFound(err) {
|
||||||
|
return httperror.NotFound("Unable to find an environment with the specified identifier inside the database", err)
|
||||||
|
} else if err != nil {
|
||||||
|
return httperror.InternalServerError("Unable to find an environment with the specified identifier inside the database", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := handler.KubernetesClientFactory.CreateRemoteMetricsClient(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return httperror.InternalServerError(
|
||||||
|
"failed to create metrics KubeClient",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, err := request.RetrieveRouteVariableValue(r, "namespace")
|
||||||
|
if err != nil {
|
||||||
|
return httperror.BadRequest(
|
||||||
|
"Invalid namespace identifier route variable",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics, err := cli.MetricsV1beta1().PodMetricses(namespace).List(r.Context(), v1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return httperror.InternalServerError(
|
||||||
|
"Failed to fetch metrics",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.JSON(w, metrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @id getKubernetesMetricsForPod
|
||||||
|
// @summary Get live metrics for a pod
|
||||||
|
// @description Get live metrics for a pod
|
||||||
|
// @description **Access policy**: authenticated
|
||||||
|
// @tags kubernetes
|
||||||
|
// @security ApiKeyAuth
|
||||||
|
// @security jwt
|
||||||
|
// @accept json
|
||||||
|
// @produce json
|
||||||
|
// @param id path int true "Environment (Endpoint) identifier"
|
||||||
|
// @param namespace path string true "Namespace"
|
||||||
|
// @param name path string true "Pod identifier"
|
||||||
|
// @success 200 {object} v1beta1.PodMetrics "Success"
|
||||||
|
// @failure 400 "Invalid request"
|
||||||
|
// @failure 500 "Server error"
|
||||||
|
// @router /kubernetes/{id}/metrics/pods/{namespace}/{name} [get]
|
||||||
|
func (handler *Handler) getKubernetesMetricsForPod(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||||
|
endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
|
||||||
|
if err != nil {
|
||||||
|
return httperror.BadRequest(
|
||||||
|
"Invalid environment identifier route variable",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
|
||||||
|
if handler.DataStore.IsErrObjectNotFound(err) {
|
||||||
|
return httperror.NotFound("Unable to find an environment with the specified identifier inside the database", err)
|
||||||
|
} else if err != nil {
|
||||||
|
return httperror.InternalServerError("Unable to find an environment with the specified identifier inside the database", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := handler.KubernetesClientFactory.CreateRemoteMetricsClient(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return httperror.InternalServerError(
|
||||||
|
"failed to create metrics KubeClient",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, err := request.RetrieveRouteVariableValue(r, "namespace")
|
||||||
|
if err != nil {
|
||||||
|
return httperror.BadRequest(
|
||||||
|
"Invalid namespace identifier route variable",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
podName, err := request.RetrieveRouteVariableValue(r, "name")
|
||||||
|
if err != nil {
|
||||||
|
return httperror.BadRequest(
|
||||||
|
"Invalid pod identifier route variable",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics, err := cli.MetricsV1beta1().PodMetricses(namespace).Get(
|
||||||
|
r.Context(),
|
||||||
|
podName,
|
||||||
|
v1.GetOptions{},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return httperror.InternalServerError(
|
||||||
|
"Failed to fetch metrics",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.JSON(w, metrics)
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
metricsv "k8s.io/metrics/pkg/client/clientset/versioned"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -225,6 +226,34 @@ func (factory *ClientFactory) createRemoteClient(endpointURL string) (*kubernete
|
||||||
return kubernetes.NewForConfig(config)
|
return kubernetes.NewForConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (factory *ClientFactory) CreateRemoteMetricsClient(endpoint *portainer.Endpoint) (*metricsv.Clientset, error) {
|
||||||
|
endpointURL := fmt.Sprintf("https://%s/kubernetes", endpoint.URL)
|
||||||
|
|
||||||
|
signature, err := factory.signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := clientcmd.BuildConfigFromFlags(endpointURL, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Insecure = true
|
||||||
|
config.QPS = DefaultKubeClientQPS
|
||||||
|
config.Burst = DefaultKubeClientBurst
|
||||||
|
|
||||||
|
config.Wrap(func(rt http.RoundTripper) http.RoundTripper {
|
||||||
|
return &agentHeaderRoundTripper{
|
||||||
|
signatureHeader: signature,
|
||||||
|
publicKeyHeader: factory.signatureService.EncodedPublicKey(),
|
||||||
|
roundTripper: rt,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return metricsv.NewForConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
func buildLocalClient() (*kubernetes.Clientset, error) {
|
func buildLocalClient() (*kubernetes.Clientset, error) {
|
||||||
config, err := rest.InClusterConfig()
|
config, err := rest.InClusterConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
import angular from 'angular';
|
|
||||||
import PortainerError from 'Portainer/error';
|
|
||||||
import { KubernetesCommonParams } from 'Kubernetes/models/common/params';
|
|
||||||
|
|
||||||
class KubernetesMetricsService {
|
|
||||||
/* @ngInject */
|
|
||||||
constructor($async, KubernetesMetrics) {
|
|
||||||
this.$async = $async;
|
|
||||||
this.KubernetesMetrics = KubernetesMetrics;
|
|
||||||
|
|
||||||
this.capabilitiesAsync = this.capabilitiesAsync.bind(this);
|
|
||||||
|
|
||||||
this.getPodAsync = this.getPodAsync.bind(this);
|
|
||||||
this.getNodeAsync = this.getNodeAsync.bind(this);
|
|
||||||
|
|
||||||
this.getPodsAsync = this.getPodsAsync.bind(this);
|
|
||||||
this.getNodesAsync = this.getNodesAsync.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET
|
|
||||||
*/
|
|
||||||
async capabilitiesAsync(endpointID) {
|
|
||||||
try {
|
|
||||||
await this.KubernetesMetrics().capabilities({ endpointId: endpointID }).$promise;
|
|
||||||
} catch (err) {
|
|
||||||
throw new PortainerError('Unable to retrieve metrics', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
capabilities(endpointID) {
|
|
||||||
return this.$async(this.capabilitiesAsync, endpointID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stats of Node
|
|
||||||
*
|
|
||||||
* @param {string} nodeName
|
|
||||||
*/
|
|
||||||
async getNodeAsync(nodeName) {
|
|
||||||
try {
|
|
||||||
const params = new KubernetesCommonParams();
|
|
||||||
params.id = nodeName;
|
|
||||||
const data = await this.KubernetesMetrics().getNode(params).$promise;
|
|
||||||
return data;
|
|
||||||
} catch (err) {
|
|
||||||
throw new PortainerError('Unable to retrieve node stats', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getNode(nodeName) {
|
|
||||||
return this.$async(this.getNodeAsync, nodeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stats
|
|
||||||
*
|
|
||||||
* @param {string} namespace
|
|
||||||
* @param {string} podName
|
|
||||||
*/
|
|
||||||
async getPodAsync(namespace, podName) {
|
|
||||||
try {
|
|
||||||
const params = new KubernetesCommonParams();
|
|
||||||
params.id = podName;
|
|
||||||
const data = await this.KubernetesMetrics(namespace).getPod(params).$promise;
|
|
||||||
return data;
|
|
||||||
} catch (err) {
|
|
||||||
throw new PortainerError('Unable to retrieve pod stats', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPod(namespace, podName) {
|
|
||||||
return this.$async(this.getPodAsync, namespace, podName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stats of Nodes in cluster
|
|
||||||
*
|
|
||||||
* @param {string} endpointID
|
|
||||||
*/
|
|
||||||
async getNodesAsync(endpointID) {
|
|
||||||
try {
|
|
||||||
const data = await this.KubernetesMetrics().getNodes({ endpointId: endpointID }).$promise;
|
|
||||||
return data;
|
|
||||||
} catch (err) {
|
|
||||||
throw new PortainerError('Unable to retrieve nodes stats', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getNodes(endpointID) {
|
|
||||||
return this.$async(this.getNodesAsync, endpointID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stats of Pods in a namespace
|
|
||||||
*
|
|
||||||
* @param {string} namespace
|
|
||||||
*/
|
|
||||||
async getPodsAsync(namespace) {
|
|
||||||
try {
|
|
||||||
const data = await this.KubernetesMetrics(namespace).getPods().$promise;
|
|
||||||
return data;
|
|
||||||
} catch (err) {
|
|
||||||
throw new PortainerError('Unable to retrieve pod stats', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPods(namespace) {
|
|
||||||
return this.$async(this.getPodsAsync, namespace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default KubernetesMetricsService;
|
|
||||||
angular.module('portainer.kubernetes').service('KubernetesMetricsService', KubernetesMetricsService);
|
|
|
@ -1,39 +0,0 @@
|
||||||
angular.module('portainer.kubernetes').factory('KubernetesMetrics', [
|
|
||||||
'$resource',
|
|
||||||
'API_ENDPOINT_ENDPOINTS',
|
|
||||||
'EndpointProvider',
|
|
||||||
function KubernetesMetrics($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) {
|
|
||||||
'use strict';
|
|
||||||
return function (namespace) {
|
|
||||||
const url = API_ENDPOINT_ENDPOINTS + '/:endpointId/kubernetes/apis/metrics.k8s.io/v1beta1';
|
|
||||||
const podUrl = `${url}${namespace ? '/namespaces/:namespace' : ''}/pods/:id`;
|
|
||||||
|
|
||||||
return $resource(
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
endpointId: EndpointProvider.endpointID,
|
|
||||||
namespace: namespace,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
capabilities: { method: 'GET' },
|
|
||||||
getPod: {
|
|
||||||
method: 'GET',
|
|
||||||
url: podUrl,
|
|
||||||
},
|
|
||||||
getNode: {
|
|
||||||
method: 'GET',
|
|
||||||
url: `${url}/nodes/:id`,
|
|
||||||
},
|
|
||||||
getPods: {
|
|
||||||
method: 'GET',
|
|
||||||
url: `${url}/namespaces/:namespace/pods`,
|
|
||||||
},
|
|
||||||
getNodes: {
|
|
||||||
method: 'GET',
|
|
||||||
url: `${url}/nodes`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
]);
|
|
|
@ -4,10 +4,11 @@ import _ from 'lodash-es';
|
||||||
import filesizeParser from 'filesize-parser';
|
import filesizeParser from 'filesize-parser';
|
||||||
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
|
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
|
||||||
import KubernetesPodConverter from 'Kubernetes/pod/converter';
|
import KubernetesPodConverter from 'Kubernetes/pod/converter';
|
||||||
|
import { getMetricsForPod } from '@/react/kubernetes/services/service.ts';
|
||||||
|
|
||||||
class KubernetesApplicationStatsController {
|
class KubernetesApplicationStatsController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor($async, $state, $interval, $document, Notifications, KubernetesPodService, KubernetesNodeService, KubernetesMetricsService, ChartService) {
|
constructor($async, $state, $interval, $document, Notifications, KubernetesPodService, KubernetesNodeService, ChartService) {
|
||||||
this.$async = $async;
|
this.$async = $async;
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
this.$interval = $interval;
|
this.$interval = $interval;
|
||||||
|
@ -15,7 +16,6 @@ class KubernetesApplicationStatsController {
|
||||||
this.Notifications = Notifications;
|
this.Notifications = Notifications;
|
||||||
this.KubernetesPodService = KubernetesPodService;
|
this.KubernetesPodService = KubernetesPodService;
|
||||||
this.KubernetesNodeService = KubernetesNodeService;
|
this.KubernetesNodeService = KubernetesNodeService;
|
||||||
this.KubernetesMetricsService = KubernetesMetricsService;
|
|
||||||
this.ChartService = ChartService;
|
this.ChartService = ChartService;
|
||||||
|
|
||||||
this.onInit = this.onInit.bind(this);
|
this.onInit = this.onInit.bind(this);
|
||||||
|
@ -84,7 +84,7 @@ class KubernetesApplicationStatsController {
|
||||||
getStats() {
|
getStats() {
|
||||||
return this.$async(async () => {
|
return this.$async(async () => {
|
||||||
try {
|
try {
|
||||||
const stats = await this.KubernetesMetricsService.getPod(this.state.transition.namespace, this.state.transition.podName);
|
const stats = await getMetricsForPod(this.$state.params.endpointId, this.state.transition.namespace, this.state.transition.podName);
|
||||||
const container = _.find(stats.containers, { name: this.state.transition.containerName });
|
const container = _.find(stats.containers, { name: this.state.transition.containerName });
|
||||||
if (container) {
|
if (container) {
|
||||||
const memory = filesizeParser(container.usage.memory);
|
const memory = filesizeParser(container.usage.memory);
|
||||||
|
@ -126,7 +126,7 @@ class KubernetesApplicationStatsController {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.KubernetesMetricsService.getPod(this.state.transition.namespace, this.state.transition.podName);
|
await getMetricsForPod(this.$state.params.endpointId, this.state.transition.namespace, this.state.transition.podName);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.state.getMetrics = false;
|
this.state.getMetrics = false;
|
||||||
this.state.viewReady = true;
|
this.state.viewReady = true;
|
||||||
|
|
|
@ -3,27 +3,17 @@ import _ from 'lodash-es';
|
||||||
import filesizeParser from 'filesize-parser';
|
import filesizeParser from 'filesize-parser';
|
||||||
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
|
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
|
||||||
import { KubernetesResourceReservation } from 'Kubernetes/models/resource-reservation/models';
|
import { KubernetesResourceReservation } from 'Kubernetes/models/resource-reservation/models';
|
||||||
|
import { getMetricsForAllNodes } from '@/react/kubernetes/services/service.ts';
|
||||||
|
|
||||||
class KubernetesClusterController {
|
class KubernetesClusterController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor(
|
constructor($async, $state, Notifications, LocalStorage, Authentication, KubernetesNodeService, KubernetesApplicationService, KubernetesEndpointService) {
|
||||||
$async,
|
|
||||||
$state,
|
|
||||||
Authentication,
|
|
||||||
Notifications,
|
|
||||||
LocalStorage,
|
|
||||||
KubernetesNodeService,
|
|
||||||
KubernetesMetricsService,
|
|
||||||
KubernetesApplicationService,
|
|
||||||
KubernetesEndpointService
|
|
||||||
) {
|
|
||||||
this.$async = $async;
|
this.$async = $async;
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
this.Authentication = Authentication;
|
this.Authentication = Authentication;
|
||||||
this.Notifications = Notifications;
|
this.Notifications = Notifications;
|
||||||
this.LocalStorage = LocalStorage;
|
this.LocalStorage = LocalStorage;
|
||||||
this.KubernetesNodeService = KubernetesNodeService;
|
this.KubernetesNodeService = KubernetesNodeService;
|
||||||
this.KubernetesMetricsService = KubernetesMetricsService;
|
|
||||||
this.KubernetesApplicationService = KubernetesApplicationService;
|
this.KubernetesApplicationService = KubernetesApplicationService;
|
||||||
this.KubernetesEndpointService = KubernetesEndpointService;
|
this.KubernetesEndpointService = KubernetesEndpointService;
|
||||||
|
|
||||||
|
@ -108,7 +98,7 @@ class KubernetesClusterController {
|
||||||
|
|
||||||
async getResourceUsage(endpointId) {
|
async getResourceUsage(endpointId) {
|
||||||
try {
|
try {
|
||||||
const nodeMetrics = await this.KubernetesMetricsService.getNodes(endpointId);
|
const nodeMetrics = await getMetricsForAllNodes(endpointId);
|
||||||
const resourceUsageList = nodeMetrics.items.map((i) => i.usage);
|
const resourceUsageList = nodeMetrics.items.map((i) => i.usage);
|
||||||
const clusterResourceUsage = resourceUsageList.reduce((total, u) => {
|
const clusterResourceUsage = resourceUsageList.reduce((total, u) => {
|
||||||
total.CPU += KubernetesResourceReservationHelper.parseCPU(u.cpu);
|
total.CPU += KubernetesResourceReservationHelper.parseCPU(u.cpu);
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { KubernetesNodeTaintEffects, KubernetesNodeAvailabilities } from 'Kubern
|
||||||
import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper';
|
import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper';
|
||||||
import { KubernetesNodeHelper } from 'Kubernetes/node/helper';
|
import { KubernetesNodeHelper } from 'Kubernetes/node/helper';
|
||||||
import { confirmUpdateNode } from '@/react/kubernetes/cluster/NodeView/ConfirmUpdateNode';
|
import { confirmUpdateNode } from '@/react/kubernetes/cluster/NodeView/ConfirmUpdateNode';
|
||||||
|
import { getMetricsForNode } from '@/react/kubernetes/services/service.ts';
|
||||||
|
|
||||||
class KubernetesNodeController {
|
class KubernetesNodeController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
|
@ -22,7 +23,6 @@ class KubernetesNodeController {
|
||||||
KubernetesPodService,
|
KubernetesPodService,
|
||||||
KubernetesApplicationService,
|
KubernetesApplicationService,
|
||||||
KubernetesEndpointService,
|
KubernetesEndpointService,
|
||||||
KubernetesMetricsService,
|
|
||||||
Authentication
|
Authentication
|
||||||
) {
|
) {
|
||||||
this.$async = $async;
|
this.$async = $async;
|
||||||
|
@ -34,7 +34,6 @@ class KubernetesNodeController {
|
||||||
this.KubernetesPodService = KubernetesPodService;
|
this.KubernetesPodService = KubernetesPodService;
|
||||||
this.KubernetesApplicationService = KubernetesApplicationService;
|
this.KubernetesApplicationService = KubernetesApplicationService;
|
||||||
this.KubernetesEndpointService = KubernetesEndpointService;
|
this.KubernetesEndpointService = KubernetesEndpointService;
|
||||||
this.KubernetesMetricsService = KubernetesMetricsService;
|
|
||||||
this.Authentication = Authentication;
|
this.Authentication = Authentication;
|
||||||
|
|
||||||
this.onInit = this.onInit.bind(this);
|
this.onInit = this.onInit.bind(this);
|
||||||
|
@ -300,7 +299,7 @@ class KubernetesNodeController {
|
||||||
async getNodeUsageAsync() {
|
async getNodeUsageAsync() {
|
||||||
try {
|
try {
|
||||||
const nodeName = this.$transition$.params().name;
|
const nodeName = this.$transition$.params().name;
|
||||||
const node = await this.KubernetesMetricsService.getNode(nodeName);
|
const node = await getMetricsForNode(this.$state.params.endpointId, nodeName);
|
||||||
this.resourceUsage = new KubernetesResourceReservation();
|
this.resourceUsage = new KubernetesResourceReservation();
|
||||||
this.resourceUsage.CPU = KubernetesResourceReservationHelper.parseCPU(node.usage.cpu);
|
this.resourceUsage.CPU = KubernetesResourceReservationHelper.parseCPU(node.usage.cpu);
|
||||||
this.resourceUsage.Memory = KubernetesResourceReservationHelper.megaBytesValue(node.usage.memory);
|
this.resourceUsage.Memory = KubernetesResourceReservationHelper.megaBytesValue(node.usage.memory);
|
||||||
|
|
|
@ -3,17 +3,17 @@ import moment from 'moment';
|
||||||
import filesizeParser from 'filesize-parser';
|
import filesizeParser from 'filesize-parser';
|
||||||
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
|
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
|
||||||
import { PORTAINER_FADEOUT } from '@/constants';
|
import { PORTAINER_FADEOUT } from '@/constants';
|
||||||
|
import { getMetricsForNode } from '@/react/kubernetes/services/service.ts';
|
||||||
|
|
||||||
class KubernetesNodeStatsController {
|
class KubernetesNodeStatsController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor($async, $state, $interval, $document, Notifications, KubernetesNodeService, KubernetesMetricsService, ChartService) {
|
constructor($async, $state, $interval, $document, Notifications, KubernetesNodeService, ChartService) {
|
||||||
this.$async = $async;
|
this.$async = $async;
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
this.$interval = $interval;
|
this.$interval = $interval;
|
||||||
this.$document = $document;
|
this.$document = $document;
|
||||||
this.Notifications = Notifications;
|
this.Notifications = Notifications;
|
||||||
this.KubernetesNodeService = KubernetesNodeService;
|
this.KubernetesNodeService = KubernetesNodeService;
|
||||||
this.KubernetesMetricsService = KubernetesMetricsService;
|
|
||||||
this.ChartService = ChartService;
|
this.ChartService = ChartService;
|
||||||
|
|
||||||
this.onInit = this.onInit.bind(this);
|
this.onInit = this.onInit.bind(this);
|
||||||
|
@ -79,7 +79,7 @@ class KubernetesNodeStatsController {
|
||||||
getStats() {
|
getStats() {
|
||||||
return this.$async(async () => {
|
return this.$async(async () => {
|
||||||
try {
|
try {
|
||||||
const stats = await this.KubernetesMetricsService.getNode(this.state.transition.nodeName);
|
const stats = await getMetricsForNode(this.$state.params.endpointId, this.state.transition.nodeName);
|
||||||
if (stats) {
|
if (stats) {
|
||||||
const memory = filesizeParser(stats.usage.memory);
|
const memory = filesizeParser(stats.usage.memory);
|
||||||
const cpu = KubernetesResourceReservationHelper.parseCPU(stats.usage.cpu);
|
const cpu = KubernetesResourceReservationHelper.parseCPU(stats.usage.cpu);
|
||||||
|
@ -111,7 +111,7 @@ class KubernetesNodeStatsController {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const nodeMetrics = await this.KubernetesMetricsService.getNode(this.state.transition.nodeName);
|
const nodeMetrics = await getMetricsForNode(this.$state.params.endpointId, this.state.transition.nodeName);
|
||||||
|
|
||||||
if (nodeMetrics) {
|
if (nodeMetrics) {
|
||||||
const node = await this.KubernetesNodeService.get(this.state.transition.nodeName);
|
const node = await this.KubernetesNodeService.get(this.state.transition.nodeName);
|
||||||
|
|
|
@ -11,23 +11,13 @@ import { buildConfirmButton } from '@@/modals/utils';
|
||||||
import { confirm } from '@@/modals/confirm';
|
import { confirm } from '@@/modals/confirm';
|
||||||
import { getIsRBACEnabled } from '@/react/kubernetes/cluster/getIsRBACEnabled';
|
import { getIsRBACEnabled } from '@/react/kubernetes/cluster/getIsRBACEnabled';
|
||||||
import { ModalType } from '@@/modals/Modal/types';
|
import { ModalType } from '@@/modals/Modal/types';
|
||||||
|
import { getMetricsForAllNodes } from '@/react/kubernetes/services/service.ts';
|
||||||
|
|
||||||
class KubernetesConfigureController {
|
class KubernetesConfigureController {
|
||||||
/* #region CONSTRUCTOR */
|
/* #region CONSTRUCTOR */
|
||||||
|
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor(
|
constructor($async, $state, $scope, Notifications, KubernetesStorageService, EndpointService, EndpointProvider, KubernetesResourcePoolService, KubernetesIngressService) {
|
||||||
$async,
|
|
||||||
$state,
|
|
||||||
$scope,
|
|
||||||
Notifications,
|
|
||||||
KubernetesStorageService,
|
|
||||||
EndpointService,
|
|
||||||
EndpointProvider,
|
|
||||||
KubernetesResourcePoolService,
|
|
||||||
KubernetesIngressService,
|
|
||||||
KubernetesMetricsService
|
|
||||||
) {
|
|
||||||
this.$async = $async;
|
this.$async = $async;
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
this.$scope = $scope;
|
this.$scope = $scope;
|
||||||
|
@ -37,7 +27,6 @@ class KubernetesConfigureController {
|
||||||
this.EndpointProvider = EndpointProvider;
|
this.EndpointProvider = EndpointProvider;
|
||||||
this.KubernetesResourcePoolService = KubernetesResourcePoolService;
|
this.KubernetesResourcePoolService = KubernetesResourcePoolService;
|
||||||
this.KubernetesIngressService = KubernetesIngressService;
|
this.KubernetesIngressService = KubernetesIngressService;
|
||||||
this.KubernetesMetricsService = KubernetesMetricsService;
|
|
||||||
|
|
||||||
this.IngressClassTypes = KubernetesIngressClassTypes;
|
this.IngressClassTypes = KubernetesIngressClassTypes;
|
||||||
|
|
||||||
|
@ -192,24 +181,26 @@ class KubernetesConfigureController {
|
||||||
}
|
}
|
||||||
|
|
||||||
enableMetricsServer() {
|
enableMetricsServer() {
|
||||||
if (this.formValues.UseServerMetrics) {
|
return this.$async(async () => {
|
||||||
this.state.metrics.userClick = true;
|
if (this.formValues.UseServerMetrics) {
|
||||||
this.state.metrics.pending = true;
|
this.state.metrics.userClick = true;
|
||||||
this.KubernetesMetricsService.capabilities(this.endpoint.Id)
|
this.state.metrics.pending = true;
|
||||||
.then(() => {
|
try {
|
||||||
|
await getMetricsForAllNodes(this.endpoint.Id);
|
||||||
this.state.metrics.isServerRunning = true;
|
this.state.metrics.isServerRunning = true;
|
||||||
this.state.metrics.pending = false;
|
this.state.metrics.pending = false;
|
||||||
|
this.state.metrics.userClick = false;
|
||||||
this.formValues.UseServerMetrics = true;
|
this.formValues.UseServerMetrics = true;
|
||||||
})
|
} catch (_) {
|
||||||
.catch(() => {
|
|
||||||
this.state.metrics.isServerRunning = false;
|
this.state.metrics.isServerRunning = false;
|
||||||
this.state.metrics.pending = false;
|
this.state.metrics.pending = false;
|
||||||
this.formValues.UseServerMetrics = false;
|
this.formValues.UseServerMetrics = false;
|
||||||
});
|
}
|
||||||
} else {
|
} else {
|
||||||
this.state.metrics.userClick = false;
|
this.state.metrics.userClick = false;
|
||||||
this.formValues.UseServerMetrics = false;
|
this.formValues.UseServerMetrics = false;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async configureAsync() {
|
async configureAsync() {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { FeatureId } from '@/react/portainer/feature-flags/enums';
|
||||||
import { updateIngressControllerClassMap, getIngressControllerClassMap } from '@/react/kubernetes/cluster/ingressClass/utils';
|
import { updateIngressControllerClassMap, getIngressControllerClassMap } from '@/react/kubernetes/cluster/ingressClass/utils';
|
||||||
import { confirmUpdate } from '@@/modals/confirm';
|
import { confirmUpdate } from '@@/modals/confirm';
|
||||||
import { confirmUpdateNamespace } from '@/react/kubernetes/namespaces/ItemView/ConfirmUpdateNamespace';
|
import { confirmUpdateNamespace } from '@/react/kubernetes/namespaces/ItemView/ConfirmUpdateNamespace';
|
||||||
|
import { getMetricsForAllNodes, getMetricsForAllPods } from '@/react/kubernetes/services/service.ts';
|
||||||
|
|
||||||
class KubernetesResourcePoolController {
|
class KubernetesResourcePoolController {
|
||||||
/* #region CONSTRUCTOR */
|
/* #region CONSTRUCTOR */
|
||||||
|
@ -28,8 +29,6 @@ class KubernetesResourcePoolController {
|
||||||
Notifications,
|
Notifications,
|
||||||
LocalStorage,
|
LocalStorage,
|
||||||
EndpointService,
|
EndpointService,
|
||||||
KubernetesNodeService,
|
|
||||||
KubernetesMetricsService,
|
|
||||||
KubernetesResourceQuotaService,
|
KubernetesResourceQuotaService,
|
||||||
KubernetesResourcePoolService,
|
KubernetesResourcePoolService,
|
||||||
KubernetesEventService,
|
KubernetesEventService,
|
||||||
|
@ -47,8 +46,6 @@ class KubernetesResourcePoolController {
|
||||||
Notifications,
|
Notifications,
|
||||||
LocalStorage,
|
LocalStorage,
|
||||||
EndpointService,
|
EndpointService,
|
||||||
KubernetesNodeService,
|
|
||||||
KubernetesMetricsService,
|
|
||||||
KubernetesResourceQuotaService,
|
KubernetesResourceQuotaService,
|
||||||
KubernetesResourcePoolService,
|
KubernetesResourcePoolService,
|
||||||
KubernetesEventService,
|
KubernetesEventService,
|
||||||
|
@ -322,7 +319,7 @@ class KubernetesResourcePoolController {
|
||||||
|
|
||||||
async getResourceUsage(namespace) {
|
async getResourceUsage(namespace) {
|
||||||
try {
|
try {
|
||||||
const namespaceMetrics = await this.KubernetesMetricsService.getPods(namespace);
|
const namespaceMetrics = await getMetricsForAllPods(this.$state.params.endpointId, namespace);
|
||||||
// extract resource usage of all containers within each pod of the namespace
|
// extract resource usage of all containers within each pod of the namespace
|
||||||
const containerResourceUsageList = namespaceMetrics.items.flatMap((i) => i.containers.map((c) => c.usage));
|
const containerResourceUsageList = namespaceMetrics.items.flatMap((i) => i.containers.map((c) => c.usage));
|
||||||
const namespaceResourceUsage = containerResourceUsageList.reduce((total, u) => {
|
const namespaceResourceUsage = containerResourceUsageList.reduce((total, u) => {
|
||||||
|
@ -369,7 +366,7 @@ class KubernetesResourcePoolController {
|
||||||
|
|
||||||
const name = this.$state.params.id;
|
const name = this.$state.params.id;
|
||||||
|
|
||||||
const [nodes, pools] = await Promise.all([this.KubernetesNodeService.get(), this.KubernetesResourcePoolService.get('', { getQuota: true })]);
|
const [nodes, pools] = await Promise.all([getMetricsForAllNodes, this.KubernetesResourcePoolService.get('', { getQuota: true })]);
|
||||||
|
|
||||||
this.ingressControllers = [];
|
this.ingressControllers = [];
|
||||||
if (this.state.ingressAvailabilityPerNamespace) {
|
if (this.state.ingressAvailabilityPerNamespace) {
|
||||||
|
|
|
@ -6,8 +6,11 @@ import { withError } from '@/react-tools/react-query';
|
||||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
import { isFulfilled } from '@/portainer/helpers/promise-utils';
|
import { isFulfilled } from '@/portainer/helpers/promise-utils';
|
||||||
|
import {
|
||||||
import { Service } from './types';
|
NodeMetrics,
|
||||||
|
NodeMetric,
|
||||||
|
Service,
|
||||||
|
} from '@/react/kubernetes/services/types';
|
||||||
|
|
||||||
export const queryKeys = {
|
export const queryKeys = {
|
||||||
clusterServices: (environmentId: EnvironmentId) =>
|
clusterServices: (environmentId: EnvironmentId) =>
|
||||||
|
@ -105,3 +108,67 @@ export async function deleteServices({
|
||||||
throw parseAxiosError(e as Error, 'Unable to delete service(s)');
|
throw parseAxiosError(e as Error, 'Unable to delete service(s)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getMetricsForAllNodes(environmentId: EnvironmentId) {
|
||||||
|
try {
|
||||||
|
const { data: nodes } = await axios.get<NodeMetrics>(
|
||||||
|
`kubernetes/${environmentId}/metrics/nodes`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
return nodes;
|
||||||
|
} catch (e) {
|
||||||
|
throw parseAxiosError(
|
||||||
|
e as Error,
|
||||||
|
'Unable to retrieve metrics for all nodes'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMetricsForNode(
|
||||||
|
environmentId: EnvironmentId,
|
||||||
|
nodeName: string
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { data: node } = await axios.get<NodeMetric>(
|
||||||
|
`kubernetes/${environmentId}/metrics/nodes/${nodeName}`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
return node;
|
||||||
|
} catch (e) {
|
||||||
|
throw parseAxiosError(e as Error, 'Unable to retrieve metrics for node');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMetricsForAllPods(
|
||||||
|
environmentId: EnvironmentId,
|
||||||
|
namespace: string
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { data: pods } = await axios.get(
|
||||||
|
`kubernetes/${environmentId}/metrics/pods/namespace/${namespace}`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
return pods;
|
||||||
|
} catch (e) {
|
||||||
|
throw parseAxiosError(
|
||||||
|
e as Error,
|
||||||
|
'Unable to retrieve metrics for all pods'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMetricsForPod(
|
||||||
|
environmentId: EnvironmentId,
|
||||||
|
namespace: string,
|
||||||
|
podName: string
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { data: pod } = await axios.get(
|
||||||
|
`kubernetes/${environmentId}/metrics/pods/namespace/${namespace}/${podName}`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
return pod;
|
||||||
|
} catch (e) {
|
||||||
|
throw parseAxiosError(e as Error, 'Unable to retrieve metrics for pod');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,3 +39,24 @@ export type Service = {
|
||||||
CreationTimestamp: string;
|
CreationTimestamp: string;
|
||||||
Applications?: Application[];
|
Applications?: Application[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type NodeMetrics = {
|
||||||
|
items: NodeMetric[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NodeMetric = {
|
||||||
|
metadata: NodeMetricMetadata;
|
||||||
|
timestamp: Date;
|
||||||
|
usage: Usage;
|
||||||
|
window: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NodeMetricMetadata = {
|
||||||
|
creationTimestamp: Date;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Usage = {
|
||||||
|
cpu: string;
|
||||||
|
memory: string;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue