diff --git a/go.mod b/go.mod index a402cf7025..74cd969ad9 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/hashicorp/terraform require ( - cloud.google.com/go/kms v1.12.1 + cloud.google.com/go/kms v1.15.0 cloud.google.com/go/storage v1.30.1 github.com/Azure/azure-sdk-for-go v59.2.0+incompatible github.com/Azure/go-autorest/autorest v0.11.27 @@ -32,7 +32,7 @@ require ( github.com/go-test/deep v1.0.3 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.40 github.com/hashicorp/consul/api v1.13.0 github.com/hashicorp/consul/sdk v0.8.0 @@ -46,6 +46,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-plugin v1.4.3 github.com/hashicorp/go-retryablehttp v0.7.4 + github.com/hashicorp/go-slug v0.12.2 github.com/hashicorp/go-tfe v1.34.0 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.6.0 @@ -87,6 +88,7 @@ require ( github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b github.com/zclconf/go-cty-yaml v1.0.3 go.opentelemetry.io/contrib/exporters/autoexport v0.45.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 go.opentelemetry.io/otel v1.20.0 go.opentelemetry.io/otel/sdk v1.20.0 go.opentelemetry.io/otel/trace v1.20.0 @@ -94,15 +96,15 @@ require ( golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/mod v0.12.0 golang.org/x/net v0.17.0 - golang.org/x/oauth2 v0.10.0 + golang.org/x/oauth2 v0.11.0 golang.org/x/sys v0.14.0 golang.org/x/term v0.13.0 golang.org/x/text v0.14.0 golang.org/x/tools v0.13.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated google.golang.org/api v0.126.0 - google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 - google.golang.org/grpc v1.58.3 + google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d + google.golang.org/grpc v1.59.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 google.golang.org/protobuf v1.31.0 honnef.co/go/tools v0.5.0-0.dev.0.20230826160118-ad5ca31ff221 @@ -113,8 +115,8 @@ require ( ) require ( - cloud.google.com/go v0.110.4 // indirect - cloud.google.com/go/compute v1.21.0 // indirect + cloud.google.com/go v0.110.7 // indirect + cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.1 // indirect github.com/AlecAivazis/survey/v2 v2.3.6 // indirect @@ -200,7 +202,6 @@ require ( github.com/hashicorp/go-msgpack v0.5.4 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect - github.com/hashicorp/go-slug v0.12.2 // indirect github.com/hashicorp/golang-lru v0.5.1 // indirect github.com/hashicorp/serf v0.9.6 // indirect github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect @@ -261,8 +262,8 @@ require ( golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 3ec3cfba02..fb5019fa45 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9 cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= +cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= @@ -70,8 +70,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= @@ -113,8 +113,8 @@ cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/kms v1.12.1 h1:xZmZuwy2cwzsocmKDOPu4BL7umg8QXagQx6fKVmf45U= -cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= +cloud.google.com/go/kms v1.15.0 h1:xYl5WEaSekKYN5gGRyhjvZKM22GVBBCzegGNVPy+aIs= +cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= @@ -425,6 +425,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -461,6 +463,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -522,8 +526,8 @@ github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -619,8 +623,9 @@ github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= @@ -1082,6 +1087,8 @@ go.opentelemetry.io/contrib/exporters/autoexport v0.45.0 h1:KU3hwb3O+fc2F15lltmD go.opentelemetry.io/contrib/exporters/autoexport v0.45.0/go.mod h1:9hFI4YY6Ehe9enzw9qGlKAjJGQAtEo75Ysrb3byOZtI= go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.46.0 h1:qmQcwJOEOfNvVOD8H7bVAEipp+6UtnDK3qHGCcjwB9o= go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.46.0/go.mod h1:d1FGIeeryqx0a2Oa5oQrK1Ug85AGfFUx+nMtoAwJ4VI= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M= go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= @@ -1262,8 +1269,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1644,12 +1651,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1688,8 +1695,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/internal/rpcapi/grpc_testing.go b/internal/rpcapi/grpc_testing.go index 4f649e2cdf..d1648640d8 100644 --- a/internal/rpcapi/grpc_testing.go +++ b/internal/rpcapi/grpc_testing.go @@ -5,6 +5,7 @@ import ( "net" "testing" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/test/bufconn" ) @@ -19,7 +20,10 @@ import ( // server end of this fake connection. func grpcClientForTesting(ctx context.Context, t *testing.T, registerServices func(srv *grpc.Server)) (conn grpc.ClientConnInterface, close func()) { fakeListener := bufconn.Listen(1024 /* buffer size */) - srv := grpc.NewServer() + srv := grpc.NewServer( + grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()), + grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()), + ) // Caller gets an opportunity to register specific services before // we actually start "serving". @@ -40,6 +44,8 @@ func grpcClientForTesting(ctx context.Context, t *testing.T, registerServices fu ctx, "testfake", grpc.WithContextDialer(fakeDialer), grpc.WithInsecure(), + grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), + grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), ) if err != nil { t.Fatalf("failed to connect to the fake server: %s", err) diff --git a/internal/rpcapi/server.go b/internal/rpcapi/server.go index 30b9a53138..1928e3a563 100644 --- a/internal/rpcapi/server.go +++ b/internal/rpcapi/server.go @@ -6,6 +6,7 @@ import ( "os" "github.com/hashicorp/go-plugin" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" ) @@ -34,7 +35,12 @@ func ServePlugin(ctx context.Context, opts ServerOpts) error { }, }, GRPCServer: func(opts []grpc.ServerOption) *grpc.Server { - server := grpc.NewServer(opts...) + fullOpts := []grpc.ServerOption{ + grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()), + grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()), + } + fullOpts = append(fullOpts, opts...) + server := grpc.NewServer(fullOpts...) // We'll also monitor the given context for cancellation // and terminate the server gracefully if we get cancelled. go func() { diff --git a/internal/rpcapi/setup.go b/internal/rpcapi/setup.go index a3e18b4f7b..0aae5d5843 100644 --- a/internal/rpcapi/setup.go +++ b/internal/rpcapi/setup.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/hashicorp/terraform/internal/rpcapi/terraform1" + "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -39,7 +40,13 @@ func (s *setupServer) Handshake(ctx context.Context, req *terraform1.Handshake_R return nil, status.Error(codes.FailedPrecondition, "handshake already completed") } - serverCaps, err := s.initOthers(ctx, req.Capabilities) + var serverCaps *terraform1.ServerCapabilities + var err error + { + ctx, span := tracer.Start(ctx, "initialize RPC services") + serverCaps, err = s.initOthers(ctx, req.Capabilities) + span.End() + } s.initOthers = nil // cannot handshake again if err != nil { return nil, err diff --git a/internal/rpcapi/telemetry.go b/internal/rpcapi/telemetry.go new file mode 100644 index 0000000000..d8485a9854 --- /dev/null +++ b/internal/rpcapi/telemetry.go @@ -0,0 +1,20 @@ +package rpcapi + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" +) + +// tracer is the OpenTelemetry tracer to use for tracing for code in this +// package. +// +// When creating tracing spans in gRPC service functions, always use the +// a [context.Context] descended from the one passed in to the service +// function so that the spans can attach to the automatically-generated +// server request span and, if the client is also using OpenTelemetry, +// to the client's request span. +var tracer trace.Tracer + +func init() { + tracer = otel.Tracer("github.com/hashicorp/terraform/internal/rpcapi") +} diff --git a/internal/rpcapi/telemetry_test.go b/internal/rpcapi/telemetry_test.go new file mode 100644 index 0000000000..33919b2475 --- /dev/null +++ b/internal/rpcapi/telemetry_test.go @@ -0,0 +1,297 @@ +package rpcapi + +import ( + "context" + "testing" + "time" + + "github.com/davecgh/go-spew/spew" + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/internal/rpcapi/terraform1" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/instrumentation" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + semconv "go.opentelemetry.io/otel/semconv/v1.17.0" + "go.opentelemetry.io/otel/trace" + "google.golang.org/grpc" +) + +// initTelemetryForTest configures OpenTelemetry to collect spans into a +// local in-memory buffer and returns an object that provides access to that +// buffer. +// +// The OpenTelemetry tracer provider is a global cross-cutting concern shared +// throughout the program, so it isn't valid to use this function in any test +// that calls t.Parallel, or in subtests of a parent test that has already +// used this function. +func initTelemetryForTest(t *testing.T, providerOptions ...sdktrace.TracerProviderOption) *tracetest.InMemoryExporter { + t.Helper() + + exp := tracetest.NewInMemoryExporter() + sp := sdktrace.NewSimpleSpanProcessor(exp) + providerOptions = append( + []sdktrace.TracerProviderOption{ + sdktrace.WithSpanProcessor(sp), + }, + providerOptions..., + ) + provider := sdktrace.NewTracerProvider(providerOptions...) + otel.SetTracerProvider(provider) + + pgtr := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}) + otel.SetTextMapPropagator(pgtr) + + // We'll automatically shut down the provider at the end of the test run, + // because otherwise a subsequent test which runs something that generates + // telemetry _without_ calling initTelemetryForTest (which is optional) + // could end up appending irrelevant spans to an earlier test's exporter. + t.Cleanup(func() { + provider.Shutdown(context.Background()) + otel.SetTracerProvider(nil) + otel.SetTextMapPropagator(nil) + }) + + t.Log("OpenTelemetry initialized") + return exp +} + +// findTestTelemetrySpan tests each of the spans that have been reported to the +// given [tracetest.InMemoryExporter] with the given predicate function and +// returns the first one for which the predicate matches. +// +// If the predicate returns false for all spans then this function will fail +// the test using the given [testing.T]. +func findTestTelemetrySpan(t *testing.T, exp *tracetest.InMemoryExporter, predicate func(tracetest.SpanStub) bool) tracetest.SpanStub { + for _, span := range exp.GetSpans() { + if predicate(span) { + return span + } + } + t.Fatal("no spans matched the predicate") + return tracetest.SpanStub{} +} + +// findTestTelemetrySpans tests each of the spans that have been reported to the +// given [tracetest.InMemoryExporter] with the given predicate function and +// returns only those for which the predicate matches. +// +// If no spans match at all then the result is a zero-length slice. If you are +// expecting to find exactly one matching span then [findTestTelemetrySpan] +// (singular) might be more convenient. +func findTestTelemetrySpans(t *testing.T, exp *tracetest.InMemoryExporter, predicate func(tracetest.SpanStub) bool) tracetest.SpanStubs { + var ret tracetest.SpanStubs + for _, span := range exp.GetSpans() { + if predicate(span) { + ret = append(ret, span) + } + } + return ret +} + +// overwriteTestSpanTimestamps overwrites the timestamps in all of the given +// spans to be exactly the given fakeTime, as a way to avoid considering exact +// timestamps when comparing actual spans with desired spans. +// +// This function overwrites both the start and end times of the spans themselves +// and also the timestamps of any events associated with the spans. +func overwriteTestSpanTimestamps(spans tracetest.SpanStubs, fakeTime time.Time) { + for i := range spans { + spans[i].StartTime = fakeTime + spans[i].EndTime = fakeTime + for j := range spans[i].Events { + spans[i].Events[j].Time = fakeTime + } + } +} + +func fixedTraceID(n uint32) trace.TraceID { + return trace.TraceID{ + 0xfe, 0xed, 0xfa, 0xce, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + uint8(n >> 24), uint8(n >> 16), uint8(n >> 8), uint8(n >> 0), + } +} + +func fixedSpanID(n uint32) trace.SpanID { + return trace.SpanID{ + 0xfa, 0xce, 0xfe, 0xed, + uint8(n >> 24), uint8(n >> 16), uint8(n >> 8), uint8(n >> 0), + } +} + +func TestTelemetryInTests(t *testing.T) { + ctx := context.Background() + + testResource := resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("telemetry test"), + semconv.ServiceVersionKey.String("1.2.3"), + ) + + telemetry := initTelemetryForTest(t, + sdktrace.WithResource(testResource), + ) + + var parentSpanContext, childSpanContext trace.SpanContext + + tracer := otel.Tracer("test thingy") + { + ctx, parentSpan := tracer.Start(ctx, "parent span") + parentSpanContext = parentSpan.SpanContext() + { + _, childSpan := tracer.Start(ctx, "child span") + childSpanContext = childSpan.SpanContext() + childSpan.AddEvent("did something totally hilarious") + childSpan.SetStatus(codes.Error, "it went wrong") + childSpan.End() + } + parentSpan.End() + } + + gotSpans := telemetry.GetSpans() + + // The spans contain real timestamps that make them annoying to compare, + // so we'll just replace those with fixed timestamps so we can easily + // compare everything else. + fakeTime := time.Now() + overwriteTestSpanTimestamps(gotSpans, fakeTime) + + wantSpans := tracetest.SpanStubs{ + // These are ordered by the calls to Span.End above, so child should + // always appear first. (That's a detail of this in-memory-only + // exporter, not a general guarantee about OpenTracing.) + { + Name: "child span", + SpanContext: childSpanContext, + Parent: parentSpanContext, + SpanKind: trace.SpanKindInternal, + StartTime: fakeTime, + EndTime: fakeTime, + Events: []sdktrace.Event{ + { + Name: "did something totally hilarious", + Time: fakeTime, + }, + }, + Status: sdktrace.Status{ + Code: codes.Error, + Description: "it went wrong", + }, + Resource: testResource, + InstrumentationLibrary: instrumentation.Scope{ + Name: "test thingy", + }, + }, + { + Name: "parent span", + SpanContext: parentSpanContext, + SpanKind: trace.SpanKindInternal, + StartTime: fakeTime, + EndTime: fakeTime, + ChildSpanCount: 1, + Resource: testResource, + InstrumentationLibrary: instrumentation.Scope{ + Name: "test thingy", + }, + }, + } + + if diff := cmp.Diff(wantSpans, gotSpans); diff != "" { + t.Errorf("wrong spans\n%s", diff) + } +} + +func TestTelemetryInTestsGRPC(t *testing.T) { + ctx := context.Background() + + testResource := resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("TestTelemetryInTestsGRPC"), + ) + telemetry := initTelemetryForTest(t, + sdktrace.WithResource(testResource), + ) + + client, close := grpcClientForTesting(ctx, t, func(srv *grpc.Server) { + setup := &setupServer{ + initOthers: func(ctx context.Context, cc *terraform1.ClientCapabilities) (*terraform1.ServerCapabilities, error) { + return &terraform1.ServerCapabilities{}, nil + }, + } + terraform1.RegisterSetupServer(srv, setup) + }) + defer close() + setupClient := terraform1.NewSetupClient(client) + + { + ctx, span := otel.Tracer("TestTelemetryInTestsGRPC").Start(ctx, "root") + _, err := setupClient.Handshake(ctx, &terraform1.Handshake_Request{ + Capabilities: &terraform1.ClientCapabilities{}, + }) + if err != nil { + t.Fatal(err) + } + span.End() + } + + clientSpan := findTestTelemetrySpan(t, telemetry, func(ss tracetest.SpanStub) bool { + return ss.SpanKind == trace.SpanKindClient + }) + serverSpan := findTestTelemetrySpan(t, telemetry, func(ss tracetest.SpanStub) bool { + return ss.SpanKind == trace.SpanKindServer + }) + t.Run("client span", func(t *testing.T) { + span := clientSpan + t.Logf("client span: %s", spew.Sdump(span)) + if got, want := span.Name, "terraform1.Setup/Handshake"; got != want { + t.Errorf("wrong name\ngot: %s\nwant: %s", got, want) + } + attrs := otelAttributesMap(span.Attributes) + if got, want := attrs["rpc.system"], "grpc"; got != want { + t.Errorf("wrong rpc.system\ngot: %s\nwant: %s", got, want) + } + if got, want := attrs["rpc.service"], "terraform1.Setup"; got != want { + t.Errorf("wrong rpc.service\ngot: %s\nwant: %s", got, want) + } + if got, want := attrs["rpc.method"], "Handshake"; got != want { + t.Errorf("wrong rpc.method\ngot: %s\nwant: %s", got, want) + } + }) + t.Run("server span", func(t *testing.T) { + span := serverSpan + t.Logf("server span: %s", spew.Sdump(span)) + if got, want := span.Name, "terraform1.Setup/Handshake"; got != want { + t.Errorf("wrong name\ngot: %s\nwant: %s", got, want) + } + if got, want := span.Parent.SpanID(), clientSpan.SpanContext.SpanID(); got != want { + t.Errorf("server span is not a child of the client span\nclient span ID: %s\nserver span parent ID: %s", want, got) + } + if got, want := serverSpan.SpanContext.TraceID(), clientSpan.SpanContext.TraceID(); got != want { + t.Errorf("server span belongs to different trace than client span\nclient trace ID: %s\nserver trace ID: %s", want, got) + } + attrs := otelAttributesMap(span.Attributes) + if got, want := attrs["rpc.system"], "grpc"; got != want { + t.Errorf("wrong rpc.system\ngot: %s\nwant: %s", got, want) + } + if got, want := attrs["rpc.service"], "terraform1.Setup"; got != want { + t.Errorf("wrong rpc.service\ngot: %s\nwant: %s", got, want) + } + if got, want := attrs["rpc.method"], "Handshake"; got != want { + t.Errorf("wrong rpc.method\ngot: %s\nwant: %s", got, want) + } + }) +} + +func otelAttributesMap(kvs []attribute.KeyValue) map[string]any { + ret := make(map[string]any, len(kvs)) + for _, kv := range kvs { + ret[string(kv.Key)] = kv.Value.AsInterface() + } + return ret +}