diff --git a/mmv1/third_party/terraform/go.mod.erb b/mmv1/third_party/terraform/go.mod.erb index a2cab776d78e..33575c5a327f 100644 --- a/mmv1/third_party/terraform/go.mod.erb +++ b/mmv1/third_party/terraform/go.mod.erb @@ -4,7 +4,7 @@ module github.com/hashicorp/terraform-provider-google go 1.21 require ( - cloud.google.com/go/bigtable v1.19.0 + cloud.google.com/go/bigtable v1.23.0 github.com/GoogleCloudPlatform/declarative-resource-client-library v1.66.0 github.com/apparentlymart/go-cidr v1.1.0 github.com/davecgh/go-spew v1.1.1 @@ -27,21 +27,23 @@ require ( github.com/mitchellh/hashstructure v1.1.0 github.com/sirupsen/logrus v1.8.1 golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 - golang.org/x/net v0.22.0 - golang.org/x/oauth2 v0.18.0 - google.golang.org/api v0.171.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c - google.golang.org/grpc v1.62.1 + golang.org/x/net v0.24.0 + golang.org/x/oauth2 v0.19.0 + google.golang.org/api v0.176.1 + google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be + google.golang.org/grpc v1.63.2 google.golang.org/protobuf v1.33.0 ) require ( bitbucket.org/creachadair/stringset v0.0.8 // indirect - cloud.google.com/go v0.112.0 // indirect - cloud.google.com/go/compute v1.23.4 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/longrunning v0.5.5 // indirect + cloud.google.com/go v0.112.2 // indirect + cloud.google.com/go/auth v0.3.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect + cloud.google.com/go/compute v1.25.1 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/iam v1.1.7 // indirect + cloud.google.com/go/longrunning v0.5.6 // indirect github.com/ProtonMail/go-crypto v1.1.0-alpha.0 // indirect github.com/agext/levenshtein v1.2.2 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect @@ -60,7 +62,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect @@ -98,14 +100,14 @@ require ( go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/crypto v0.21.0 // indirect + golang.org/x/crypto v0.22.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect + google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/mmv1/third_party/terraform/go.sum b/mmv1/third_party/terraform/go.sum index b936e1ca8590..35128dd71308 100644 --- a/mmv1/third_party/terraform/go.sum +++ b/mmv1/third_party/terraform/go.sum @@ -3,16 +3,32 @@ bitbucket.org/creachadair/stringset v0.0.8/go.mod h1:AgthVMyMxC/6FK1KBJ2ALdqkZOb cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go v0.112.2 h1:ZaGT6LiG7dBzi6zNOvVZwacaXlmf3lRqnC4DQzqyRQw= +cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= +cloud.google.com/go/auth v0.3.0 h1:PRyzEpGfx/Z9e8+lHsbkoUVXD0gnu4MNmm7Gp8TQNIs= +cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= +cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/bigtable v1.19.0 h1:wiq9LT0kukfInzvy1joMDijCw/OD1UChpSbORXYn0LI= cloud.google.com/go/bigtable v1.19.0/go.mod h1:xl5kPa8PTkJjdBxg6qdGH88464nNqmbISHSRU+D2yFE= +cloud.google.com/go/bigtable v1.23.0 h1:ufk3XFeq5ZmFmkTZrWiCEMjn9kefKbHT8LVsrX+iqqc= +cloud.google.com/go/bigtable v1.23.0/go.mod h1:WWRrYMBZpmHUO76ccwN7lx681FdyUWbIK2B4DDly0P4= cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw= cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= 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/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= +cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/longrunning v0.5.6 h1:xAe8+0YaWoCKr9t1+aWe+OeQgN/iJK1fEgZSXmjuEaE= +cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -114,6 +130,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/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.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -257,6 +275,7 @@ 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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= @@ -283,6 +302,7 @@ go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGX go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -294,6 +314,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= @@ -318,9 +340,13 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= 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= @@ -348,10 +374,13 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -378,6 +407,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/api v0.176.1 h1:DJSXnV6An+NhJ1J+GWtoF2nHEuqB1VNoTfnIbjNvwD4= +google.golang.org/api v0.176.1/go.mod h1:j2MaSDYcvYV1lkZ1+SMW4IeF90SrEyFA+tluDYWRrFg= 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/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= @@ -388,10 +419,16 @@ google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU= google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= +google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw= +google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU= +google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= 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= @@ -400,6 +437,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= 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= diff --git a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.erb b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.erb index fae027d235ad..237477004ae5 100644 --- a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.erb +++ b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.erb @@ -289,6 +289,7 @@ var handwrittenResources = map[string]*schema.Resource{ "google_bigtable_gc_policy": bigtable.ResourceBigtableGCPolicy(), "google_bigtable_instance": bigtable.ResourceBigtableInstance(), "google_bigtable_table": bigtable.ResourceBigtableTable(), + "google_bigtable_authorized_view": bigtable.ResourceBigtableAuthorizedView(), "google_billing_subaccount": resourcemanager.ResourceBillingSubaccount(), "google_cloudfunctions_function": cloudfunctions.ResourceCloudFunctionsFunction(), "google_composer_environment": composer.ResourceComposerEnvironment(), diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view.go new file mode 100644 index 000000000000..4a26b6e82a8b --- /dev/null +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view.go @@ -0,0 +1,463 @@ +package bigtable + +import ( + "context" + "encoding/base64" + "fmt" + "log" + "reflect" + "time" + + "cloud.google.com/go/bigtable" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +var familySubsetSchemaElem *schema.Resource = &schema.Resource{ + Schema: map[string]*schema.Schema{ + "family_name": { + Type: schema.TypeString, + Required: true, + Description: `Name of the column family to be included in the authorized view.`, + }, + "qualifiers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `Base64-encoded individual exact column qualifiers of the column family to be included in the authorized view.`, + }, + "qualifier_prefixes": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `Base64-encoded prefixes for qualifiers of the column family to be included in the authorized view. Every qualifier starting with one of these prefixes is included in the authorized view. To provide access to all qualifiers, include the empty string as a prefix ("").`, + }, + }, +} + +func ResourceBigtableAuthorizedView() *schema.Resource { + return &schema.Resource{ + Create: resourceBigtableAuthorizedViewCreate, + Read: resourceBigtableAuthorizedViewRead, + Update: resourceBigtableAuthorizedViewUpdate, + Delete: resourceBigtableAuthorizedViewDestroy, + + Importer: &schema.ResourceImporter{ + State: resourceBigtableAuthorizedViewImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The name of the authorized view. Must be 1-50 characters and must only contain hyphens, underscores, periods, letters and numbers.`, + }, + + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: `The ID of the project in which the resource belongs. If it is not provided, the provider project is used.`, + }, + + "instance_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareResourceNames, + Description: `The name of the Bigtable instance in which the authorized view belongs.`, + }, + + "table_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareResourceNames, + Description: `The name of the Bigtable table in which the authorized view belongs.`, + }, + + "deletion_protection": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{"PROTECTED", "UNPROTECTED"}, false), + Description: `A field to make the authorized view protected against data loss i.e. when set to PROTECTED, deleting the authorized view, the table containing the authorized view, and the instance containing the authorized view would be prohibited. +If not provided, currently deletion protection will be set to UNPROTECTED as it is the API default value. Note this field configs the deletion protection provided by the API in the backend, and should not be confused with Terraform-side deletion protection.`, + }, + + "subset_view": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: `An AuthorizedView permitting access to an explicit subset of a Table.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "row_prefixes": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `Base64-encoded row prefixes to be included in the authorized view. To provide access to all rows, include the empty string as a prefix ("").`, + }, + "family_subsets": { + Type: schema.TypeSet, + Optional: true, + Description: `Subsets of column families to be included in the authorized view.`, + Elem: familySubsetSchemaElem, + }, + }, + }, + }, + }, + UseJSONNumber: true, + } +} + +func resourceBigtableAuthorizedViewCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + ctx := context.Background() + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return err + } + + instanceName := tpgresource.GetResourceNameFromSelfLink(d.Get("instance_name").(string)) + c, err := config.BigTableClientFactory(userAgent).NewAdminClient(project, instanceName) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + if err := d.Set("instance_name", instanceName); err != nil { + return fmt.Errorf("Error setting instance_name: %s", err) + } + + defer c.Close() + + authorizedViewId := d.Get("name").(string) + tableId := d.Get("table_name").(string) + authorizedViewConf := bigtable.AuthorizedViewConf{ + AuthorizedViewID: authorizedViewId, + TableID: tableId, + } + + // Check if deletion protection is given + // If not given, currently tblConf.DeletionProtection will be set to false in the API + deletionProtection := d.Get("deletion_protection") + if deletionProtection == "PROTECTED" { + authorizedViewConf.DeletionProtection = bigtable.Protected + } else if deletionProtection == "UNPROTECTED" { + authorizedViewConf.DeletionProtection = bigtable.Unprotected + } + + subsetView, ok := d.GetOk("subset_view") + if !ok || len(subsetView.([]interface{})) != 1 { + return fmt.Errorf("subset_view must be specified for authorized view %s", authorizedViewId) + } + subsetViewConf, err := generateSubsetViewConfig(subsetView.([]interface{})) + if err != nil { + return err + } + authorizedViewConf.AuthorizedView = subsetViewConf + + ctxWithTimeout, cancel := context.WithTimeout(ctx, d.Timeout(schema.TimeoutCreate)) + defer cancel() // Always call cancel. + err = c.CreateAuthorizedView(ctxWithTimeout, &authorizedViewConf) + if err != nil { + return fmt.Errorf("Error creating authorized view. %s", err) + } + + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/instances/{{instance_name}}/tables/{{table_name}}/authorizedViews/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return resourceBigtableAuthorizedViewRead(d, meta) +} + +func resourceBigtableAuthorizedViewRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + ctx := context.Background() + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return err + } + + instanceName := tpgresource.GetResourceNameFromSelfLink(d.Get("instance_name").(string)) + c, err := config.BigTableClientFactory(userAgent).NewAdminClient(project, instanceName) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + + defer c.Close() + + authorizedViewId := d.Get("name").(string) + tableId := d.Get("table_name").(string) + authorizedViewInfo, err := c.AuthorizedViewInfo(ctx, tableId, authorizedViewId) + if err != nil { + if tpgresource.IsNotFoundGrpcError(err) { + log.Printf("[WARN] Removing %s because it's gone", authorizedViewId) + d.SetId("") + return nil + } + return err + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error setting project: %s", err) + } + + deletionProtection := authorizedViewInfo.DeletionProtection + if deletionProtection == bigtable.Protected { + if err := d.Set("deletion_protection", "PROTECTED"); err != nil { + return fmt.Errorf("Error setting deletion_protection: %s", err) + } + } else if deletionProtection == bigtable.Unprotected { + if err := d.Set("deletion_protection", "UNPROTECTED"); err != nil { + return fmt.Errorf("Error setting deletion_protection: %s", err) + } + } else { + return fmt.Errorf("Error setting deletion_protection, it should be either PROTECTED or UNPROTECTED") + } + + if sv, ok := authorizedViewInfo.AuthorizedView.(*bigtable.SubsetViewInfo); ok { + subsetView := flattenSubsetViewInfo(sv) + if err := d.Set("subset_view", subsetView); err != nil { + return fmt.Errorf("Error setting subset_view: %s", err) + } + } else { + return fmt.Errorf("Error parsing server returned subset_view since it's empty") + } + + return nil +} + +func resourceBigtableAuthorizedViewUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + ctx := context.Background() + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return err + } + + instanceName := tpgresource.GetResourceNameFromSelfLink(d.Get("instance_name").(string)) + c, err := config.BigTableClientFactory(userAgent).NewAdminClient(project, instanceName) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + defer c.Close() + + authorizedViewId := d.Get("name").(string) + tableId := d.Get("table_name").(string) + authorizedViewConf := bigtable.AuthorizedViewConf{ + AuthorizedViewID: authorizedViewId, + TableID: tableId, + } + + if d.HasChange("subset_view") { + subsetView := d.Get("subset_view") + if len(subsetView.([]interface{})) != 1 { + return fmt.Errorf("subset_view must be specified for authorized view %s", authorizedViewId) + } + subsetViewConf, err := generateSubsetViewConfig(subsetView.([]interface{})) + if err != nil { + return err + } + authorizedViewConf.AuthorizedView = subsetViewConf + } + + if d.HasChange("deletion_protection") { + deletionProtection := d.Get("deletion_protection") + if deletionProtection == "PROTECTED" { + authorizedViewConf.DeletionProtection = bigtable.Protected + } else if deletionProtection == "UNPROTECTED" { + authorizedViewConf.DeletionProtection = bigtable.Unprotected + } + } + + updateAuthorizedViewConf := bigtable.UpdateAuthorizedViewConf{ + AuthorizedViewConf: authorizedViewConf, + IgnoreWarnings: true, + } + + ctxWithTimeout, cancel := context.WithTimeout(ctx, d.Timeout(schema.TimeoutUpdate)) + defer cancel() // Always call cancel. + err = c.UpdateAuthorizedView(ctxWithTimeout, updateAuthorizedViewConf) + if err != nil { + return fmt.Errorf("Error updating authorized view. %s", err) + } + + return resourceBigtableAuthorizedViewRead(d, meta) +} + +func resourceBigtableAuthorizedViewDestroy(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + ctx := context.Background() + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return err + } + + instanceName := tpgresource.GetResourceNameFromSelfLink(d.Get("instance_name").(string)) + c, err := config.BigTableClientFactory(userAgent).NewAdminClient(project, instanceName) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + + defer c.Close() + + authorizedViewId := d.Get("name").(string) + tableId := d.Get("table_name").(string) + err = c.DeleteAuthorizedView(ctx, tableId, authorizedViewId) + if err != nil { + return fmt.Errorf("Error deleting authorized view. %s", err) + } + + d.SetId("") + + return nil +} + +func resourceBigtableAuthorizedViewImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "projects/(?P[^/]+)/instances/(?P[^/]+)/tables/(?P[^/]+)/authorizedViews/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/instances/{{instance_name}}/tables/{{table_name}}/authorizedViews/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func generateSubsetViewConfig(subsetView []interface{}) (*bigtable.SubsetViewConf, error) { + subsetViewConf := bigtable.SubsetViewConf{} + + if len(subsetView) == 0 { + return nil, fmt.Errorf("Error constructing SubsetViewConfig; empty subset_view list") + } + if subsetView[0] == nil { + return &subsetViewConf, nil + } + sv, ok := subsetView[0].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("Error constructing SubsetViewConfig; element in subset_view list has wrong type: %s", reflect.TypeOf(subsetView[0])) + } + if rowPrefixes, ok := sv["row_prefixes"]; ok { + for _, rowPrefix := range rowPrefixes.(*schema.Set).List() { + decodedRowPrefix, err := base64.StdEncoding.DecodeString(rowPrefix.(string)) + if err != nil { + return nil, err + } + subsetViewConf.AddRowPrefix(decodedRowPrefix) + } + } + if familySubsets, ok := sv["family_subsets"]; ok { + for _, familySubset := range familySubsets.(*schema.Set).List() { + familySubsetElement := familySubset.(map[string]interface{}) + familyName := familySubsetElement["family_name"].(string) + if qualifiers, ok := familySubsetElement["qualifiers"]; ok { + for _, qualifier := range qualifiers.(*schema.Set).List() { + decodedQualifier, err := base64.StdEncoding.DecodeString(qualifier.(string)) + if err != nil { + return nil, err + } + subsetViewConf.AddFamilySubsetQualifier(familyName, decodedQualifier) + } + } + if qualifierPrefixes, ok := familySubsetElement["qualifier_prefixes"]; ok { + for _, qualifierPrefix := range qualifierPrefixes.(*schema.Set).List() { + decodedQualifierPrefix, err := base64.StdEncoding.DecodeString(qualifierPrefix.(string)) + if err != nil { + return nil, err + } + subsetViewConf.AddFamilySubsetQualifierPrefix(familyName, decodedQualifierPrefix) + } + } + } + } + return &subsetViewConf, nil +} + +func flattenSubsetViewInfo(subsetViewInfo *bigtable.SubsetViewInfo) []map[string]interface{} { + subsetView := make([]map[string]interface{}, 1) + + rowPrefixes := []string{} + for _, prefix := range subsetViewInfo.RowPrefixes { + encodedRowPrefix := base64.StdEncoding.EncodeToString(prefix) + rowPrefixes = append(rowPrefixes, encodedRowPrefix) + } + familySubsets := []map[string]interface{}{} + for k, v := range subsetViewInfo.FamilySubsets { + familySubsetElement := make(map[string]interface{}) + familySubsetElement["family_name"] = k + qualifiers := []string{} + for _, qualifier := range v.Qualifiers { + encodedQualifier := base64.StdEncoding.EncodeToString(qualifier) + qualifiers = append(qualifiers, encodedQualifier) + } + if len(qualifiers) > 0 { + familySubsetElement["qualifiers"] = qualifiers + } + qualifierPrefixes := []string{} + for _, qualifierPrefix := range v.QualifierPrefixes { + encodedQualifierPrefix := base64.StdEncoding.EncodeToString(qualifierPrefix) + qualifierPrefixes = append(qualifierPrefixes, encodedQualifierPrefix) + } + if len(qualifierPrefixes) > 0 { + familySubsetElement["qualifier_prefixes"] = qualifierPrefixes + } + familySubsets = append(familySubsets, familySubsetElement) + } + subsetView[0] = make(map[string]interface{}) + if len(rowPrefixes) > 0 { + subsetView[0]["row_prefixes"] = rowPrefixes + } + if len(familySubsets) > 0 { + subsetView[0]["family_subsets"] = familySubsets + } + + return subsetView +} diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_internal_test.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_internal_test.go new file mode 100644 index 000000000000..7b431838426b --- /dev/null +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_internal_test.go @@ -0,0 +1,346 @@ +package bigtable + +import ( + "reflect" + "strings" + "testing" + + "cloud.google.com/go/bigtable" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func TestUnitBigtable_flattenSubsetViewInfo(t *testing.T) { + cases := map[string]struct { + sv bigtable.SubsetViewInfo + want []map[string]interface{} + orWant []map[string]interface{} + }{ + "empty subset view": { + sv: bigtable.SubsetViewInfo{}, + want: []map[string]interface{}{ + map[string]interface{}{}, + }, + orWant: nil, + }, + "subset view with row prefixes only": { + sv: bigtable.SubsetViewInfo{ + RowPrefixes: [][]byte{[]byte("row1"), []byte("row2")}, + }, + want: []map[string]interface{}{ + map[string]interface{}{ + "row_prefixes": []string{"cm93MQ==", "cm93Mg=="}, + }, + }, + orWant: nil, + }, + "subset view with family subsets only": { + sv: bigtable.SubsetViewInfo{ + FamilySubsets: map[string]bigtable.FamilySubset{ + "fam1": { + QualifierPrefixes: [][]byte{[]byte("col")}, + }, + "fam2": { + Qualifiers: [][]byte{[]byte("col1"), []byte("col2")}, + }, + }, + }, + want: []map[string]interface{}{ + map[string]interface{}{ + "family_subsets": []map[string]interface{}{ + map[string]interface{}{ + "family_name": "fam1", + "qualifier_prefixes": []string{"Y29s"}, + }, map[string]interface{}{ + "family_name": "fam2", + "qualifiers": []string{"Y29sMQ==", "Y29sMg=="}, + }, + }, + }, + }, + orWant: []map[string]interface{}{ + map[string]interface{}{ + "family_subsets": []map[string]interface{}{ + map[string]interface{}{ + "family_name": "fam2", + "qualifiers": []string{"Y29sMQ==", "Y29sMg=="}, + }, + map[string]interface{}{ + "family_name": "fam1", + "qualifier_prefixes": []string{"Y29s"}, + }, + }, + }, + }, + }, + "subset view with qualifiers only": { + sv: bigtable.SubsetViewInfo{ + FamilySubsets: map[string]bigtable.FamilySubset{ + "fam": { + Qualifiers: [][]byte{[]byte("col")}, + }, + }, + }, + want: []map[string]interface{}{ + map[string]interface{}{ + "family_subsets": []map[string]interface{}{ + map[string]interface{}{ + "family_name": "fam", + "qualifiers": []string{"Y29s"}, + }, + }, + }, + }, + orWant: nil, + }, + "subset view with qualifier prefixes only": { + sv: bigtable.SubsetViewInfo{ + FamilySubsets: map[string]bigtable.FamilySubset{ + "fam": { + QualifierPrefixes: [][]byte{[]byte("col")}, + }, + }, + }, + want: []map[string]interface{}{ + map[string]interface{}{ + "family_subsets": []map[string]interface{}{ + map[string]interface{}{ + "family_name": "fam", + "qualifier_prefixes": []string{"Y29s"}, + }, + }, + }, + }, + orWant: nil, + }, + "subset view with empty arrays": { + sv: bigtable.SubsetViewInfo{ + RowPrefixes: [][]byte{}, + FamilySubsets: map[string]bigtable.FamilySubset{}, + }, + want: []map[string]interface{}{ + map[string]interface{}{}, + }, + orWant: nil, + }, + } + + for tn, tc := range cases { + got := flattenSubsetViewInfo(&tc.sv) + if tc.want != nil && !(reflect.DeepEqual(got, tc.want) || reflect.DeepEqual(got, tc.orWant)) { + t.Errorf("bad: %s, got %q, want %q", tn, got, tc.want) + } + } +} + +func TestUnitBigtable_generateSubsetViewConfig(t *testing.T) { + cases := map[string]struct { + sv []interface{} + want *bigtable.SubsetViewConf + orWant *bigtable.SubsetViewConf + wantError string + }{ + "empty subset view list": { + sv: []interface{}{}, + want: nil, + orWant: nil, + wantError: "empty subset_view list", + }, + "subset view list with wrong type element": { + sv: []interface{}{ + "random-string", + }, + want: nil, + orWant: nil, + wantError: "element in subset_view list has wrong type", + }, + "subset view list with nil element": { + sv: []interface{}{ + nil, + }, + want: &bigtable.SubsetViewConf{}, + orWant: nil, + wantError: "", + }, + "subset view list with empty element": { + sv: []interface{}{ + map[string]interface{}{}, + }, + want: &bigtable.SubsetViewConf{}, + orWant: nil, + wantError: "", + }, + "subset view list with empty lists": { + sv: []interface{}{ + map[string]interface{}{ + "row_prefixes": schema.NewSet(schema.HashString, []interface{}{}), + "family_subsets": schema.NewSet(schema.HashResource(familySubsetSchemaElem), []interface{}{}), + }, + }, + want: &bigtable.SubsetViewConf{}, + orWant: nil, + wantError: "", + }, + "subset view list with row prefixes only": { + sv: []interface{}{ + map[string]interface{}{ + "row_prefixes": schema.NewSet(schema.HashString, []interface{}{"cm93MQ==", "cm93Mg=="}), + }, + }, + want: &bigtable.SubsetViewConf{ + RowPrefixes: [][]byte{[]byte("row1"), []byte("row2")}, + }, + orWant: &bigtable.SubsetViewConf{ + RowPrefixes: [][]byte{[]byte("row2"), []byte("row1")}, + }, + wantError: "", + }, + "subset view list with invalid row prefixes encoding": { + sv: []interface{}{ + map[string]interface{}{ + "row_prefixes": schema.NewSet(schema.HashString, []interface{}{"#"}), + }, + }, + want: nil, + orWant: nil, + wantError: "illegal base64 data", + }, + "subset view list with empty row prefixes element": { + sv: []interface{}{ + map[string]interface{}{ + "row_prefixes": schema.NewSet(schema.HashString, []interface{}{""}), + }, + }, + want: &bigtable.SubsetViewConf{ + RowPrefixes: [][]byte{[]byte("")}, + }, + orWant: nil, + wantError: "", + }, + "subset view list with family subsets only": { + sv: []interface{}{ + map[string]interface{}{ + "family_subsets": schema.NewSet(schema.HashResource(familySubsetSchemaElem), []interface{}{ + map[string]interface{}{ + "family_name": "fam1", + "qualifier_prefixes": schema.NewSet(schema.HashString, []interface{}{"Y29s"}), + }, map[string]interface{}{ + "family_name": "fam2", + "qualifiers": schema.NewSet(schema.HashString, []interface{}{"Y29sMQ==", "Y29sMg=="}), + }, + }), + }, + }, + want: &bigtable.SubsetViewConf{ + FamilySubsets: map[string]bigtable.FamilySubset{ + "fam1": { + QualifierPrefixes: [][]byte{[]byte("col")}, + }, + "fam2": { + Qualifiers: [][]byte{[]byte("col1"), []byte("col2")}, + }, + }, + }, + orWant: &bigtable.SubsetViewConf{ + FamilySubsets: map[string]bigtable.FamilySubset{ + "fam1": { + QualifierPrefixes: [][]byte{[]byte("col")}, + }, + "fam2": { + Qualifiers: [][]byte{[]byte("col2"), []byte("col1")}, + }, + }, + }, + wantError: "", + }, + "subset view list with qualifiers only": { + sv: []interface{}{ + map[string]interface{}{ + "family_subsets": schema.NewSet(schema.HashResource(familySubsetSchemaElem), []interface{}{ + map[string]interface{}{ + "family_name": "fam", + "qualifiers": schema.NewSet(schema.HashString, []interface{}{"Y29sMQ==", "Y29sMg=="}), + }, + }), + }, + }, + want: &bigtable.SubsetViewConf{ + FamilySubsets: map[string]bigtable.FamilySubset{ + "fam": { + Qualifiers: [][]byte{[]byte("col1"), []byte("col2")}, + }, + }, + }, + orWant: &bigtable.SubsetViewConf{ + FamilySubsets: map[string]bigtable.FamilySubset{ + "fam": { + Qualifiers: [][]byte{[]byte("col2"), []byte("col1")}, + }, + }, + }, + wantError: "", + }, + "subset view list with qualifier prefixes only": { + sv: []interface{}{ + map[string]interface{}{ + "family_subsets": schema.NewSet(schema.HashResource(familySubsetSchemaElem), []interface{}{ + map[string]interface{}{ + "family_name": "fam", + "qualifier_prefixes": schema.NewSet(schema.HashString, []interface{}{"Y29s"}), + }, + }), + }, + }, + want: &bigtable.SubsetViewConf{ + FamilySubsets: map[string]bigtable.FamilySubset{ + "fam": { + QualifierPrefixes: [][]byte{[]byte("col")}, + }, + }, + }, + orWant: nil, + wantError: "", + }, + "subset view list with invalid qualifiers encoding": { + sv: []interface{}{ + map[string]interface{}{ + "family_subsets": schema.NewSet(schema.HashResource(familySubsetSchemaElem), []interface{}{ + map[string]interface{}{ + "family_name": "fam", + "qualifiers": schema.NewSet(schema.HashString, []interface{}{"#"}), + }, + }), + }, + }, + want: nil, + orWant: nil, + wantError: "illegal base64 data", + }, + "subset view list with invalid qualifier prefixes encoding": { + sv: []interface{}{ + map[string]interface{}{ + "family_subsets": schema.NewSet(schema.HashResource(familySubsetSchemaElem), []interface{}{ + map[string]interface{}{ + "family_name": "fam", + "qualifier_prefixes": schema.NewSet(schema.HashString, []interface{}{"#"}), + }, + }), + }, + }, + want: nil, + orWant: nil, + wantError: "illegal base64 data", + }, + } + + for tn, tc := range cases { + got, gotErr := generateSubsetViewConfig(tc.sv) + if (gotErr != nil && tc.wantError == "") || + (gotErr == nil && tc.wantError != "") || + (gotErr != nil && !strings.Contains(gotErr.Error(), tc.wantError)) { + t.Errorf("bad error: %s, got %q, want %q", tn, gotErr, tc.wantError) + } + if tc.want != nil && !(reflect.DeepEqual(got, tc.want) || reflect.DeepEqual(got, tc.orWant)) { + t.Errorf("bad: %s, got %q, want %q", tn, got, tc.want) + } + } +} diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_test.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_test.go new file mode 100644 index 000000000000..15e87531b051 --- /dev/null +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_test.go @@ -0,0 +1,449 @@ +package bigtable_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccBigtableAuthorizedView_basic(t *testing.T) { + // bigtable instance does not use the shared HTTP client, this test creates an instance + acctest.SkipIfVcr(t) + t.Parallel() + + instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + tableName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + authorizedViewName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + familyName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckBigtableTableDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigtableAuthorizedViewInvalidDeletionProtection(instanceName, tableName, authorizedViewName, familyName), + ExpectError: regexp.MustCompile(".*expected deletion_protection to be one of.*"), + }, + { + Config: testAccBigtableAuthorizedViewInvalidSubsetView(instanceName, tableName, authorizedViewName, familyName), + ExpectError: regexp.MustCompile(".*subset_view must be specified for authorized view.*"), + }, + { + Config: testAccBigtableAuthorizedViewInvalidEncoding(instanceName, tableName, authorizedViewName, familyName), + ExpectError: regexp.MustCompile(".*illegal base64 data.*"), + }, + { + Config: testAccBigtableAuthorizedViewBasic(instanceName, tableName, authorizedViewName, familyName), + }, + { + ResourceName: "google_bigtable_authorized_view.authorized_view", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBigtableAuthorizedViewWithRowPrefixesOnly(instanceName, tableName, authorizedViewName, familyName), + }, + { + ResourceName: "google_bigtable_authorized_view.authorized_view", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccBigtableAuthorizedView_update(t *testing.T) { + // bigtable instance does not use the shared HTTP client, this test creates an instance + acctest.SkipIfVcr(t) + t.Parallel() + + instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + tableName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + authorizedViewName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + familyName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckBigtableTableDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigtableAuthorizedViewWithQualifiersOnly(instanceName, tableName, authorizedViewName, familyName), + }, + { + ResourceName: "google_bigtable_authorized_view.authorized_view", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBigtableAuthorizedViewWithFamilySubsetsOnly(instanceName, tableName, authorizedViewName, familyName), + }, + { + ResourceName: "google_bigtable_authorized_view.authorized_view", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"subset_view.0.family_subsets"}, // The order of the two family subsets is indeterministic. + }, + }, + }) +} + +func TestAccBigtableAuthorizedView_destroy(t *testing.T) { + // bigtable instance does not use the shared HTTP client, this test creates an instance + acctest.SkipIfVcr(t) + t.Parallel() + + instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + tableName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + authorizedViewName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + familyName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckBigtableTableDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigtableAuthorizedViewWithQualifierPrefixesOnly(instanceName, tableName, authorizedViewName, familyName), + }, + { + ResourceName: "google_bigtable_authorized_view.authorized_view", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBigtableAuthorizedViewDestroy(instanceName, tableName, familyName), + }, + { + ResourceName: "google_bigtable_table.table", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckBigtableAuthorizedViewDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + var ctx = context.Background() + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_bigtable_authorized_view" { + continue + } + + config := acctest.GoogleProviderConfig(t) + c, err := config.BigTableClientFactory(config.UserAgent).NewAdminClient(config.Project, rs.Primary.Attributes["instance_name"]) + if err != nil { + // The instance is already gone + return nil + } + + _, err = c.AuthorizedViewInfo(ctx, rs.Primary.Attributes["table_name"], rs.Primary.Attributes["name"]) + if err == nil { + return fmt.Errorf("AuthorizedView still present. Found %s in %s.", rs.Primary.Attributes["name"], rs.Primary.Attributes["table_name"]) + } + + c.Close() + } + + return nil + } +} + +func testAccBigtableAuthorizedViewInvalidDeletionProtection(instanceName, tableName, authorizedViewName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } +} +resource "google_bigtable_authorized_view" "authorized_view" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + table_name = google_bigtable_table.table.name + deletion_protection = "random" + subset_view {} +} +`, instanceName, instanceName, tableName, familyName, authorizedViewName) +} + +func testAccBigtableAuthorizedViewInvalidSubsetView(instanceName, tableName, authorizedViewName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } +} +resource "google_bigtable_authorized_view" "authorized_view" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + table_name = google_bigtable_table.table.name + deletion_protection = "UNPROTECTED" +} +`, instanceName, instanceName, tableName, familyName, authorizedViewName) +} + +func testAccBigtableAuthorizedViewInvalidEncoding(instanceName, tableName, authorizedViewName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } +} +resource "google_bigtable_authorized_view" "authorized_view" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + table_name = google_bigtable_table.table.name + deletion_protection = "UNPROTECTED" + subset_view { + row_prefixes = ["#"] + } +} +`, instanceName, instanceName, tableName, familyName, authorizedViewName) +} + +func testAccBigtableAuthorizedViewBasic(instanceName, tableName, authorizedViewName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } +} + +resource "google_bigtable_authorized_view" "authorized_view" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + table_name = google_bigtable_table.table.name + deletion_protection = "UNPROTECTED" + subset_view {} +} +`, instanceName, instanceName, tableName, familyName, authorizedViewName) +} + +func testAccBigtableAuthorizedViewWithRowPrefixesOnly(instanceName, tableName, authorizedViewName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } +} + +resource "google_bigtable_authorized_view" "authorized_view" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + table_name = google_bigtable_table.table.name + deletion_protection = "UNPROTECTED" + + subset_view { + row_prefixes = [base64encode("row1#"), base64encode("row2#")] + } +} +`, instanceName, instanceName, tableName, familyName, authorizedViewName) +} + +func testAccBigtableAuthorizedViewWithFamilySubsetsOnly(instanceName, tableName, authorizedViewName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } + column_family { + family = "%s-second" + } +} + +resource "google_bigtable_authorized_view" "authorized_view" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + table_name = google_bigtable_table.table.name + deletion_protection = "UNPROTECTED" + + subset_view { + family_subsets { + family_name = "%s" + qualifiers = [base64encode("qualifier"), base64encode("qualifier-second")] + } + family_subsets { + family_name = "%s-second" + qualifier_prefixes = [""] + } + } +} +`, instanceName, instanceName, tableName, familyName, familyName, authorizedViewName, familyName, familyName) +} + +func testAccBigtableAuthorizedViewWithQualifiersOnly(instanceName, tableName, authorizedViewName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } +} + +resource "google_bigtable_authorized_view" "authorized_view" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + table_name = google_bigtable_table.table.name + deletion_protection = "UNPROTECTED" + + subset_view { + family_subsets { + family_name = "%s" + qualifiers = [base64encode("qualifier")] + } + } +} +`, instanceName, instanceName, tableName, familyName, authorizedViewName, familyName) +} + +func testAccBigtableAuthorizedViewWithQualifierPrefixesOnly(instanceName, tableName, authorizedViewName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } +} + +resource "google_bigtable_authorized_view" "authorized_view" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + table_name = google_bigtable_table.table.name + deletion_protection = "UNPROTECTED" + + subset_view { + family_subsets { + family_name = "%s" + qualifier_prefixes = [""] + } + } +} +`, instanceName, instanceName, tableName, familyName, authorizedViewName, familyName) +} + +func testAccBigtableAuthorizedViewDestroy(instanceName, tableName, familyName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + } + deletion_protection = false +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = google_bigtable_instance.instance.id + column_family { + family = "%s" + } +} +`, instanceName, instanceName, tableName, familyName) +} diff --git a/mmv1/third_party/terraform/website/docs/r/bigtable_authorized_view.html.markdown b/mmv1/third_party/terraform/website/docs/r/bigtable_authorized_view.html.markdown new file mode 100644 index 000000000000..b69ad6f4b349 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/r/bigtable_authorized_view.html.markdown @@ -0,0 +1,161 @@ +--- +subcategory: "Cloud Bigtable" +description: |- + Creates a Google Cloud Bigtable authorized view inside a table. +--- + +# google_bigtable_authorized_view + +Creates a Google Cloud Bigtable authorized view inside a table. For more information see +[the official documentation](https://cloud.google.com/bigtable/) and +[API](https://cloud.google.com/bigtable/docs/go/reference). + +-> **Note:** It is strongly recommended to set `lifecycle { prevent_destroy = true }` +on authorized views in order to prevent accidental data loss. See +[Terraform docs](https://www.terraform.io/docs/configuration/resources.html#prevent_destroy) +for more information on lifecycle parameters. + + +## Example Usage + +```hcl +resource "google_bigtable_instance" "instance" { + name = "tf-instance" + + cluster { + cluster_id = "tf-instance-cluster" + zone = "us-central1-b" + num_nodes = 3 + storage_type = "HDD" + } + + lifecycle { + prevent_destroy = true + } +} + +resource "google_bigtable_table" "table" { + name = "tf-table" + instance_name = google_bigtable_instance.instance.name + split_keys = ["a", "b", "c"] + + lifecycle { + prevent_destroy = true + } + + column_family { + family = "family-first" + } + + column_family { + family = "family-second" + } + + change_stream_retention = "24h0m0s" +} + +resource "google_bigtable_authorized_view" "authorized_view" { + name = "tf-authorized-view" + instance_name = google_bigtable_instance.instance.name + table_name = google_bigtable_table.table.name + + lifecycle { + prevent_destroy = true + } + + subset_view { + row_prefixes = [base64encode("prefix#)] + + family_subsets { + family_name = "family-first" + qualifiers = [base64encode("qualifier"), base64encode("qualifier-second")] + } + + family_subsets { + family_name = "family-second" + qualifier_prefixes = [""] + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the authorized view. Must be 1-50 characters and must only contain hyphens, underscores, periods, letters and numbers. + +* `project` - (Optional) The ID of the project in which the resource belongs. If it + is not provided, the provider project is used. + +* `instance_name` - (Required) The name of the Bigtable instance in which the authorized view belongs. + +* `table_name` - (Required) The name of the Bigtable table in which the authorized view belongs. + +* `column_family` - (Optional) A group of columns within a table which share a common configuration. This can be specified multiple times. Structure is documented below. + +* `deletion_protection` - (Optional) A field to make the table protected against data loss i.e. when set to PROTECTED, deleting the table, the column families in the table, and the instance containing the table would be prohibited. +If not provided, currently deletion protection will be set to UNPROTECTED as it is the API default value. Note this field configs the deletion protection provided by the API in the backend, and should not be confused with Terraform-side deletion protection. + +* `subset_view` - (Optional) An AuthorizedView permitting access to an explicit subset of a Table. Structure is documented below. + +----- + +`subset_view` supports the following arguments: + +* `row_prefixes` - (Optional) A list of Base64-encoded row prefixes to be included in the authorized view. To provide access to all rows, include the empty string as a prefix (""). + +* `family_subsets` - (Optional) A group of column family subsets to be included in the authorized view. This can be specified multiple times. Structure is documented below. + +----- + +`family_subsets` supports the following arguments: + +* `family_name` - (Required) Name of the column family to be included in the authorized view. The specified column family must exist in the parent table of this authorized view. + +* `qualifiers` - (Optional) A list of Base64-encoded individual exact column qualifiers of the column family to be included in the authorized view. + +* `qualifier_prefixes` - (Optional) A list of Base64-encoded prefixes for qualifiers of the column family to be included in the authorized view. +Every qualifier starting with one of these prefixes is included in the authorized view. To provide access to all qualifiers, include the empty string as a prefix (""). + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are +exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/instances/{{instance_name}}/tables/{{table_name}}/authorizedViews/{{name}}` + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. + +## Import + +Bigtable Authorized Views can be imported using any of these accepted formats: + +* `projects/{{project}}/instances/{{instance_name}}/tables/{{table_name}}/authorizedViews/{{name}}` +* `{{project}}/{{instance_name}}/{{table_name}}/{{name}}` +* `{{instance_name}}/{{table_name}}/{{name}}` + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Bigtable Authorized Views using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/instances/{{instance_name}}/tables/{{table_name}}/authorizedViews/{{name}}" + to = google_bigtable_authorized_view.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), Bigtable Authorized Views can be imported using one of the formats above. For example: + +``` +$ terraform import google_bigtable_authorized_view.default projects/{{project}}/instances/{{instance_name}}/tables/{{table_name}}/authorizedViews/{{name}} +$ terraform import google_bigtable_authorized_view.default {{project}}/{{instance_name}}/{{table_name}}/{{name}} +$ terraform import google_bigtable_authorized_view.default {{instance_name}}/{{table_name}}/{{name}} +``` + +