diff --git a/cmd/linode-cosi-driver/main.go b/cmd/linode-cosi-driver/main.go index c50cf40..88d735a 100644 --- a/cmd/linode-cosi-driver/main.go +++ b/cmd/linode-cosi-driver/main.go @@ -27,12 +27,14 @@ import ( "syscall" "time" + "github.com/go-logr/logr" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery" "github.com/linode/linode-cosi-driver/pkg/endpoint" "github.com/linode/linode-cosi-driver/pkg/envflag" "github.com/linode/linode-cosi-driver/pkg/grpc/handlers" grpclogger "github.com/linode/linode-cosi-driver/pkg/grpc/logger" + "github.com/linode/linode-cosi-driver/pkg/kubereader/tracedkubereader" "github.com/linode/linode-cosi-driver/pkg/linodeclient" "github.com/linode/linode-cosi-driver/pkg/linodeclient/tracedclient" maxprocslogger "github.com/linode/linode-cosi-driver/pkg/maxprocs/logger" @@ -47,7 +49,11 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.21.0" "go.uber.org/automaxprocs/maxprocs" "google.golang.org/grpc" + v1 "k8s.io/api/core/v1" cosi "sigs.k8s.io/container-object-storage-interface-spec" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/config" + ctrlLog "sigs.k8s.io/controller-runtime/pkg/log" ) const ( @@ -67,12 +73,26 @@ func main() { // TODO: any logger settup must be done here, before first log call. log := slog.Default() + ctrlLog.SetLogger(logr.FromSlogHandler(log.Handler())) + + kubeclient, err := client.New(config.GetConfigOrDie(), client.Options{ + Cache: &client.CacheOptions{ + DisableFor: []client.Object{ + &v1.Secret{}, + }, + }, + }) + if err != nil { + slog.Error("initializing kube client failed", "error", err) + os.Exit(1) + } if err := run(context.Background(), log, mainOptions{ cosiEndpoint: cosiEndpoint, linodeToken: linodeToken, linodeURL: linodeURL, linodeAPIVersion: linodeAPIVersion, + kubeclient: kubeclient, }, ); err != nil { slog.Error("critical failure", "error", err) @@ -85,6 +105,7 @@ type mainOptions struct { linodeToken string linodeURL string linodeAPIVersion string + kubeclient client.Client } func run(ctx context.Context, log *slog.Logger, opts mainOptions) error { @@ -112,7 +133,7 @@ func run(ctx context.Context, log *slog.Logger, opts mainOptions) error { // initialize Linode client client, err := linodeclient.NewLinodeClient( opts.linodeToken, - fmt.Sprintf("LinodeCOSI/%s", version.Version), + version.UserAgent(), opts.linodeURL, opts.linodeAPIVersion) if err != nil { @@ -121,10 +142,13 @@ func run(ctx context.Context, log *slog.Logger, opts mainOptions) error { client.SetLogger(restylogger.Wrap(log)) + podName := os.Getenv(envK8sPodName) + // create provisioner server prvSrv, err := provisioner.New( log, - tracedclient.NewClientWithTracing(client, os.Getenv(envK8sPodName)), + tracedclient.NewClientWithTracing(client, podName), + tracedkubereader.NewKubeReaderWithTracing(opts.kubeclient, podName), ) if err != nil { return fmt.Errorf("failed to create provisioner server: %w", err) diff --git a/go.mod b/go.mod index d665a3c..8362282 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,11 @@ module github.com/linode/linode-cosi-driver -go 1.22 +go 1.22.0 -toolchain go1.22.3 +toolchain go1.22.5 require ( + github.com/go-logr/logr v1.4.2 github.com/go-resty/resty/v2 v2.13.1 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 github.com/linode/linodego v1.37.0 @@ -17,23 +18,42 @@ require ( go.opentelemetry.io/otel/trace v1.28.0 go.uber.org/automaxprocs v1.5.3 google.golang.org/grpc v1.65.0 + k8s.io/api v0.30.3 + k8s.io/apimachinery v0.30.3 sigs.k8s.io/container-object-storage-interface-spec v0.1.0 + sigs.k8s.io/controller-runtime v0.18.4 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/imdario/mergo v0.3.6 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.53.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.4.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect @@ -49,10 +69,23 @@ require ( go.opentelemetry.io/otel/sdk/log v0.4.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/client-go v0.30.3 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index e7a7d4c..2e2dada 100644 --- a/go.sum +++ b/go.sum @@ -4,31 +4,87 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 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/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g= github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +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.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 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/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +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/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/linode/linodego v1.37.0 h1:B/2Spzv9jYXzKA+p+GD8fVCNJ7Wuw6P91ZDD9eCkkso= github.com/linode/linodego v1.37.0/go.mod h1:L7GXKFD3PoN2xSEtFc04wIXP5WK65O10jYQx0PQISWQ= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +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/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/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= +github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= @@ -41,8 +97,21 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +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/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/contrib/bridges/prometheus v0.53.0 h1:BdkKDtcrHThgjcEia1737OUuFdP6xzBKAMx2sNZCkvE= go.opentelemetry.io/contrib/bridges/prometheus v0.53.0/go.mod h1:ZkhVxcJgeXlL/lVyT/vxNHVFiSG5qOaDwYaSgD8IfZo= @@ -90,13 +159,26 @@ go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -108,9 +190,13 @@ golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -127,6 +213,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -140,9 +228,16 @@ golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= @@ -151,9 +246,40 @@ google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= +k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= +k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= +k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= +k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= +k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= +k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/container-object-storage-interface-spec v0.1.0 h1:WHeei3OywFyebPwBkVUuuV1SuGjG6Qm4BBmnfFTVa1Y= sigs.k8s.io/container-object-storage-interface-spec v0.1.0/go.mod h1:SzF/yVSh88TgYdBOAXqhT96XjU8pCQtoeQKxzIOOmWQ= +sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= +sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/kubereader/resource.go b/pkg/kubereader/resource.go new file mode 100644 index 0000000..a3b5e4c --- /dev/null +++ b/pkg/kubereader/resource.go @@ -0,0 +1,23 @@ +// Copyright 2024 Akamai Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kubereader + +import ( + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type KubeReader interface { + client.Reader +} diff --git a/pkg/kubereader/tracedkubereader/tracedkubereader.gen.go b/pkg/kubereader/tracedkubereader/tracedkubereader.gen.go new file mode 100644 index 0000000..d46a368 --- /dev/null +++ b/pkg/kubereader/tracedkubereader/tracedkubereader.gen.go @@ -0,0 +1,85 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: https://raw.githubusercontent.com/hexdigest/gowrap/6c8f05695fec23df85903a8da0af66ac414e2a63/templates/opentelemetry +// gowrap: http://github.com/hexdigest/gowrap + +package tracedkubereader + +//go:generate gowrap gen -p github.com/linode/linode-cosi-driver/pkg/kubereader -i KubeReader -t https://raw.githubusercontent.com/hexdigest/gowrap/6c8f05695fec23df85903a8da0af66ac414e2a63/templates/opentelemetry -o tracedkubereader.gen.go -l "" + +import ( + "context" + + "github.com/linode/linode-cosi-driver/pkg/kubereader" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// KubeReaderWithTracing implements kubereader.KubeReader interface instrumented with opentracing spans +type KubeReaderWithTracing struct { + kubereader.KubeReader + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// NewKubeReaderWithTracing returns KubeReaderWithTracing +func NewKubeReaderWithTracing(base kubereader.KubeReader, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) KubeReaderWithTracing { + d := KubeReaderWithTracing{ + KubeReader: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Get implements kubereader.KubeReader +func (_d KubeReaderWithTracing) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "kubereader.KubeReader.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "key": key, + "obj": obj, + "opts": opts}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.KubeReader.Get(ctx, key, obj, opts...) +} + +// List implements kubereader.KubeReader +func (_d KubeReaderWithTracing) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "kubereader.KubeReader.List") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "list": list, + "opts": opts}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.KubeReader.List(ctx, list, opts...) +} diff --git a/pkg/servers/provisioner/consts.go b/pkg/servers/provisioner/consts.go index b2bfc40..7b11d13 100644 --- a/pkg/servers/provisioner/consts.go +++ b/pkg/servers/provisioner/consts.go @@ -1,4 +1,4 @@ -// Copyright 2023 Akamai Technologies, Inc. +// Copyright 2023-2024 Akamai Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ const ( ParamACL = "cosi.linode.com/v1/acl" ParamCORS = "cosi.linode.com/v1/cors" ParamPermissions = "cosi.linode.com/v1/permissions" + ParamSecretRef = "cosi.linode.com/v1/secretRef" //nolint:gosec // this is key under which secret reference is placed ) type ParamCORSValue string @@ -59,12 +60,22 @@ const ( S3SecretAccessSecretKey = "accessSecretKey" ) +const ( + LinodeTokenKey = "LINODE_TOKEN" + LinodeAPIURLKey = "LINODE_API_URL" + LinodeAPIVersionKey = "LINODE_API_VERSION" + LinodeDebugKey = "LINODE_DEBUG" + // LinodeCAKey = "LINODE_CA" // TODO: enable setting Linode CA from string in Linode Go. +) + var ( - ErrNotFound = linodego.Error{Code: http.StatusNotFound} - ErrBucketExists = errors.New("bucket exists with different parameters") - ErrUnsuportedAuth = errors.New("unsupported authentication schema") - ErrMissingRegion = errors.New("region was not provided") - ErrUnknownPermsissions = errors.New("unknown permissions") + ErrNotFound = linodego.Error{Code: http.StatusNotFound} + ErrBucketExists = errors.New("bucket exists with different parameters") + ErrUnsuportedAuth = errors.New("unsupported authentication schema") + ErrMissingRegion = errors.New("region was not provided") + ErrUnknownPermsissions = errors.New("unknown permissions") + ErrInvalidSecretReference = errors.New("invalid secret reference") + ErrInvalidSecret = errors.New("invalid secret") ) const ( diff --git a/pkg/servers/provisioner/provisioner.go b/pkg/servers/provisioner/provisioner.go index 1347a86..41d19a2 100644 --- a/pkg/servers/provisioner/provisioner.go +++ b/pkg/servers/provisioner/provisioner.go @@ -1,4 +1,4 @@ -// Copyright 2023 Akamai Technologies, Inc. +// Copyright 2023-2024 Akamai Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,15 +20,20 @@ import ( "fmt" "log/slog" "strconv" + "strings" "sync" "github.com/linode/linode-cosi-driver/pkg/linodeclient" "github.com/linode/linode-cosi-driver/pkg/observability/tracing" + "github.com/linode/linode-cosi-driver/pkg/version" "github.com/linode/linodego" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/codes" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" cosi "sigs.k8s.io/container-object-storage-interface-spec" + "sigs.k8s.io/controller-runtime/pkg/client" ) // Server implements cosi.ProvisionerServer interface. @@ -36,17 +41,19 @@ type Server struct { log *slog.Logger once sync.Once - client linodeclient.Client + client linodeclient.Client + kubeclient client.Reader } // Interface guards. var _ cosi.ProvisionerServer = (*Server)(nil) // New returns provisioner.Server with default values. -func New(logger *slog.Logger, client linodeclient.Client) (*Server, error) { +func New(logger *slog.Logger, client linodeclient.Client, kubeclient client.Reader) (*Server, error) { srv := &Server{ - log: logger, - client: client, + log: logger, + client: client, + kubeclient: kubeclient, } return srv, srv.registerMetrics() @@ -76,6 +83,18 @@ func (s *Server) DriverCreateBucket(ctx context.Context, req *cosi.DriverCreateB ctx, span := s.init(ctx, "DriverCreateBucket") defer span.End() + var ( + client linodeclient.Client = s.client + err error + ) + + if ref, ok := req.GetParameters()[ParamSecretRef]; ok { + client, err = s.scopedClient(ctx, ref) + if err != nil { + return nil, tracing.Error(span, codes.Internal, err) + } + } + label := req.GetName() region := req.GetParameters()[ParamRegion] cors := ParamCORSValue(req.GetParameters()[ParamCORS]) @@ -103,7 +122,7 @@ func (s *Server) DriverCreateBucket(ctx context.Context, req *cosi.DriverCreateB return nil, tracing.Error(span, codes.InvalidArgument, ErrMissingRegion) } - bucket, err := s.client.GetObjectStorageBucket(ctx, region, label) + bucket, err := client.GetObjectStorageBucket(ctx, region, label) if err != nil { if !errors.Is(err, ErrNotFound) { log.ErrorContext(ctx, "failed to check if bucket exists", "error", err) @@ -119,7 +138,7 @@ func (s *Server) DriverCreateBucket(ctx context.Context, req *cosi.DriverCreateB log.InfoContext(ctx, "creating bucket") - bucket, err = s.client.CreateObjectStorageBucket(ctx, opts) + bucket, err = client.CreateObjectStorageBucket(ctx, opts) if err != nil { log.ErrorContext(ctx, "failed to create bucket", "error", err) return nil, tracing.Error(span, codes.Internal, fmt.Errorf("failed to create bucket: %w", err)) @@ -137,7 +156,7 @@ func (s *Server) DriverCreateBucket(ctx context.Context, req *cosi.DriverCreateB KeyBucketCreationTimestamp, bucket.Region, ) - access, err := s.client.GetObjectStorageBucketAccess(ctx, region, label) + access, err := client.GetObjectStorageBucketAccess(ctx, region, label) if err != nil { log.ErrorContext(ctx, "failed to check bucket access", "error", err) return nil, tracing.Error(span, codes.Internal, fmt.Errorf("failed to check bucket access: %w", err)) @@ -168,6 +187,20 @@ func (s *Server) DriverDeleteBucket(ctx context.Context, req *cosi.DriverDeleteB ctx, span := s.init(ctx, "DriverDeleteBucket") defer span.End() + // TODO: requires COSI v1alpha2 + client := s.client + // var ( + // client linodeclient.Client = s.client + // err error + // ) + // + // if ref, ok := req.GetParameters()[ParamSecretRef]; ok { + // client, err = s.scopedClient(ctx, ref) + // if err != nil { + // return nil, tracing.Error(span, codes.Internal, err) + // } + // } + region, label := parseBucketID(req.GetBucketId()) log := s.logAttr( @@ -184,7 +217,7 @@ func (s *Server) DriverDeleteBucket(ctx context.Context, req *cosi.DriverDeleteB log.InfoContext(ctx, "bucket deletion initiated") - err := s.client.DeleteObjectStorageBucket(ctx, region, label) + err := client.DeleteObjectStorageBucket(ctx, region, label) if err == nil || errors.Is(err, ErrNotFound) { log.InfoContext(ctx, "bucket deleted") return &cosi.DriverDeleteBucketResponse{}, tracing.Error(span, codes.OK, err, "bucket deleted") @@ -205,6 +238,18 @@ func (s *Server) DriverGrantBucketAccess(ctx context.Context, req *cosi.DriverGr ctx, span := s.init(ctx, "DriverGrantBucketAccess") defer span.End() + var ( + client linodeclient.Client = s.client + err error + ) + + if ref, ok := req.GetParameters()[ParamSecretRef]; ok { + client, err = s.scopedClient(ctx, ref) + if err != nil { + return nil, tracing.Error(span, codes.Internal, err) + } + } + region, label := parseBucketID(req.GetBucketId()) name := req.GetName() auth := req.GetAuthenticationType() @@ -255,7 +300,7 @@ func (s *Server) DriverGrantBucketAccess(ctx context.Context, req *cosi.DriverGr log.InfoContext(ctx, "creating object storage key") - key, err := s.client.CreateObjectStorageKey(ctx, opts) + key, err := client.CreateObjectStorageKey(ctx, opts) if err != nil { log.ErrorContext(ctx, "failed to create object storage key", "error", err) return nil, tracing.Error(span, codes.InvalidArgument, fmt.Errorf("failed to create object storage key: %w", err)) @@ -276,6 +321,20 @@ func (s *Server) DriverRevokeBucketAccess(ctx context.Context, req *cosi.DriverR ctx, span := s.init(ctx, "DriverRevokeBucketAccess") defer span.End() + // TODO: requires COSI v1alpha2 + client := s.client + // var ( + // client linodeclient.Client = s.client + // err error + // ) + // + // if ref, ok := req.GetParameters()[ParamSecretRef]; ok { + // client, err = s.scopedClient(ctx, ref) + // if err != nil { + // return nil, tracing.Error(span, codes.Internal, err) + // } + // } + region, label := parseBucketID(req.GetBucketId()) id, err := strconv.Atoi(req.GetAccountId()) @@ -300,7 +359,7 @@ func (s *Server) DriverRevokeBucketAccess(ctx context.Context, req *cosi.DriverR return nil, tracing.Error(span, codes.InvalidArgument, fmt.Errorf("account id is invalid: %w", err)) } - err = s.client.DeleteObjectStorageKey(ctx, id) + err = client.DeleteObjectStorageKey(ctx, id) if err == nil || errors.Is(err, ErrNotFound) { log.InfoContext(ctx, "key deleted") return &cosi.DriverRevokeBucketAccessResponse{}, tracing.Error(span, codes.OK, nil, "key deleted") @@ -310,3 +369,64 @@ func (s *Server) DriverRevokeBucketAccess(ctx context.Context, req *cosi.DriverR return nil, tracing.Error(span, codes.Internal, fmt.Errorf("failed to delete key: %w", err)) } + +func (s *Server) scopedClient(ctx context.Context, secretRef string) (linodeclient.Client, error) { + const namespacedName = 2 + + if s.kubeclient == nil || secretRef == "" { + return s.client, nil + } + + ref := strings.Split(secretRef, "/") + if len(ref) != namespacedName { + return nil, ErrInvalidSecretReference + } + + secret := v1.Secret{} + + if err := s.kubeclient.Get(ctx, types.NamespacedName{ + Namespace: ref[0], + Name: ref[1], + }, &secret); err != nil { + return nil, fmt.Errorf("unable to obtain secret %s: %w", secretRef, err) + } + + var errs error + + token, err := stringFromSecret(&secret, LinodeTokenKey, true) + if err != nil { + errs = errors.Join(errs, err) + } + + apiURL, err := stringFromSecret(&secret, LinodeAPIURLKey, true) + if err != nil { + errs = errors.Join(errs, err) + } + + apiVersion, err := stringFromSecret(&secret, LinodeAPIVersionKey, true) + if err != nil { + errs = errors.Join(errs, err) + } + + if errs != nil { + return nil, errs + } + + debug, _ := boolFromSecret(&secret, LinodeDebugKey, false) + + client, err := linodeclient.NewLinodeClient( + token, + version.UserAgent(), + apiURL, + apiVersion, + ) + if err != nil { + return nil, err + } + + client.SetDebug(debug) + + // client.SetRootCertificateFromString() // TODO: set CA dynamically + + return client, nil +} diff --git a/pkg/servers/provisioner/provisioner_test.go b/pkg/servers/provisioner/provisioner_test.go index 3e14f29..1b2e0ef 100644 --- a/pkg/servers/provisioner/provisioner_test.go +++ b/pkg/servers/provisioner/provisioner_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 Akamai Technologies, Inc. +// Copyright 2023-2024 Akamai Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import ( grpccodes "google.golang.org/grpc/codes" "google.golang.org/grpc/status" cosi "sigs.k8s.io/container-object-storage-interface-spec" + "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -84,6 +85,7 @@ func TestDriverCreateBucket(t *testing.T) { for _, tc := range []struct { testName string client linodeclient.Client + kubeclient client.Reader request *cosi.DriverCreateBucketRequest expectedResponse *cosi.DriverCreateBucketResponse expectedError error @@ -141,7 +143,7 @@ func TestDriverCreateBucket(t *testing.T) { ctx, cancel := testutils.ContextFromT(context.Background(), t) defer cancel() - srv, err := provisioner.New(nil, tc.client) + srv, err := provisioner.New(nil, tc.client, tc.kubeclient) if err != nil { t.Fatalf("failed to create provisioner server: %v", err) } @@ -169,6 +171,7 @@ func TestDriverDeleteBucket(t *testing.T) { for _, tc := range []struct { testName string client linodeclient.Client + kubeclient client.Reader request *cosi.DriverDeleteBucketRequest expectedError error }{ @@ -188,7 +191,7 @@ func TestDriverDeleteBucket(t *testing.T) { ctx, cancel := testutils.ContextFromT(context.Background(), t) defer cancel() - srv, err := provisioner.New(nil, tc.client) + srv, err := provisioner.New(nil, tc.client, tc.kubeclient) if err != nil { t.Fatalf("failed to create provisioner server: %v", err) } @@ -209,6 +212,7 @@ func TestDriverGrantBucketAccess(t *testing.T) { for _, tc := range []struct { testName string client linodeclient.Client + kubeclient client.Reader request *cosi.DriverGrantBucketAccessRequest expectedResponse *cosi.DriverGrantBucketAccessResponse expectedError error @@ -266,7 +270,7 @@ func TestDriverGrantBucketAccess(t *testing.T) { ctx, cancel := testutils.ContextFromT(context.Background(), t) defer cancel() - srv, err := provisioner.New(nil, tc.client) + srv, err := provisioner.New(nil, tc.client, tc.kubeclient) if err != nil { t.Fatalf("failed to create provisioner server: %v", err) } @@ -294,6 +298,7 @@ func TestDriverRevokeBucketAccess(t *testing.T) { for _, tc := range []struct { testName string client linodeclient.Client + kubeclient client.Reader request *cosi.DriverRevokeBucketAccessRequest expectedError error }{ @@ -317,7 +322,7 @@ func TestDriverRevokeBucketAccess(t *testing.T) { ctx, cancel := testutils.ContextFromT(context.Background(), t) defer cancel() - srv, err := provisioner.New(nil, tc.client) + srv, err := provisioner.New(nil, tc.client, tc.kubeclient) if err != nil { t.Fatalf("failed to create provisioner server: %v", err) } diff --git a/pkg/servers/provisioner/provisionerintegration_test.go b/pkg/servers/provisioner/provisionerintegration_test.go index 9f31c9d..6fa71a2 100644 --- a/pkg/servers/provisioner/provisionerintegration_test.go +++ b/pkg/servers/provisioner/provisionerintegration_test.go @@ -63,7 +63,7 @@ func TestHappyPath(t *testing.T) { return } - srv, err := provisioner.New(slog.Default(), client) + srv, err := provisioner.New(slog.Default(), client, nil) if err != nil { t.Errorf("failed to provisioner: %v", err.Error()) return diff --git a/pkg/servers/provisioner/utils.go b/pkg/servers/provisioner/utils.go index 11e0303..f126678 100644 --- a/pkg/servers/provisioner/utils.go +++ b/pkg/servers/provisioner/utils.go @@ -1,4 +1,4 @@ -// Copyright 2023 Akamai Technologies, Inc. +// Copyright 2023-2024 Akamai Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,9 +15,12 @@ package provisioner import ( + "encoding/base64" "fmt" + "strconv" "strings" + v1 "k8s.io/api/core/v1" cosi "sigs.k8s.io/container-object-storage-interface-spec" ) @@ -52,3 +55,35 @@ func credentials(region, label, accessKey, secretKey string) map[string]*cosi.Cr }, } } + +func boolFromSecret(secret *v1.Secret, key string, required bool) (bool, error) { + s, err := stringFromSecret(secret, key, required) + if err != nil { + return false, err + } + + val, err := strconv.ParseBool(s) + if err != nil { + return false, err + } + + return val, nil +} + +func stringFromSecret(secret *v1.Secret, key string, required bool) (string, error) { + b, ok := secret.Data[key] + if !ok && required { + return "", fmt.Errorf("%w: %s not found", ErrInvalidSecret, key) + } + + enc := base64.StdEncoding + + dbuf := make([]byte, len(b)) + + n, err := enc.Decode(dbuf, b) + if err != nil { + return "", err + } + + return string(dbuf[:n]), nil +} diff --git a/pkg/version/version.go b/pkg/version/version.go index 762fdc7..8d91804 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,4 +1,4 @@ -// Copyright 2023 Akamai Technologies, Inc. +// Copyright 2023-2024 Akamai Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,4 +14,12 @@ package version +import ( + "fmt" +) + var Version string + +func UserAgent() string { + return fmt.Sprintf("LinodeCOSI/%s", Version) +}