commit 309b8a187d9721f4e37ce3aafdb277fc00bd4a5d Author: Seán C McCord Date: Fri Oct 20 17:28:58 2023 -0400 initial commit diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..786d7c4 --- /dev/null +++ b/go.mod @@ -0,0 +1,79 @@ +module git.cycore.io/scm/talos-upgrade + +go 1.20 + +require ( + github.com/charmbracelet/bubbles v0.16.1 + github.com/charmbracelet/bubbletea v0.24.2 + github.com/charmbracelet/lipgloss v0.7.1 + github.com/cosi-project/runtime v0.3.1 + github.com/google/go-github/v55 v55.0.0 + github.com/pkg/errors v0.9.1 + github.com/siderolabs/talos/pkg/machinery v1.5.2 + github.com/stretchr/testify v1.8.4 + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 + golang.org/x/mod v0.12.0 +) + +require ( + github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect + github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect + github.com/ProtonMail/gopenpgp/v2 v2.7.2 // indirect + github.com/adrg/xdg v0.4.0 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/containerd/go-cni v1.1.9 // indirect + github.com/containernetworking/cni v1.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/gertd/go-pluralize v0.2.1 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/josharian/native v1.1.0 // indirect + github.com/jsimonetti/rtnetlink v1.3.4 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mdlayher/ethtool v0.1.0 // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect + github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/sahilm/fuzzy v0.1.0 // indirect + github.com/siderolabs/crypto v0.4.1 // indirect + github.com/siderolabs/gen v0.4.5 // indirect + github.com/siderolabs/go-api-signature v0.2.6 // indirect + github.com/siderolabs/go-blockdevice v0.4.6 // indirect + github.com/siderolabs/go-pointer v1.0.0 // indirect + github.com/siderolabs/net v0.4.0 // indirect + github.com/siderolabs/protoenc v0.2.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect + google.golang.org/grpc v1.57.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c337a80 --- /dev/null +++ b/go.sum @@ -0,0 +1,286 @@ +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= +github.com/ProtonMail/gopenpgp/v2 v2.7.2 h1:mIwxSUPezxNYq0RA5106VPWyKC+Ly3FvBUnBJh/7GWw= +github.com/ProtonMail/gopenpgp/v2 v2.7.2/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= +github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= +github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/brianvoe/gofakeit/v6 v6.17.0 h1:obbQTJeHfktJtiZzq0Q1bEpsNUs+yHrYlPVWt7BtmJ4= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY= +github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc= +github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY= +github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg= +github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E= +github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/containerd/go-cni v1.1.9 h1:ORi7P1dYzCwVM6XPN4n3CbkuOx/NZ2DOqy+SHRdo9rU= +github.com/containerd/go-cni v1.1.9/go.mod h1:XYrZJ1d5W6E2VOvjffL3IZq0Dz6bsVlERHbekNK90PM= +github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ= +github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/cosi-project/runtime v0.3.1 h1:dRGKOlEDKjvuC+VIG4N2Z5iAftaqgS1h3ttmvbK4nMk= +github.com/cosi-project/runtime v0.3.1/go.mod h1:Q+oiWic2l6TaGuIWtUo0E9tL2RDT2APHvjUc/mJtn24= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlLgiA= +github.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg= +github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jsimonetti/rtnetlink v1.3.4 h1:uUcd9SE8sQe/enLBEVaWDkgGYWNsX3EU4eIxbEZYmF0= +github.com/jsimonetti/rtnetlink v1.3.4/go.mod h1:jGCNm5lJdGplEXKCVwqhQ5tRIGV0dNREhLyNWVzBxHc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mdlayher/ethtool v0.1.0 h1:XAWHsmKhyPOo42qq/yTPb0eFBGUKKTR1rE0dVrWVQ0Y= +github.com/mdlayher/ethtool v0.1.0/go.mod h1:fBMLn2UhfRGtcH5ZFjr+6GUiHEjZsItFD7fSn7jbZVQ= +github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= +github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= +github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/siderolabs/crypto v0.4.1 h1:PP84WSDDyCCbjYKePcc0IaMSPXDndz8V3cQ9hMRSvpA= +github.com/siderolabs/crypto v0.4.1/go.mod h1:nJmvkqWy1Hngbzw3eg2TdtJ/ZYHHofQK1NbmmYywW8k= +github.com/siderolabs/gen v0.4.5 h1:rwXUVJlL7hYza1LrSVXfT905ZC9Rgei37jMKKs/+eP0= +github.com/siderolabs/gen v0.4.5/go.mod h1:wS8tFq7sn5vqKAuyS30vJUig3tX5v6q79VG4KfUnILM= +github.com/siderolabs/go-api-signature v0.2.6 h1:X4Q+J7CmyfUHKUR+4x4RqmmSSksQ2pYGDajwVX8ZaJ0= +github.com/siderolabs/go-api-signature v0.2.6/go.mod h1:jt7azUqWctrkn7XuTPunfkWllvGPIfRJW8AS3OVkiqE= +github.com/siderolabs/go-blockdevice v0.4.6 h1:yfxFYzXezzszB0mSF2ZG8jPPampoNXa9r8W8nM0IoZI= +github.com/siderolabs/go-blockdevice v0.4.6/go.mod h1:4PeOuk71pReJj1JQEXDE7kIIQJPVe8a+HZQa+qjxSEA= +github.com/siderolabs/go-pointer v1.0.0 h1:6TshPKep2doDQJAAtHUuHWXbca8ZfyRySjSBT/4GsMU= +github.com/siderolabs/go-pointer v1.0.0/go.mod h1:HTRFUNYa3R+k0FFKNv11zgkaCLzEkWVzoYZ433P3kHc= +github.com/siderolabs/go-retry v0.3.2 h1:FzWslFm4y8RY1wU0gIskm0oZHOpsSibZqlR8N8/k4Eo= +github.com/siderolabs/net v0.4.0 h1:1bOgVay/ijPkJz4qct98nHsiB/ysLQU0KLoBC4qLm7I= +github.com/siderolabs/net v0.4.0/go.mod h1:/ibG+Hm9HU27agp5r9Q3eZicEfjquzNzQNux5uEk0kM= +github.com/siderolabs/protoenc v0.2.0 h1:QFxWIAo//12+/bm27GNYoK/TpQGTYsRrrZCu9jSghvU= +github.com/siderolabs/protoenc v0.2.0/go.mod h1:mu4gc6pJxhdJYpuloacKE4jsJojj87qDXwn8LUvs2bY= +github.com/siderolabs/talos/pkg/machinery v1.5.2 h1:XENjTuWdcCSgmPK6HsN81RAzN0T9mD8VjaRPM1pQMB8= +github.com/siderolabs/talos/pkg/machinery v1.5.2/go.mod h1:7Mmswfab95ULNclTI4ZGR8hZaQyrjDVfSyYGVECgFBs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e h1:S83+ibolgyZ0bqz7KEsUOPErxcv4VzlszxY+31OfB/E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..68e29fa --- /dev/null +++ b/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "os/signal" + "syscall" + + "git.cycore.io/scm/talos-upgrade/pkg/upgrade" + tea "github.com/charmbracelet/bubbletea" +) + +func main() { + ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt) + defer cancel() + + core, err := upgrade.NewCore(ctx) + if err != nil { + log.Fatal("failed to create upgrade core:", err) + } + + p := tea.NewProgram(&upgrade.LoadState{Core: core}, tea.WithAltScreen()) + + if _, err := p.Run(); err != nil { + fmt.Println("failure running program:", err) + os.Exit(1) + } +} diff --git a/pkg/node/list.go b/pkg/node/list.go new file mode 100644 index 0000000..b89e686 --- /dev/null +++ b/pkg/node/list.go @@ -0,0 +1,74 @@ +package node + +import ( + "fmt" + + "github.com/charmbracelet/bubbles/list" + "github.com/siderolabs/talos/pkg/machinery/config/machine" + "golang.org/x/exp/slog" +) + +type ListItem struct { + Node *Node +} + +func (i *ListItem) FilterValue() string { + return fmt.Sprintf("%s %s %s", i.Node.Spec.Hostname, i.Node.Spec.MachineType.String(), i.Node.Spec.OperatingSystem) +} + +func (i *ListItem) Title() string { + return i.Node.Spec.Hostname +} + +func (i *ListItem) Description() string { + var nodeType = "worker" + + if i == nil || i.Node == nil { + return "invalid node" + } + + if err := i.Node.Update(); err != nil { + slog.Warn("failed to update node data", "error", err.Error()) + } + + nodeVersion, err := i.Node.Version() + if err != nil { + nodeVersion = "invalid version" + } + + if i.Node.Spec.MachineType == machine.TypeControlPlane { + nodeType = "controlplane" + } + + return fmt.Sprintf("%s (%s)", nodeVersion, nodeType) +} + +func ListFromNodes(in []*Node) list.Model { + items := make([]list.Item, len(in)) + + for i, n := range in { + item := &ListItem{Node: n} + + items[i] = item + } + + return list.New(items, list.NewDefaultDelegate(), 0, 0) +} + +// NotVersion filters the list of Nodes, removing all Nodes which are the given version. +func NotVersion(in []*Node, version string) (out []*Node) { + for _, n := range in { + nodeVersion, err := n.Version() + if err != nil { + nodeVersion = "invalid version" + } + + if version == nodeVersion { + continue + } + + out = append(out, n) + } + + return +} diff --git a/pkg/node/node.go b/pkg/node/node.go new file mode 100644 index 0000000..a3abf34 --- /dev/null +++ b/pkg/node/node.go @@ -0,0 +1,135 @@ +package node + +import ( + "context" + "fmt" + + "github.com/cosi-project/runtime/pkg/resource" + "github.com/pkg/errors" + "github.com/siderolabs/talos/pkg/machinery/client" + "github.com/siderolabs/talos/pkg/machinery/resources/cluster" + "golang.org/x/mod/semver" +) + +type Role string + +const ( + RoleControlPlane = "controlplane" + RoleWorker = "worker" +) + +type Node struct { + Client *client.Client + Metadata *resource.Metadata + Spec *cluster.MemberSpec +} + +func (n *Node) Update() error { + if n == nil || n.Client == nil { + return errors.New("no Talos client found in Node") + } + + updatedNodeResp, err := n.Client.COSI.Get(context.Background(), resource.NewMetadata("cluster", "Members.cluster.talos.dev", n.Metadata.ID(), n.Metadata.Version())) + if err != nil { + return errors.Wrap(err, "failed to update node data") + } + + updatedNode, ok := updatedNodeResp.Spec().(*cluster.MemberSpec) + if !ok { + return errors.New("failed to type assert node data") + } + + n.Metadata = updatedNodeResp.Metadata() + n.Spec = updatedNode + + return nil +} + +func (n *Node) Version() (string, error) { + if n.Spec == nil { + return "", errors.New("no node member data yet") + } + + matches := VersionRegexp.FindStringSubmatch(n.Spec.OperatingSystem) + if len(matches) != 2 { + return "", errors.Errorf("failed to parse OperatingSystem %q for version", n.Spec.OperatingSystem) + } + + if !semver.IsValid(matches[1]) { + return "", errors.Errorf("invalid semver in release version: %q", matches[1]) + } + + return matches[1], nil +} + +func GetNodes(ctx context.Context, c *client.Client) (ret []*Node, err error) { + if c == nil { + return nil, errors.New("no Talos client provided") + } + + list, err := c.COSI.List(ctx, resource.NewMetadata("cluster", "Members.cluster.talos.dev", "", resource.VersionUndefined)) + if err != nil { + return nil, fmt.Errorf("failed to list cluster members: %w", err) + } + + for _, i := range list.Items { + node, ok := i.Spec().(*cluster.MemberSpec) + if !ok { + return nil, fmt.Errorf("failed to interpret result as a node: %w", err) + } + + ret = append(ret, &Node{ + Client: c, + Metadata: i.Metadata(), + Spec: node, + }) + } + + return ret, nil +} + +func LowestVersion(list []*Node) (lowest string, err error) { + if list == nil { + return "", errors.New("no nodes") + } + + for _, n := range list { + nodeVersion, err := n.Version() + if err != nil { + return "", errors.Wrapf(err, "failed to parse node version") + } + + if lowest == "" { + lowest = nodeVersion + } + + if semver.Compare(lowest, nodeVersion) > 0 { + lowest = nodeVersion + } + } + + return lowest, nil +} + +func HighestVersion(list []*Node) (highest string, err error) { + if list == nil { + return "", errors.New("no nodes") + } + + for _, n := range list { + nodeVersion, err := n.Version() + if err != nil { + return "", errors.Wrapf(err, "failed to parse node version") + } + + if highest == "" { + highest = nodeVersion + } + + if semver.Compare(highest, nodeVersion) < 0 { + highest = nodeVersion + } + } + + return highest, nil +} diff --git a/pkg/node/node_test.go b/pkg/node/node_test.go new file mode 100644 index 0000000..76345ab --- /dev/null +++ b/pkg/node/node_test.go @@ -0,0 +1,61 @@ +package node_test + +import ( + "context" + "testing" + + "git.cycore.io/scm/talos-upgrade/pkg/node" + "github.com/siderolabs/talos/pkg/machinery/client" + clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" + "github.com/stretchr/testify/assert" +) + +func TestGetNodes(t *testing.T) { + ctx := context.Background() + + cfg, err := clientconfig.Open("/home/scmccord/.config/talos/config.yaml") + assert.Nil(t, err) + + c, err := client.New(ctx, client.WithConfig(cfg)) + assert.Nil(t, err) + + _, err = node.GetNodes(ctx, c) + assert.Nil(t, err) +} + +func TestNodeVersion(t *testing.T) { + osString := "Talos (v1.5.1)" + osVersion := "v1.5.1" + + n := &node.Node{ + OperatingSystem: osString, + } + + ver, err := n.Version() + assert.Nil(t, err) + assert.Equal(t, osVersion, ver) +} + +func TestHighestLowestVersion(t *testing.T) { + expectedHighest := "v1.8.9" + expectedLowest := "v0.3.4" + + list := []*node.Node{ + { OperatingSystem: "Talos (v1.0.3)" }, + { OperatingSystem: "Talos (v1.2.1)" }, + { OperatingSystem: "Talos (v1.2.1)" }, + { OperatingSystem: "Talos (v1.4.3)" }, + { OperatingSystem: "Talos (v1.8.9)" }, + { OperatingSystem: "Talos (v0.3.4)" }, + { OperatingSystem: "Talos (v1.3.4)" }, + } + + highest, err := node.HighestVersion(list) + assert.Nil(t, err) + assert.Equal(t, expectedHighest, highest) + + lowest, err := node.LowestVersion(list) + assert.Nil(t, err) + assert.Equal(t, expectedLowest, lowest) +} + diff --git a/pkg/node/version.go b/pkg/node/version.go new file mode 100644 index 0000000..ee8e11b --- /dev/null +++ b/pkg/node/version.go @@ -0,0 +1,7 @@ +package node + +import "regexp" + +// VersionRegexp describes the regular expression for determining the version +// from the OS Release field of the Node. +var VersionRegexp = regexp.MustCompile(`^.*\((v.*)\)`) diff --git a/pkg/palette/palette.go b/pkg/palette/palette.go new file mode 100644 index 0000000..e1e05ee --- /dev/null +++ b/pkg/palette/palette.go @@ -0,0 +1,24 @@ +package palette + +const ( + Background = "#202020" + Foreground = "#d0d0d0" + + Black = "#000000" + Red = "#ee4a59" + Green = "#22ff22" + Yellow = "#f0df33" + Blue = "#7766ff" + Purple = "#cf55f0" + Cyan = "#33dbc3" + White = "#808080" + + BrightBlack = "#666666" + BrightRed = "#ff4090" + BrightGreen = "#99ff99" + BrightYellow = "#f0af00" + BrightBlue = "#50afff" + BridgeViolet = "#af60af" + BridgeCyan = "#95c5ff" + BridgeWhite = "#ffffff" +) diff --git a/pkg/release/list.go b/pkg/release/list.go new file mode 100644 index 0000000..c5e2a63 --- /dev/null +++ b/pkg/release/list.go @@ -0,0 +1,91 @@ +package release + +import ( + "fmt" + + "github.com/charmbracelet/bubbles/list" + "github.com/google/go-github/v55/github" + "golang.org/x/mod/semver" +) + +// ImageFormat describes the format of the installer container image for the given release. +var ImageFormat = `ghcr.io/siderolabs/installer:%s` + +type ListItem struct { + Release string + Note string +} + +func (i *ListItem) Title() string { + return i.Release +} + +func (i *ListItem) Description() string { + return i.Note +} + +func (i *ListItem) FilterValue() string { + return i.Release +} + +func (i *ListItem) Image() string { + return fmt.Sprintf(ImageFormat, i.Release) +} + +func ToList(releases []*github.RepositoryRelease, lowestInstalled, highestInstalled string) list.Model { + items := make([]list.Item, len(releases)) + + nextRelease := FindNextRelease(releases, lowestInstalled, highestInstalled) + + for i, r := range releases { + item := &ListItem{ + Release: r.GetName(), + } + + if semver.Compare(lowestInstalled, r.GetName()) == 0 { + item.Note = "lowest installed" + } + + if semver.Compare(highestInstalled, r.GetName()) == 0 { + item.Note = "highest installed" + } + + if semver.Compare(nextRelease, r.GetName()) == 0 { + item.Note = "recommended" + } + + items[i] = item + } + + return list.New(items, list.NewDefaultDelegate(), 0, 0) +} + +func FindNextRelease(releases []*github.RepositoryRelease, lowestInstalled, highestInstalled string) string { + nextRelease := highestInstalled + + // If we internally differ, we should upgrade everyone to the current highest installed release, first. + if lowestInstalled != highestInstalled { + return highestInstalled + } + + for _, r := range releases { + if semver.Compare(highestInstalled, r.GetName()) > 0 { // if this release is older than or the same age as the current + // highest-installed release, ignore it + continue + } + + // if we haven't selected a next-highest release yet, set us as it + if nextRelease == highestInstalled { + nextRelease = r.GetName() + + continue + } + + // If the "next" release is higher than this release, set this release to next, instead + if semver.Compare(nextRelease, r.GetName()) < 0 { + nextRelease = r.GetName() + } + } + + return nextRelease +} diff --git a/pkg/release/release.go b/pkg/release/release.go new file mode 100644 index 0000000..2c282d2 --- /dev/null +++ b/pkg/release/release.go @@ -0,0 +1,56 @@ +package release + +import ( + "context" + "fmt" + "net/http" + + "golang.org/x/mod/semver" + "github.com/google/go-github/v55/github" + "github.com/pkg/errors" +) + +func GetAll(ctx context.Context) (ret []*github.RepositoryRelease, err error) { + c := github.NewClient(nil) + if c == nil { + return nil, fmt.Errorf("failed to obtain Github client") + } + + list, resp, err := c.Repositories.ListReleases(ctx, "siderolabs", "talos", nil) + if err != nil { + return nil, errors.Wrap(err, "failed to list Talos releases") + } + + if resp.StatusCode != http.StatusOK { + return nil, errors.Errorf("received non-200 response code (%d) from Github release list request", resp.StatusCode) + } + + for _, r := range list { + if r.GetDraft() || r.GetPrerelease() { + continue + } + + ret = append(ret, r) + } + + return ret, nil +} + +func GetAfter(ctx context.Context, referenceRelease string) (ret []*github.RepositoryRelease, err error) { + if !semver.IsValid(referenceRelease) { + return nil, errors.Wrap(err, "failed to parse reference release") + } + + list, err := GetAll(ctx) + if err != nil { + return nil, err + } + + for _, r := range list { + if semver.Compare(referenceRelease, r.GetName()) < 0 { + ret = append(ret, r) + } + } + + return ret, nil +} diff --git a/pkg/release/release_test.go b/pkg/release/release_test.go new file mode 100644 index 0000000..29c1fe7 --- /dev/null +++ b/pkg/release/release_test.go @@ -0,0 +1,33 @@ +package release_test + +import ( + "context" + "testing" + + "git.cycore.io/scm/talos-upgrade/pkg/release" + "github.com/stretchr/testify/assert" +) + +func TestGetAllReleases(t *testing.T) { + ctx := context.Background() + + list, err := release.GetAll(ctx) + assert.Nil(t, err) + assert.NotEmpty(t, list) + + t.Logf("retrieved %d releases", len(list)) +} + +func TestGetAfter(t *testing.T) { + ctx := context.Background() + + referenceRelease := "v1.4.1" + + list, err := release.GetAfter(ctx, referenceRelease) + assert.Nil(t, err) + assert.NotEmpty(t, list) + + for _, r := range list { + t.Logf("release %s should be after %s", r.GetName(), referenceRelease) + } +} diff --git a/pkg/upgrade/core.go b/pkg/upgrade/core.go new file mode 100644 index 0000000..cf0bbcc --- /dev/null +++ b/pkg/upgrade/core.go @@ -0,0 +1,54 @@ +package upgrade + +import ( + "context" + + "git.cycore.io/scm/talos-upgrade/pkg/node" + "github.com/charmbracelet/lipgloss" + "github.com/google/go-github/v55/github" + "github.com/pkg/errors" + "github.com/siderolabs/talos/pkg/machinery/client" + clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" +) + +var docStyle = lipgloss.NewStyle().Margin(1, 2) + +func NewCore(ctx context.Context) (*CoreState,error) { + cfg, err := clientconfig.Open("/home/scmccord/.config/talos/config.yaml") + if err != nil { + return nil, errors.Wrap(err, "failed to open Talos configuration") + } + + tc, err := client.New(ctx, client.WithConfig(cfg)) + if err != nil { + return nil, errors.Wrap(err, "failed to create Talos client") + } + + return &CoreState{ + ctx: ctx, + TalosClient: tc, + }, nil +} + +type CoreState struct { + ctx context.Context + + SelectedVersion string + SelectedImage string + + CurrentReleases []*github.RepositoryRelease + + Nodes []*node.Node + + Talosconfig string + TalosContext string + TalosClient *client.Client + LowestTalosVersion string + HighestTalosVersion string + + Kubeconfig string + KubeContext string + + Width, Height int +} + diff --git a/pkg/upgrade/loadStatus.go b/pkg/upgrade/loadStatus.go new file mode 100644 index 0000000..4828781 --- /dev/null +++ b/pkg/upgrade/loadStatus.go @@ -0,0 +1,106 @@ +package upgrade + +import ( + "git.cycore.io/scm/talos-upgrade/pkg/palette" + "git.cycore.io/scm/talos-upgrade/pkg/release" + "github.com/charmbracelet/bubbles/spinner" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/google/go-github/v55/github" + "github.com/pkg/errors" +) + +type LoadState struct { + Core *CoreState + + progressPercent float64 + + Err error + + spinner spinner.Model + + textStyle func(...string) string + spinnerStyle lipgloss.Style + + helpStyle func(...string) string +} + +func (l *LoadState) Init() tea.Cmd { + l.spinner = spinner.New( + spinner.WithSpinner(spinner.Globe), + ) + + l.textStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(palette.Foreground)).Render + + l.spinnerStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(palette.Blue)) + + l.helpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(palette.BrightBlack)).Render + + go func() { + var err error + + defer func() { + l.progressPercent = 1.0 + + l.Err = err + }() + + if err = l.Core.UpdateNodeList(l.Core.ctx); err != nil { + err = errors.Wrap(err, "failed to update node list") + + return + } + + l.progressPercent = 0.5 + + if l.Core.CurrentReleases == nil { + var list []*github.RepositoryRelease + + //list, err := release.GetAfter(s.Core.ctx, s.Core.LowestTalosVersion) + list, err = release.GetAll(l.Core.ctx) + if err != nil { + err = errors.Wrap(err, "failed to load current Talos releases") + + return + } + + l.Core.CurrentReleases = list + } + }() + + return l.spinner.Tick +} + +func (l *LoadState) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + return l, tea.Quit + case tea.WindowSizeMsg: + l.Core.Width = msg.Width + l.Core.Height = msg.Height + + return l, nil + case spinner.TickMsg: + if l.progressPercent == 1.0 { + return NewSelectRelease(l.Core), nil + } + + var cmd tea.Cmd + + l.spinner, cmd = l.spinner.Update(msg) + + return l, cmd + default: + if l.progressPercent == 1.0 { + return NewSelectRelease(l.Core), nil + } + + return l, nil + } +} + +func (l *LoadState) View() string { + pad := " " + return "\n" + + pad + l.spinner.View() + " loading system status..." +} diff --git a/pkg/upgrade/node.go b/pkg/upgrade/node.go new file mode 100644 index 0000000..d8eff39 --- /dev/null +++ b/pkg/upgrade/node.go @@ -0,0 +1,87 @@ +package upgrade + +import ( + "context" + "fmt" + + "git.cycore.io/scm/talos-upgrade/pkg/node" + "git.cycore.io/scm/talos-upgrade/pkg/palette" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/pkg/errors" +) + +type Node struct { + core *CoreState + node *node.Node +} + +func (n *Node) Init() tea.Cmd { + return nil +} + +func (n *Node) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + return nil, nil +} + +func (n *Node) View() string { + ver, err := n.node.Version() + if err != nil { + ver = "Unknown" + } + + if ver == n.core.SelectedVersion { + return upgradeDone(ver) + } + + return ver +} + +func (c *CoreState) UpdateNodeList(ctx context.Context) error { + list, err := node.GetNodes(ctx, c.TalosClient) + if err != nil { + return err + } + + c.Nodes = list + + lowest, err := node.LowestVersion(c.Nodes) + if err != nil { + return errors.Wrap(err, "failed to determiner lowest installed Talos version") + } + + c.LowestTalosVersion = lowest + + highest, err := node.HighestVersion(c.Nodes) + if err != nil { + return errors.Wrap(err, "failed to determiner highest installed Talos version") + } + + c.HighestTalosVersion = highest + + return nil +} + +func checkMark() string { + return lipgloss.NewStyle().SetString("✓"). + Foreground(lipgloss.Color(palette.BrightGreen)). + PaddingRight(1). + String() +} + +func upgradeDone(version string) string { + verString := lipgloss.NewStyle(). + SetString(version). + Foreground(lipgloss.Color(palette.Green)). + PaddingRight(1). + String() + + return fmt.Sprintf("%s %s", checkMark(), verString) +} + +func upgradeActive() string { + return lipgloss.NewStyle().SetString("upgrading..."). + Foreground(lipgloss.Color(palette.Yellow)). + PaddingRight(1). + String() +} diff --git a/pkg/upgrade/selectNode.go b/pkg/upgrade/selectNode.go new file mode 100644 index 0000000..fc6fddb --- /dev/null +++ b/pkg/upgrade/selectNode.go @@ -0,0 +1,74 @@ +package upgrade + +import ( + "git.cycore.io/scm/talos-upgrade/pkg/node" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" +) + +type SelectNode struct { + Core *CoreState + + list list.Model +} + +func NewSelectNode(core *CoreState) *SelectNode { + upgradableNodes := node.NotVersion(core.Nodes, core.SelectedVersion) + + s := &SelectNode{ + Core: core, + list: node.ListFromNodes(upgradableNodes), + } + + if len(upgradableNodes) == 0 { + s.list.Title = "All nodes upgraded!" + } else { + s.list.Title = "Select Node to Upgrade" + } + + frameWidth, frameHeight := docStyle.GetFrameSize() + + s.list.SetSize(s.Core.Width-frameWidth, s.Core.Height-frameHeight) + + return s +} + +func (s *SelectNode) Init() tea.Cmd { + return nil +} + +func (s *SelectNode) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + if msg.String() == "ctrl+c" { + return s, tea.Quit + } + if msg.String() == "enter" { + selectedItem := s.list.Items()[s.list.Index()] + selectedNode := selectedItem.(*node.ListItem) + + return &Node{ + core: s.Core, + node: selectedNode.Node, + }, nil + } + case tea.WindowSizeMsg: + s.Core.Width = msg.Width + s.Core.Height = msg.Height + + frameWidth, frameHeight := docStyle.GetFrameSize() + + s.list.SetSize(msg.Width-frameWidth, msg.Height-frameHeight) + default: + } + + var cmd tea.Cmd + + s.list, cmd = s.list.Update(msg) + + return s, cmd +} + +func (s *SelectNode) View() string { + return docStyle.Render(s.list.View()) +} diff --git a/pkg/upgrade/selectRelease.go b/pkg/upgrade/selectRelease.go new file mode 100644 index 0000000..38b4845 --- /dev/null +++ b/pkg/upgrade/selectRelease.go @@ -0,0 +1,68 @@ +package upgrade + +import ( + "git.cycore.io/scm/talos-upgrade/pkg/release" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" +) + +type SelectRelease struct { + Core *CoreState + + list list.Model +} + +func NewSelectRelease(core *CoreState) *SelectRelease { + s := &SelectRelease{ + Core: core, + list: release.ToList(core.CurrentReleases, core.LowestTalosVersion, core.HighestTalosVersion), + } + + s.list.Title = "Select Talos Release" + + frameWidth, frameHeight := docStyle.GetFrameSize() + + s.list.SetSize(s.Core.Width-frameWidth, s.Core.Height-frameHeight) + + return s +} + +func (s *SelectRelease) Init() tea.Cmd { + return nil +} + +func (s *SelectRelease) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + if msg.String() == "ctrl+c" { + return s, tea.Quit + } + if msg.String() == "enter" { + selectedItem := s.list.Items()[s.list.Index()] + selectedRelease := selectedItem.(*release.ListItem) + + s.Core.SelectedVersion = selectedRelease.Release + s.Core.SelectedImage = selectedRelease.Image() + + return NewSelectNode(s.Core), nil + } + case tea.WindowSizeMsg: + s.Core.Width = msg.Width + s.Core.Height = msg.Height + + frameWidth, frameHeight := docStyle.GetFrameSize() + + s.list.SetSize(msg.Width-frameWidth, msg.Height-frameHeight) + default: + } + + var cmd tea.Cmd + + s.list, cmd = s.list.Update(msg) + + return s, cmd +} + +func (s *SelectRelease) View() string { + return docStyle.Render(s.list.View()) +} diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go new file mode 100644 index 0000000..7e588c7 --- /dev/null +++ b/pkg/upgrade/upgrade.go @@ -0,0 +1,32 @@ +package upgrade + +import ( + "fmt" + "log" + + tea "github.com/charmbracelet/bubbletea" +) + +type Upgrader struct { + core *CoreState +} + +func (u *Upgrader) Init() tea.Cmd { + return nil +} + +func (u *Upgrader) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + return u, tea.Quit + default: + log.Println(msg) + } + + // assess state to determine which model to instantiate and call + return nil, nil +} + +func (u *Upgrader) View() string { + return fmt.Sprintf("selected version %q, image: %q", u.core.SelectedVersion, u.core.SelectedImage) +}