From 067ed4610786264796de013d9196114286f88a1e Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Thu, 24 Oct 2024 11:48:20 -0700 Subject: [PATCH 01/15] Monitor docker event API Subscribe to the Docker API to monitor container creation and deletion events. Upon receiving these events, the event monitor immediately sends them as API events down the aggregated event channel. Signed-off-by: Nino Kodabande --- go.mod | 25 +++- go.sum | 66 ++++++++--- pkg/guestagent/events/docker.go | 173 ++++++++++++++++++++++++++++ pkg/guestagent/events/eventutils.go | 63 ++++++++++ pkg/guestagent/guestagent_linux.go | 12 ++ pkg/portfwd/listener.go | 2 +- 6 files changed, 322 insertions(+), 19 deletions(-) create mode 100644 pkg/guestagent/events/docker.go create mode 100644 pkg/guestagent/events/eventutils.go diff --git a/go.mod b/go.mod index 0b05d9545a1..fc5a03d9fbc 100644 --- a/go.mod +++ b/go.mod @@ -63,17 +63,22 @@ require ( github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/containerd/log v0.1.0 // indirect + github.com/creack/pty v1.1.18 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e // indirect github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/djherbis/times v1.6.0 // indirect + github.com/docker/docker v27.3.1+incompatible + github.com/docker/go-connections v0.5.0 github.com/elliotchance/orderedmap v1.8.0 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/fatih/color v1.18.0 // indirect - // gomodjail:unconfined + github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect @@ -101,9 +106,13 @@ require ( github.com/mdlayher/socket v0.5.1 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -115,13 +124,17 @@ require ( github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yuin/gopher-lua v1.1.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect golang.org/x/crypto v0.40.0 // indirect golang.org/x/mod v0.25.0 // indirect golang.org/x/oauth2 v0.28.0 // indirect golang.org/x/term v0.33.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.34.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect @@ -135,3 +148,9 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) + +require ( + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect +) diff --git a/go.sum b/go.sum index b79170c3772..4c1957066ce 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeX al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Code-Hex/go-infinity-channel v1.0.0 h1:M8BWlfDOxq9or9yvF9+YkceoTkDI1pFAqvnP87Zh0Nw= github.com/Code-Hex/go-infinity-channel v1.0.0/go.mod h1:5yUVg/Fqao9dAjcpzoQ33WwfdMWmISOrQloDRn3bsvY= github.com/Code-Hex/vz/v3 v3.7.0 h1:VEkfq5TVKnv85M81gQVPzLH9JzHrUJN/QQMpDZ+odPA= @@ -30,6 +32,9 @@ github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0 github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cheggaaa/pb/v3 v3.1.7 h1:2FsIW307kt7A/rz/ZI2lvPO+v3wKazzE4K/0LtTWsOI= github.com/cheggaaa/pb/v3 v3.1.7/go.mod h1:/Ji89zfVPeC/u5j8ukD0MBPHt2bzTYp74lQ7KlgFWTQ= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= @@ -43,8 +48,9 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -57,10 +63,16 @@ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/diskfs/go-diskfs v1.6.0 h1:YmK5+vLSfkwC6kKKRTRPGaDGNF+Xh8FXeiNHwryDfu4= github.com/diskfs/go-diskfs v1.6.0/go.mod h1:bRFumZeGFCO8C2KNswrQeuj2m1WCVr4Ms5IjWMczMDk= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= +github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/elastic/go-libaudit/v2 v2.6.2 h1:1PM6wVBTJHJQYsKl8jfA9/Aw9pFty5uUezPiUfKtOI4= @@ -75,6 +87,8 @@ github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtz github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -82,8 +96,9 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/ github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -125,6 +140,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/yamlfmt v0.17.2 h1:TkXxhmj7dnpmOnlWGOXog92Gs6MWcTZqnf3kuyp8yFQ= github.com/google/yamlfmt v0.17.2/go.mod h1:gs0UEklJOYkUJ+OOCG0hg9n+DzucKDPlJElTUasVNK8= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= @@ -190,11 +207,17 @@ github.com/mikefarah/yq/v4 v4.45.1 h1:EW+HjKEVa55pUYFJseEHEHdQ0+ulunY+q42zF3M7Za github.com/mikefarah/yq/v4 v4.45.1/go.mod h1:djgN2vD749hpjVNGYTShr5Kmv5LYljhCG3lUTuEe3LM= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= @@ -207,6 +230,8 @@ github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= @@ -229,8 +254,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI= @@ -270,16 +295,24 @@ github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= +go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= 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= @@ -406,8 +439,11 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= diff --git a/pkg/guestagent/events/docker.go b/pkg/guestagent/events/docker.go new file mode 100644 index 00000000000..3347158f9a7 --- /dev/null +++ b/pkg/guestagent/events/docker.go @@ -0,0 +1,173 @@ +package events + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/events" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/client" + "github.com/docker/go-connections/nat" + "github.com/lima-vm/lima/pkg/guestagent/api" + "github.com/sirupsen/logrus" +) + +type DockerEventMonitor struct { + dockerClient *client.Client + // We maintain a record of all active containers because neither the stop nor + // die events provide the port mapping. As API consumers, it's our responsibility + // to track this information. The map uses the container ID as the key and + // stores all published ports associated with that container as the value. + runningContainers map[string][]*api.IPPort +} + +func NewDockerEventMonitor() *DockerEventMonitor { + return &DockerEventMonitor{ + runningContainers: make(map[string][]*api.IPPort), + } +} + +func (d *DockerEventMonitor) createAndVerifyClient(ctx context.Context) (bool, error) { + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return false, fmt.Errorf("error creating Docker client: %s", err) + } + + _, err = cli.Info(ctx) + if err != nil { + return false, fmt.Errorf("error getting Docker info: %s", err) + } + d.dockerClient = cli + return true, nil +} + +func (d *DockerEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Event) error { + if err := tryGetClient(ctx, d.createAndVerifyClient); err != nil { + return fmt.Errorf("failed getting docker client: %w", err) + } + defer d.dockerClient.Close() + + if err := d.initializeRunningContainers(ctx, ch); err != nil { + logrus.Errorf("failed to initialize existing docker container published ports: %s", err) + } + + msgCh, errCh := d.dockerClient.Events(ctx, events.ListOptions{ + Filters: filters.NewArgs( + filters.Arg("type", string(types.ContainerObject)), + filters.Arg("event", string(events.ActionStart)), + filters.Arg("event", string(events.ActionStop)), + filters.Arg("event", string(events.ActionDie))), + }) + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("context cancellation: %w", ctx.Err()) + + case event := <-msgCh: + container, err := d.dockerClient.ContainerInspect(ctx, event.ID) + if err != nil { + logrus.Errorf("inspecting container [%v] failed: %v", event.ID, err) + continue + } + portMap := container.NetworkSettings.NetworkSettingsBase.Ports + logrus.Debugf("received an event: {Status: %+v ContainerID: %+v Ports: %+v}", + event.Action, + event.ID, + portMap) + + switch event.Action { + case events.ActionStart: + if len(portMap) != 0 { + validatePortMapping(portMap) + ipPorts, err := convertToIPPort(portMap) + if err != nil { + logrus.Errorf("converting docker's portMapping: %+v to api.IPPort: %v failed: %s", portMap, ipPorts, err) + continue + } + logrus.Infof("successfully converted PortMapping:%+v to IPPorts: %+v", portMap, ipPorts) + d.runningContainers[event.ID] = ipPorts + sendEvent(false, ipPorts, ch) + } + case events.ActionStop, events.ActionDie: + ipPorts, ok := d.runningContainers[event.ID] + if !ok { + continue + } + delete(d.runningContainers, event.ID) + sendEvent(true, ipPorts, ch) + } + case err := <-errCh: + return fmt.Errorf("receiving container event failed: %w", err) + } + } +} + +func (d *DockerEventMonitor) initializeRunningContainers(ctx context.Context, ch chan *api.Event) error { + containers, err := d.dockerClient.ContainerList(ctx, container.ListOptions{ + Filters: filters.NewArgs(filters.Arg("status", "running")), + }) + if err != nil { + return err + } + + for _, container := range containers { + if len(container.Ports) != 0 { + var ipPorts []*api.IPPort + for _, port := range container.Ports { + if port.IP == "" || port.PublicPort == 0 { + continue + } + + ipPorts = append(ipPorts, &api.IPPort{ + Protocol: strings.ToLower(port.Type), + Ip: port.IP, + Port: int32(port.PublicPort), + }) + } + sendEvent(false, ipPorts, ch) + d.runningContainers[container.ID] = ipPorts + } + } + return nil +} + +func convertToIPPort(portMap nat.PortMap) ([]*api.IPPort, error) { + var ipPorts []*api.IPPort + for key, portBindings := range portMap { + for _, portBinding := range portBindings { + hostPort, err := strconv.ParseInt(portBinding.HostPort, 10, 32) + if err != nil { + return ipPorts, err + } + if portBinding.HostIP == "" || hostPort == 0 { + continue + } + + logrus.Debugf("converted the following PortMapping to IPPort, containerPort:%v HostPort:%v IP:%v Protocol:%v", + key.Port(), portBinding.HostPort, portBinding.HostIP, key.Proto()) + + ipPorts = append(ipPorts, &api.IPPort{ + Protocol: strings.ToLower(key.Proto()), + Ip: portBinding.HostIP, + Port: int32(hostPort), + }) + } + } + return ipPorts, nil +} + +// Removes entries in port mapping that do not hold any values +// for IP and Port e.g 9000/tcp:[]. +func validatePortMapping(portMap nat.PortMap) { + for k, v := range portMap { + if len(v) == 0 { + logrus.Debugf("removing entry: %v from the portmappings: %v", k, portMap) + delete(portMap, k) + } + } +} diff --git a/pkg/guestagent/events/eventutils.go b/pkg/guestagent/events/eventutils.go new file mode 100644 index 00000000000..67bb8a1650a --- /dev/null +++ b/pkg/guestagent/events/eventutils.go @@ -0,0 +1,63 @@ +package events + +import ( + "context" + "fmt" + "time" + + "github.com/lima-vm/lima/pkg/guestagent/api" + "github.com/sirupsen/logrus" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func sendEvent(remove bool, ipPorts []*api.IPPort, ch chan *api.Event) { + var ev *api.Event + if remove { + ev = &api.Event{ + LocalPortsRemoved: ipPorts, + Time: timestamppb.Now(), + } + } else { + ev = &api.Event{ + LocalPortsAdded: ipPorts, + Time: timestamppb.Now(), + } + } + ch <- ev + logrus.Infof("sent the following event to hostAgent: %+v", ev) +} + +func tryGetClient(ctx context.Context, serving func(context.Context) (bool, error)) error { + initialInterval := 2 * time.Second + finalInterval := 10 * time.Second + maxAttempt := 5 + + ticker := time.NewTicker(initialInterval) + defer ticker.Stop() + attempts := 0 + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled, stopping attempts to connect to deamon") + case <-ticker.C: + isServing, err := serving(ctx) + if !isServing { + attempts++ + if attempts >= maxAttempt { + ticker.Stop() + ticker = time.NewTicker(finalInterval) + } + logrus.Debugf("trying to connect to the deamon...") + continue + } + if err != nil { + logrus.Errorf("error getting container engine's server info: %v", err) + continue + } + + logrus.Info("successfully connected to daemon") + return nil + } + } +} diff --git a/pkg/guestagent/guestagent_linux.go b/pkg/guestagent/guestagent_linux.go index 0bcd49efa49..dc9c10e62cb 100644 --- a/pkg/guestagent/guestagent_linux.go +++ b/pkg/guestagent/guestagent_linux.go @@ -18,6 +18,7 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "github.com/lima-vm/lima/pkg/guestagent/api" + "github.com/lima-vm/lima/pkg/guestagent/events" "github.com/lima-vm/lima/pkg/guestagent/iptables" "github.com/lima-vm/lima/pkg/guestagent/kubernetesservice" "github.com/lima-vm/lima/pkg/guestagent/procnettcp" @@ -28,6 +29,7 @@ func New(newTicker func() (<-chan time.Time, func()), iptablesIdle time.Duration a := &agent{ newTicker: newTicker, kubernetesServiceWatcher: kubernetesservice.NewServiceWatcher(), + dockerEventMonitor: events.NewDockerEventMonitor(), } auditClient, err := libaudit.NewMulticastAuditClient(nil) @@ -102,6 +104,7 @@ type agent struct { latestIPTables []iptables.Entry latestIPTablesMu sync.RWMutex kubernetesServiceWatcher *kubernetesservice.ServiceWatcher + dockerEventMonitor *events.DockerEventMonitor } // setWorthCheckingIPTablesRoutine sets worthCheckingIPTables to be true @@ -197,6 +200,13 @@ func isEventEmpty(ev *api.Event) bool { func (a *agent) Events(ctx context.Context, ch chan *api.Event) { defer close(ch) + + go func() { + if err := a.dockerEventMonitor.MonitorPorts(ctx, ch); err != nil { + errorCh <- err + } + }() + tickerCh, tickerClose := a.newTicker() defer tickerClose() var st eventState @@ -209,6 +219,8 @@ func (a *agent) Events(ctx context.Context, ch chan *api.Event) { select { case <-ctx.Done(): return + case err := <-errorCh: + logrus.Errorf("container engine event monitoring failed: %s", err) case _, ok := <-tickerCh: if !ok { return diff --git a/pkg/portfwd/listener.go b/pkg/portfwd/listener.go index e4b250dd882..2d5980ab34c 100644 --- a/pkg/portfwd/listener.go +++ b/pkg/portfwd/listener.go @@ -71,13 +71,13 @@ func (p *ClosableListeners) Remove(_ context.Context, protocol, hostAddress, gue func (p *ClosableListeners) forwardTCP(ctx context.Context, client *guestagentclient.GuestAgentClient, hostAddress, guestAddress string) { key := key("tcp", hostAddress, guestAddress) - p.listenersRW.Lock() _, ok := p.listeners[key] if ok { p.listenersRW.Unlock() return } + defer p.Remove(ctx, "tcp", hostAddress, guestAddress) tcpLis, err := Listen(ctx, p.listenConfig, hostAddress) if err != nil { logrus.Errorf("failed to listen to TCP connection: %v", err) From f5d59ea7542dee7382c702eba4bbfa5fb888ad00 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Tue, 29 Oct 2024 23:18:35 -0700 Subject: [PATCH 02/15] Monitor containerd event API Subscribe to the containerd API to monitor published ports for containers. Upon receiving these events, the event monitor immediately sends them as API events down the aggregated event channel. Signed-off-by: Nino Kodabande --- go.mod | 23 ++- go.sum | 147 ++++++++++++++++ pkg/guestagent/events/containerd.go | 256 ++++++++++++++++++++++++++++ pkg/guestagent/events/docker.go | 8 +- pkg/guestagent/events/eventutils.go | 39 +---- pkg/guestagent/guestagent_linux.go | 8 + 6 files changed, 443 insertions(+), 38 deletions(-) create mode 100644 pkg/guestagent/events/containerd.go diff --git a/go.mod b/go.mod index fc5a03d9fbc..b0d76fa9b1e 100644 --- a/go.mod +++ b/go.mod @@ -56,13 +56,17 @@ require ( require ( github.com/Code-Hex/go-infinity-channel v1.0.0 // indirect + github.com/Microsoft/hcsshim v0.11.7 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/a8m/envsubst v1.4.2 // indirect github.com/alecthomas/participle/v2 v2.1.4 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect + github.com/containerd/cgroups v1.1.0 // indirect + github.com/containerd/fifo v1.1.0 // indirect github.com/containerd/log v0.1.0 // indirect + github.com/containerd/ttrpc v1.2.5 // indirect github.com/creack/pty v1.1.18 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e // indirect @@ -71,6 +75,7 @@ require ( github.com/djherbis/times v1.6.0 // indirect github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 + github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/elliotchance/orderedmap v1.8.0 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/fatih/color v1.18.0 // indirect @@ -83,7 +88,8 @@ require ( github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/goccy/go-json v0.10.5 // indirect - github.com/gogo/protobuf v1.3.2 // indirect + github.com/gogo/protobuf v1.3.2 + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect @@ -97,6 +103,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/kr/fs v0.1.0 // indirect github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 // indirect github.com/magiconair/properties v1.8.10 // indirect @@ -107,16 +114,22 @@ require ( github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/locker v1.0.1 // indirect + github.com/moby/sys/mountinfo v0.6.2 // indirect + github.com/moby/sys/signal v0.7.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/opencontainers/runtime-spec v1.1.0 // indirect + github.com/opencontainers/selinux v1.11.0 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/sftp v1.13.9 // indirect + github.com/prometheus/procfs v0.10.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect @@ -124,6 +137,7 @@ require ( github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yuin/gopher-lua v1.1.1 // indirect + go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect go.opentelemetry.io/otel v1.37.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect @@ -150,7 +164,12 @@ require ( ) require ( - go.opentelemetry.io/auto/sdk v1.1.0 // indirect + github.com/containerd/containerd v1.6.23 + github.com/containerd/typeurl v1.0.2 // indirect + github.com/gogo/googleapis v1.4.0 // indirect + github.com/opencontainers/runc v1.1.5 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect go.opentelemetry.io/otel/sdk v1.37.0 // indirect ) + +require go.opentelemetry.io/auto/sdk v1.1.0 // indirect diff --git a/go.sum b/go.sum index 4c1957066ce..633d1df41cd 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,19 @@ al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA= al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Code-Hex/go-infinity-channel v1.0.0 h1:M8BWlfDOxq9or9yvF9+YkceoTkDI1pFAqvnP87Zh0Nw= github.com/Code-Hex/go-infinity-channel v1.0.0/go.mod h1:5yUVg/Fqao9dAjcpzoQ33WwfdMWmISOrQloDRn3bsvY= github.com/Code-Hex/vz/v3 v3.7.0 h1:VEkfq5TVKnv85M81gQVPzLH9JzHrUJN/QQMpDZ+odPA= github.com/Code-Hex/vz/v3 v3.7.0/go.mod h1:1LsW0jqW0r0cQ+IeR4hHbjdqOtSidNCVMWhStMHGho8= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ= +github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= @@ -35,22 +39,41 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2 github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cheggaaa/pb/v3 v3.1.7 h1:2FsIW307kt7A/rz/ZI2lvPO+v3wKazzE4K/0LtTWsOI= github.com/cheggaaa/pb/v3 v3.1.7/go.mod h1:/Ji89zfVPeC/u5j8ukD0MBPHt2bzTYp74lQ7KlgFWTQ= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.6.23 h1:KYJd6UJhKHzwMhiD70iTtSmU+k4565ac22GOTI3AuTA= +github.com/containerd/containerd v1.6.23/go.mod h1:UrQOiyzrLi3n4aezYJbQH6Il+YzTvnHFbEuO3yfDrM4= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= +github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= +github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oLU= +github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= +github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/containers/gvisor-tap-vsock v0.8.6 h1:9SeAXK+K2o36CtrgYk6zRXbU3zrayjvkrI8b7/O6u5A= github.com/containers/gvisor-tap-vsock v0.8.6/go.mod h1:+0mtKmm4STeSDnZe+DGnIwN4EH2f7AcWir7PwT28Ti0= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -73,6 +96,9 @@ github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFT github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/elastic/go-libaudit/v2 v2.6.2 h1:1PM6wVBTJHJQYsKl8jfA9/Aw9pFty5uUezPiUfKtOI4= @@ -85,12 +111,17 @@ github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1Ugj github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= @@ -115,14 +146,42 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +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.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/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/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -136,10 +195,12 @@ github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgY github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/yamlfmt v0.17.2 h1:TkXxhmj7dnpmOnlWGOXog92Gs6MWcTZqnf3kuyp8yFQ= github.com/google/yamlfmt v0.17.2/go.mod h1:gs0UEklJOYkUJ+OOCG0hg9n+DzucKDPlJElTUasVNK8= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -162,14 +223,18 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lima-vm/go-qcow2reader v0.6.0 h1:dNstUGQxEUPbmiiVnu/cek2x7scrHe2VJy5JseLLflo= @@ -209,6 +274,13 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= +github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -218,6 +290,7 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= @@ -232,6 +305,14 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= +github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= +github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= @@ -249,6 +330,9 @@ github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6kt github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -256,14 +340,18 @@ github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZe github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI= github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU= github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= @@ -272,17 +360,24 @@ github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -293,6 +388,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= @@ -325,6 +422,10 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -338,10 +439,16 @@ golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -354,8 +461,11 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -370,15 +480,23 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/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-20190222072716-a9d3bda3a223/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-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/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-20211116061358-0a5406a5449c/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-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -423,6 +541,11 @@ golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -439,13 +562,34 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +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.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -459,6 +603,7 @@ gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= @@ -466,6 +611,8 @@ gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= gvisor.dev/gvisor v0.0.0-20240916094835-a174eb65023f h1:O2w2DymsOlM/nv2pLNWCMCYOldgBBMkD7H0/prN5W2k= gvisor.dev/gvisor v0.0.0-20240916094835-a174eb65023f/go.mod h1:sxc3Uvk/vHcd3tj7/DHVBoR5wvWT/MmRq2pj7HRJnwU= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.32.6 h1:UiBAMRzTP24Tz9UT1uhhmAv1auGTT9PT/npywSk9JrU= k8s.io/api v0.32.6/go.mod h1:+iFCyQN34v2rsL53iQEN9lYE03mFdgPvgSXvATIDteg= k8s.io/apimachinery v0.32.6 h1:odtEUjg7OT3132sBFsFn4Arj4Gd+BplYekmLQP8L3ak= diff --git a/pkg/guestagent/events/containerd.go b/pkg/guestagent/events/containerd.go new file mode 100644 index 00000000000..4ed58376086 --- /dev/null +++ b/pkg/guestagent/events/containerd.go @@ -0,0 +1,256 @@ +package events + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/api/events" + "github.com/lima-vm/lima/pkg/guestagent/api" + "github.com/sirupsen/logrus" + "github.com/gogo/protobuf/proto" + + containerdNamespace "github.com/containerd/containerd/namespaces" +) + +const ( + portsKey = "nerdctl/ports" + namespaceKey = "nerdctl/namespace" +) + +type ContainerdEventMonitor struct { + containerdClient *containerd.Client + runningContainers map[string][]*api.IPPort +} + +func NewContainerdEventMonitor() *ContainerdEventMonitor { + return &ContainerdEventMonitor{ + runningContainers: make(map[string][]*api.IPPort), + } +} + +func (c *ContainerdEventMonitor) createAndVerifyClient(ctx context.Context) (bool, error) { + containerdSockets := []string{ + "/run/k3s/containerd/containerd.sock", + "/run/containerd/containerd.sock", + } + + for _, socket := range containerdSockets { + logrus.Debugf("reading containerd socket %s", socket) + if _, err := os.Stat(socket); os.IsNotExist(err) { + continue + } else if err != nil { + return false, nil + } + + cli, err := containerd.New(socket, containerd.WithDefaultNamespace(containerdNamespace.Default)) + if err == nil { + serving, err := cli.IsServing(ctx) + if err != nil { + logrus.Tracef("error getting containerd server: %s", err) + return false, nil + } + c.containerdClient = cli + logrus.Infof("successfully connected to containerd daemon: %s", socket) + return serving, nil + } + + logrus.Tracef("error creating Containerd client: %s", err) + } + + return false, nil +} + +func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Event) error { + if err := tryGetClient(ctx, c.createAndVerifyClient); err != nil { + return fmt.Errorf("failed getting containerd client: %w", err) + } + defer c.containerdClient.Close() + + subscribeFilters := []string{ + `topic=="/tasks/start"`, + `topic=="/containers/update"`, + `topic=="/tasks/exit"`, + } + msgCh, errCh := c.containerdClient.Subscribe(ctx, subscribeFilters...) + + if err := c.initializeRunningContainers(ctx, ch); err != nil { + logrus.Errorf("failed to initialize existing containers published ports: %v", err) + } + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("context cancellation: %w", ctx.Err()) + + case err := <-errCh: + return fmt.Errorf("receiving container event failed: %w", err) + + case envelope := <-msgCh: + logrus.Debugf("received an event: %+v", envelope.Topic) + switch envelope.Topic { + case "/tasks/start": + startTask := &events.TaskStart{} + + err := proto.Unmarshal(envelope.Event.GetValue(), startTask) + if err != nil { + logrus.Errorf("failed to unmarshal container's start task: %v", err) + continue + } + + ipPorts, err := c.createIPPort(ctx, envelope.Namespace, startTask.ContainerID) + if err != nil { + logrus.Errorf("creating IPPorts, for the following start task: %v failed: %s", startTask, err) + continue + } + + logrus.Debugf("received the following startTask: %v for: %v", startTask, ipPorts) + + if len(ipPorts) != 0 { + sendEvent(false, ipPorts, ch) + c.runningContainers[startTask.ContainerID] = ipPorts + } + + case "/containers/update": + cuEvent := &events.ContainerUpdate{} + err := proto.Unmarshal(envelope.Event.GetValue(), cuEvent) + if err != nil { + logrus.Errorf("failed to unmarshal container update event: %v", err) + continue + } + + ipPorts, err := c.createIPPort(ctx, envelope.Namespace, cuEvent.ID) + if err != nil { + logrus.Errorf("creating IPPorts, for the following exit task: %v failed: %s", cuEvent, err) + continue + } + + logrus.Debugf("received the following updateTask: %v for: %v", cuEvent, ipPorts) + + if exsitingipPorts, ok := c.runningContainers[cuEvent.ID]; ok { + if !ipPortsEqual(ipPorts, exsitingipPorts) { + // first remove the existing entry + sendEvent(true, exsitingipPorts, ch) + // then update with the new entry + sendEvent(false, ipPorts, ch) + c.runningContainers[cuEvent.ID] = ipPorts + } + } + case "/tasks/exit": + exitTask := &events.TaskExit{} + err := proto.Unmarshal(envelope.Event.GetValue(), exitTask) + if err != nil { + logrus.Errorf("failed to unmarshal container's exit task: %v", err) + continue + } + + ipPorts, err := c.createIPPort(ctx, envelope.Namespace, exitTask.ContainerID) + if err != nil { + logrus.Errorf("creating IPPorts, for the following exit task: %v failed: %s", exitTask, err) + continue + } + + logrus.Debugf("received the following exitTask: %v for: %v", exitTask, ipPorts) + + if len(ipPorts) != 0 { + sendEvent(true, ipPorts, ch) + delete(c.runningContainers, exitTask.ContainerID) + } + } + } + } +} + +func (c *ContainerdEventMonitor) initializeRunningContainers(ctx context.Context, ch chan *api.Event) error { + containers, err := c.containerdClient.Containers(ctx) + if err != nil { + return err + } + + for _, container := range containers { + task, err := container.Task(ctx, nil) + if err != nil { + logrus.Errorf("failed getting container %s task: %s", container.ID(), err) + continue + } + + status, err := task.Status(ctx) + if err != nil { + logrus.Errorf("failed getting container %s task status: %s", container.ID(), err) + continue + } + if status.Status != containerd.Running { + continue + } + + labels, err := container.Labels(ctx) + if err != nil { + logrus.Errorf("failed getting container %s labels: %s", container.ID(), err) + continue + } + + ipPorts, err := c.createIPPort(ctx, labels[namespaceKey], container.ID()) + if err != nil { + logrus.Errorf("creating IPPorts, while initializing containers the following: %v failed: %s", container.ID(), err) + } + + sendEvent(false, ipPorts, ch) + } + + return nil +} + +func (c *ContainerdEventMonitor) createIPPort(ctx context.Context, namespace, containerID string) ([]*api.IPPort, error) { + container, err := c.containerdClient.ContainerService().Get( + containerdNamespace.WithNamespace(ctx, namespace), containerID) + if err != nil { + return nil, err + } + + var ipPorts []*api.IPPort + + containerPorts := container.Labels[portsKey] + if containerPorts == "" { + return ipPorts, nil + } + + var ports []Port + err = json.Unmarshal([]byte(containerPorts), &ports) + if err != nil { + return nil, err + } + + for _, port := range ports { + ipPorts = append(ipPorts, &api.IPPort{ + Protocol: strings.ToLower(port.Protocol), + Ip: port.HostIP, + Port: int32(port.HostPort), + }) + } + + return ipPorts, nil +} + +func ipPortsEqual(a, b []*api.IPPort) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i].Protocol != b[i].Protocol || a[i].Ip != b[i].Ip || a[i].Port != b[i].Port { + return false + } + } + return true +} + +// Port is representing nerdctl/ports entry in the +// event envelope's labels. +type Port struct { + HostPort int + ContainerPort int + Protocol string + HostIP string +} diff --git a/pkg/guestagent/events/docker.go b/pkg/guestagent/events/docker.go index 3347158f9a7..cdf5fed841f 100644 --- a/pkg/guestagent/events/docker.go +++ b/pkg/guestagent/events/docker.go @@ -34,14 +34,18 @@ func NewDockerEventMonitor() *DockerEventMonitor { func (d *DockerEventMonitor) createAndVerifyClient(ctx context.Context) (bool, error) { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { - return false, fmt.Errorf("error creating Docker client: %s", err) + logrus.Tracef("error creating Docker client: %s", err) + return false, nil } _, err = cli.Info(ctx) if err != nil { - return false, fmt.Errorf("error getting Docker info: %s", err) + logrus.Tracef("error getting Docker info: %s", err) + return false, nil } + d.dockerClient = cli + logrus.Info("successfully connected to docker daemon") return true, nil } diff --git a/pkg/guestagent/events/eventutils.go b/pkg/guestagent/events/eventutils.go index 67bb8a1650a..d9c4cfbe457 100644 --- a/pkg/guestagent/events/eventutils.go +++ b/pkg/guestagent/events/eventutils.go @@ -2,12 +2,12 @@ package events import ( "context" - "fmt" "time" "github.com/lima-vm/lima/pkg/guestagent/api" "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/timestamppb" + "k8s.io/apimachinery/pkg/util/wait" ) func sendEvent(remove bool, ipPorts []*api.IPPort, ch chan *api.Event) { @@ -27,37 +27,8 @@ func sendEvent(remove bool, ipPorts []*api.IPPort, ch chan *api.Event) { logrus.Infof("sent the following event to hostAgent: %+v", ev) } -func tryGetClient(ctx context.Context, serving func(context.Context) (bool, error)) error { - initialInterval := 2 * time.Second - finalInterval := 10 * time.Second - maxAttempt := 5 - - ticker := time.NewTicker(initialInterval) - defer ticker.Stop() - attempts := 0 - - for { - select { - case <-ctx.Done(): - return fmt.Errorf("context cancelled, stopping attempts to connect to deamon") - case <-ticker.C: - isServing, err := serving(ctx) - if !isServing { - attempts++ - if attempts >= maxAttempt { - ticker.Stop() - ticker = time.NewTicker(finalInterval) - } - logrus.Debugf("trying to connect to the deamon...") - continue - } - if err != nil { - logrus.Errorf("error getting container engine's server info: %v", err) - continue - } - - logrus.Info("successfully connected to daemon") - return nil - } - } +func tryGetClient(ctx context.Context, tryConnect func(context.Context) (bool, error)) error { + const retryInterval = 10 * time.Second + const pollImmediately = true + return wait.PollUntilContextCancel(ctx, retryInterval, pollImmediately, tryConnect) } diff --git a/pkg/guestagent/guestagent_linux.go b/pkg/guestagent/guestagent_linux.go index dc9c10e62cb..9739d22c03f 100644 --- a/pkg/guestagent/guestagent_linux.go +++ b/pkg/guestagent/guestagent_linux.go @@ -30,6 +30,7 @@ func New(newTicker func() (<-chan time.Time, func()), iptablesIdle time.Duration newTicker: newTicker, kubernetesServiceWatcher: kubernetesservice.NewServiceWatcher(), dockerEventMonitor: events.NewDockerEventMonitor(), + containerdEventMonitor: events.NewContainerdEventMonitor(), } auditClient, err := libaudit.NewMulticastAuditClient(nil) @@ -105,6 +106,7 @@ type agent struct { latestIPTablesMu sync.RWMutex kubernetesServiceWatcher *kubernetesservice.ServiceWatcher dockerEventMonitor *events.DockerEventMonitor + containerdEventMonitor *events.ContainerdEventMonitor } // setWorthCheckingIPTablesRoutine sets worthCheckingIPTables to be true @@ -201,6 +203,12 @@ func isEventEmpty(ev *api.Event) bool { func (a *agent) Events(ctx context.Context, ch chan *api.Event) { defer close(ch) + errorCh := make(chan error) + go func() { + if err := a.containerdEventMonitor.MonitorPorts(ctx, ch); err != nil { + errorCh <- err + } + }() go func() { if err := a.dockerEventMonitor.MonitorPorts(ctx, ch); err != nil { errorCh <- err From fbfbf24ebaa3c8627d8ddd3f9efb5ae9a79172c5 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Wed, 30 Oct 2024 14:56:17 -0700 Subject: [PATCH 03/15] Add kubernetes service watcher Subscribes to kube API for the published ports from NodePort and Loadbalancer type. Signed-off-by: Nino Kodabande --- pkg/guestagent/events/containerd.go | 10 +- pkg/guestagent/events/docker.go | 6 +- pkg/guestagent/events/eventutils.go | 16 +- pkg/guestagent/events/kubernetes.go | 282 ++++++++++++++++++++++++++++ pkg/guestagent/guestagent_linux.go | 10 +- 5 files changed, 305 insertions(+), 19 deletions(-) create mode 100644 pkg/guestagent/events/kubernetes.go diff --git a/pkg/guestagent/events/containerd.go b/pkg/guestagent/events/containerd.go index 4ed58376086..09e8ca525b3 100644 --- a/pkg/guestagent/events/containerd.go +++ b/pkg/guestagent/events/containerd.go @@ -110,7 +110,7 @@ func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api. logrus.Debugf("received the following startTask: %v for: %v", startTask, ipPorts) if len(ipPorts) != 0 { - sendEvent(false, ipPorts, ch) + sendHostAgentEvent(false, ipPorts, ch) c.runningContainers[startTask.ContainerID] = ipPorts } @@ -133,9 +133,9 @@ func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api. if exsitingipPorts, ok := c.runningContainers[cuEvent.ID]; ok { if !ipPortsEqual(ipPorts, exsitingipPorts) { // first remove the existing entry - sendEvent(true, exsitingipPorts, ch) + sendHostAgentEvent(true, exsitingipPorts, ch) // then update with the new entry - sendEvent(false, ipPorts, ch) + sendHostAgentEvent(false, ipPorts, ch) c.runningContainers[cuEvent.ID] = ipPorts } } @@ -156,7 +156,7 @@ func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api. logrus.Debugf("received the following exitTask: %v for: %v", exitTask, ipPorts) if len(ipPorts) != 0 { - sendEvent(true, ipPorts, ch) + sendHostAgentEvent(true, ipPorts, ch) delete(c.runningContainers, exitTask.ContainerID) } } @@ -197,7 +197,7 @@ func (c *ContainerdEventMonitor) initializeRunningContainers(ctx context.Context logrus.Errorf("creating IPPorts, while initializing containers the following: %v failed: %s", container.ID(), err) } - sendEvent(false, ipPorts, ch) + sendHostAgentEvent(false, ipPorts, ch) } return nil diff --git a/pkg/guestagent/events/docker.go b/pkg/guestagent/events/docker.go index cdf5fed841f..b2c05d8a464 100644 --- a/pkg/guestagent/events/docker.go +++ b/pkg/guestagent/events/docker.go @@ -95,7 +95,7 @@ func (d *DockerEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Even } logrus.Infof("successfully converted PortMapping:%+v to IPPorts: %+v", portMap, ipPorts) d.runningContainers[event.ID] = ipPorts - sendEvent(false, ipPorts, ch) + sendHostAgentEvent(false, ipPorts, ch) } case events.ActionStop, events.ActionDie: ipPorts, ok := d.runningContainers[event.ID] @@ -103,7 +103,7 @@ func (d *DockerEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Even continue } delete(d.runningContainers, event.ID) - sendEvent(true, ipPorts, ch) + sendHostAgentEvent(true, ipPorts, ch) } case err := <-errCh: return fmt.Errorf("receiving container event failed: %w", err) @@ -133,7 +133,7 @@ func (d *DockerEventMonitor) initializeRunningContainers(ctx context.Context, ch Port: int32(port.PublicPort), }) } - sendEvent(false, ipPorts, ch) + sendHostAgentEvent(false, ipPorts, ch) d.runningContainers[container.ID] = ipPorts } } diff --git a/pkg/guestagent/events/eventutils.go b/pkg/guestagent/events/eventutils.go index d9c4cfbe457..4cbab8bb770 100644 --- a/pkg/guestagent/events/eventutils.go +++ b/pkg/guestagent/events/eventutils.go @@ -10,18 +10,14 @@ import ( "k8s.io/apimachinery/pkg/util/wait" ) -func sendEvent(remove bool, ipPorts []*api.IPPort, ch chan *api.Event) { - var ev *api.Event +func sendHostAgentEvent(remove bool, ipPorts []*api.IPPort, ch chan *api.Event) { + ev := &api.Event{ + Time: timestamppb.Now(), + } if remove { - ev = &api.Event{ - LocalPortsRemoved: ipPorts, - Time: timestamppb.Now(), - } + ev.LocalPortsRemoved = ipPorts } else { - ev = &api.Event{ - LocalPortsAdded: ipPorts, - Time: timestamppb.Now(), - } + ev.LocalPortsAdded = ipPorts } ch <- ev logrus.Infof("sent the following event to hostAgent: %+v", ev) diff --git a/pkg/guestagent/events/kubernetes.go b/pkg/guestagent/events/kubernetes.go new file mode 100644 index 00000000000..f4288ef9bfe --- /dev/null +++ b/pkg/guestagent/events/kubernetes.go @@ -0,0 +1,282 @@ +package events + +import ( + "context" + "errors" + "fmt" + "net/url" + "os" + "strings" + "time" + + "github.com/lima-vm/lima/pkg/guestagent/api" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/clientcmd" +) + +type event struct { + UID types.UID + namespace string + name string + portMapping map[int32]corev1.Protocol + deleted bool +} + +type KubeServiceWatcher struct { + kubeClient kubernetes.Interface + eventCh chan event + errorCh chan error +} + +func NewKubeServiceWatcher() *KubeServiceWatcher { + return &KubeServiceWatcher{ + eventCh: make(chan event), + errorCh: make(chan error), + } +} + +func (k *KubeServiceWatcher) createAndVerifyClient(ctx context.Context) (bool, error) { + kubeClient, err := tryGetKubeClient() + if err != nil { + logrus.Tracef("failed to get kube client: %s", err) + return false, nil + } + + informerFactory := informers.NewSharedInformerFactory(kubeClient, time.Hour) + serviceInformer := informerFactory.Core().V1().Services().Informer() + + _, err = serviceInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj any) { + logrus.Tracef("Service Informer: Add func called with: %+v", obj) + handleUpdate(nil, obj, k.eventCh) + }, + DeleteFunc: func(obj any) { + logrus.Tracef("Service Informer: Del func called with: %+v", obj) + handleUpdate(obj, nil, k.eventCh) + }, + UpdateFunc: func(oldObj, newObj any) { + logrus.Tracef("Service Informer: Update func called with old object %+v and new Object: %+v", oldObj, newObj) + handleUpdate(oldObj, newObj, k.eventCh) + }, + }) + if err != nil { + // this error can not be ignored and must be returned + return false, fmt.Errorf("error setting eventHandler: %w", err) + } + err = serviceInformer.SetWatchErrorHandler(func(_ *cache.Reflector, err error) { + k.errorCh <- fmt.Errorf("kubernetes: error watching service: %w", err) + }) + if err != nil { + // this error can not be ignored and must be returned + return false, fmt.Errorf("error setting errorHandler: %w", err) + } + informerFactory.WaitForCacheSync(ctx.Done()) + informerFactory.Start(ctx.Done()) + k.kubeClient = kubeClient + return true, nil +} + +func (k *KubeServiceWatcher) initializeServices(ctx context.Context) error { + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + services, err := k.kubeClient.CoreV1().Services(corev1.NamespaceAll).List(ctx, v1.ListOptions{}) + if err != nil { + logrus.Errorf("Listing services failed: %s", err) + switch { + default: + return err + case isTimeout(err): + case errors.Is(err, unix.ENETUNREACH): + case errors.Is(err, unix.ECONNREFUSED): + case isAPINotReady(err): + } + continue + } + + // List the initial set of services asynchronously, so that we don't have to + // worry about the channel blocking. + go func() { + for _, svc := range services.Items { + handleUpdate(nil, svc, k.eventCh) + } + }() + return nil + + case <-ctx.Done(): + return fmt.Errorf("context cancelled during initialization: %w", ctx.Err()) + } + } +} + +func (k *KubeServiceWatcher) MonitorServices(ctx context.Context, ch chan *api.Event) error { + if err := tryGetClient(ctx, k.createAndVerifyClient); err != nil { + return fmt.Errorf("failed getting kube client: %w", err) + } + + if err := k.initializeServices(ctx); err != nil { + return fmt.Errorf("failed initializing services: %w", err) + } + for { + select { + case <-ctx.Done(): + return fmt.Errorf("context cancellation: %w", ctx.Err()) + case err := <-k.errorCh: + logrus.Errorf("received an error from kube API: %s", err) + case event := <-k.eventCh: + logrus.Debugf("received an event from kube API: %+v", event) + ipPorts := createIPPortFromPortMapping(event.portMapping) + sendHostAgentEvent(event.deleted, ipPorts, ch) + } + } +} + +func createIPPortFromPortMapping(portMapping map[int32]corev1.Protocol) (ipPorts []*api.IPPort) { + for port, proto := range portMapping { + ipPorts = append(ipPorts, &api.IPPort{ + Ip: "0.0.0.0", + Protocol: strings.ToLower(string(proto)), + Port: port, + }) + } + return ipPorts +} + +func handleUpdate(oldObj, newObj any, eventCh chan<- event) { + deleted := make(map[int32]corev1.Protocol) + added := make(map[int32]corev1.Protocol) + oldSvc, _ := oldObj.(*corev1.Service) + newSvc, _ := newObj.(*corev1.Service) + namespace := "" + name := "" + + if oldSvc != nil { + namespace = oldSvc.Namespace + name = oldSvc.Name + + if oldSvc.Spec.Type == corev1.ServiceTypeNodePort { + for _, port := range oldSvc.Spec.Ports { + deleted[port.NodePort] = port.Protocol + } + } + + if oldSvc.Spec.Type == corev1.ServiceTypeLoadBalancer { + for _, port := range oldSvc.Spec.Ports { + deleted[port.Port] = port.Protocol + } + } + } + + if newSvc != nil { + namespace = newSvc.Namespace + name = newSvc.Name + + if newSvc.Spec.Type == corev1.ServiceTypeNodePort { + for _, port := range newSvc.Spec.Ports { + delete(deleted, port.NodePort) + added[port.NodePort] = port.Protocol + } + } + + if newSvc.Spec.Type == corev1.ServiceTypeLoadBalancer { + for _, port := range newSvc.Spec.Ports { + delete(deleted, port.Port) + added[port.Port] = port.Protocol + } + } + } + + if len(deleted) > 0 { + sendEvents(deleted, oldSvc, true, eventCh) + } + + if len(added) > 0 { + sendEvents(added, newSvc, false, eventCh) + } + + logrus.Debugf("kubernetes service update: %s/%s has -%d +%d service port", + namespace, name, len(deleted), len(added)) +} + +func sendEvents(mapping map[int32]corev1.Protocol, svc *corev1.Service, deleted bool, eventCh chan<- event) { + if svc != nil { + eventCh <- event{ + UID: svc.UID, + namespace: svc.Namespace, + name: svc.Name, + portMapping: mapping, + deleted: deleted, + } + } +} + +func tryGetKubeClient() (kubernetes.Interface, error) { + candidateKubeConfigs := []string{ + "/etc/rancher/k3s/k3s.yaml", + "/root/.kube/config", + } + + for _, kubeconfig := range candidateKubeConfigs { + _, err := os.Stat(kubeconfig) + if err != nil { + if os.IsNotExist(err) { + continue + } + + return nil, fmt.Errorf("stat kubeconfig %s failed: %w", kubeconfig, err) + } + + restConfig, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + return nil, fmt.Errorf("build kubeconfig from %s failed: %w", kubeconfig, err) + } + u, err := url.Parse(restConfig.Host) + if err != nil { + return nil, fmt.Errorf("parse kubeconfig host %s failed: %w", restConfig.Host, err) + } + if u.Hostname() != "127.0.0.1" { // might need to support IPv6 + // ensures the kubeconfig points to local k8s + continue + } + + kubeClient, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return nil, err + } + + return kubeClient, nil + } + + return nil, errors.New("no valid kubeconfig found") +} + +func isTimeout(err error) bool { + type timeout interface { + Timeout() bool + } + + var timeoutError timeout + + if !errors.As(err, &timeoutError) { + return timeoutError != nil && timeoutError.Timeout() + } + + return false +} + +// This is a k3s error that is received over +// the HTTP, Also, it is worth noting that this +// error is wrapped. This is why we are not testing +// against the real error object using errors.Is(). +func isAPINotReady(err error) bool { + return strings.Contains(err.Error(), "apiserver not ready") || strings.Contains(err.Error(), "starting") +} diff --git a/pkg/guestagent/guestagent_linux.go b/pkg/guestagent/guestagent_linux.go index 9739d22c03f..21bc603375b 100644 --- a/pkg/guestagent/guestagent_linux.go +++ b/pkg/guestagent/guestagent_linux.go @@ -31,6 +31,7 @@ func New(newTicker func() (<-chan time.Time, func()), iptablesIdle time.Duration kubernetesServiceWatcher: kubernetesservice.NewServiceWatcher(), dockerEventMonitor: events.NewDockerEventMonitor(), containerdEventMonitor: events.NewContainerdEventMonitor(), + kubeServiceWatcher: events.NewKubeServiceWatcher(), } auditClient, err := libaudit.NewMulticastAuditClient(nil) @@ -107,6 +108,7 @@ type agent struct { kubernetesServiceWatcher *kubernetesservice.ServiceWatcher dockerEventMonitor *events.DockerEventMonitor containerdEventMonitor *events.ContainerdEventMonitor + kubeServiceWatcher *events.KubeServiceWatcher } // setWorthCheckingIPTablesRoutine sets worthCheckingIPTables to be true @@ -204,6 +206,12 @@ func (a *agent) Events(ctx context.Context, ch chan *api.Event) { defer close(ch) errorCh := make(chan error) + go func() { + if err := a.kubeServiceWatcher.MonitorServices(ctx, ch); err != nil { + errorCh <- err + } + }() + go func() { if err := a.containerdEventMonitor.MonitorPorts(ctx, ch); err != nil { errorCh <- err @@ -228,7 +236,7 @@ func (a *agent) Events(ctx context.Context, ch chan *api.Event) { case <-ctx.Done(): return case err := <-errorCh: - logrus.Errorf("container engine event monitoring failed: %s", err) + logrus.Errorf("event monitoring failed: %s", err) case _, ok := <-tickerCh: if !ok { return From e13a413b59c36e9282130e05bfa2b7ce49d972ca Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Thu, 31 Oct 2024 10:13:33 -0700 Subject: [PATCH 04/15] Removes kuberneteservice The Kubernetes service is not needed since it has been replaced by the event-driven process. Signed-off-by: Nino Kodabande --- pkg/guestagent/guestagent_linux.go | 45 ++++++++---------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/pkg/guestagent/guestagent_linux.go b/pkg/guestagent/guestagent_linux.go index 21bc603375b..e519fc1dc73 100644 --- a/pkg/guestagent/guestagent_linux.go +++ b/pkg/guestagent/guestagent_linux.go @@ -20,18 +20,16 @@ import ( "github.com/lima-vm/lima/pkg/guestagent/api" "github.com/lima-vm/lima/pkg/guestagent/events" "github.com/lima-vm/lima/pkg/guestagent/iptables" - "github.com/lima-vm/lima/pkg/guestagent/kubernetesservice" "github.com/lima-vm/lima/pkg/guestagent/procnettcp" "github.com/lima-vm/lima/pkg/guestagent/timesync" ) func New(newTicker func() (<-chan time.Time, func()), iptablesIdle time.Duration) (Agent, error) { a := &agent{ - newTicker: newTicker, - kubernetesServiceWatcher: kubernetesservice.NewServiceWatcher(), - dockerEventMonitor: events.NewDockerEventMonitor(), - containerdEventMonitor: events.NewContainerdEventMonitor(), - kubeServiceWatcher: events.NewKubeServiceWatcher(), + newTicker: newTicker, + dockerEventMonitor: events.NewDockerEventMonitor(), + containerdEventMonitor: events.NewContainerdEventMonitor(), + kubeServiceWatcher: events.NewKubeServiceWatcher(), } auditClient, err := libaudit.NewMulticastAuditClient(nil) @@ -89,7 +87,6 @@ func startGuestAgentRoutines(a *agent, supportsAuditing bool) *agent { if !supportsAuditing { a.worthCheckingIPTables = true } - go a.kubernetesServiceWatcher.Start() go a.fixSystemTimeSkew() return a @@ -101,14 +98,13 @@ type agent struct { // reload /proc/net/tcp. newTicker func() (<-chan time.Time, func()) - worthCheckingIPTables bool - worthCheckingIPTablesMu sync.RWMutex - latestIPTables []iptables.Entry - latestIPTablesMu sync.RWMutex - kubernetesServiceWatcher *kubernetesservice.ServiceWatcher - dockerEventMonitor *events.DockerEventMonitor - containerdEventMonitor *events.ContainerdEventMonitor - kubeServiceWatcher *events.KubeServiceWatcher + worthCheckingIPTables bool + worthCheckingIPTablesMu sync.RWMutex + latestIPTables []iptables.Entry + latestIPTablesMu sync.RWMutex + dockerEventMonitor *events.DockerEventMonitor + containerdEventMonitor *events.ContainerdEventMonitor + kubeServiceWatcher *events.KubeServiceWatcher } // setWorthCheckingIPTablesRoutine sets worthCheckingIPTables to be true @@ -318,25 +314,6 @@ func (a *agent) LocalPorts(_ context.Context) ([]*api.IPPort, error) { } } - kubernetesEntries := a.kubernetesServiceWatcher.GetPorts() - for _, entry := range kubernetesEntries { - found := false - for _, re := range res { - if re.Port == int32(entry.Port) { - found = true - } - } - - if !found { - res = append(res, - &api.IPPort{ - Ip: entry.IP.String(), - Port: int32(entry.Port), - Protocol: string(entry.Protocol), - }) - } - } - return res, nil } From f9f37f143ef3898dd70ee61c4a1eee8add1bbab1 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Mon, 9 Jun 2025 22:50:00 -0700 Subject: [PATCH 05/15] Fixes go lint issues Signed-off-by: Nino Kodabande --- go.mod | 5 +- go.sum | 51 +++---------------- pkg/guestagent/events/containerd.go | 9 ++-- pkg/guestagent/events/docker.go | 6 ++- pkg/guestagent/events/eventutils.go | 6 ++- .../{kubernetes.go => kubernetes_linux.go} | 6 ++- pkg/guestagent/events/kubernetes_stub.go | 13 +++++ 7 files changed, 44 insertions(+), 52 deletions(-) rename pkg/guestagent/events/{kubernetes.go => kubernetes_linux.go} (98%) create mode 100644 pkg/guestagent/events/kubernetes_stub.go diff --git a/go.mod b/go.mod index b0d76fa9b1e..1fdd637f218 100644 --- a/go.mod +++ b/go.mod @@ -164,10 +164,11 @@ require ( ) require ( - github.com/containerd/containerd v1.6.23 + github.com/containerd/containerd v1.6.38 + github.com/containerd/errdefs v0.1.0 // indirect github.com/containerd/typeurl v1.0.2 // indirect github.com/gogo/googleapis v1.4.0 // indirect - github.com/opencontainers/runc v1.1.5 // indirect + github.com/moby/sys/user v0.1.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect go.opentelemetry.io/otel/sdk v1.37.0 // indirect ) diff --git a/go.sum b/go.sum index 633d1df41cd..37761fda97e 100644 --- a/go.sum +++ b/go.sum @@ -40,19 +40,18 @@ github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEe github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cheggaaa/pb/v3 v3.1.7 h1:2FsIW307kt7A/rz/ZI2lvPO+v3wKazzE4K/0LtTWsOI= github.com/cheggaaa/pb/v3 v3.1.7/go.mod h1:/Ji89zfVPeC/u5j8ukD0MBPHt2bzTYp74lQ7KlgFWTQ= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.6.23 h1:KYJd6UJhKHzwMhiD70iTtSmU+k4565ac22GOTI3AuTA= -github.com/containerd/containerd v1.6.23/go.mod h1:UrQOiyzrLi3n4aezYJbQH6Il+YzTvnHFbEuO3yfDrM4= +github.com/containerd/containerd v1.6.38 h1:AgSP9hVZT8JHzIAUjA7/wSmkTCuhzJCsaJ8QJ+zP84g= +github.com/containerd/containerd v1.6.38/go.mod h1:MtQjP1WJnC0DoVVzDWj5V1i0m0evpOlSmDPOV7w7zJY= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= +github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= +github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -65,15 +64,12 @@ github.com/containers/gvisor-tap-vsock v0.8.6 h1:9SeAXK+K2o36CtrgYk6zRXbU3zrayjv github.com/containers/gvisor-tap-vsock v0.8.6/go.mod h1:+0mtKmm4STeSDnZe+DGnIwN4EH2f7AcWir7PwT28Ti0= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -98,7 +94,6 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/elastic/go-libaudit/v2 v2.6.2 h1:1PM6wVBTJHJQYsKl8jfA9/Aw9pFty5uUezPiUfKtOI4= @@ -121,7 +116,6 @@ github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBd github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= @@ -146,8 +140,6 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -167,7 +159,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= @@ -180,8 +171,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/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/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -230,11 +219,8 @@ github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lima-vm/go-qcow2reader v0.6.0 h1:dNstUGQxEUPbmiiVnu/cek2x7scrHe2VJy5JseLLflo= @@ -276,11 +262,12 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -290,7 +277,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= @@ -305,12 +291,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= -github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= @@ -340,18 +322,14 @@ github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZe github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI= github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= -github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU= github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= @@ -361,7 +339,6 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -370,14 +347,10 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -448,7 +421,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -485,18 +457,12 @@ golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/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-20211116061358-0a5406a5449c/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-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -567,7 +533,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= @@ -588,8 +554,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -603,7 +567,6 @@ gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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/pkg/guestagent/events/containerd.go b/pkg/guestagent/events/containerd.go index 09e8ca525b3..74d10222c7c 100644 --- a/pkg/guestagent/events/containerd.go +++ b/pkg/guestagent/events/containerd.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + package events import ( @@ -9,11 +12,11 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/api/events" - "github.com/lima-vm/lima/pkg/guestagent/api" - "github.com/sirupsen/logrus" + containerdNamespace "github.com/containerd/containerd/namespaces" "github.com/gogo/protobuf/proto" + "github.com/sirupsen/logrus" - containerdNamespace "github.com/containerd/containerd/namespaces" + "github.com/lima-vm/lima/pkg/guestagent/api" ) const ( diff --git a/pkg/guestagent/events/docker.go b/pkg/guestagent/events/docker.go index b2c05d8a464..ef59ecc8f97 100644 --- a/pkg/guestagent/events/docker.go +++ b/pkg/guestagent/events/docker.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + package events import ( @@ -12,8 +15,9 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" - "github.com/lima-vm/lima/pkg/guestagent/api" "github.com/sirupsen/logrus" + + "github.com/lima-vm/lima/pkg/guestagent/api" ) type DockerEventMonitor struct { diff --git a/pkg/guestagent/events/eventutils.go b/pkg/guestagent/events/eventutils.go index 4cbab8bb770..7c133c39312 100644 --- a/pkg/guestagent/events/eventutils.go +++ b/pkg/guestagent/events/eventutils.go @@ -1,13 +1,17 @@ +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + package events import ( "context" "time" - "github.com/lima-vm/lima/pkg/guestagent/api" "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/timestamppb" "k8s.io/apimachinery/pkg/util/wait" + + "github.com/lima-vm/lima/pkg/guestagent/api" ) func sendHostAgentEvent(remove bool, ipPorts []*api.IPPort, ch chan *api.Event) { diff --git a/pkg/guestagent/events/kubernetes.go b/pkg/guestagent/events/kubernetes_linux.go similarity index 98% rename from pkg/guestagent/events/kubernetes.go rename to pkg/guestagent/events/kubernetes_linux.go index f4288ef9bfe..db5bc6b0085 100644 --- a/pkg/guestagent/events/kubernetes.go +++ b/pkg/guestagent/events/kubernetes_linux.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + package events import ( @@ -9,7 +12,6 @@ import ( "strings" "time" - "github.com/lima-vm/lima/pkg/guestagent/api" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" corev1 "k8s.io/api/core/v1" @@ -19,6 +21,8 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" + + "github.com/lima-vm/lima/pkg/guestagent/api" ) type event struct { diff --git a/pkg/guestagent/events/kubernetes_stub.go b/pkg/guestagent/events/kubernetes_stub.go new file mode 100644 index 00000000000..d7c0d4ac990 --- /dev/null +++ b/pkg/guestagent/events/kubernetes_stub.go @@ -0,0 +1,13 @@ +//go:build !linux +// +build !linux + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package events + +type KubeServiceWatcher struct{} + +func NewKubeServiceWatcher() *KubeServiceWatcher { + panic("NewKubeServiceWatcher is not implemented on this platform") +} From 0b27f2c346fbb045e70a9b7f5649e5e9068644e1 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Wed, 25 Jun 2025 14:17:11 -0700 Subject: [PATCH 06/15] Add PortMonitor to limayaml Also, handle the defaults for Docker, Containerd Signed-off-by: Nino Kodabande --- cmd/lima-guestagent/daemon_linux.go | 32 +++++++++++++++--- pkg/guestagent/guestagent_linux.go | 14 ++++++-- pkg/limayaml/defaults.go | 52 +++++++++++++++++++++++++++++ pkg/limayaml/defaults_test.go | 34 ++++++++++++++++--- pkg/limayaml/limayaml.go | 16 +++++++++ pkg/limayaml/validate.go | 50 +++++++++++++++++++++++++++ 6 files changed, 185 insertions(+), 13 deletions(-) diff --git a/cmd/lima-guestagent/daemon_linux.go b/cmd/lima-guestagent/daemon_linux.go index 919edb19a53..d5b2999ff4f 100644 --- a/cmd/lima-guestagent/daemon_linux.go +++ b/cmd/lima-guestagent/daemon_linux.go @@ -28,15 +28,24 @@ func newDaemonCommand() *cobra.Command { daemonCommand.Flags().Duration("tick", 3*time.Second, "Tick for polling events") daemonCommand.Flags().Int("vsock-port", 0, "Use vsock server instead a UNIX socket") daemonCommand.Flags().String("virtio-port", "", "Use virtio server instead a UNIX socket") + daemonCommand.Flags().StringSlice("docker-sockets", []string{}, "Paths to Docker socket files to monitor for exposed ports") + daemonCommand.Flags().StringSlice("containerd-sockets", []string{}, "Paths to Containerd socket files to monitor for exposed ports") + daemonCommand.Flags().String("kubernetes-config", "", "Path to Kubernetes config file to monitor for ports") return daemonCommand } func daemonAction(cmd *cobra.Command, _ []string) error { + if os.Geteuid() != 0 { + return errors.New("must run as the root user") + } socket := "/run/lima-guestagent.sock" tick, err := cmd.Flags().GetDuration("tick") if err != nil { return err } + if tick == 0 { + return errors.New("tick must be specified") + } vSockPort, err := cmd.Flags().GetInt("vsock-port") if err != nil { return err @@ -45,12 +54,19 @@ func daemonAction(cmd *cobra.Command, _ []string) error { if err != nil { return err } - if tick == 0 { - return errors.New("tick must be specified") + dockerSockets, err := cmd.Flags().GetStringSlice("docker-sockets") + if err != nil { + return err } - if os.Geteuid() != 0 { - return errors.New("must run as the root user") + containerdSockets, err := cmd.Flags().GetStringSlice("containerd-sockets") + if err != nil { + return err } + kubernetesConfig, err := cmd.Flags().GetString("kubernetes-config") + if err != nil { + return err + } + logrus.Infof("event tick: %v", tick) newTicker := func() (<-chan time.Time, func()) { @@ -61,7 +77,13 @@ func daemonAction(cmd *cobra.Command, _ []string) error { return ticker.C, ticker.Stop } - agent, err := guestagent.New(newTicker, tick*20) + agent, err := guestagent.New(&guestagent.Config{ + Ticker: newTicker, + IptablesIdle: tick * 20, + DockerSockets: dockerSockets, + ContainerdSockets: containerdSockets, + KubernetesConfig: kubernetesConfig, + }) if err != nil { return err } diff --git a/pkg/guestagent/guestagent_linux.go b/pkg/guestagent/guestagent_linux.go index e519fc1dc73..8bd60a3ab28 100644 --- a/pkg/guestagent/guestagent_linux.go +++ b/pkg/guestagent/guestagent_linux.go @@ -24,9 +24,17 @@ import ( "github.com/lima-vm/lima/pkg/guestagent/timesync" ) -func New(newTicker func() (<-chan time.Time, func()), iptablesIdle time.Duration) (Agent, error) { +type Config struct{ + Ticker func() (<-chan time.Time, func()) + IptablesIdle time.Duration + DockerSockets []string + ContainerdSockets []string + KubernetesConfig string +} + +func New(cfg *Config) (Agent, error) { a := &agent{ - newTicker: newTicker, + newTicker: cfg.Ticker, dockerEventMonitor: events.NewDockerEventMonitor(), containerdEventMonitor: events.NewContainerdEventMonitor(), kubeServiceWatcher: events.NewKubeServiceWatcher(), @@ -70,7 +78,7 @@ func New(newTicker func() (<-chan time.Time, func()), iptablesIdle time.Duration } } - go a.setWorthCheckingIPTablesRoutine(auditClient, iptablesIdle) + go a.setWorthCheckingIPTablesRoutine(auditClient, cfg.IptablesIdle) } else { a.worthCheckingIPTables = true } diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 629cbcc3f97..06e61d6d89e 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -593,6 +593,58 @@ func FillDefault(y, d, o *LimaYAML, filePath string, warn bool) { // After defaults processing the singular HostPort and GuestPort values should not be used again. } + // Manage PortMonitors sockets for Docker + y.PortMonitors.Docker.Sockets = slices.Concat( + o.PortMonitors.Docker.Sockets, + y.PortMonitors.Docker.Sockets, + d.PortMonitors.Docker.Sockets) + + for i := range y.PortMonitors.Docker.Sockets { + if out, err := executeGuestTemplate(y.PortMonitors.Docker.Sockets[i], instDir, y.User, y.Param); err == nil { + y.PortMonitors.Docker.Sockets[i] = out.String() + } else { + logrus.WithError(err).Warnf("Couldn't process Docker socket %q as a template", y.PortMonitors.Docker.Sockets[i]) + } + } + + // Manage PortMonitors sockets for Containerd + y.PortMonitors.Containerd.Sockets = slices.Concat( + o.PortMonitors.Containerd.Sockets, + y.PortMonitors.Containerd.Sockets, + d.PortMonitors.Containerd.Sockets) + + for i := range y.PortMonitors.Containerd.Sockets { + if out, err := executeGuestTemplate(y.PortMonitors.Containerd.Sockets[i], instDir, y.User, y.Param); err == nil { + y.PortMonitors.Containerd.Sockets[i] = out.String() + } else { + logrus.WithError(err).Warnf("Couldn't process Containerd socket %q as a template", y.PortMonitors.Docker.Sockets[i]) + } + } + + if y.Containerd.System != nil && *y.Containerd.System { + if out, err := executeGuestTemplate("/run/containerd/containerd.sock", instDir, y.User, y.Param); err == nil { + y.PortMonitors.Containerd.Sockets = unique(append(y.PortMonitors.Containerd.Sockets, out.String())) + } else { + logrus.WithError(err).Warnf("Couldn't process Containerd system socket") + } + } + if y.Containerd.User != nil && *y.Containerd.User { + if out, err := executeGuestTemplate("/run/user/{{.UID}}/containerd/containerd.sock", instDir, y.User, y.Param); err == nil { + y.PortMonitors.Containerd.Sockets = unique(append(y.PortMonitors.Containerd.Sockets, out.String())) + } else { + logrus.WithError(err).Warnf("Couldn't process Containerd user socket") + } + } + + // Manage PortMonitors config for kubernetes + if y.PortMonitors.Kubernetes.ConfigPath == "" { + y.PortMonitors.Kubernetes.ConfigPath = d.PortMonitors.Kubernetes.ConfigPath + } + + if o.PortMonitors.Kubernetes.ConfigPath != "" { + y.PortMonitors.Kubernetes.ConfigPath = o.PortMonitors.Kubernetes.ConfigPath + } + y.CopyToHost = slices.Concat(o.CopyToHost, y.CopyToHost, d.CopyToHost) for i := range y.CopyToHost { FillCopyToHostDefaults(&y.CopyToHost[i], instDir, y.User, y.Param) diff --git a/pkg/limayaml/defaults_test.go b/pkg/limayaml/defaults_test.go index 70f6810c855..616e800a8fd 100644 --- a/pkg/limayaml/defaults_test.go +++ b/pkg/limayaml/defaults_test.go @@ -143,6 +143,9 @@ func TestFillDefault(t *testing.T) { // All these slices and maps are empty in "builtin". Add minimal entries here to see that // their values are retained and defaults for their fields are applied correctly. + + t.Log("Builtin defaults are set when y is (mostly) empty") + y = LimaYAML{ HostResolver: HostResolver{ Hosts: map[string]string{ @@ -279,9 +282,6 @@ func TestFillDefault(t *testing.T) { defaultPortForward, defaultPortForward, } - expect.CopyToHost = []CopyToHost{ - {}, - } // Setting GuestPort and HostPort for DeepEqual(), but they are not supposed to be used // after FillDefault() has been called and the ...PortRange fields have been set. @@ -297,6 +297,14 @@ func TestFillDefault(t *testing.T) { expect.PortForwards[3].GuestSocket = fmt.Sprintf("%s | %s | %s | %s", user.HomeDir, user.Uid, user.Username, y.Param["ONE"]) expect.PortForwards[3].HostSocket = fmt.Sprintf("%s | %s | %s | %s | %s | %s", hostHome, instDir, instName, currentUser.Uid, currentUser.Username, y.Param["ONE"]) + expect.PortMonitors.Containerd.Sockets = []string{ + fmt.Sprintf("/run/user/%s/containerd/containerd.sock", user.Uid), + } + + expect.CopyToHost = []CopyToHost{ + {}, + } + expect.CopyToHost[0].GuestFile = fmt.Sprintf("%s | %s | %s | %s", user.HomeDir, user.Uid, user.Username, y.Param["ONE"]) expect.CopyToHost[0].HostFile = fmt.Sprintf("%s | %s | %s | %s | %s | %s", hostHome, instDir, instName, currentUser.Uid, currentUser.Username, y.Param["ONE"]) @@ -334,7 +342,11 @@ func TestFillDefault(t *testing.T) { // Choose values that are different from the "builtin" defaults // Calling filepath.Abs() to add a drive letter on Windows + + t.Log("User-provided defaults should override builtin defaults") + varLog, _ := filepath.Abs("/var/log") + defaultUID := 8080 d = LimaYAML{ VMType: ptr.Of("vz"), OS: ptr.Of("unknown"), @@ -462,7 +474,7 @@ func TestFillDefault(t *testing.T) { Comment: ptr.Of("Foo Bar"), Home: ptr.Of("/tmp"), Shell: ptr.Of("/bin/tcsh"), - UID: ptr.Of(uint32(8080)), + UID: ptr.Of(uint32(defaultUID)), }, } @@ -508,6 +520,9 @@ func TestFillDefault(t *testing.T) { } } expect.Plain = ptr.Of(false) + expect.PortMonitors.Containerd.Sockets = []string{ + "/run/containerd/containerd.sock", + } y = LimaYAML{} FillDefault(&y, &d, &LimaYAML{}, filePath, false) @@ -518,6 +533,8 @@ func TestFillDefault(t *testing.T) { // ------------------------------------------------------------------------------------ // User-provided defaults should not override user-provided config values + t.Log("User-provided defaults should not override user-provided config values") + y = filledDefaults y.DNS = []net.IP{net.ParseIP("8.8.8.8")} y.AdditionalDisks = []Disk{{Name: "overridden"}} @@ -555,6 +572,9 @@ func TestFillDefault(t *testing.T) { // ------------------------------------------------------------------------------------ // User-provided overrides should override user-provided config settings + t.Log("User-provided overrides should override user-provided config settings") + + overrideUID := 1122 o = LimaYAML{ VMType: ptr.Of("qemu"), OS: ptr.Of(LINUX), @@ -694,7 +714,7 @@ func TestFillDefault(t *testing.T) { Comment: ptr.Of("foo bar baz"), Home: ptr.Of("/override"), Shell: ptr.Of("/bin/sh"), - UID: ptr.Of(uint32(1122)), + UID: ptr.Of(uint32(overrideUID)), }, } @@ -705,6 +725,10 @@ func TestFillDefault(t *testing.T) { expect.Provision = slices.Concat(o.Provision, y.Provision, dExpect.Provision) expect.Probes = slices.Concat(o.Probes, y.Probes, dExpect.Probes) expect.PortForwards = slices.Concat(o.PortForwards, y.PortForwards, dExpect.PortForwards) + expect.PortMonitors.Containerd.Sockets = []string{ + fmt.Sprintf("/run/user/%s/containerd/containerd.sock", user.Uid), + "/run/containerd/containerd.sock", + } expect.CopyToHost = slices.Concat(o.CopyToHost, y.CopyToHost, dExpect.CopyToHost) expect.Containerd.Archives = slices.Concat(o.Containerd.Archives, y.Containerd.Archives, dExpect.Containerd.Archives) expect.Containerd.Archives[3].Arch = *expect.Arch diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index d72e5b602c8..005ad3c4f7d 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -36,6 +36,7 @@ type LimaYAML struct { GuestInstallPrefix *string `yaml:"guestInstallPrefix,omitempty" json:"guestInstallPrefix,omitempty" jsonschema:"nullable"` Probes []Probe `yaml:"probes,omitempty" json:"probes,omitempty"` PortForwards []PortForward `yaml:"portForwards,omitempty" json:"portForwards,omitempty"` + PortMonitors PortMonitor `yaml:"portMonitors,omitempty" json:"portMonitors,omitempty" jsonschema:"nullable"` CopyToHost []CopyToHost `yaml:"copyToHost,omitempty" json:"copyToHost,omitempty"` Message string `yaml:"message,omitempty" json:"message,omitempty"` Networks []Network `yaml:"networks,omitempty" json:"networks,omitempty" jsonschema:"nullable"` @@ -317,3 +318,18 @@ type CACertificates struct { Files []string `yaml:"files,omitempty" json:"files,omitempty" jsonschema:"nullable"` Certs []string `yaml:"certs,omitempty" json:"certs,omitempty" jsonschema:"nullable"` } + +// Engine is the name of the container engine, e.g. "docker", "containerd". +type Engine struct { + Sockets []string `yaml:"sockets,omitempty" json:"sockets,omitempty"` +} + +type Kubernetes struct { + ConfigPath string `yaml:"configPath,omitempty" json:"configPath,omitempty"` +} + +type PortMonitor struct { + Docker Engine `yaml:"docker,omitempty" json:"docker,omitempty"` + Containerd Engine `yaml:"containerd,omitempty" json:"containerd,omitempty"` + Kubernetes Kubernetes `yaml:"kubernetes,omitempty" json:"kubernetes,omitempty"` +} diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go index 9b959f25d1a..e8bd4300e6a 100644 --- a/pkg/limayaml/validate.go +++ b/pkg/limayaml/validate.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "net" + "net/url" "os" "path" "path/filepath" @@ -375,6 +376,19 @@ func Validate(y *LimaYAML, warn bool) error { // Not validating that the various GuestPortRanges and HostPortRanges are not overlapping. Rules will be // processed sequentially and the first matching rule for a guest port determines forwarding behavior. } + + for _, socket := range y.PortMonitors.Containerd.Sockets { + if err := validateSocket("containerd", socket); err != nil { + return err + } + } + + for _, socket := range y.PortMonitors.Docker.Sockets { + if err := validateSocket("docker", socket); err != nil { + return err + } + } + for i, rule := range y.CopyToHost { field := fmt.Sprintf("CopyToHost[%d]", i) if rule.GuestFile != "" { @@ -647,3 +661,39 @@ func ValidateAgainstLatestConfig(yNew, yLatest []byte) error { return nil } + +func validateSocket(engine, socket string) error { + if socket == "" { + return fmt.Errorf("%s socket path must not be empty", engine) + } + + if strings.Contains(socket, "://") { + u, err := url.Parse(socket) + if err != nil { + return fmt.Errorf("%s socket path %q is not a valid URL: %w", engine, socket, err) + } + switch u.Scheme { + case "unix", "file": + if u.Path == "" { + return fmt.Errorf("%s socket path %q is not a valid URL: missing path", engine, socket) + } + return validateUnixSocket(engine, u.Path) + case "tcp": + if u.Host == "" { + return fmt.Errorf("%s socket path %q is not a valid URL: missing host", engine, socket) + } + return nil + default: + return fmt.Errorf("%s socket path %q is not a valid URL: unsupported scheme %q", engine, socket, u.Scheme) + } + } + + return validateUnixSocket(engine, socket) +} + +func validateUnixSocket(engine, path string) error { + if !filepath.IsAbs(path) { + return fmt.Errorf("%s socket path must be absolute, got %s", engine, path) + } + return nil +} From d0d5167e26fb38a9ff86e2ba82ec476242aad863 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Wed, 25 Jun 2025 14:40:23 -0700 Subject: [PATCH 07/15] Update docker event monitor This changes the Docker event monitor to accept socket and create a per socket client to monitor events. Signed-off-by: Nino Kodabande --- pkg/guestagent/events/docker.go | 67 ++++++++++++++++++------------ pkg/guestagent/guestagent_linux.go | 16 ++++--- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/pkg/guestagent/events/docker.go b/pkg/guestagent/events/docker.go index ef59ecc8f97..6c7b7a46e11 100644 --- a/pkg/guestagent/events/docker.go +++ b/pkg/guestagent/events/docker.go @@ -21,7 +21,7 @@ import ( ) type DockerEventMonitor struct { - dockerClient *client.Client + dockerClients []*client.Client // We maintain a record of all active containers because neither the stop nor // die events provide the port mapping. As API consumers, it's our responsibility // to track this information. The map uses the container ID as the key and @@ -29,41 +29,56 @@ type DockerEventMonitor struct { runningContainers map[string][]*api.IPPort } -func NewDockerEventMonitor() *DockerEventMonitor { +func NewDockerEventMonitor(dockerSocketPaths []string) (*DockerEventMonitor, error) { + var dockerClients []*client.Client + for _, socket := range dockerSocketPaths { + cli, err := client.NewClientWithOpts(client.WithHost(socket), client.WithAPIVersionNegotiation()) + if err != nil { + logrus.Errorf("error creating Docker client for socket %s: %s", socket, err) + continue + } + if _, err := cli.Ping(context.Background()); err != nil { + logrus.Errorf("error pinging Docker client for socket %s: %s", socket, err) + continue + } + logrus.Infof("successfully connected to docker daemon at %s", socket) + dockerClients = append(dockerClients, cli) + } + if len(dockerClients) == 0 { + return nil, fmt.Errorf("no valid Docker clients created from provided sockets: %v", dockerSocketPaths) + } return &DockerEventMonitor{ + dockerClients: dockerClients, runningContainers: make(map[string][]*api.IPPort), - } + }, nil } -func (d *DockerEventMonitor) createAndVerifyClient(ctx context.Context) (bool, error) { - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - if err != nil { - logrus.Tracef("error creating Docker client: %s", err) - return false, nil +func (d *DockerEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Event) error { + errCh := make(chan error, len(d.dockerClients)) + for _, cli := range d.dockerClients { + go func(c *client.Client) { + if err := d.monitorClient(ctx, c, ch); err != nil { + errCh <- fmt.Errorf("monitoring ports failed: %w", err) + } + }(cli) } - _, err = cli.Info(ctx) - if err != nil { - logrus.Tracef("error getting Docker info: %s", err) - return false, nil + select { + case <-ctx.Done(): + return ctx.Err() + case err := <-errCh: + return err } - - d.dockerClient = cli - logrus.Info("successfully connected to docker daemon") - return true, nil } -func (d *DockerEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Event) error { - if err := tryGetClient(ctx, d.createAndVerifyClient); err != nil { - return fmt.Errorf("failed getting docker client: %w", err) - } - defer d.dockerClient.Close() +func (d *DockerEventMonitor) monitorClient(ctx context.Context, cli *client.Client, ch chan *api.Event) error { + defer cli.Close() - if err := d.initializeRunningContainers(ctx, ch); err != nil { + if err := d.initializeRunningContainers(ctx, cli, ch); err != nil { logrus.Errorf("failed to initialize existing docker container published ports: %s", err) } - msgCh, errCh := d.dockerClient.Events(ctx, events.ListOptions{ + msgCh, errCh := cli.Events(ctx, events.ListOptions{ Filters: filters.NewArgs( filters.Arg("type", string(types.ContainerObject)), filters.Arg("event", string(events.ActionStart)), @@ -77,7 +92,7 @@ func (d *DockerEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Even return fmt.Errorf("context cancellation: %w", ctx.Err()) case event := <-msgCh: - container, err := d.dockerClient.ContainerInspect(ctx, event.ID) + container, err := cli.ContainerInspect(ctx, event.ID) if err != nil { logrus.Errorf("inspecting container [%v] failed: %v", event.ID, err) continue @@ -115,8 +130,8 @@ func (d *DockerEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Even } } -func (d *DockerEventMonitor) initializeRunningContainers(ctx context.Context, ch chan *api.Event) error { - containers, err := d.dockerClient.ContainerList(ctx, container.ListOptions{ +func (d *DockerEventMonitor) initializeRunningContainers(ctx context.Context, cli *client.Client, ch chan *api.Event) error { + containers, err := cli.ContainerList(ctx, container.ListOptions{ Filters: filters.NewArgs(filters.Arg("status", "running")), }) if err != nil { diff --git a/pkg/guestagent/guestagent_linux.go b/pkg/guestagent/guestagent_linux.go index 8bd60a3ab28..d02d28b27e0 100644 --- a/pkg/guestagent/guestagent_linux.go +++ b/pkg/guestagent/guestagent_linux.go @@ -24,18 +24,22 @@ import ( "github.com/lima-vm/lima/pkg/guestagent/timesync" ) -type Config struct{ - Ticker func() (<-chan time.Time, func()) - IptablesIdle time.Duration - DockerSockets []string +type Config struct { + Ticker func() (<-chan time.Time, func()) + IptablesIdle time.Duration + DockerSockets []string ContainerdSockets []string - KubernetesConfig string + KubernetesConfig string } func New(cfg *Config) (Agent, error) { + dockerEventMonitor, err := events.NewDockerEventMonitor(cfg.DockerSockets) + if err != nil { + return nil, err + } a := &agent{ newTicker: cfg.Ticker, - dockerEventMonitor: events.NewDockerEventMonitor(), + dockerEventMonitor: dockerEventMonitor, containerdEventMonitor: events.NewContainerdEventMonitor(), kubeServiceWatcher: events.NewKubeServiceWatcher(), } From 764e77bc1810b60cd05c289c38f81d1344b30ef4 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Wed, 25 Jun 2025 15:55:14 -0700 Subject: [PATCH 08/15] Pass multiple sockets to containerd This will start a containerd client per socket Signed-off-by: Nino Kodabande --- pkg/guestagent/events/containerd.go | 109 ++++++++++++---------- pkg/guestagent/events/eventutils.go | 10 -- pkg/guestagent/events/kubernetes_linux.go | 7 ++ pkg/guestagent/guestagent_linux.go | 8 +- 4 files changed, 74 insertions(+), 60 deletions(-) diff --git a/pkg/guestagent/events/containerd.go b/pkg/guestagent/events/containerd.go index 74d10222c7c..9529cf67b67 100644 --- a/pkg/guestagent/events/containerd.go +++ b/pkg/guestagent/events/containerd.go @@ -9,6 +9,7 @@ import ( "fmt" "os" "strings" + "time" "github.com/containerd/containerd" "github.com/containerd/containerd/api/events" @@ -20,67 +21,79 @@ import ( ) const ( - portsKey = "nerdctl/ports" - namespaceKey = "nerdctl/namespace" + portsKey = "nerdctl/ports" + namespaceKey = "nerdctl/namespace" + defaultSocketTimeout = 5 * time.Second ) type ContainerdEventMonitor struct { - containerdClient *containerd.Client + clients []*containerd.Client runningContainers map[string][]*api.IPPort } -func NewContainerdEventMonitor() *ContainerdEventMonitor { - return &ContainerdEventMonitor{ - runningContainers: make(map[string][]*api.IPPort), - } -} - -func (c *ContainerdEventMonitor) createAndVerifyClient(ctx context.Context) (bool, error) { - containerdSockets := []string{ - "/run/k3s/containerd/containerd.sock", - "/run/containerd/containerd.sock", - } - - for _, socket := range containerdSockets { +func NewContainerdEventMonitor(socketPaths []string) (*ContainerdEventMonitor, error) { + var clients []*containerd.Client + for _, socket := range socketPaths { logrus.Debugf("reading containerd socket %s", socket) if _, err := os.Stat(socket); os.IsNotExist(err) { + logrus.Debugf("containerd socket %s does not exist", socket) continue } else if err != nil { - return false, nil + return nil, fmt.Errorf("error checking containerd socket %s: %w", socket, err) } - cli, err := containerd.New(socket, containerd.WithDefaultNamespace(containerdNamespace.Default)) - if err == nil { - serving, err := cli.IsServing(ctx) - if err != nil { - logrus.Tracef("error getting containerd server: %s", err) - return false, nil - } - c.containerdClient = cli - logrus.Infof("successfully connected to containerd daemon: %s", socket) - return serving, nil + if err != nil { + logrus.Errorf("failed to create Containerd client for socket %s: %s", socket, err) + continue + } + ctx, cancel := context.WithTimeout(context.Background(), defaultSocketTimeout) + serving, err := cli.IsServing(ctx) + cancel() + if err == nil && serving { + logrus.Infof("successfully connected to containerd daemon at %s", socket) + clients = append(clients, cli) + } else { + logrus.Errorf("error checking if containerd client for socket %s is serving: %s", socket, err) + cli.Close() } - - logrus.Tracef("error creating Containerd client: %s", err) } - - return false, nil + if len(clients) == 0 { + return nil, fmt.Errorf("no valid Containerd clients created from provided sockets: %v", socketPaths) + } + return &ContainerdEventMonitor{ + clients: clients, + runningContainers: make(map[string][]*api.IPPort), + }, nil } func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api.Event) error { - if err := tryGetClient(ctx, c.createAndVerifyClient); err != nil { - return fmt.Errorf("failed getting containerd client: %w", err) + errCh := make(chan error, len(c.clients)) + + for _, cli := range c.clients { + go func(client *containerd.Client) { + defer client.Close() + if err := c.monitorClient(ctx, client, ch); err != nil { + errCh <- fmt.Errorf("monitoring ports failed: %w", err) + } + }(cli) } - defer c.containerdClient.Close() + select { + case <-ctx.Done(): + return ctx.Err() + case err := <-errCh: + return err + } +} +func (c *ContainerdEventMonitor) monitorClient(ctx context.Context, cli *containerd.Client, ch chan *api.Event) error { subscribeFilters := []string{ `topic=="/tasks/start"`, `topic=="/containers/update"`, `topic=="/tasks/exit"`, } - msgCh, errCh := c.containerdClient.Subscribe(ctx, subscribeFilters...) + msgCh, errCh := cli.Subscribe(ctx, subscribeFilters...) - if err := c.initializeRunningContainers(ctx, ch); err != nil { + if err := c.initializeRunningContainers(ctx, cli, ch); err != nil { logrus.Errorf("failed to initialize existing containers published ports: %v", err) } @@ -104,7 +117,7 @@ func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api. continue } - ipPorts, err := c.createIPPort(ctx, envelope.Namespace, startTask.ContainerID) + ipPorts, err := c.createIPPort(ctx, cli, envelope.Namespace, startTask.ContainerID) if err != nil { logrus.Errorf("creating IPPorts, for the following start task: %v failed: %s", startTask, err) continue @@ -125,7 +138,7 @@ func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api. continue } - ipPorts, err := c.createIPPort(ctx, envelope.Namespace, cuEvent.ID) + ipPorts, err := c.createIPPort(ctx, cli, envelope.Namespace, cuEvent.ID) if err != nil { logrus.Errorf("creating IPPorts, for the following exit task: %v failed: %s", cuEvent, err) continue @@ -150,7 +163,7 @@ func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api. continue } - ipPorts, err := c.createIPPort(ctx, envelope.Namespace, exitTask.ContainerID) + ipPorts, err := c.createIPPort(ctx, cli, envelope.Namespace, exitTask.ContainerID) if err != nil { logrus.Errorf("creating IPPorts, for the following exit task: %v failed: %s", exitTask, err) continue @@ -167,27 +180,24 @@ func (c *ContainerdEventMonitor) MonitorPorts(ctx context.Context, ch chan *api. } } -func (c *ContainerdEventMonitor) initializeRunningContainers(ctx context.Context, ch chan *api.Event) error { - containers, err := c.containerdClient.Containers(ctx) +func (c *ContainerdEventMonitor) initializeRunningContainers(ctx context.Context, cli *containerd.Client, ch chan *api.Event) error { + containers, err := cli.Containers(ctx) if err != nil { return err } for _, container := range containers { task, err := container.Task(ctx, nil) - if err != nil { + if err != nil || task == nil { logrus.Errorf("failed getting container %s task: %s", container.ID(), err) continue } status, err := task.Status(ctx) - if err != nil { + if err != nil || status.Status != containerd.Running { logrus.Errorf("failed getting container %s task status: %s", container.ID(), err) continue } - if status.Status != containerd.Running { - continue - } labels, err := container.Labels(ctx) if err != nil { @@ -195,19 +205,20 @@ func (c *ContainerdEventMonitor) initializeRunningContainers(ctx context.Context continue } - ipPorts, err := c.createIPPort(ctx, labels[namespaceKey], container.ID()) + ipPorts, err := c.createIPPort(ctx, cli, labels[namespaceKey], container.ID()) if err != nil { logrus.Errorf("creating IPPorts, while initializing containers the following: %v failed: %s", container.ID(), err) } sendHostAgentEvent(false, ipPorts, ch) + c.runningContainers[container.ID()] = ipPorts } return nil } -func (c *ContainerdEventMonitor) createIPPort(ctx context.Context, namespace, containerID string) ([]*api.IPPort, error) { - container, err := c.containerdClient.ContainerService().Get( +func (c *ContainerdEventMonitor) createIPPort(ctx context.Context, cli *containerd.Client, namespace, containerID string) ([]*api.IPPort, error) { + container, err := cli.ContainerService().Get( containerdNamespace.WithNamespace(ctx, namespace), containerID) if err != nil { return nil, err diff --git a/pkg/guestagent/events/eventutils.go b/pkg/guestagent/events/eventutils.go index 7c133c39312..25bf1a1c666 100644 --- a/pkg/guestagent/events/eventutils.go +++ b/pkg/guestagent/events/eventutils.go @@ -4,12 +4,8 @@ package events import ( - "context" - "time" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/timestamppb" - "k8s.io/apimachinery/pkg/util/wait" "github.com/lima-vm/lima/pkg/guestagent/api" ) @@ -26,9 +22,3 @@ func sendHostAgentEvent(remove bool, ipPorts []*api.IPPort, ch chan *api.Event) ch <- ev logrus.Infof("sent the following event to hostAgent: %+v", ev) } - -func tryGetClient(ctx context.Context, tryConnect func(context.Context) (bool, error)) error { - const retryInterval = 10 * time.Second - const pollImmediately = true - return wait.PollUntilContextCancel(ctx, retryInterval, pollImmediately, tryConnect) -} diff --git a/pkg/guestagent/events/kubernetes_linux.go b/pkg/guestagent/events/kubernetes_linux.go index db5bc6b0085..685171b0886 100644 --- a/pkg/guestagent/events/kubernetes_linux.go +++ b/pkg/guestagent/events/kubernetes_linux.go @@ -21,6 +21,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" + "k8s.io/apimachinery/pkg/util/wait" "github.com/lima-vm/lima/pkg/guestagent/api" ) @@ -284,3 +285,9 @@ func isTimeout(err error) bool { func isAPINotReady(err error) bool { return strings.Contains(err.Error(), "apiserver not ready") || strings.Contains(err.Error(), "starting") } + +func tryGetClient(ctx context.Context, tryConnect func(context.Context) (bool, error)) error { + const retryInterval = 10 * time.Second + const pollImmediately = true + return wait.PollUntilContextCancel(ctx, retryInterval, pollImmediately, tryConnect) +} diff --git a/pkg/guestagent/guestagent_linux.go b/pkg/guestagent/guestagent_linux.go index d02d28b27e0..e76092f85d3 100644 --- a/pkg/guestagent/guestagent_linux.go +++ b/pkg/guestagent/guestagent_linux.go @@ -37,10 +37,16 @@ func New(cfg *Config) (Agent, error) { if err != nil { return nil, err } + + containerdEventMonitor, err := events.NewContainerdEventMonitor(cfg.ContainerdSockets) + if err != nil { + return nil, err + } + a := &agent{ newTicker: cfg.Ticker, dockerEventMonitor: dockerEventMonitor, - containerdEventMonitor: events.NewContainerdEventMonitor(), + containerdEventMonitor: containerdEventMonitor, kubeServiceWatcher: events.NewKubeServiceWatcher(), } From 531ede0c593bf17a7e177d888d5642d47dba1f10 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Thu, 26 Jun 2025 10:13:55 -0700 Subject: [PATCH 09/15] Update kubernetes Service Watcher Changes the kubernetes service watcher to accept a list of config paths. Signed-off-by: Nino Kodabande --- cmd/lima-guestagent/daemon_linux.go | 8 ++++---- pkg/guestagent/events/kubernetes_linux.go | 25 ++++++++++------------- pkg/guestagent/guestagent_linux.go | 6 ++++-- pkg/limayaml/defaults.go | 11 ++++------ pkg/limayaml/limayaml.go | 2 +- 5 files changed, 24 insertions(+), 28 deletions(-) diff --git a/cmd/lima-guestagent/daemon_linux.go b/cmd/lima-guestagent/daemon_linux.go index d5b2999ff4f..577f80c2b76 100644 --- a/cmd/lima-guestagent/daemon_linux.go +++ b/cmd/lima-guestagent/daemon_linux.go @@ -30,7 +30,7 @@ func newDaemonCommand() *cobra.Command { daemonCommand.Flags().String("virtio-port", "", "Use virtio server instead a UNIX socket") daemonCommand.Flags().StringSlice("docker-sockets", []string{}, "Paths to Docker socket files to monitor for exposed ports") daemonCommand.Flags().StringSlice("containerd-sockets", []string{}, "Paths to Containerd socket files to monitor for exposed ports") - daemonCommand.Flags().String("kubernetes-config", "", "Path to Kubernetes config file to monitor for ports") + daemonCommand.Flags().StringSlice("kubernetes-configs", []string{}, "Path to Kubernetes config files to monitor for ports") return daemonCommand } @@ -62,7 +62,7 @@ func daemonAction(cmd *cobra.Command, _ []string) error { if err != nil { return err } - kubernetesConfig, err := cmd.Flags().GetString("kubernetes-config") + kubernetesConfigs, err := cmd.Flags().GetStringSlice("kubernetes-configs") if err != nil { return err } @@ -78,11 +78,11 @@ func daemonAction(cmd *cobra.Command, _ []string) error { } agent, err := guestagent.New(&guestagent.Config{ - Ticker: newTicker, + Ticker: newTicker, IptablesIdle: tick * 20, DockerSockets: dockerSockets, ContainerdSockets: containerdSockets, - KubernetesConfig: kubernetesConfig, + KubernetesConfigs: kubernetesConfigs, }) if err != nil { return err diff --git a/pkg/guestagent/events/kubernetes_linux.go b/pkg/guestagent/events/kubernetes_linux.go index 685171b0886..2caa554f604 100644 --- a/pkg/guestagent/events/kubernetes_linux.go +++ b/pkg/guestagent/events/kubernetes_linux.go @@ -17,11 +17,11 @@ import ( corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" - "k8s.io/apimachinery/pkg/util/wait" "github.com/lima-vm/lima/pkg/guestagent/api" ) @@ -35,20 +35,22 @@ type event struct { } type KubeServiceWatcher struct { - kubeClient kubernetes.Interface - eventCh chan event - errorCh chan error + kubeConfigPaths []string + kubeClient kubernetes.Interface + eventCh chan event + errorCh chan error } -func NewKubeServiceWatcher() *KubeServiceWatcher { +func NewKubeServiceWatcher(cfgPaths []string) *KubeServiceWatcher { return &KubeServiceWatcher{ - eventCh: make(chan event), - errorCh: make(chan error), + kubeConfigPaths: cfgPaths, + eventCh: make(chan event), + errorCh: make(chan error), } } func (k *KubeServiceWatcher) createAndVerifyClient(ctx context.Context) (bool, error) { - kubeClient, err := tryGetKubeClient() + kubeClient, err := tryGetKubeClient(k.kubeConfigPaths) if err != nil { logrus.Tracef("failed to get kube client: %s", err) return false, nil @@ -224,12 +226,7 @@ func sendEvents(mapping map[int32]corev1.Protocol, svc *corev1.Service, deleted } } -func tryGetKubeClient() (kubernetes.Interface, error) { - candidateKubeConfigs := []string{ - "/etc/rancher/k3s/k3s.yaml", - "/root/.kube/config", - } - +func tryGetKubeClient(candidateKubeConfigs []string) (kubernetes.Interface, error) { for _, kubeconfig := range candidateKubeConfigs { _, err := os.Stat(kubeconfig) if err != nil { diff --git a/pkg/guestagent/guestagent_linux.go b/pkg/guestagent/guestagent_linux.go index e76092f85d3..bfb136e85e4 100644 --- a/pkg/guestagent/guestagent_linux.go +++ b/pkg/guestagent/guestagent_linux.go @@ -29,7 +29,7 @@ type Config struct { IptablesIdle time.Duration DockerSockets []string ContainerdSockets []string - KubernetesConfig string + KubernetesConfigs []string } func New(cfg *Config) (Agent, error) { @@ -43,11 +43,13 @@ func New(cfg *Config) (Agent, error) { return nil, err } + kubeServiceWatcher := events.NewKubeServiceWatcher(cfg.KubernetesConfigs) + a := &agent{ newTicker: cfg.Ticker, dockerEventMonitor: dockerEventMonitor, containerdEventMonitor: containerdEventMonitor, - kubeServiceWatcher: events.NewKubeServiceWatcher(), + kubeServiceWatcher: kubeServiceWatcher, } auditClient, err := libaudit.NewMulticastAuditClient(nil) diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 06e61d6d89e..6df02e1331a 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -637,13 +637,10 @@ func FillDefault(y, d, o *LimaYAML, filePath string, warn bool) { } // Manage PortMonitors config for kubernetes - if y.PortMonitors.Kubernetes.ConfigPath == "" { - y.PortMonitors.Kubernetes.ConfigPath = d.PortMonitors.Kubernetes.ConfigPath - } - - if o.PortMonitors.Kubernetes.ConfigPath != "" { - y.PortMonitors.Kubernetes.ConfigPath = o.PortMonitors.Kubernetes.ConfigPath - } + y.PortMonitors.Kubernetes.Configs = unique(slices.Concat( + o.PortMonitors.Kubernetes.Configs, + y.PortMonitors.Kubernetes.Configs, + d.PortMonitors.Kubernetes.Configs)) y.CopyToHost = slices.Concat(o.CopyToHost, y.CopyToHost, d.CopyToHost) for i := range y.CopyToHost { diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index 005ad3c4f7d..922c827a6d5 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -325,7 +325,7 @@ type Engine struct { } type Kubernetes struct { - ConfigPath string `yaml:"configPath,omitempty" json:"configPath,omitempty"` + Configs []string `yaml:"configs,omitempty" json:"configs,omitempty"` // Paths to Kubernetes config files, e.g. "/etc/rancher/k3s/k3s.yaml" } type PortMonitor struct { From 8c0583f904b32596ffefd6812499e2a520555794 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Thu, 26 Jun 2025 12:34:48 -0700 Subject: [PATCH 10/15] Add PortMonitors to template that generates ISO Signed-off-by: Nino Kodabande --- .../boot/25-guestagent-base.sh | 28 +++++++++++++++---- pkg/cidata/cidata.TEMPLATE.d/lima.env | 3 ++ pkg/cidata/cidata.go | 5 ++++ pkg/cidata/template.go | 15 ++++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh b/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh index f5089144a65..e02d9e6b353 100644 --- a/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh +++ b/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh @@ -41,9 +41,13 @@ name="lima-guestagent" description="Forward ports to the lima-hostagent" command=${LIMA_CIDATA_GUEST_INSTALL_PREFIX}/bin/lima-guestagent -command_args="daemon --debug=${LIMA_CIDATA_DEBUG} --vsock-port \"${LIMA_CIDATA_VSOCK_PORT}\" --virtio-port \"${LIMA_CIDATA_VIRTIO_PORT}\"" -command_background=true -pidfile="/run/lima-guestagent.pid" +command_args="daemon --debug=${LIMA_CIDATA_DEBUG} \ +--docker-sockets \"${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}" \ +--containerd-sockets \"{LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}" \ +--kubernetes-configs \"{LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}" \ +--vsock-port \"${LIMA_CIDATA_VSOCK_PORT}\" \ +--virtio-port \"${LIMA_CIDATA_VIRTIO_PORT}\"" +command_background=true pidfile="/run/lima-guestagent.pid" EOF chmod 755 /etc/init.d/lima-guestagent @@ -53,11 +57,23 @@ else # Remove legacy systemd service rm -f "${LIMA_CIDATA_HOME}/.config/systemd/user/lima-guestagent.service" + docker_args="" + if [ -n "${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}" ]; then + docker_args="--docker-sockets \"${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}\"" + fi + containerd_args="" + if [ -n "${LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}" ]; then + containerd_args="--containerd-sockets \"${LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}\"" + fi + kubernetes_args="" + if [ -n "${LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}" ]; then + kubernetes_args="--kubernetes-configs \"${LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}\"" + fi if [ "${LIMA_CIDATA_VSOCK_PORT}" != "0" ]; then - sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --vsock-port "${LIMA_CIDATA_VSOCK_PORT}" + sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --vsock-port "${LIMA_CIDATA_VSOCK_PORT}" ${docker_args} ${containerd_args} ${kubernetes_args} elif [ "${LIMA_CIDATA_VIRTIO_PORT}" != "" ]; then - sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --virtio-port "${LIMA_CIDATA_VIRTIO_PORT}" + sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --virtio-port "${LIMA_CIDATA_VIRTIO_PORT}" ${docker_args} ${containerd_args} ${kubernetes_args} else - sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd + sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd ${docker_args} ${containerd_args} ${kubernetes_args} fi fi diff --git a/pkg/cidata/cidata.TEMPLATE.d/lima.env b/pkg/cidata/cidata.TEMPLATE.d/lima.env index 89d2d34f108..45143db03a4 100644 --- a/pkg/cidata/cidata.TEMPLATE.d/lima.env +++ b/pkg/cidata/cidata.TEMPLATE.d/lima.env @@ -54,6 +54,9 @@ LIMA_CIDATA_SKIP_DEFAULT_DEPENDENCY_RESOLUTION= LIMA_CIDATA_VMTYPE={{ .VMType }} LIMA_CIDATA_VSOCK_PORT={{ .VSockPort }} LIMA_CIDATA_VIRTIO_PORT={{ .VirtioPort}} +LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS={{ .PortMonitor.Docker.Sockets }} +LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS={{ .PortMonitor.Containerd.Sockets }} +LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS={{ .PortMonitor.Kubernetes.Configs }} {{- if .Plain}} LIMA_CIDATA_PLAIN=1 {{- else}} diff --git a/pkg/cidata/cidata.go b/pkg/cidata/cidata.go index 8439ca022f9..258f6ab1e20 100644 --- a/pkg/cidata/cidata.go +++ b/pkg/cidata/cidata.go @@ -143,6 +143,11 @@ func templateArgs(bootScripts bool, instDir, name string, instConfig *limayaml.L Plain: *instConfig.Plain, TimeZone: *instConfig.TimeZone, Param: instConfig.Param, + PortMonitor: PortMonitor{ + Docker: Engine{Sockets: instConfig.PortMonitors.Docker.Sockets}, + Containerd: Engine{Sockets: instConfig.PortMonitors.Containerd.Sockets}, + Kubernetes: Kubernetes{Configs: instConfig.PortMonitors.Kubernetes.Configs}, + }, } firstUsernetIndex := limayaml.FirstUsernetIndex(instConfig) diff --git a/pkg/cidata/template.go b/pkg/cidata/template.go index 80622def553..baf2c0f3665 100644 --- a/pkg/cidata/template.go +++ b/pkg/cidata/template.go @@ -65,6 +65,20 @@ type Disk struct { FSType string FSArgs []string } +type Engine struct { + Sockets []string +} + +type Kubernetes struct { + Configs []string +} + +type PortMonitor struct { + Docker Engine + Containerd Engine + Kubernetes Kubernetes +} + type TemplateArgs struct { Debug bool Name string // instance name @@ -105,6 +119,7 @@ type TemplateArgs struct { VirtioPort string Plain bool TimeZone string + PortMonitor PortMonitor } func ValidateTemplateArgs(args *TemplateArgs) error { From fb0dcd1bfe332fc3ecd72919d97ea9a4255d38dc Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Thu, 26 Jun 2025 12:56:55 -0700 Subject: [PATCH 11/15] Fixes build issue for other platforms Signed-off-by: Nino Kodabande --- .../boot/25-guestagent-base.sh | 28 ++++++++++++++----- .../{containerd.go => containerd_linux.go} | 0 pkg/guestagent/events/containerd_stub.go | 13 +++++++++ .../events/{docker.go => docker_linux.go} | 0 pkg/guestagent/events/docker_stub.go | 13 +++++++++ pkg/guestagent/events/eventutils.go | 3 ++ 6 files changed, 50 insertions(+), 7 deletions(-) rename pkg/guestagent/events/{containerd.go => containerd_linux.go} (100%) create mode 100644 pkg/guestagent/events/containerd_stub.go rename pkg/guestagent/events/{docker.go => docker_linux.go} (100%) create mode 100644 pkg/guestagent/events/docker_stub.go diff --git a/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh b/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh index e02d9e6b353..026015affb1 100644 --- a/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh +++ b/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh @@ -59,21 +59,35 @@ else docker_args="" if [ -n "${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}" ]; then - docker_args="--docker-sockets \"${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}\"" + docker_args="--docker-sockets=${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}" fi + containerd_args="" if [ -n "${LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}" ]; then - containerd_args="--containerd-sockets \"${LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}\"" + containerd_args="--containerd-sockets=${LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}" fi + kubernetes_args="" if [ -n "${LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}" ]; then - kubernetes_args="--kubernetes-configs \"${LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}\"" + kubernetes_args="--kubernetes-configs=${LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}" fi + if [ "${LIMA_CIDATA_VSOCK_PORT}" != "0" ]; then - sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --vsock-port "${LIMA_CIDATA_VSOCK_PORT}" ${docker_args} ${containerd_args} ${kubernetes_args} - elif [ "${LIMA_CIDATA_VIRTIO_PORT}" != "" ]; then - sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --virtio-port "${LIMA_CIDATA_VIRTIO_PORT}" ${docker_args} ${containerd_args} ${kubernetes_args} + sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}/bin/lima-guestagent" install-systemd \ + --vsock-port "${LIMA_CIDATA_VSOCK_PORT}" \ + ${docker_args:+${docker_args}} \ + ${containerd_args:+${containerd_args}} \ + ${kubernetes_args:+${kubernetes_args}} + elif [ -n "${LIMA_CIDATA_VIRTIO_PORT}" ]; then + sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}/bin/lima-guestagent" install-systemd \ + --virtio-port "${LIMA_CIDATA_VIRTIO_PORT}" \ + ${docker_args:+${docker_args}} \ + ${containerd_args:+${containerd_args}} \ + ${kubernetes_args:+${kubernetes_args}} else - sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd ${docker_args} ${containerd_args} ${kubernetes_args} + sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}/bin/lima-guestagent" install-systemd \ + ${docker_args:+${docker_args}} \ + ${containerd_args:+${containerd_args}} \ + ${kubernetes_args:+${kubernetes_args}} fi fi diff --git a/pkg/guestagent/events/containerd.go b/pkg/guestagent/events/containerd_linux.go similarity index 100% rename from pkg/guestagent/events/containerd.go rename to pkg/guestagent/events/containerd_linux.go diff --git a/pkg/guestagent/events/containerd_stub.go b/pkg/guestagent/events/containerd_stub.go new file mode 100644 index 00000000000..1a67044a08b --- /dev/null +++ b/pkg/guestagent/events/containerd_stub.go @@ -0,0 +1,13 @@ +//go:build !linux +// +build !linux + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package events + +type ContainerdEventMonitor struct{} + +func NewContainerdEventMonitor(_ []string) (*ContainerdEventMonitor, error) { + panic("Containerd event monitoring is not implemented on this platform") +} diff --git a/pkg/guestagent/events/docker.go b/pkg/guestagent/events/docker_linux.go similarity index 100% rename from pkg/guestagent/events/docker.go rename to pkg/guestagent/events/docker_linux.go diff --git a/pkg/guestagent/events/docker_stub.go b/pkg/guestagent/events/docker_stub.go new file mode 100644 index 00000000000..164e892e8b0 --- /dev/null +++ b/pkg/guestagent/events/docker_stub.go @@ -0,0 +1,13 @@ +//go:build !linux +// +build !linux + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package events + +type DockerEventMonitor struct{} + +func NewDockerEventMonitor(_ []string) (*DockerEventMonitor, error) { + panic("Dockert event monitoring is not implemented on this platform") +} diff --git a/pkg/guestagent/events/eventutils.go b/pkg/guestagent/events/eventutils.go index 25bf1a1c666..2ce9da15c8b 100644 --- a/pkg/guestagent/events/eventutils.go +++ b/pkg/guestagent/events/eventutils.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + // SPDX-FileCopyrightText: Copyright The Lima Authors // SPDX-License-Identifier: Apache-2.0 From 98a2ccf41eb3373532d01a9d8d8dae4b60738d73 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Mon, 7 Jul 2025 09:55:57 -0700 Subject: [PATCH 12/15] Add Port Watcher configs to install systemd Signed-off-by: Nino Kodabande --- cmd/lima-guestagent/install_systemd_linux.go | 33 +++++++++++++++++-- .../boot/25-guestagent-base.sh | 15 +++++++-- pkg/cidata/cidata.TEMPLATE.d/lima.env | 6 ++-- pkg/cidata/cidata.go | 6 ++-- pkg/cidata/template.go | 13 ++------ 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/cmd/lima-guestagent/install_systemd_linux.go b/cmd/lima-guestagent/install_systemd_linux.go index bc654a56246..194903df3a3 100644 --- a/cmd/lima-guestagent/install_systemd_linux.go +++ b/cmd/lima-guestagent/install_systemd_linux.go @@ -26,6 +26,9 @@ func newInstallSystemdCommand() *cobra.Command { } installSystemdCommand.Flags().Int("vsock-port", 0, "Use vsock server on specified port") installSystemdCommand.Flags().String("virtio-port", "", "Use virtio server instead a UNIX socket") + installSystemdCommand.Flags().StringSlice("docker-sockets", []string{}, "Paths to Docker socket files to monitor for exposed ports") + installSystemdCommand.Flags().StringSlice("containerd-sockets", []string{}, "Paths to Containerd socket files to monitor for exposed ports") + installSystemdCommand.Flags().StringSlice("kubernetes-configs", []string{}, "Path to Kubernetes config files to monitor for ports") return installSystemdCommand } @@ -38,7 +41,24 @@ func installSystemdAction(cmd *cobra.Command, _ []string) error { if err != nil { return err } - unit, err := generateSystemdUnit(vsockPort, virtioPort) + dockerSockets, err := cmd.Flags().GetStringSlice("docker-sockets") + if err != nil { + return err + } + containerdSockets, err := cmd.Flags().GetStringSlice("containerd-sockets") + if err != nil { + return err + } + kubernetesConfigs, err := cmd.Flags().GetStringSlice("kubernetes-configs") + if err != nil { + return err + } + unit, err := generateSystemdUnit( + vsockPort, + virtioPort, + dockerSockets, + containerdSockets, + kubernetesConfigs) if err != nil { return err } @@ -77,7 +97,7 @@ func installSystemdAction(cmd *cobra.Command, _ []string) error { //go:embed lima-guestagent.TEMPLATE.service var systemdUnitTemplate string -func generateSystemdUnit(vsockPort int, virtioPort string) ([]byte, error) { +func generateSystemdUnit(vsockPort int, virtioPort string, dockerSockets, containerdSockets, kubeConfigs []string) ([]byte, error) { selfExeAbs, err := os.Executable() if err != nil { return nil, err @@ -90,6 +110,15 @@ func generateSystemdUnit(vsockPort int, virtioPort string) ([]byte, error) { if virtioPort != "" { args = append(args, fmt.Sprintf("--virtio-port %s", virtioPort)) } + if len(dockerSockets) > 0 { + args = append(args, fmt.Sprintf("--docker-sockets %s", strings.Join(dockerSockets, ","))) + } + if len(containerdSockets) > 0 { + args = append(args, fmt.Sprintf("--containerd-sockets %s", strings.Join(containerdSockets, ","))) + } + if len(kubeConfigs) > 0 { + args = append(args, fmt.Sprintf("--kubernetes-configs %s", strings.Join(kubeConfigs, ","))) + } m := map[string]string{ "Binary": selfExeAbs, diff --git a/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh b/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh index 026015affb1..8fc6ca0d078 100644 --- a/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh +++ b/pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh @@ -20,6 +20,12 @@ fi # Install or update the guestagent binary install -m 755 "${LIMA_CIDATA_MNT}"/lima-guestagent "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent +strip_array() { + val="${1#[}" # remove leading [ + val="${val%]}" # remove trailing ] + printf '%s\n' "$val" | xargs # trim spaces +} + # Launch the guestagent service if [ -f /sbin/openrc-run ]; then # Convert .env to conf.d by wrapping values in double quotes. @@ -58,17 +64,20 @@ else rm -f "${LIMA_CIDATA_HOME}/.config/systemd/user/lima-guestagent.service" docker_args="" - if [ -n "${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}" ]; then + docker_items="$(strip_array "${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}")" + if [ -n "$docker_items" ]; then docker_args="--docker-sockets=${LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS}" fi containerd_args="" - if [ -n "${LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}" ]; then + containerd_items="$(strip_array "${LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}")" + if [ -n "$containerd_items" ]; then containerd_args="--containerd-sockets=${LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS}" fi kubernetes_args="" - if [ -n "${LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}" ]; then + kubernetes_items="$(strip_array "${LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}")" + if [ -n "$kubernetes_items" ]; then kubernetes_args="--kubernetes-configs=${LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS}" fi diff --git a/pkg/cidata/cidata.TEMPLATE.d/lima.env b/pkg/cidata/cidata.TEMPLATE.d/lima.env index 45143db03a4..36bf6fd8a02 100644 --- a/pkg/cidata/cidata.TEMPLATE.d/lima.env +++ b/pkg/cidata/cidata.TEMPLATE.d/lima.env @@ -54,9 +54,9 @@ LIMA_CIDATA_SKIP_DEFAULT_DEPENDENCY_RESOLUTION= LIMA_CIDATA_VMTYPE={{ .VMType }} LIMA_CIDATA_VSOCK_PORT={{ .VSockPort }} LIMA_CIDATA_VIRTIO_PORT={{ .VirtioPort}} -LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS={{ .PortMonitor.Docker.Sockets }} -LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS={{ .PortMonitor.Containerd.Sockets }} -LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS={{ .PortMonitor.Kubernetes.Configs }} +LIMA_CIDATA_DOCKER_PORT_MONITOR_SOCKETS={{ .PortMonitor.Docker }} +LIMA_CIDATA_CONTAINERD_PORT_MONITOR_SOCKETS={{ .PortMonitor.Containerd }} +LIMA_CIDATA_KUBERNETES_SERVICE_WATCHER_CONFIGS={{ .PortMonitor.Kubernetes }} {{- if .Plain}} LIMA_CIDATA_PLAIN=1 {{- else}} diff --git a/pkg/cidata/cidata.go b/pkg/cidata/cidata.go index 258f6ab1e20..452cb94bd59 100644 --- a/pkg/cidata/cidata.go +++ b/pkg/cidata/cidata.go @@ -144,9 +144,9 @@ func templateArgs(bootScripts bool, instDir, name string, instConfig *limayaml.L TimeZone: *instConfig.TimeZone, Param: instConfig.Param, PortMonitor: PortMonitor{ - Docker: Engine{Sockets: instConfig.PortMonitors.Docker.Sockets}, - Containerd: Engine{Sockets: instConfig.PortMonitors.Containerd.Sockets}, - Kubernetes: Kubernetes{Configs: instConfig.PortMonitors.Kubernetes.Configs}, + Docker: strings.Join(instConfig.PortMonitors.Docker.Sockets, ","), + Containerd: strings.Join(instConfig.PortMonitors.Containerd.Sockets, ","), + Kubernetes: strings.Join(instConfig.PortMonitors.Kubernetes.Configs, ","), }, } diff --git a/pkg/cidata/template.go b/pkg/cidata/template.go index baf2c0f3665..3b89b1ce7cf 100644 --- a/pkg/cidata/template.go +++ b/pkg/cidata/template.go @@ -65,18 +65,11 @@ type Disk struct { FSType string FSArgs []string } -type Engine struct { - Sockets []string -} - -type Kubernetes struct { - Configs []string -} type PortMonitor struct { - Docker Engine - Containerd Engine - Kubernetes Kubernetes + Docker string + Containerd string + Kubernetes string } type TemplateArgs struct { From 4cb817755ace4ed287e6ab0666457cfb17b4f896 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Tue, 8 Jul 2025 11:18:14 -0700 Subject: [PATCH 13/15] Add retry to create docker client Signed-off-by: Nino Kodabande --- pkg/guestagent/events/docker_linux.go | 57 ++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/pkg/guestagent/events/docker_linux.go b/pkg/guestagent/events/docker_linux.go index 6c7b7a46e11..e6d43825286 100644 --- a/pkg/guestagent/events/docker_linux.go +++ b/pkg/guestagent/events/docker_linux.go @@ -6,8 +6,10 @@ package events import ( "context" "fmt" + "os" "strconv" "strings" + "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -30,23 +32,60 @@ type DockerEventMonitor struct { } func NewDockerEventMonitor(dockerSocketPaths []string) (*DockerEventMonitor, error) { + const ( + maxRetries = 5 + retryDelay = 2 * time.Second + ) + var dockerClients []*client.Client + for _, socket := range dockerSocketPaths { - cli, err := client.NewClientWithOpts(client.WithHost(socket), client.WithAPIVersionNegotiation()) - if err != nil { - logrus.Errorf("error creating Docker client for socket %s: %s", socket, err) + logrus.Debugf("attempting to read Docker socket %s", socket) + + info, statErr := os.Stat(socket) + if os.IsNotExist(statErr) { + logrus.Debugf("Docker socket %s does not exist", socket) continue - } - if _, err := cli.Ping(context.Background()); err != nil { - logrus.Errorf("error pinging Docker client for socket %s: %s", socket, err) + } else if statErr != nil { + return nil, fmt.Errorf("error checking Docker socket %s: %w", socket, statErr) + } else if info.IsDir() { + logrus.Debugf("Docker socket %s is a directory, skipping", socket) continue } - logrus.Infof("successfully connected to docker daemon at %s", socket) - dockerClients = append(dockerClients, cli) + + var cli *client.Client + var err error + + for attempt := 1; attempt <= maxRetries; attempt++ { + cli, err = client.NewClientWithOpts(client.WithHost(socket), client.WithAPIVersionNegotiation()) + if err == nil { + if _, err = cli.Ping(context.Background()); err == nil { + logrus.Infof("successfully connected to Docker daemon at %s", socket) + dockerClients = append(dockerClients, cli) + break + } + } + + logrus.Warnf("attempt %d/%d: failed to connect to Docker at %s: %s", attempt, maxRetries, socket, err) + + if attempt < maxRetries { + select { + case <-time.After(retryDelay): + case <-context.Background().Done(): + logrus.Warn("retry canceled, context done") + return nil, context.Canceled + } + } else { + logrus.Errorf("failed to connect to Docker at %s after %d attempts: %v", socket, maxRetries, err) + } + } } + if len(dockerClients) == 0 { - return nil, fmt.Errorf("no valid Docker clients created from provided sockets: %v", dockerSocketPaths) + logrus.Warn("no valid Docker clients created from provided sockets, please check the socket paths") + return nil, nil } + return &DockerEventMonitor{ dockerClients: dockerClients, runningContainers: make(map[string][]*api.IPPort), From ff06f8812f7a2b2dd00dae1725c2b43fea515c82 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Tue, 8 Jul 2025 12:31:22 -0700 Subject: [PATCH 14/15] Add retry to containerd client creation Signed-off-by: Nino Kodabande --- pkg/guestagent/events/containerd_linux.go | 66 +++++++++++++++++------ 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/pkg/guestagent/events/containerd_linux.go b/pkg/guestagent/events/containerd_linux.go index 9529cf67b67..473802b8c64 100644 --- a/pkg/guestagent/events/containerd_linux.go +++ b/pkg/guestagent/events/containerd_linux.go @@ -32,34 +32,70 @@ type ContainerdEventMonitor struct { } func NewContainerdEventMonitor(socketPaths []string) (*ContainerdEventMonitor, error) { + const ( + maxRetries = 5 + retryDelay = 2 * time.Second + ) + var clients []*containerd.Client + for _, socket := range socketPaths { logrus.Debugf("reading containerd socket %s", socket) - if _, err := os.Stat(socket); os.IsNotExist(err) { + + info, err := os.Stat(socket) + if os.IsNotExist(err) { logrus.Debugf("containerd socket %s does not exist", socket) continue } else if err != nil { return nil, fmt.Errorf("error checking containerd socket %s: %w", socket, err) - } - cli, err := containerd.New(socket, containerd.WithDefaultNamespace(containerdNamespace.Default)) - if err != nil { - logrus.Errorf("failed to create Containerd client for socket %s: %s", socket, err) + } else if info.IsDir() { + logrus.Warnf("containerd socket %s is a directory, skipping", socket) continue } - ctx, cancel := context.WithTimeout(context.Background(), defaultSocketTimeout) - serving, err := cli.IsServing(ctx) - cancel() - if err == nil && serving { - logrus.Infof("successfully connected to containerd daemon at %s", socket) - clients = append(clients, cli) - } else { - logrus.Errorf("error checking if containerd client for socket %s is serving: %s", socket, err) - cli.Close() + + var cli *containerd.Client + var lastErr error + + for attempt := 1; attempt <= maxRetries; attempt++ { + cli, err = containerd.New(socket, containerd.WithDefaultNamespace(containerdNamespace.Default)) + if err != nil { + logrus.Warnf("attempt %d/%d: failed to create client for socket %s: %v", attempt, maxRetries, socket, err) + lastErr = err + } else { + ctx, cancel := context.WithTimeout(context.Background(), defaultSocketTimeout) + serving, serveErr := cli.IsServing(ctx) + cancel() + + if serveErr == nil && serving { + logrus.Infof("successfully connected to containerd daemon at %s (attempt %d)", socket, attempt) + clients = append(clients, cli) + break + } + + logrus.Warnf("attempt %d/%d: containerd client at %s not serving: %v", attempt, maxRetries, socket, serveErr) + lastErr = serveErr + cli.Close() + } + + select { + case <-time.After(retryDelay): + continue + case <-context.Background().Done(): + logrus.Warn("retry canceled, context done") + return nil, context.Canceled + } + } + + if cli == nil { + logrus.Errorf("failed to connect to containerd at %s after %d attempts: %v", socket, maxRetries, lastErr) } } + if len(clients) == 0 { - return nil, fmt.Errorf("no valid Containerd clients created from provided sockets: %v", socketPaths) + logrus.Warn("no valid Containerd clients created from provided sockets") + return nil, nil } + return &ContainerdEventMonitor{ clients: clients, runningContainers: make(map[string][]*api.IPPort), From c5c68f2ca10b41d666430b0d504e818e5419f14f Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Wed, 9 Jul 2025 11:05:40 -0700 Subject: [PATCH 15/15] Add portMonitor property to appropriate templates Signed-off-by: Nino Kodabande --- templates/docker-rootful.yaml | 4 ++++ templates/docker.yaml | 4 ++++ templates/k3s.yaml | 4 ++++ templates/k8s.yaml | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/templates/docker-rootful.yaml b/templates/docker-rootful.yaml index 037b6b839f4..d7ab60edf25 100644 --- a/templates/docker-rootful.yaml +++ b/templates/docker-rootful.yaml @@ -68,3 +68,7 @@ message: | docker context use lima-{{.Name}} docker run hello-world ------ +portMonitors: + docker: + sockets: + - "/var/run/docker.sock" diff --git a/templates/docker.yaml b/templates/docker.yaml index da1148095c4..296d3bf67d3 100644 --- a/templates/docker.yaml +++ b/templates/docker.yaml @@ -70,3 +70,7 @@ message: | docker context use lima-{{.Name}} docker run hello-world ------ +portMonitors: + docker: + sockets: + - "/run/user/{{.UID}}/docker.sock" diff --git a/templates/k3s.yaml b/templates/k3s.yaml index 9b84d591114..98d8a38783d 100644 --- a/templates/k3s.yaml +++ b/templates/k3s.yaml @@ -49,3 +49,7 @@ message: | export KUBECONFIG="{{.Dir}}/copied-from-guest/kubeconfig.yaml" kubectl ... ------ +portMonitors: + kubernetes: + configs: + - "/etc/rancher/k3s/k3s.yaml" diff --git a/templates/k8s.yaml b/templates/k8s.yaml index 3bcc6c9afc6..9e0309144cf 100644 --- a/templates/k8s.yaml +++ b/templates/k8s.yaml @@ -176,3 +176,7 @@ message: | export KUBECONFIG="{{.Dir}}/copied-from-guest/kubeconfig.yaml" kubectl ... ------ +portMonitors: + kubernetes: + configs: + - "/etc/kubernetes/admin.conf"