cli: add status cmd

The new command allows checking the status of an upgrade
and which versions are installed.
Also remove the unused restclient.
And make GetConstellationVersion a function.
This commit is contained in:
Otto Bittner 2023-03-24 11:51:18 +01:00
parent 93e55d2f78
commit c8c2953d7b
19 changed files with 707 additions and 835 deletions

View File

@ -71,14 +71,6 @@ def go_dependencies():
sum = "h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=",
version = "v0.0.0-20180502004556-fa1af6a1f4f5",
)
go_repository(
name = "com_github_ajg_form",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/ajg/form",
sum = "h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=",
version = "v1.5.1",
)
go_repository(
name = "com_github_alcortesm_tgz",
@ -113,14 +105,6 @@ def go_dependencies():
sum = "h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=",
version = "v0.0.0-20190924025748-f65c72e2690d",
)
go_repository(
name = "com_github_andreasbriese_bbloom",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/AndreasBriese/bbloom",
sum = "h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=",
version = "v0.0.0-20190306092124-e2d15f34fcf9",
)
go_repository(
name = "com_github_andybalholm_brotli",
@ -557,14 +541,6 @@ def go_dependencies():
sum = "h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=",
version = "v0.2.0",
)
go_repository(
name = "com_github_aymerick_raymond",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/aymerick/raymond",
sum = "h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=",
version = "v2.0.3-0.20180322193309-b565731e1464+incompatible",
)
go_repository(
name = "com_github_azure_azure_amqp_common_go_v2",
@ -1085,14 +1061,6 @@ def go_dependencies():
sum = "h1:wpFFOoomK3389ue2lAb0Boag6XPht5QYpipxmSNL4d8=",
version = "v5.3.0",
)
go_repository(
name = "com_github_cheekybits_is",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/cheekybits/is",
sum = "h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=",
version = "v0.0.0-20150225183255-68e9c0620927",
)
go_repository(
name = "com_github_chzyer_logex",
@ -1166,22 +1134,6 @@ def go_dependencies():
sum = "h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=",
version = "v0.0.0-20200109182630-33d98a066a53",
)
go_repository(
name = "com_github_cloudykit_jet",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/CloudyKit/jet",
sum = "h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE=",
version = "v2.1.3-0.20180809161101-62edd43e4f88+incompatible",
)
go_repository(
name = "com_github_cloudykit_jet_v3",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/CloudyKit/jet/v3",
sum = "h1:1PwO5w5VCtlUUl+KTOBsTGZlhjWkcybsGaAau52tOy8=",
version = "v3.0.0",
)
go_repository(
name = "com_github_cloudykit_jet_v6",
@ -1246,8 +1198,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/cockroachdb/logtags",
sum = "h1:6jduT9Hfc0njg5jJ1DdKCFPdMBrp/mdZfCpa5h+WM74=",
version = "v0.0.0-20211118104740-dabe8e521a4f",
sum = "h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=",
version = "v0.0.0-20190617123548-eb05cc24525f",
)
go_repository(
name = "com_github_cockroachdb_redact",
@ -1257,14 +1209,6 @@ def go_dependencies():
sum = "h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=",
version = "v1.1.3",
)
go_repository(
name = "com_github_cockroachdb_sentry_go",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/cockroachdb/sentry-go",
sum = "h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=",
version = "v0.6.1-cockroachdb.2",
)
go_repository(
name = "com_github_codahale_hdrhistogram",
@ -1636,30 +1580,6 @@ def go_dependencies():
sum = "h1:3mD6Kb1mUOYeLpJvTVSDwSg5ZsfSxfvxGRTxRsJsITA=",
version = "v0.1.1",
)
go_repository(
name = "com_github_dgraph_io_badger",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/dgraph-io/badger",
sum = "h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo=",
version = "v1.6.0",
)
go_repository(
name = "com_github_dgraph_io_badger_v2",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/dgraph-io/badger/v2",
sum = "h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=",
version = "v2.2007.4",
)
go_repository(
name = "com_github_dgraph_io_ristretto",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/dgraph-io/ristretto",
sum = "h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=",
version = "v0.0.3-0.20200630154024-f66de99634de",
)
go_repository(
name = "com_github_dgrijalva_jwt_go",
@ -1669,14 +1589,6 @@ def go_dependencies():
sum = "h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=",
version = "v3.2.0+incompatible",
)
go_repository(
name = "com_github_dgryski_go_farm",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/dgryski/go-farm",
sum = "h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=",
version = "v0.0.0-20190423205320-6a90982ecee2",
)
go_repository(
name = "com_github_dgryski_go_rendezvous",
@ -1711,14 +1623,6 @@ def go_dependencies():
sum = "h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=",
version = "v3.0.0-20221208165359-362910506bc2",
)
go_repository(
name = "com_github_djherbis_atime",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/djherbis/atime",
sum = "h1:rgwVbP/5by8BvvjBNrbh64Qz33idKT3pSnMSJsxhi0g=",
version = "v1.1.0",
)
go_repository(
name = "com_github_dnaeon_go_vcr",
@ -1923,14 +1827,6 @@ def go_dependencies():
sum = "h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY=",
version = "v0.9.1",
)
go_repository(
name = "com_github_etcd_io_bbolt",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/etcd-io/bbolt",
sum = "h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=",
version = "v1.3.3",
)
go_repository(
name = "com_github_etcd_io_gofail",
@ -1996,14 +1892,6 @@ def go_dependencies():
sum = "h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8=",
version = "v0.0.0-20150708232844-fd3d7953fd52",
)
go_repository(
name = "com_github_fasthttp_contrib_websocket",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/fasthttp-contrib/websocket",
sum = "h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc=",
version = "v0.0.0-20160511215533-1f3b11f56072",
)
go_repository(
name = "com_github_fatih_camelcase",
@ -2038,14 +1926,6 @@ def go_dependencies():
sum = "h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=",
version = "v1.0.3",
)
go_repository(
name = "com_github_flosch_pongo2",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/flosch/pongo2",
sum = "h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=",
version = "v0.0.0-20190707114632-bbf5a6c351f4",
)
go_repository(
name = "com_github_flosch_pongo2_v4",
@ -2146,14 +2026,6 @@ def go_dependencies():
sum = "h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=",
version = "v2.4.0",
)
go_repository(
name = "com_github_gavv_httpexpect",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gavv/httpexpect",
sum = "h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=",
version = "v2.0.0+incompatible",
)
go_repository(
name = "com_github_gertd_go_pluralize",
@ -2213,14 +2085,6 @@ def go_dependencies():
sum = "h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=",
version = "v0.3.5",
)
go_repository(
name = "com_github_go_check_check",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/go-check/check",
sum = "h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=",
version = "v0.0.0-20180628173108-788fd7840127",
)
go_repository(
name = "com_github_go_chi_chi",
@ -2366,14 +2230,6 @@ def go_dependencies():
sum = "h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=",
version = "v0.0.0-20170121215854-22fa46961aab",
)
go_repository(
name = "com_github_go_ole_go_ole",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/go-ole/go-ole",
sum = "h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=",
version = "v1.2.6",
)
go_repository(
name = "com_github_go_openapi_analysis",
@ -2648,30 +2504,6 @@ def go_dependencies():
sum = "h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=",
version = "v0.2.3",
)
go_repository(
name = "com_github_gobwas_httphead",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gobwas/httphead",
sum = "h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=",
version = "v0.1.0",
)
go_repository(
name = "com_github_gobwas_pool",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gobwas/pool",
sum = "h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=",
version = "v0.2.1",
)
go_repository(
name = "com_github_gobwas_ws",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gobwas/ws",
sum = "h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=",
version = "v1.1.0",
)
go_repository(
name = "com_github_goccy_go_json",
@ -2727,8 +2559,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gogo/googleapis",
sum = "h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=",
version = "v1.4.1",
sum = "h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI=",
version = "v1.4.0",
)
go_repository(
name = "com_github_gogo_protobuf",
@ -2738,14 +2570,6 @@ def go_dependencies():
sum = "h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=",
version = "v1.3.2",
)
go_repository(
name = "com_github_gogo_status",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gogo/status",
sum = "h1:+eIkrewn5q6b30y+g/BJINVVdi2xH7je5MPJ3ZPK3JA=",
version = "v1.1.0",
)
go_repository(
name = "com_github_golang_glog",
@ -2768,8 +2592,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/golang-jwt/jwt",
sum = "h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=",
version = "v3.2.2+incompatible",
sum = "h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=",
version = "v3.2.1+incompatible",
)
go_repository(
name = "com_github_golang_jwt_jwt_v4",
@ -2921,8 +2745,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/google/go-querystring",
sum = "h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=",
version = "v1.1.0",
sum = "h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=",
version = "v1.0.0",
)
go_repository(
name = "com_github_google_go_replayers_grpcreplay",
@ -3173,8 +2997,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gopherjs/gopherjs",
sum = "h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=",
version = "v1.17.2",
sum = "h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=",
version = "v0.0.0-20181017120253-0766667cb4d1",
)
go_repository(
name = "com_github_gordonklaus_ineffassign",
@ -3233,22 +3057,14 @@ def go_dependencies():
sum = "h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=",
version = "v1.8.0",
)
go_repository(
name = "com_github_gorilla_securecookie",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gorilla/securecookie",
sum = "h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=",
version = "v1.1.1",
)
go_repository(
name = "com_github_gorilla_websocket",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/gorilla/websocket",
sum = "h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=",
version = "v1.5.0",
sum = "h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=",
version = "v1.4.2",
)
go_repository(
name = "com_github_gosuri_uitable",
@ -3625,14 +3441,6 @@ def go_dependencies():
sum = "h1:0U6+BtN6LhaYuTnIJq4Wyq5cpn6O2kWrxAtcqBmYY6w=",
version = "v1.3.0",
)
go_repository(
name = "com_github_hydrogen18_memlistener",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/hydrogen18/memlistener",
sum = "h1:KyZDvZ/GGn+r+Y3DKZ7UOQ/TP4xV6HNkrwiVMB1GnNY=",
version = "v0.0.0-20200120041712-dcc25e7acd91",
)
go_repository(
name = "com_github_iancoleman_strcase",
@ -3659,14 +3467,6 @@ def go_dependencies():
sum = "h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=",
version = "v0.3.13",
)
go_repository(
name = "com_github_imkira_go_interpol",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/imkira/go-interpol",
sum = "h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=",
version = "v1.1.0",
)
go_repository(
name = "com_github_in_toto_in_toto_golang",
@ -3702,38 +3502,6 @@ def go_dependencies():
sum = "h1:JyZjdMQu9Kl/wLXe9xA6s1X+tF6BWsQPFGJMEeCfWzE=",
version = "v0.2.0",
)
go_repository(
name = "com_github_iris_contrib_blackfriday",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/iris-contrib/blackfriday",
sum = "h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4=",
version = "v2.0.0+incompatible",
)
go_repository(
name = "com_github_iris_contrib_go_uuid",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/iris-contrib/go.uuid",
sum = "h1:XZubAYg61/JwnJNbZilGjf3b3pB80+OQg2qf6c8BfWE=",
version = "v2.0.0+incompatible",
)
go_repository(
name = "com_github_iris_contrib_httpexpect_v2",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/iris-contrib/httpexpect/v2",
sum = "h1:A69ilxKGW1jDRKK5UAhjTL4uJYh3RjD4qzt9vNZ7fpY=",
version = "v2.3.1",
)
go_repository(
name = "com_github_iris_contrib_i18n",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/iris-contrib/i18n",
sum = "h1:Kyp9KiXwsyZRTeoNjgVCrWks7D8ht9+kg6yCjh8K97o=",
version = "v0.0.0-20171121225848-987a633949d0",
)
go_repository(
name = "com_github_iris_contrib_jade",
@ -3743,14 +3511,6 @@ def go_dependencies():
sum = "h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0=",
version = "v1.1.4",
)
go_repository(
name = "com_github_iris_contrib_pongo2",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/iris-contrib/pongo2",
sum = "h1:zGP7pW51oi5eQZMIlGA3I+FHY9/HOQWDB+572yin0to=",
version = "v0.0.1",
)
go_repository(
name = "com_github_iris_contrib_schema",
@ -3996,22 +3756,6 @@ def go_dependencies():
sum = "h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=",
version = "v1.3.0",
)
go_repository(
name = "com_github_joker_hpp",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/Joker/hpp",
sum = "h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=",
version = "v1.0.0",
)
go_repository(
name = "com_github_joker_jade",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/Joker/jade",
sum = "h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8=",
version = "v1.0.1-0.20190614124447-d475f43051e7",
)
go_repository(
name = "com_github_jonboulle_clockwork",
@ -4077,22 +3821,6 @@ def go_dependencies():
sum = "h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=",
version = "v4.20.0+incompatible",
)
go_repository(
name = "com_github_juju_errors",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/juju/errors",
sum = "h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=",
version = "v0.0.0-20181118221551-089d3ea4e4d5",
)
go_repository(
name = "com_github_juju_loggo",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/juju/loggo",
sum = "h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8=",
version = "v0.0.0-20180524022052-584905176618",
)
go_repository(
name = "com_github_juju_ratelimit",
@ -4102,14 +3830,6 @@ def go_dependencies():
sum = "h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY=",
version = "v1.0.1",
)
go_repository(
name = "com_github_juju_testing",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/juju/testing",
sum = "h1:WQM1NildKThwdP7qWrNAFGzp4ijNLw8RlgENkaI4MJs=",
version = "v0.0.0-20180920084828-472a3e8b2073",
)
go_repository(
name = "com_github_julienschmidt_httprouter",
@ -4119,14 +3839,6 @@ def go_dependencies():
sum = "h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=",
version = "v1.3.0",
)
go_repository(
name = "com_github_k0kubun_colorstring",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/k0kubun/colorstring",
sum = "h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=",
version = "v0.0.0-20150214042306-9440f1994b88",
)
go_repository(
name = "com_github_k0kubun_go_ansi",
@ -4168,22 +3880,6 @@ def go_dependencies():
sum = "h1:grB/oCf5baZhmYIeDMfgN3LYrtEcmK8pbxlRvEZ2pgw=",
version = "v12.2.0-beta5",
)
go_repository(
name = "com_github_kataras_jwt",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/kataras/jwt",
sum = "h1:u71baOsYD22HWeSOg32tCHbczPjdCk7V4MMeJqTtmGk=",
version = "v0.1.8",
)
go_repository(
name = "com_github_kataras_neffos",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/kataras/neffos",
sum = "h1:swTzKZ3Mo2sIQ8ATKSKf0xDG1tuhr6w4tZmmRsvCYlg=",
version = "v0.0.20",
)
go_repository(
name = "com_github_kataras_pio",
@ -4259,14 +3955,6 @@ def go_dependencies():
sum = "h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=",
version = "v1.15.12",
)
go_repository(
name = "com_github_klauspost_cpuid",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/klauspost/cpuid",
sum = "h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=",
version = "v1.2.1",
)
go_repository(
name = "com_github_klauspost_cpuid_v2",
@ -4473,14 +4161,6 @@ def go_dependencies():
sum = "h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=",
version = "v1.1.0",
)
go_repository(
name = "com_github_lufia_plan9stats",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/lufia/plan9stats",
sum = "h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=",
version = "v0.0.0-20211012122336-39d0f177ccd0",
)
go_repository(
name = "com_github_lyft_protoc_gen_star",
@ -4633,14 +4313,6 @@ def go_dependencies():
sum = "h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=",
version = "v1.2.0",
)
go_repository(
name = "com_github_matryer_try",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/matryer/try",
sum = "h1:JAEbJn3j/FrhdWA9jW8B5ajsLIjeuEHLi8xE4fk997o=",
version = "v0.0.0-20161228173917-9ac251b645a2",
)
go_repository(
name = "com_github_mattn_go_colorable",
@ -4706,14 +4378,6 @@ def go_dependencies():
sum = "h1:xsEx/XUoVlI6yXjqBK062zYhRTZltCNmYPx6v+8DNaY=",
version = "v0.0.1",
)
go_repository(
name = "com_github_mattn_goveralls",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/mattn/goveralls",
sum = "h1:7eJB6EqsPhRVxvwEXGnqdO2sJI0PTsrWoTMXEk9/OQc=",
version = "v0.0.2",
)
go_repository(
name = "com_github_matttproud_golang_protobuf_extensions",
@ -4755,22 +4419,6 @@ def go_dependencies():
sum = "h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw=",
version = "v0.4.0",
)
go_repository(
name = "com_github_mediocregopher_mediocre_go_lib",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/mediocregopher/mediocre-go-lib",
sum = "h1:3dQJqqDouawQgl3gBE1PNHKFkJYGEuFb1DbSlaxdosE=",
version = "v0.0.0-20181029021733-cb65787f37ed",
)
go_repository(
name = "com_github_mediocregopher_radix_v3",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/mediocregopher/radix/v3",
sum = "h1:HI8EgkaM7WzsrFpYAkOXIgUKbjNonb2Ne7K6Le61Pmg=",
version = "v3.8.0",
)
go_repository(
name = "com_github_mediocregopher_radix_v4",
@ -4861,14 +4509,6 @@ def go_dependencies():
sum = "h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=",
version = "v0.0.0-20190812172519-36a3d3bbc4f3",
)
go_repository(
name = "com_github_minio_highwayhash",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/minio/highwayhash",
sum = "h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=",
version = "v1.0.2",
)
go_repository(
name = "com_github_mistifyio_go_zfs",
@ -5071,14 +4711,6 @@ def go_dependencies():
sum = "h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=",
version = "v1.0.0",
)
go_repository(
name = "com_github_moul_http2curl",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/moul/http2curl",
sum = "h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=",
version = "v1.0.0",
)
go_repository(
name = "com_github_mr_tron_base58",
@ -5138,22 +4770,14 @@ def go_dependencies():
sum = "h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=",
version = "v0.3.2",
)
go_repository(
name = "com_github_nats_io_jwt_v2",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/nats-io/jwt/v2",
sum = "h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI=",
version = "v2.3.0",
)
go_repository(
name = "com_github_nats_io_nats_go",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/nats-io/nats.go",
sum = "h1:zvLE7fGBQYW6MWaFaRdsgm9qT39PJDQoju+DS8KsO1g=",
version = "v1.16.0",
sum = "h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=",
version = "v1.9.1",
)
go_repository(
name = "com_github_nats_io_nats_server_v2",
@ -5168,8 +4792,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/nats-io/nkeys",
sum = "h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=",
version = "v0.3.0",
sum = "h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k=",
version = "v0.1.3",
)
go_repository(
name = "com_github_nats_io_nuid",
@ -5569,14 +5193,6 @@ def go_dependencies():
sum = "h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=",
version = "v1.1.1",
)
go_repository(
name = "com_github_power_devops_perfstat",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/power-devops/perfstat",
sum = "h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=",
version = "v0.0.0-20210106213030-5aafc221ea8c",
)
go_repository(
name = "com_github_poy_onpar",
@ -5819,8 +5435,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/ryanuber/columnize",
sum = "h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=",
version = "v2.1.0+incompatible",
sum = "h1:UFr9zpz4xgTnIE5yIMtWAMngCdZ9p/+q6lTbgelo80M=",
version = "v0.0.0-20160712163229-9b3edd62028f",
)
go_repository(
name = "com_github_ryanuber_go_glob",
@ -5882,14 +5498,6 @@ def go_dependencies():
sum = "h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=",
version = "v3.13.1",
)
go_repository(
name = "com_github_sclevine_agouti",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/sclevine/agouti",
sum = "h1:8IBJS6PWz3uTlMP3YBIR5f+KAldcGuOeFkFbUWfBgK4=",
version = "v3.0.0+incompatible",
)
go_repository(
name = "com_github_sean_seed",
@ -5947,14 +5555,6 @@ def go_dependencies():
sum = "h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=",
version = "v1.3.0",
)
go_repository(
name = "com_github_shirou_gopsutil_v3",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/shirou/gopsutil/v3",
sum = "h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y=",
version = "v3.22.8",
)
go_repository(
name = "com_github_shopify_goreferrer",
@ -6125,8 +5725,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/smartystreets/assertions",
sum = "h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs=",
version = "v1.13.0",
sum = "h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=",
version = "v1.0.0",
)
go_repository(
name = "com_github_smartystreets_go_aws_auth",
@ -6331,14 +5931,6 @@ def go_dependencies():
sum = "h1:KCkDvNUMof10e3QExio9OPZJT8SbdKojLBumw8YZycQ=",
version = "v2.6.4",
)
go_repository(
name = "com_github_tdewolff_test",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/tdewolff/test",
sum = "h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM=",
version = "v1.0.7",
)
go_repository(
name = "com_github_tedsuo_ifrit",
@ -6420,22 +6012,6 @@ def go_dependencies():
sum = "h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=",
version = "v1.1.0",
)
go_repository(
name = "com_github_tklauser_go_sysconf",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/tklauser/go-sysconf",
sum = "h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=",
version = "v0.3.10",
)
go_repository(
name = "com_github_tklauser_numcpus",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/tklauser/numcpus",
sum = "h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=",
version = "v0.4.0",
)
go_repository(
name = "com_github_tmc_grpc_websocket_proxy",
@ -6466,8 +6042,8 @@ def go_dependencies():
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/ugorji/go",
sum = "h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=",
version = "v1.2.7",
sum = "h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=",
version = "v1.1.7",
)
go_repository(
name = "com_github_ugorji_go_codec",
@ -6525,14 +6101,6 @@ def go_dependencies():
sum = "h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=",
version = "v1.2.1",
)
go_repository(
name = "com_github_valyala_tcplisten",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/valyala/tcplisten",
sum = "h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=",
version = "v1.0.0",
)
go_repository(
name = "com_github_vbatts_tar_split",
@ -6735,14 +6303,6 @@ def go_dependencies():
sum = "h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=",
version = "v0.0.3-0.20170626215501-b2862e3d0a77",
)
go_repository(
name = "com_github_yalp_jsonpath",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/yalp/jsonpath",
sum = "h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=",
version = "v0.0.0-20180802001716-5cc68e5049a0",
)
go_repository(
name = "com_github_yosssi_ace",
@ -6785,30 +6345,6 @@ def go_dependencies():
sum = "h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak=",
version = "v0.8.0",
)
go_repository(
name = "com_github_yudai_gojsondiff",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/yudai/gojsondiff",
sum = "h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=",
version = "v1.0.0",
)
go_repository(
name = "com_github_yudai_golcs",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/yudai/golcs",
sum = "h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=",
version = "v0.0.0-20170316035057-ecda9a501e82",
)
go_repository(
name = "com_github_yudai_pp",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/yudai/pp",
sum = "h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=",
version = "v2.0.1+incompatible",
)
go_repository(
name = "com_github_yuin_goldmark",
@ -6818,14 +6354,6 @@ def go_dependencies():
sum = "h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=",
version = "v1.4.13",
)
go_repository(
name = "com_github_yusufpapurcu_wmi",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/yusufpapurcu/wmi",
sum = "h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=",
version = "v1.2.2",
)
go_repository(
name = "com_github_yvasiyarov_go_metrics",
@ -8015,14 +7543,6 @@ def go_dependencies():
sum = "h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=",
version = "v1.2.1",
)
go_repository(
name = "in_gopkg_go_playground_validator_v8",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "gopkg.in/go-playground/validator.v8",
sum = "h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=",
version = "v8.18.2",
)
go_repository(
name = "in_gopkg_go_playground_validator_v9",
@ -8065,14 +7585,6 @@ def go_dependencies():
sum = "h1:BJa69CDh0awSsLUmZ9+BowBdokpduDZSM9Zk8oKHfN4=",
version = "v1.0.5",
)
go_repository(
name = "in_gopkg_mgo_v2",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "gopkg.in/mgo.v2",
sum = "h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU=",
version = "v2.0.0-20180705113604-9856a29383ce",
)
go_repository(
name = "in_gopkg_natefinch_lumberjack_v2",
@ -8642,14 +8154,6 @@ def go_dependencies():
sum = "h1:xMMXJlJbsU8w3V5N2FLDQ8YgU8s1EoULdbQBcAeNJkY=",
version = "v0.0.0-20230313181309-38a27ef9d749",
)
go_repository(
name = "io_moul_http2curl",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "moul.io/http2curl",
sum = "h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=",
version = "v1.0.0",
)
go_repository(
name = "io_opencensus_go",

View File

@ -59,6 +59,7 @@ func NewRootCmd() *cobra.Command {
rootCmd.AddCommand(cmd.NewTerminateCmd())
rootCmd.AddCommand(cmd.NewVersionCmd())
rootCmd.AddCommand(cmd.NewIAMCmd())
rootCmd.AddCommand(cmd.NewStatusCmd())
return rootCmd
}

View File

@ -9,6 +9,7 @@ go_library(
"create.go",
"iam.go",
"rollback.go",
"status.go",
"terminate.go",
"upgrade.go",
"validators.go",

View File

@ -0,0 +1,92 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package cloudcmd
import (
"context"
"fmt"
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
)
// TargetVersions bundles version information about the target versions of a cluster.
type TargetVersions struct {
// image version
image string
// CSP specific path to the image
imageReference string
// kubernetes version
kubernetes string
}
// NewTargetVersions returns the target versions for the cluster.
func NewTargetVersions(nodeVersion updatev1alpha1.NodeVersion) (TargetVersions, error) {
return TargetVersions{
image: nodeVersion.Spec.ImageVersion,
imageReference: nodeVersion.Spec.ImageReference,
kubernetes: nodeVersion.Spec.KubernetesClusterVersion,
}, nil
}
// Image return the image version.
func (c *TargetVersions) Image() string {
return c.image
}
// ImagePath return the image path.
func (c *TargetVersions) ImagePath() string {
return c.imageReference
}
// Kubernetes return the Kubernetes version.
func (c *TargetVersions) Kubernetes() string {
return c.kubernetes
}
// ClusterStatus returns a map from node name to NodeStatus.
func ClusterStatus(ctx context.Context, kubeclient kubeClient) (map[string]NodeStatus, error) {
nodes, err := kubeclient.GetNodes(ctx)
if err != nil {
return nil, fmt.Errorf("getting nodes: %w", err)
}
clusterStatus := map[string]NodeStatus{}
for _, node := range nodes {
clusterStatus[node.ObjectMeta.Name] = NewNodeStatus(node)
}
return clusterStatus, nil
}
// NodeStatus bundles status information about a node.
type NodeStatus struct {
kubeletVersion string
imageVersion string
}
// NewNodeStatus returns a new NodeStatus.
func NewNodeStatus(node corev1.Node) NodeStatus {
return NodeStatus{
kubeletVersion: node.Status.NodeInfo.KubeletVersion,
imageVersion: node.ObjectMeta.Annotations["constellation.edgeless.systems/node-image"],
}
}
// KubeletVersion returns the kubelet version of the node.
func (n *NodeStatus) KubeletVersion() string {
return n.kubeletVersion
}
// ImageVersion returns the node image of the node.
func (n *NodeStatus) ImageVersion() string {
return n.imageVersion
}
type kubeClient interface {
GetNodes(ctx context.Context) ([]corev1.Node, error)
}

View File

@ -40,10 +40,24 @@ import (
// ErrInProgress signals that an upgrade is in progress inside the cluster.
var ErrInProgress = errors.New("upgrade in progress")
// GetConstellationVersion queries the constellation-version object for a given field.
func GetConstellationVersion(ctx context.Context, client DynamicInterface) (updatev1alpha1.NodeVersion, error) {
raw, err := client.GetCurrent(ctx, "constellation-version")
if err != nil {
return updatev1alpha1.NodeVersion{}, err
}
var nodeVersion updatev1alpha1.NodeVersion
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.UnstructuredContent(), &nodeVersion); err != nil {
return updatev1alpha1.NodeVersion{}, fmt.Errorf("converting unstructured to NodeVersion: %w", err)
}
return nodeVersion, nil
}
// Upgrader handles upgrading the cluster's components using the CLI.
type Upgrader struct {
stableInterface stableInterface
dynamicInterface dynamicInterface
dynamicInterface DynamicInterface
helmClient helmInterface
imageFetcher imageFetcher
outWriter io.Writer
@ -75,7 +89,7 @@ func NewUpgrader(outWriter io.Writer, log debugLog) (*Upgrader, error) {
return &Upgrader{
stableInterface: &stableClient{client: kubeClient},
dynamicInterface: &dynamicClient{client: unstructuredClient},
dynamicInterface: &NodeVersionClient{client: unstructuredClient},
helmClient: helmClient,
imageFetcher: image.New(),
outWriter: outWriter,
@ -168,7 +182,7 @@ func (u *Upgrader) KubernetesVersion() (string, error) {
// CurrentImage returns the currently used image version of the cluster.
func (u *Upgrader) CurrentImage(ctx context.Context) (string, error) {
nodeVersion, err := u.getConstellationVersion(ctx)
nodeVersion, err := GetConstellationVersion(ctx, u.dynamicInterface)
if err != nil {
return "", fmt.Errorf("getting constellation-version: %w", err)
}
@ -177,7 +191,7 @@ func (u *Upgrader) CurrentImage(ctx context.Context) (string, error) {
// CurrentKubernetesVersion returns the currently used Kubernetes version.
func (u *Upgrader) CurrentKubernetesVersion(ctx context.Context) (string, error) {
nodeVersion, err := u.getConstellationVersion(ctx)
nodeVersion, err := GetConstellationVersion(ctx, u.dynamicInterface)
if err != nil {
return "", fmt.Errorf("getting constellation-version: %w", err)
}
@ -248,7 +262,7 @@ func (u *Upgrader) applyNodeVersion(ctx context.Context, nodeVersion updatev1alp
}
u.log.Debugf("Triggering NodeVersion upgrade now")
// Send the updated NodeVersion resource
updated, err := u.dynamicInterface.update(ctx, &unstructured.Unstructured{Object: raw})
updated, err := u.dynamicInterface.Update(ctx, &unstructured.Unstructured{Object: raw})
if err != nil {
return updatev1alpha1.NodeVersion{}, fmt.Errorf("updating NodeVersion: %w", err)
}
@ -262,7 +276,7 @@ func (u *Upgrader) applyNodeVersion(ctx context.Context, nodeVersion updatev1alp
}
func (u *Upgrader) checkClusterStatus(ctx context.Context) (updatev1alpha1.NodeVersion, error) {
nodeVersion, err := u.getConstellationVersion(ctx)
nodeVersion, err := GetConstellationVersion(ctx, u.dynamicInterface)
if err != nil {
return updatev1alpha1.NodeVersion{}, fmt.Errorf("retrieving current image: %w", err)
}
@ -306,18 +320,38 @@ func (u *Upgrader) updateK8s(nodeVersion *updatev1alpha1.NodeVersion, newCluster
return &configMap, nil
}
// getFromConstellationVersion queries the constellation-version object for a given field.
func (u *Upgrader) getConstellationVersion(ctx context.Context) (updatev1alpha1.NodeVersion, error) {
raw, err := u.dynamicInterface.getCurrent(ctx, "constellation-version")
if err != nil {
return updatev1alpha1.NodeVersion{}, err
}
var nodeVersion updatev1alpha1.NodeVersion
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.UnstructuredContent(), &nodeVersion); err != nil {
return updatev1alpha1.NodeVersion{}, fmt.Errorf("converting unstructured to NodeVersion: %w", err)
}
// NodeVersionClient implements the DynamicInterface interface to interact with NodeVersion objects.
type NodeVersionClient struct {
client dynamic.Interface
}
return nodeVersion, nil
// NewNodeVersionClient returns a new NodeVersionClient.
func NewNodeVersionClient(client dynamic.Interface) *NodeVersionClient {
return &NodeVersionClient{client: client}
}
// GetCurrent returns the current NodeVersion object.
func (u *NodeVersionClient) GetCurrent(ctx context.Context, name string) (*unstructured.Unstructured, error) {
return u.client.Resource(schema.GroupVersionResource{
Group: "update.edgeless.systems",
Version: "v1alpha1",
Resource: "nodeversions",
}).Get(ctx, name, metav1.GetOptions{})
}
// Update updates the NodeVersion object.
func (u *NodeVersionClient) Update(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
return u.client.Resource(schema.GroupVersionResource{
Group: "update.edgeless.systems",
Version: "v1alpha1",
Resource: "nodeversions",
}).Update(ctx, obj, metav1.UpdateOptions{})
}
// DynamicInterface is a general interface to query custom resources.
type DynamicInterface interface {
GetCurrent(ctx context.Context, name string) (*unstructured.Unstructured, error)
Update(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
}
// upgradeInProgress checks if an upgrade is in progress.
@ -338,11 +372,6 @@ func upgradeInProgress(nodeVersion updatev1alpha1.NodeVersion) bool {
return false
}
type dynamicInterface interface {
getCurrent(ctx context.Context, name string) (*unstructured.Unstructured, error)
update(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
}
type stableInterface interface {
getCurrentConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error)
updateConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error)
@ -350,28 +379,6 @@ type stableInterface interface {
kubernetesVersion() (string, error)
}
type dynamicClient struct {
client dynamic.Interface
}
// getCurrent returns the current image definition.
func (u *dynamicClient) getCurrent(ctx context.Context, name string) (*unstructured.Unstructured, error) {
return u.client.Resource(schema.GroupVersionResource{
Group: "update.edgeless.systems",
Version: "v1alpha1",
Resource: "nodeversions",
}).Get(ctx, name, metav1.GetOptions{})
}
// update updates the image definition.
func (u *dynamicClient) update(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
return u.client.Resource(schema.GroupVersionResource{
Group: "update.edgeless.systems",
Version: "v1alpha1",
Resource: "nodeversions",
}).Update(ctx, obj, metav1.UpdateOptions{})
}
type stableClient struct {
client kubernetes.Interface
}

View File

@ -426,11 +426,11 @@ type stubDynamicClient struct {
updateErr error
}
func (u *stubDynamicClient) getCurrent(_ context.Context, _ string) (*unstructured.Unstructured, error) {
func (u *stubDynamicClient) GetCurrent(_ context.Context, _ string) (*unstructured.Unstructured, error) {
return u.object, u.getErr
}
func (u *stubDynamicClient) update(_ context.Context, updatedObject *unstructured.Unstructured) (*unstructured.Unstructured, error) {
func (u *stubDynamicClient) Update(_ context.Context, updatedObject *unstructured.Unstructured) (*unstructured.Unstructured, error) {
u.updatedObject = updatedObject
return u.updatedObject, u.updateErr
}

View File

@ -21,6 +21,7 @@ go_library(
"miniup.go",
"recover.go",
"spinner.go",
"status.go",
"terminate.go",
"upgrade.go",
"upgradeapply.go",
@ -67,6 +68,7 @@ go_library(
"//internal/versions",
"//internal/versionsapi",
"//internal/versionsapi/fetcher",
"//operators/constellation-node-operator/api/v1alpha1",
"//verify/verifyproto",
"@com_github_mattn_go_isatty//:go-isatty",
"@com_github_siderolabs_talos_pkg_machinery//config/encoder",
@ -74,6 +76,7 @@ go_library(
"@com_github_spf13_cobra//:cobra",
"@io_k8s_api//core/v1:core",
"@io_k8s_apimachinery//pkg/runtime",
"@io_k8s_client_go//dynamic",
"@io_k8s_client_go//tools/clientcmd",
"@io_k8s_client_go//tools/clientcmd/api/latest",
"@io_k8s_sigs_yaml//:yaml",
@ -97,6 +100,7 @@ go_test(
"init_test.go",
"recover_test.go",
"spinner_test.go",
"status_test.go",
"terminate_test.go",
"upgradeapply_test.go",
"upgradecheck_test.go",
@ -111,6 +115,7 @@ go_test(
"//bootstrapper/initproto",
"//cli/internal/cloudcmd",
"//cli/internal/clusterid",
"//cli/internal/helm",
"//cli/internal/iamid",
"//disk-mapper/recoverproto",
"//internal/atls",
@ -130,6 +135,7 @@ go_test(
"//internal/variant",
"//internal/versions",
"//internal/versionsapi",
"//operators/constellation-node-operator/api/v1alpha1",
"//verify/verifyproto",
"@com_github_spf13_afero//:afero",
"@com_github_spf13_cobra//:cobra",
@ -137,6 +143,9 @@ go_test(
"@com_github_stretchr_testify//require",
"@in_gopkg_yaml_v3//:yaml_v3",
"@io_k8s_api//core/v1:core",
"@io_k8s_apimachinery//pkg/apis/meta/v1:meta",
"@io_k8s_apimachinery//pkg/apis/meta/v1/unstructured",
"@io_k8s_apimachinery//pkg/runtime",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_google_grpc//codes",
"@org_golang_google_grpc//status",

View File

@ -33,7 +33,7 @@ import (
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
grpcstatus "google.golang.org/grpc/status"
)
func TestRecoverCmdArgumentValidation(t *testing.T) {
@ -63,8 +63,8 @@ func TestRecoverCmdArgumentValidation(t *testing.T) {
func TestRecover(t *testing.T) {
someErr := errors.New("error")
unavailableErr := status.Error(codes.Unavailable, "unavailable")
lbErr := status.Error(codes.Unavailable, `connection error: desc = "transport: authentication handshake failed: read tcp`)
unavailableErr := grpcstatus.Error(codes.Unavailable, "unavailable")
lbErr := grpcstatus.Error(codes.Unavailable, `connection error: desc = "transport: authentication handshake failed: read tcp`)
testCases := map[string]struct {
doer *stubDoer
@ -336,7 +336,7 @@ func (d *stubDoer) Do(context.Context) error {
if len(d.returns) > 1 {
d.returns = d.returns[1:]
} else {
d.returns = []error{status.Error(codes.Unavailable, "unavailable")}
d.returns = []error{grpcstatus.Error(codes.Unavailable, "unavailable")}
}
return err
}

175
cli/internal/cmd/status.go Normal file
View File

@ -0,0 +1,175 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package cmd
import (
"context"
"fmt"
"strings"
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/file"
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
"github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
"github.com/spf13/afero"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
)
// NewStatusCmd returns a new cobra.Command for the statuus command.
func NewStatusCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Short: "show status of a Constellation cluster",
Long: "Show status of a constellation cluster.\n\n" +
"Shows microservice, image and Kubernetes versions installed in the cluster. Also show status of current version upgrades.",
Args: cobra.NoArgs,
RunE: runStatus,
}
return cmd
}
// runStatus runs the terminate command.
func runStatus(cmd *cobra.Command, args []string) error {
log, err := newCLILogger(cmd)
if err != nil {
return fmt.Errorf("creating logger: %w", err)
}
defer log.Sync()
kubeClient := kubectl.New()
fileHandler := file.NewHandler(afero.NewOsFs())
kubeConfig, err := fileHandler.Read(constants.AdminConfFilename)
if err != nil {
return fmt.Errorf("reading admin.conf: %w", err)
}
// need kubectl client to fetch nodes.
if err := kubeClient.Initialize(kubeConfig); err != nil {
return err
}
restConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeConfig)
if err != nil {
return fmt.Errorf("creating k8s client config from kubeconfig: %w", err)
}
// need unstructed client to fetch NodeVersion CRD.
unstructuredClient, err := dynamic.NewForConfig(restConfig)
if err != nil {
return fmt.Errorf("setting up custom resource client: %w", err)
}
// need helm client to fetch service versions.
helmClient, err := helm.NewClient(kubectl.New(), constants.AdminConfFilename, constants.HelmNamespace, log)
if err != nil {
return fmt.Errorf("setting up helm client: %w", err)
}
output, err := status(cmd.Context(), kubeClient, helmClient, cloudcmd.NewNodeVersionClient(unstructuredClient))
if err != nil {
return fmt.Errorf("getting status: %w", err)
}
cmd.Print(output)
return nil
}
// status queries the cluster for the relevant status information and returns the output string.
func status(ctx context.Context, kubeClient kubeClient, helmClient helmClient, dynamicInterface cloudcmd.DynamicInterface) (string, error) {
nodeVersion, err := cloudcmd.GetConstellationVersion(ctx, dynamicInterface)
if err != nil {
return "", fmt.Errorf("getting constellation version: %w", err)
}
if len(nodeVersion.Status.Conditions) != 1 {
return "", fmt.Errorf("expected exactly one condition, got %d", len(nodeVersion.Status.Conditions))
}
targetVersions, err := cloudcmd.NewTargetVersions(nodeVersion)
if err != nil {
return "", fmt.Errorf("getting configured versions: %w", err)
}
serviceVersions, err := helmClient.Versions()
if err != nil {
return "", fmt.Errorf("getting service versions: %w", err)
}
status, err := cloudcmd.ClusterStatus(ctx, kubeClient)
if err != nil {
return "", fmt.Errorf("getting cluster status: %w", err)
}
return statusOutput(targetVersions, serviceVersions, status, nodeVersion), nil
}
// statusOutput creates the status cmd output string by formatting the received information.
func statusOutput(targetVersions cloudcmd.TargetVersions, serviceVersions helm.ServiceVersions, status map[string]cloudcmd.NodeStatus, nodeVersion v1alpha1.NodeVersion) string {
builder := strings.Builder{}
builder.WriteString(targetVersionsString(targetVersions))
builder.WriteString(serviceVersionsString(serviceVersions))
builder.WriteString(fmt.Sprintf("Cluster status: %s\n", nodeVersion.Status.Conditions[0].Message))
builder.WriteString(nodeStatusString(status, targetVersions))
return builder.String()
}
// nodeStatusString creates the node status part of the output string.
func nodeStatusString(status map[string]cloudcmd.NodeStatus, targetVersions cloudcmd.TargetVersions) string {
var upToDateImages int
var upToDateK8s int
for _, node := range status {
if node.KubeletVersion() == targetVersions.Kubernetes() {
upToDateK8s++
}
if node.ImageVersion() == targetVersions.ImagePath() {
upToDateImages++
}
}
builder := strings.Builder{}
if upToDateImages != len(status) || upToDateK8s != len(status) {
builder.WriteString(fmt.Sprintf("\tImage: %d/%d\n", upToDateImages, len(status)))
builder.WriteString(fmt.Sprintf("\tKubernetes: %d/%d\n", upToDateK8s, len(status)))
}
return builder.String()
}
// serviceVersionsString creates the service versions part of the output string.
func serviceVersionsString(versions helm.ServiceVersions) string {
builder := strings.Builder{}
builder.WriteString("Installed service versions:\n")
builder.WriteString(fmt.Sprintf("\tCilium: %s\n", versions.Cilium()))
builder.WriteString(fmt.Sprintf("\tcert-manager: %s\n", versions.CertManager()))
builder.WriteString(fmt.Sprintf("\tconstellation-operators: %s\n", versions.ConstellationOperators()))
builder.WriteString(fmt.Sprintf("\tconstellation-services: %s\n", versions.ConstellationServices()))
return builder.String()
}
// targetVersionsString creates the target versions part of the output string.
func targetVersionsString(target cloudcmd.TargetVersions) string {
builder := strings.Builder{}
builder.WriteString("Target versions:\n")
builder.WriteString(fmt.Sprintf("\tImage: %s\n", target.Image()))
builder.WriteString(fmt.Sprintf("\tKubernetes: %s\n", target.Kubernetes()))
return builder.String()
}
type kubeClient interface {
GetNodes(ctx context.Context) ([]corev1.Node, error)
}
type helmClient interface {
Versions() (helm.ServiceVersions, error)
}

View File

@ -0,0 +1,193 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package cmd
import (
"context"
"testing"
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)
const successOutput = `Target versions:
Image: v1.1.0
Kubernetes: v1.2.3
Installed service versions:
Cilium: v1.0.0
cert-manager: v1.0.0
constellation-operators: v1.1.0
constellation-services: v1.1.0
Cluster status: Node version of every node is up to date
`
const inProgressOutput = `Target versions:
Image: v1.1.0
Kubernetes: v1.2.3
Installed service versions:
Cilium: v1.0.0
cert-manager: v1.0.0
constellation-operators: v1.1.0
constellation-services: v1.1.0
Cluster status: Some node versions are out of date
Image: 1/2
Kubernetes: 1/2
`
// TestStatus checks that the status function produces the correct strings.
func TestStatus(t *testing.T) {
testCases := map[string]struct {
kubeClient stubKubeClient
helmClient stubHelmClient
nodeVersion updatev1alpha1.NodeVersion
dynamicErr error
expectedOutput string
wantErr bool
}{
"success": {
kubeClient: stubKubeClient{
nodes: []corev1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Name: "node1",
Annotations: map[string]string{
"constellation.edgeless.systems/node-image": "v1.1.0",
},
},
Status: corev1.NodeStatus{
NodeInfo: corev1.NodeSystemInfo{
KubeletVersion: "v1.2.3",
},
},
},
},
},
helmClient: stubHelmClient{
serviceVersions: helm.NewServiceVersions("v1.0.0", "v1.0.0", "v1.1.0", "v1.1.0"),
},
nodeVersion: updatev1alpha1.NodeVersion{
Spec: updatev1alpha1.NodeVersionSpec{
ImageVersion: "v1.1.0",
ImageReference: "v1.1.0",
KubernetesClusterVersion: "v1.2.3",
},
Status: updatev1alpha1.NodeVersionStatus{
Conditions: []metav1.Condition{
{
Message: "Node version of every node is up to date",
},
},
},
},
expectedOutput: successOutput,
},
"one of two nodes not upgraded": {
kubeClient: stubKubeClient{
nodes: []corev1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Name: "outdated",
Annotations: map[string]string{
"constellation.edgeless.systems/node-image": "v1.0.0",
},
},
Status: corev1.NodeStatus{
NodeInfo: corev1.NodeSystemInfo{
KubeletVersion: "v1.2.2",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "uptodate",
Annotations: map[string]string{
"constellation.edgeless.systems/node-image": "v1.1.0",
},
},
Status: corev1.NodeStatus{
NodeInfo: corev1.NodeSystemInfo{
KubeletVersion: "v1.2.3",
},
},
},
},
},
helmClient: stubHelmClient{
serviceVersions: helm.NewServiceVersions("v1.0.0", "v1.0.0", "v1.1.0", "v1.1.0"),
},
nodeVersion: updatev1alpha1.NodeVersion{
Spec: updatev1alpha1.NodeVersionSpec{
ImageVersion: "v1.1.0",
ImageReference: "v1.1.0",
KubernetesClusterVersion: "v1.2.3",
},
Status: updatev1alpha1.NodeVersionStatus{
Conditions: []metav1.Condition{
{
Message: "Some node versions are out of date",
},
},
},
},
expectedOutput: inProgressOutput,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
require := require.New(t)
assert := assert.New(t)
raw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.nodeVersion)
require.NoError(err)
output, err := status(context.Background(), tc.kubeClient, tc.helmClient, &stubDynamicInterface{data: unstructured.Unstructured{Object: raw}, err: tc.dynamicErr})
if tc.wantErr {
assert.Error(err)
return
}
require.NoError(err)
assert.Equal(tc.expectedOutput, output)
})
}
}
type stubKubeClient struct {
nodes []corev1.Node
err error
}
func (s stubKubeClient) GetNodes(_ context.Context) ([]corev1.Node, error) {
return s.nodes, s.err
}
type stubHelmClient struct {
serviceVersions helm.ServiceVersions
err error
}
func (s stubHelmClient) Versions() (helm.ServiceVersions, error) {
return s.serviceVersions, s.err
}
type stubDynamicInterface struct {
data unstructured.Unstructured
err error
}
func (s *stubDynamicInterface) GetCurrent(_ context.Context, _ string) (*unstructured.Unstructured, error) {
return &s.data, s.err
}
func (s *stubDynamicInterface) Update(_ context.Context, _ *unstructured.Unstructured) (*unstructured.Unstructured, error) {
return &s.data, s.err
}

View File

@ -264,7 +264,7 @@ func (v *versionCollector) currentVersions(ctx context.Context) (serviceVersion
return "", "", "", fmt.Errorf("setting up helm client: %w", err)
}
serviceVersion, err = helmClient.Versions()
serviceVersions, err := helmClient.Versions()
if err != nil {
return "", "", "", fmt.Errorf("getting service versions: %w", err)
}
@ -279,7 +279,7 @@ func (v *versionCollector) currentVersions(ctx context.Context) (serviceVersion
return "", "", "", fmt.Errorf("getting image version: %w", err)
}
return serviceVersion, imageVersion, k8sVersion, nil
return serviceVersions.ConstellationServices(), imageVersion, k8sVersion, nil
}
// supportedVersions returns slices of supported versions.

View File

@ -39,6 +39,9 @@ const (
DenyDestructive = false
)
// ErrConfirmationMissing signals that an action requires user confirmation.
var ErrConfirmationMissing = errors.New("action requires user confirmation")
// Client handles interaction with helm and the cluster.
type Client struct {
config *action.Configuration
@ -144,13 +147,30 @@ func (c *Client) Upgrade(ctx context.Context, config *config.Config, timeout tim
}
// Versions queries the cluster for running versions and returns a map of releaseName -> version.
func (c *Client) Versions() (string, error) {
serviceVersion, err := c.currentVersion(constellationServicesInfo.releaseName)
func (c *Client) Versions() (ServiceVersions, error) {
ciliumVersion, err := c.currentVersion(ciliumInfo.releaseName)
if err != nil {
return "", fmt.Errorf("getting constellation-services version: %w", err)
return ServiceVersions{}, fmt.Errorf("getting %s version: %w", ciliumInfo.releaseName, err)
}
certManagerVersion, err := c.currentVersion(certManagerInfo.releaseName)
if err != nil {
return ServiceVersions{}, fmt.Errorf("getting %s version: %w", certManagerInfo.releaseName, err)
}
operatorsVersion, err := c.currentVersion(constellationOperatorsInfo.releaseName)
if err != nil {
return ServiceVersions{}, fmt.Errorf("getting %s version: %w", constellationOperatorsInfo.releaseName, err)
}
servicesVersion, err := c.currentVersion(constellationServicesInfo.releaseName)
if err != nil {
return ServiceVersions{}, fmt.Errorf("getting %s version: %w", constellationServicesInfo.releaseName, err)
}
return compatibility.EnsurePrefixV(serviceVersion), nil
return ServiceVersions{
cilium: compatibility.EnsurePrefixV(ciliumVersion),
certManager: compatibility.EnsurePrefixV(certManagerVersion),
constellationOperators: compatibility.EnsurePrefixV(operatorsVersion),
constellationServices: compatibility.EnsurePrefixV(servicesVersion),
}, nil
}
// currentVersion returns the version of the currently installed helm release.
@ -174,8 +194,43 @@ func (c *Client) currentVersion(release string) (string, error) {
return rel[0].Chart.Metadata.Version, nil
}
// ErrConfirmationMissing signals that an action requires user confirmation.
var ErrConfirmationMissing = errors.New("action requires user confirmation")
// ServiceVersions bundles the versions of all services that are part of Constellation.
type ServiceVersions struct {
cilium string
certManager string
constellationOperators string
constellationServices string
}
// NewServiceVersions returns a new ServiceVersions struct.
func NewServiceVersions(cilium, certManager, constellationOperators, constellationServices string) ServiceVersions {
return ServiceVersions{
cilium: cilium,
certManager: certManager,
constellationOperators: constellationOperators,
constellationServices: constellationServices,
}
}
// Cilium returns the version of the Cilium release.
func (s ServiceVersions) Cilium() string {
return s.cilium
}
// CertManager returns the version of the cert-manager release.
func (s ServiceVersions) CertManager() string {
return s.certManager
}
// ConstellationOperators returns the version of the constellation-operators release.
func (s ServiceVersions) ConstellationOperators() string {
return s.constellationOperators
}
// ConstellationServices returns the version of the constellation-services release.
func (s ServiceVersions) ConstellationServices() string {
return s.constellationServices
}
// TODO: v2.8: remove fileHandler argument.
func (c *Client) upgradeRelease(

View File

@ -34,6 +34,7 @@ Commands:
* [azure](#constellation-iam-create-azure): Create IAM configuration on Microsoft Azure for your Constellation cluster
* [gcp](#constellation-iam-create-gcp): Create IAM configuration on GCP for your Constellation cluster
* [destroy](#constellation-iam-destroy): Destroy an IAM configuration and delete local Terraform files
* [status](#constellation-status): show status of a Constellation cluster
## constellation config
@ -673,3 +674,31 @@ constellation iam destroy [flags]
--force disable version compatibility checks - might result in corrupted clusters
```
## constellation status
show status of a Constellation cluster
### Synopsis
Show status of a constellation cluster.
Shows microservice, image and Kubernetes versions installed in the cluster. Also show status of current version upgrades.
```
constellation status [flags]
```
### Options
```
-h, --help help for status
```
### Options inherited from parent commands
```
--config string path to the configuration file (default "constellation-conf.yaml")
--debug enable debug logging
--force disable version compatibility checks - might result in corrupted clusters
```

View File

@ -57,3 +57,38 @@ If you are interested, you can monitor pods restarting in the `kube-system` name
Image and Kubernetes upgrades take longer.
For each node in your cluster, a new node has to be created and joined.
The process usually takes up to ten minutes per node.
## Check the status
Upgrades are asynchronous operations.
After you run `upgrade apply`, it will take a while until the upgrade has completed.
To understand if an upgrade is finished, you can run:
```bash
constellation status
```
This command displays the following information:
* The installed services and their versions
* The image and Kubernetes version the cluster is expecting on each node
* How many nodes are up to date
Here's an example output:
```shell-session
Target versions:
Image: v2.6.0
Kubernetes: v1.25.8
Installed service versions:
Cilium: v1.12.1
cert-manager: v1.10.0
constellation-operators: v2.6.0
constellation-services: v2.6.0
Cluster status: Some node versions are out of date
Image: 23/25
Kubernetes: 25/25
```
This output indicates that the cluster is running Kubernetes version `1.25.8`, and all nodes have the appropriate binaries installed.
23 out of 25 nodes have already upgraded to the targeted image version of `2.6.0`, while two are still in progress.

3
go.mod
View File

@ -113,7 +113,6 @@ require (
k8s.io/apiextensions-apiserver v0.26.3
k8s.io/apimachinery v0.26.3
k8s.io/apiserver v0.26.3
k8s.io/cli-runtime v0.26.3
k8s.io/client-go v0.26.3
k8s.io/cluster-bootstrap v0.26.3
k8s.io/kubelet v0.26.3
@ -123,6 +122,8 @@ require (
sigs.k8s.io/yaml v1.3.0
)
require k8s.io/cli-runtime v0.26.3 // indirect
require (
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/iam v0.12.0 // indirect

View File

@ -3,29 +3,20 @@ load("//bazel/go:go_test.bzl", "go_test")
go_library(
name = "kubectl",
srcs = [
"kubectl.go",
"restclient.go",
],
srcs = ["kubectl.go"],
importpath = "github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl",
visibility = ["//:__subpackages__"],
deps = [
"@io_k8s_api//core/v1:core",
"@io_k8s_apiextensions_apiserver//pkg/apis/apiextensions/v1:apiextensions",
"@io_k8s_apiextensions_apiserver//pkg/client/clientset/clientset/typed/apiextensions/v1:apiextensions",
"@io_k8s_apimachinery//pkg/api/meta",
"@io_k8s_apimachinery//pkg/apis/meta/v1:meta",
"@io_k8s_apimachinery//pkg/apis/meta/v1/unstructured",
"@io_k8s_apimachinery//pkg/runtime",
"@io_k8s_apimachinery//pkg/runtime/schema",
"@io_k8s_apimachinery//pkg/runtime/serializer",
"@io_k8s_cli_runtime//pkg/resource",
"@io_k8s_client_go//discovery",
"@io_k8s_client_go//discovery/cached/memory",
"@io_k8s_client_go//dynamic",
"@io_k8s_client_go//kubernetes",
"@io_k8s_client_go//rest",
"@io_k8s_client_go//restmapper",
"@io_k8s_client_go//scale/scheme",
"@io_k8s_client_go//tools/clientcmd",
"@io_k8s_client_go//util/retry",
@ -34,16 +25,7 @@ go_library(
go_test(
name = "kubectl_test",
srcs = [
"kubectl_test.go",
"restclient_test.go",
],
srcs = ["kubectl_test.go"],
embed = [":kubectl"],
deps = [
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
"@io_k8s_client_go//rest",
"@io_k8s_client_go//tools/clientcmd",
"@io_k8s_client_go//tools/clientcmd/api",
],
deps = ["@com_github_stretchr_testify//assert"],
)

View File

@ -22,7 +22,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/scale/scheme"
@ -35,7 +34,6 @@ type Kubectl struct {
kubernetes.Interface
dynamicClient dynamic.Interface
apiextensionClient apiextensionsclientv1.ApiextensionsV1Interface
builder *resource.Builder
}
// New returns an empty Kubectl client. Need to call Initialize before usable.
@ -67,12 +65,6 @@ func (k *Kubectl) Initialize(kubeconfig []byte) error {
}
k.apiextensionClient = apiextensionClient
restClientGetter, err := newRESTClientGetter(kubeconfig)
if err != nil {
return fmt.Errorf("creating k8s RESTClientGetter from kubeconfig: %w", err)
}
k.builder = resource.NewBuilder(restClientGetter).Unstructured()
return nil
}
@ -92,22 +84,6 @@ func (k *Kubectl) ApplyCRD(ctx context.Context, rawCRD []byte) error {
return err
}
// parseCRD takes a byte slice of data and tries to create a CustomResourceDefinition object from it.
func parseCRD(crdString []byte) (*v1.CustomResourceDefinition, error) {
sch := runtime.NewScheme()
_ = scheme.AddToScheme(sch)
_ = v1.AddToScheme(sch)
obj, groupVersionKind, err := serializer.NewCodecFactory(sch).UniversalDeserializer().Decode(crdString, nil, nil)
if err != nil {
return nil, fmt.Errorf("decoding crd: %w", err)
}
if groupVersionKind.Kind == "CustomResourceDefinition" {
return obj.(*v1.CustomResourceDefinition), nil
}
return nil, errors.New("parsed []byte, but did not find a CRD")
}
// GetCRDs retrieves all custom resource definitions currently installed in the cluster.
func (k *Kubectl) GetCRDs(ctx context.Context) ([]apiextensionsv1.CustomResourceDefinition, error) {
crds, err := k.apiextensionClient.CustomResourceDefinitions().List(ctx, metav1.ListOptions{})
@ -159,6 +135,15 @@ func (k *Kubectl) ListAllNamespaces(ctx context.Context) (*corev1.NamespaceList,
return k.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
}
// GetNodes returns all nodes in the cluster.
func (k *Kubectl) GetNodes(ctx context.Context) ([]corev1.Node, error) {
nodes, err := k.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
if err != nil {
return nil, fmt.Errorf("listing nodes: %w", err)
}
return nodes.Items, nil
}
// AddTolerationsToDeployment adds [K8s tolerations] to the deployment, identified
// by name and namespace.
//
@ -213,3 +198,19 @@ func (k *Kubectl) AddNodeSelectorsToDeployment(ctx context.Context, selectors ma
}
return nil
}
// parseCRD takes a byte slice of data and tries to create a CustomResourceDefinition object from it.
func parseCRD(crdString []byte) (*v1.CustomResourceDefinition, error) {
sch := runtime.NewScheme()
_ = scheme.AddToScheme(sch)
_ = v1.AddToScheme(sch)
obj, groupVersionKind, err := serializer.NewCodecFactory(sch).UniversalDeserializer().Decode(crdString, nil, nil)
if err != nil {
return nil, fmt.Errorf("decoding crd: %w", err)
}
if groupVersionKind.Kind == "CustomResourceDefinition" {
return obj.(*v1.CustomResourceDefinition), nil
}
return nil, errors.New("parsed []byte, but did not find a CRD")
}

View File

@ -1,70 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package kubectl
import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/discovery"
"k8s.io/client-go/discovery/cached/memory"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"k8s.io/client-go/tools/clientcmd"
)
// restClientGetter implements k8s.io/cli-runtime/pkg/resource.RESTClientGetter.
type restClientGetter struct {
clientconfig clientcmd.ClientConfig
}
// newRESTClientGetter creates a new restClientGetter using a kubeconfig.
func newRESTClientGetter(kubeconfig []byte) (*restClientGetter, error) {
clientconfig, err := clientcmd.NewClientConfigFromBytes(kubeconfig)
if err != nil {
return nil, err
}
rawconfig, err := clientconfig.RawConfig()
if err != nil {
return nil, err
}
clientconfig = clientcmd.NewDefaultClientConfig(rawconfig, &clientcmd.ConfigOverrides{})
return &restClientGetter{clientconfig}, nil
}
// ToRESTConfig returns k8s REST client config.
func (r *restClientGetter) ToRESTConfig() (*rest.Config, error) {
return r.clientconfig.ClientConfig()
}
// ToDiscoveryClient creates new k8s discovery client from restClientGetter.
func (r *restClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
restconfig, err := r.clientconfig.ClientConfig()
if err != nil {
return nil, err
}
dc, err := discovery.NewDiscoveryClientForConfig(restconfig)
if err != nil {
return nil, err
}
return memory.NewMemCacheClient(dc), nil
}
// ToRESTMapper creates new k8s RESTMapper from restClientGetter.
func (r *restClientGetter) ToRESTMapper() (meta.RESTMapper, error) {
dc, err := r.ToDiscoveryClient()
if err != nil {
return nil, err
}
return restmapper.NewDeferredDiscoveryRESTMapper(dc), nil
}
// ToRawKubeConfigLoader returns the inner k8s ClientConfig.
func (r *restClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig {
return r.clientconfig
}

View File

@ -1,143 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package kubectl
import (
"errors"
"testing"
"github.com/stretchr/testify/require"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
const testingKubeconfig = `
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ""
server: https://192.0.2.0:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: ""
client-key-data: ""
`
type stubClientConfig struct {
rawConfigConfig clientcmdapi.Config
rawConfigErr error
clientConfigConfig *restclient.Config
clientConfigErr error
namespaceString string
namespaceOverridden bool
namespaceErr error
configAccessResult clientcmd.ConfigAccess
}
func (s *stubClientConfig) RawConfig() (clientcmdapi.Config, error) {
return s.rawConfigConfig, s.rawConfigErr
}
func (s *stubClientConfig) ClientConfig() (*restclient.Config, error) {
return s.clientConfigConfig, s.clientConfigErr
}
func (s *stubClientConfig) Namespace() (string, bool, error) {
return s.namespaceString, s.namespaceOverridden, s.namespaceErr
}
func (s *stubClientConfig) ConfigAccess() clientcmd.ConfigAccess {
return s.configAccessResult
}
func TestNewRESTClientGetter(t *testing.T) {
require := require.New(t)
result, err := newRESTClientGetter([]byte(testingKubeconfig))
require.NoError(err)
require.NotNil(result)
}
func TestToRESTConfig(t *testing.T) {
require := require.New(t)
getter := restClientGetter{
clientconfig: &stubClientConfig{
clientConfigConfig: &restclient.Config{},
},
}
result, err := getter.ToRESTConfig()
require.NoError(err)
require.NotNil(result)
}
func TestToDiscoveryClient(t *testing.T) {
require := require.New(t)
getter := restClientGetter{
clientconfig: &stubClientConfig{
clientConfigConfig: &restclient.Config{},
},
}
result, err := getter.ToDiscoveryClient()
require.NoError(err)
require.NotNil(result)
}
func TestToDiscoveryClientFail(t *testing.T) {
require := require.New(t)
getter := restClientGetter{
clientconfig: &stubClientConfig{
clientConfigErr: errors.New("someErr"),
},
}
_, err := getter.ToDiscoveryClient()
require.Error(err)
}
func TestToRESTMapper(t *testing.T) {
require := require.New(t)
getter := restClientGetter{
clientconfig: &stubClientConfig{
clientConfigConfig: &restclient.Config{},
},
}
result, err := getter.ToRESTMapper()
require.NoError(err)
require.NotNil(result)
}
func TestToRESTMapperFail(t *testing.T) {
require := require.New(t)
getter := restClientGetter{
clientconfig: &stubClientConfig{
clientConfigErr: errors.New("someErr"),
},
}
_, err := getter.ToRESTMapper()
require.Error(err)
}
func TestToRawKubeConfigLoader(t *testing.T) {
clientConfig := stubClientConfig{
clientConfigConfig: &restclient.Config{},
}
require := require.New(t)
getter := restClientGetter{
clientconfig: &clientConfig,
}
result := getter.ToRawKubeConfigLoader()
require.Equal(&clientConfig, result)
}