diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 6610882f836..2c3ef72011b 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-java:latest - digest: sha256:04f254abfe5f47fe73ae6f91d68d55c3b76e722a4943066c3bb0ce03573b4ad9 -# created: 2022-07-18T21:44:23.94208526Z + digest: sha256:f14e3fefe8e361e85752bd9890c8e56f2fe25f1e89cbb9597e4e3c7a429203a3 + diff --git a/.github/release-please.yml b/.github/release-please.yml index 21f4644e497..d0d8ce428c2 100644 --- a/.github/release-please.yml +++ b/.github/release-please.yml @@ -22,3 +22,7 @@ branches: bumpMinorPreMajor: true handleGHRelease: true branch: 6.14.x + - releaseType: java-yoshi + bumpMinorPreMajor: true + handleGHRelease: true + branch: 6.23.x diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index e2ce8b98e1d..87ddc5b58dc 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -84,8 +84,6 @@ branchProtectionRules: requiresCodeOwnerReviews: true requiresStrictStatusChecks: false requiredStatusCheckContexts: - - dependencies (8) - - dependencies (11) - lint - clirr - units (8) @@ -95,6 +93,20 @@ branchProtectionRules: - checkstyle - compile (8) - compile (11) + - pattern: 6.23.x + isAdminEnforced: true + requiredApprovingReviewCount: 1 + requiresCodeOwnerReviews: true + requiresStrictStatusChecks: false + requiredStatusCheckContexts: + - lint + - units (8) + - units (11) + - 'Kokoro - Test: Integration' + - cla/google + - checkstyle + - compile (8) + - compile (11) permissionRules: - team: yoshi-admins permission: admin diff --git a/.kokoro/release/publish_javadoc.sh b/.kokoro/release/publish_javadoc.sh index 40c2797223b..2a5ac207734 100755 --- a/.kokoro/release/publish_javadoc.sh +++ b/.kokoro/release/publish_javadoc.sh @@ -28,7 +28,7 @@ fi pushd $(dirname "$0")/../../ # install docuploader package -python3 -m pip install gcp-docuploader +python3 -m pip install --require-hashes -r .kokoro/requirements.txt # compile all packages mvn clean install -B -q -DskipTests=true diff --git a/.kokoro/release/publish_javadoc11.sh b/.kokoro/release/publish_javadoc11.sh index 2bbf2cb74ad..fa58188fb4e 100755 --- a/.kokoro/release/publish_javadoc11.sh +++ b/.kokoro/release/publish_javadoc11.sh @@ -28,7 +28,7 @@ fi pushd $(dirname "$0")/../../ # install docuploader package -python3 -m pip install gcp-docuploader +python3 -m pip install --require-hashes -r .kokoro/requirements.txt # compile all packages mvn clean install -B -q -DskipTests=true diff --git a/.kokoro/release/stage.sh b/.kokoro/release/stage.sh index 1dba8de1085..61e714d6ba5 100755 --- a/.kokoro/release/stage.sh +++ b/.kokoro/release/stage.sh @@ -16,7 +16,8 @@ set -eo pipefail # Start the releasetool reporter -python3 -m pip install gcp-releasetool +requirementsFile=$(realpath $(dirname "${BASH_SOURCE[0]}")/../requirements.txt) +python3 -m pip install --require-hashes -r $requirementsFile python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script source $(dirname "$0")/common.sh diff --git a/.kokoro/requirements.in b/.kokoro/requirements.in new file mode 100644 index 00000000000..cfdc2e7ed95 --- /dev/null +++ b/.kokoro/requirements.in @@ -0,0 +1,31 @@ +gcp-docuploader==0.6.3 +google-crc32c==1.3.0 +googleapis-common-protos==1.56.3 +gcp-releasetool==1.8.7 +cachetools==4.2.4 +cffi==1.15.1 +jeepney==0.7.1 +jinja2==3.0.3 +markupsafe==2.0.1 +keyring==23.4.1 +packaging==21.3 +protobuf==3.19.5 +pyjwt==2.4.0 +pyparsing==3.0.9 +pycparser==2.21 +pyperclip==1.8.2 +python-dateutil==2.8.2 +requests==2.27.1 +importlib-metadata==4.8.3 +zipp==3.6.0 +google_api_core==2.8.2 +google-cloud-storage==2.0.0 +google-cloud-core==2.3.1 +typing-extensions==4.1.1 +urllib3==1.26.12 +zipp==3.6.0 +rsa==4.9 +six==1.16.0 +attrs==22.1.0 +google-auth==2.11.0 +idna==3.4 \ No newline at end of file diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt new file mode 100644 index 00000000000..170f1c63abb --- /dev/null +++ b/.kokoro/requirements.txt @@ -0,0 +1,452 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --allow-unsafe --generate-hashes requirements.in +# +attrs==22.1.0 \ + --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \ + --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c + # via + # -r requirements.in + # gcp-releasetool +cachetools==4.2.4 \ + --hash=sha256:89ea6f1b638d5a73a4f9226be57ac5e4f399d22770b92355f92dcb0f7f001693 \ + --hash=sha256:92971d3cb7d2a97efff7c7bb1657f21a8f5fb309a37530537c71b1774189f2d1 + # via + # -r requirements.in + # google-auth +certifi==2022.9.14 \ + --hash=sha256:36973885b9542e6bd01dea287b2b4b3b21236307c56324fcc3f1160f2d655ed5 \ + --hash=sha256:e232343de1ab72c2aa521b625c80f699e356830fd0e2c620b465b304b17b0516 + # via requests +cffi==1.15.1 \ + --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ + --hash=sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef \ + --hash=sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104 \ + --hash=sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426 \ + --hash=sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405 \ + --hash=sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375 \ + --hash=sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a \ + --hash=sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e \ + --hash=sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc \ + --hash=sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf \ + --hash=sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185 \ + --hash=sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497 \ + --hash=sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3 \ + --hash=sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35 \ + --hash=sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c \ + --hash=sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83 \ + --hash=sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21 \ + --hash=sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca \ + --hash=sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984 \ + --hash=sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac \ + --hash=sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd \ + --hash=sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee \ + --hash=sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a \ + --hash=sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2 \ + --hash=sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192 \ + --hash=sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7 \ + --hash=sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585 \ + --hash=sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f \ + --hash=sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e \ + --hash=sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27 \ + --hash=sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b \ + --hash=sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e \ + --hash=sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e \ + --hash=sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d \ + --hash=sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c \ + --hash=sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415 \ + --hash=sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82 \ + --hash=sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02 \ + --hash=sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314 \ + --hash=sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325 \ + --hash=sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c \ + --hash=sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3 \ + --hash=sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914 \ + --hash=sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045 \ + --hash=sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d \ + --hash=sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9 \ + --hash=sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5 \ + --hash=sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2 \ + --hash=sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c \ + --hash=sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3 \ + --hash=sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2 \ + --hash=sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8 \ + --hash=sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d \ + --hash=sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d \ + --hash=sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9 \ + --hash=sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162 \ + --hash=sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76 \ + --hash=sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4 \ + --hash=sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e \ + --hash=sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9 \ + --hash=sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6 \ + --hash=sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b \ + --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ + --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 + # via + # -r requirements.in + # cryptography +charset-normalizer==2.0.12 \ + --hash=sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597 \ + --hash=sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df + # via requests +click==8.0.4 \ + --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ + --hash=sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb + # via + # gcp-docuploader + # gcp-releasetool +colorlog==6.7.0 \ + --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ + --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 + # via gcp-docuploader +cryptography==38.0.1 \ + --hash=sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a \ + --hash=sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f \ + --hash=sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0 \ + --hash=sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407 \ + --hash=sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7 \ + --hash=sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6 \ + --hash=sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153 \ + --hash=sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750 \ + --hash=sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad \ + --hash=sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6 \ + --hash=sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b \ + --hash=sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5 \ + --hash=sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a \ + --hash=sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d \ + --hash=sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d \ + --hash=sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294 \ + --hash=sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0 \ + --hash=sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a \ + --hash=sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac \ + --hash=sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61 \ + --hash=sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013 \ + --hash=sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e \ + --hash=sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb \ + --hash=sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9 \ + --hash=sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd \ + --hash=sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818 + # via + # gcp-releasetool + # secretstorage +gcp-docuploader==0.6.3 \ + --hash=sha256:ba8c9d76b3bbac54b0311c503a373b00edc2dc02d6d54ea9507045adb8e870f7 \ + --hash=sha256:c0f5aaa82ce1854a386197e4e359b120ad6d4e57ae2c812fce42219a3288026b + # via -r requirements.in +gcp-releasetool==1.8.7 \ + --hash=sha256:3d2a67c9db39322194afb3b427e9cb0476ce8f2a04033695f0aeb63979fc2b37 \ + --hash=sha256:5e4d28f66e90780d77f3ecf1e9155852b0c3b13cbccb08ab07e66b2357c8da8d + # via -r requirements.in +google-api-core==2.8.2 \ + --hash=sha256:06f7244c640322b508b125903bb5701bebabce8832f85aba9335ec00b3d02edc \ + --hash=sha256:93c6a91ccac79079ac6bbf8b74ee75db970cc899278b97d53bc012f35908cf50 + # via + # -r requirements.in + # google-cloud-core + # google-cloud-storage +google-auth==2.11.0 \ + --hash=sha256:be62acaae38d0049c21ca90f27a23847245c9f161ff54ede13af2cb6afecbac9 \ + --hash=sha256:ed65ecf9f681832298e29328e1ef0a3676e3732b2e56f41532d45f70a22de0fb + # via + # -r requirements.in + # gcp-releasetool + # google-api-core + # google-cloud-core + # google-cloud-storage +google-cloud-core==2.3.1 \ + --hash=sha256:113ba4f492467d5bd442c8d724c1a25ad7384045c3178369038840ecdd19346c \ + --hash=sha256:34334359cb04187bdc80ddcf613e462dfd7a3aabbc3fe4d118517ab4b9303d53 + # via + # -r requirements.in + # google-cloud-storage +google-cloud-storage==2.0.0 \ + --hash=sha256:a57a15aead0f9dfbd4381f1bfdbe8bf89818a4bd75bab846cafcefb2db846c47 \ + --hash=sha256:ec4be60bb223a3a960f0d01697d849b86d91cad815a84915a32ed3635e93a5e7 + # via + # -r requirements.in + # gcp-docuploader +google-crc32c==1.3.0 \ + --hash=sha256:04e7c220798a72fd0f08242bc8d7a05986b2a08a0573396187fd32c1dcdd58b3 \ + --hash=sha256:05340b60bf05b574159e9bd940152a47d38af3fb43803ffe71f11d704b7696a6 \ + --hash=sha256:12674a4c3b56b706153a358eaa1018c4137a5a04635b92b4652440d3d7386206 \ + --hash=sha256:127f9cc3ac41b6a859bd9dc4321097b1a4f6aa7fdf71b4f9227b9e3ebffb4422 \ + --hash=sha256:13af315c3a0eec8bb8b8d80b8b128cb3fcd17d7e4edafc39647846345a3f003a \ + --hash=sha256:1926fd8de0acb9d15ee757175ce7242e235482a783cd4ec711cc999fc103c24e \ + --hash=sha256:226f2f9b8e128a6ca6a9af9b9e8384f7b53a801907425c9a292553a3a7218ce0 \ + --hash=sha256:276de6273eb074a35bc598f8efbc00c7869c5cf2e29c90748fccc8c898c244df \ + --hash=sha256:318f73f5484b5671f0c7f5f63741ab020a599504ed81d209b5c7129ee4667407 \ + --hash=sha256:3bbce1be3687bbfebe29abdb7631b83e6b25da3f4e1856a1611eb21854b689ea \ + --hash=sha256:42ae4781333e331a1743445931b08ebdad73e188fd554259e772556fc4937c48 \ + --hash=sha256:58be56ae0529c664cc04a9c76e68bb92b091e0194d6e3c50bea7e0f266f73713 \ + --hash=sha256:5da2c81575cc3ccf05d9830f9e8d3c70954819ca9a63828210498c0774fda1a3 \ + --hash=sha256:6311853aa2bba4064d0c28ca54e7b50c4d48e3de04f6770f6c60ebda1e975267 \ + --hash=sha256:650e2917660e696041ab3dcd7abac160b4121cd9a484c08406f24c5964099829 \ + --hash=sha256:6a4db36f9721fdf391646685ecffa404eb986cbe007a3289499020daf72e88a2 \ + --hash=sha256:779cbf1ce375b96111db98fca913c1f5ec11b1d870e529b1dc7354b2681a8c3a \ + --hash=sha256:7f6fe42536d9dcd3e2ffb9d3053f5d05221ae3bbcefbe472bdf2c71c793e3183 \ + --hash=sha256:891f712ce54e0d631370e1f4997b3f182f3368179198efc30d477c75d1f44942 \ + --hash=sha256:95c68a4b9b7828ba0428f8f7e3109c5d476ca44996ed9a5f8aac6269296e2d59 \ + --hash=sha256:96a8918a78d5d64e07c8ea4ed2bc44354e3f93f46a4866a40e8db934e4c0d74b \ + --hash=sha256:9c3cf890c3c0ecfe1510a452a165431b5831e24160c5fcf2071f0f85ca5a47cd \ + --hash=sha256:9f58099ad7affc0754ae42e6d87443299f15d739b0ce03c76f515153a5cda06c \ + --hash=sha256:a0b9e622c3b2b8d0ce32f77eba617ab0d6768b82836391e4f8f9e2074582bf02 \ + --hash=sha256:a7f9cbea4245ee36190f85fe1814e2d7b1e5f2186381b082f5d59f99b7f11328 \ + --hash=sha256:bab4aebd525218bab4ee615786c4581952eadc16b1ff031813a2fd51f0cc7b08 \ + --hash=sha256:c124b8c8779bf2d35d9b721e52d4adb41c9bfbde45e6a3f25f0820caa9aba73f \ + --hash=sha256:c9da0a39b53d2fab3e5467329ed50e951eb91386e9d0d5b12daf593973c3b168 \ + --hash=sha256:ca60076c388728d3b6ac3846842474f4250c91efbfe5afa872d3ffd69dd4b318 \ + --hash=sha256:cb6994fff247987c66a8a4e550ef374671c2b82e3c0d2115e689d21e511a652d \ + --hash=sha256:d1c1d6236feab51200272d79b3d3e0f12cf2cbb12b208c835b175a21efdb0a73 \ + --hash=sha256:dd7760a88a8d3d705ff562aa93f8445ead54f58fd482e4f9e2bafb7e177375d4 \ + --hash=sha256:dda4d8a3bb0b50f540f6ff4b6033f3a74e8bf0bd5320b70fab2c03e512a62812 \ + --hash=sha256:e0f1ff55dde0ebcfbef027edc21f71c205845585fffe30d4ec4979416613e9b3 \ + --hash=sha256:e7a539b9be7b9c00f11ef16b55486141bc2cdb0c54762f84e3c6fc091917436d \ + --hash=sha256:eb0b14523758e37802f27b7f8cd973f5f3d33be7613952c0df904b68c4842f0e \ + --hash=sha256:ed447680ff21c14aaceb6a9f99a5f639f583ccfe4ce1a5e1d48eb41c3d6b3217 \ + --hash=sha256:f52a4ad2568314ee713715b1e2d79ab55fab11e8b304fd1462ff5cccf4264b3e \ + --hash=sha256:fbd60c6aaa07c31d7754edbc2334aef50601b7f1ada67a96eb1eb57c7c72378f \ + --hash=sha256:fc28e0db232c62ca0c3600884933178f0825c99be4474cdd645e378a10588125 \ + --hash=sha256:fe31de3002e7b08eb20823b3735b97c86c5926dd0581c7710a680b418a8709d4 \ + --hash=sha256:fec221a051150eeddfdfcff162e6db92c65ecf46cb0f7bb1bf812a1520ec026b \ + --hash=sha256:ff71073ebf0e42258a42a0b34f2c09ec384977e7f6808999102eedd5b49920e3 + # via + # -r requirements.in + # google-resumable-media +google-resumable-media==2.3.3 \ + --hash=sha256:27c52620bd364d1c8116eaac4ea2afcbfb81ae9139fb3199652fcac1724bfb6c \ + --hash=sha256:5b52774ea7a829a8cdaa8bd2d4c3d4bc660c91b30857ab2668d0eb830f4ea8c5 + # via google-cloud-storage +googleapis-common-protos==1.56.3 \ + --hash=sha256:6f1369b58ed6cf3a4b7054a44ebe8d03b29c309257583a2bbdc064cd1e4a1442 \ + --hash=sha256:87955d7b3a73e6e803f2572a33179de23989ebba725e05ea42f24838b792e461 + # via + # -r requirements.in + # google-api-core +idna==3.4 \ + --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ + --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 + # via + # -r requirements.in + # requests +importlib-metadata==4.8.3 \ + --hash=sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e \ + --hash=sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668 + # via + # -r requirements.in + # keyring +jeepney==0.7.1 \ + --hash=sha256:1b5a0ea5c0e7b166b2f5895b91a08c14de8915afda4407fb5022a195224958ac \ + --hash=sha256:fa9e232dfa0c498bd0b8a3a73b8d8a31978304dcef0515adc859d4e096f96f4f + # via + # -r requirements.in + # keyring + # secretstorage +jinja2==3.0.3 \ + --hash=sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8 \ + --hash=sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7 + # via + # -r requirements.in + # gcp-releasetool +keyring==23.4.1 \ + --hash=sha256:17e49fb0d6883c2b4445359434dba95aad84aabb29bbff044ad0ed7100232eca \ + --hash=sha256:89cbd74d4683ed164c8082fb38619341097741323b3786905c6dac04d6915a55 + # via + # -r requirements.in + # gcp-releasetool +markupsafe==2.0.1 \ + --hash=sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298 \ + --hash=sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64 \ + --hash=sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b \ + --hash=sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194 \ + --hash=sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567 \ + --hash=sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff \ + --hash=sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724 \ + --hash=sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74 \ + --hash=sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646 \ + --hash=sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35 \ + --hash=sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6 \ + --hash=sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a \ + --hash=sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6 \ + --hash=sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad \ + --hash=sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26 \ + --hash=sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38 \ + --hash=sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac \ + --hash=sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7 \ + --hash=sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6 \ + --hash=sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047 \ + --hash=sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75 \ + --hash=sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f \ + --hash=sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b \ + --hash=sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135 \ + --hash=sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8 \ + --hash=sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a \ + --hash=sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a \ + --hash=sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1 \ + --hash=sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9 \ + --hash=sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864 \ + --hash=sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914 \ + --hash=sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee \ + --hash=sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f \ + --hash=sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18 \ + --hash=sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8 \ + --hash=sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2 \ + --hash=sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d \ + --hash=sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b \ + --hash=sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b \ + --hash=sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86 \ + --hash=sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6 \ + --hash=sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f \ + --hash=sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb \ + --hash=sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833 \ + --hash=sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28 \ + --hash=sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e \ + --hash=sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415 \ + --hash=sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902 \ + --hash=sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f \ + --hash=sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d \ + --hash=sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9 \ + --hash=sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d \ + --hash=sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145 \ + --hash=sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066 \ + --hash=sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c \ + --hash=sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1 \ + --hash=sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a \ + --hash=sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207 \ + --hash=sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f \ + --hash=sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53 \ + --hash=sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd \ + --hash=sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134 \ + --hash=sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85 \ + --hash=sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9 \ + --hash=sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5 \ + --hash=sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94 \ + --hash=sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509 \ + --hash=sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51 \ + --hash=sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872 + # via + # -r requirements.in + # jinja2 +packaging==21.3 \ + --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ + --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 + # via + # -r requirements.in + # gcp-releasetool +protobuf==3.19.5 \ + --hash=sha256:1867f93b06a183f87696871bb8d1e99ee71dbb69d468ce1f0cc8bf3d30f982f3 \ + --hash=sha256:3c4160b601220627f7e91154e572baf5e161a9c3f445a8242d536ee3d0b7b17c \ + --hash=sha256:4ee2af7051d3b10c8a4fe6fd1a2c69f201fea36aeee7086cf202a692e1b99ee1 \ + --hash=sha256:5266c36cc0af3bb3dbf44f199d225b33da66a9a5c3bdc2b14865ad10eddf0e37 \ + --hash=sha256:5470f892961af464ae6eaf0f3099e2c1190ae8c7f36f174b89491281341f79ca \ + --hash=sha256:66d14b5b90090353efe75c9fb1bf65ef7267383034688d255b500822e37d5c2f \ + --hash=sha256:67efb5d20618020aa9596e17bfc37ca068c28ec0c1507d9507f73c93d46c9855 \ + --hash=sha256:696e6cfab94cc15a14946f2bf72719dced087d437adbd994fff34f38986628bc \ + --hash=sha256:6a02172b9650f819d01fb8e224fc69b0706458fc1ab4f1c669281243c71c1a5e \ + --hash=sha256:6eca9ae238ba615d702387a2ddea635d535d769994a9968c09a4ca920c487ab9 \ + --hash=sha256:950abd6c00e7b51f87ae8b18a0ce4d69fea217f62f171426e77de5061f6d9850 \ + --hash=sha256:9e1d74032f56ff25f417cfe84c8147047732e5059137ca42efad20cbbd25f5e0 \ + --hash=sha256:9e42b1cf2ecd8a1bd161239e693f22035ba99905ae6d7efeac8a0546c7ec1a27 \ + --hash=sha256:9f957ef53e872d58a0afd3bf6d80d48535d28c99b40e75e6634cbc33ea42fd54 \ + --hash=sha256:a89aa0c042e61e11ade320b802d6db4ee5391d8d973e46d3a48172c1597789f8 \ + --hash=sha256:c0f80876a8ff0ae7064084ed094eb86497bd5a3812e6fc96a05318b92301674e \ + --hash=sha256:c44e3282cff74ad18c7e8a0375f407f69ee50c2116364b44492a196293e08b21 \ + --hash=sha256:d249519ba5ecf5dd6b18150c9b6bcde510b273714b696f3923ff8308fc11ae49 \ + --hash=sha256:d3973a2d58aefc7d1230725c2447ce7f86a71cbc094b86a77c6ee1505ac7cdb1 \ + --hash=sha256:dca2284378a5f2a86ffed35c6ac147d14c48b525eefcd1083e5a9ce28dfa8657 \ + --hash=sha256:e63b0b3c42e51c94add62b010366cd4979cb6d5f06158bcae8faac4c294f91e1 \ + --hash=sha256:f2b599a21c9a32e171ec29a2ac54e03297736c578698e11b099d031f79da114b \ + --hash=sha256:f2bde37667b18c2b5280df83bc799204394a5d2d774e4deaf9de0eb741df6833 \ + --hash=sha256:f4f909f4dde413dec435a44b0894956d55bb928ded7d6e3c726556ca4c796e84 \ + --hash=sha256:f976234e20ab2785f54224bcdafa027674e23663b132fa3ca0caa291a6cfbde7 \ + --hash=sha256:f9cebda093c2f6bfed88f1c17cdade09d4d96096421b344026feee236532d4de + # via + # -r requirements.in + # gcp-docuploader + # gcp-releasetool + # google-api-core + # google-cloud-storage + # googleapis-common-protos +pyasn1==0.4.8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba + # via + # pyasn1-modules + # rsa +pyasn1-modules==0.2.8 \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 + # via google-auth +pycparser==2.21 \ + --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ + --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 + # via + # -r requirements.in + # cffi +pyjwt==2.4.0 \ + --hash=sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf \ + --hash=sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba + # via + # -r requirements.in + # gcp-releasetool +pyparsing==3.0.9 \ + --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ + --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc + # via + # -r requirements.in + # packaging +pyperclip==1.8.2 \ + --hash=sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57 + # via + # -r requirements.in + # gcp-releasetool +python-dateutil==2.8.2 \ + --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ + --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 + # via + # -r requirements.in + # gcp-releasetool +requests==2.27.1 \ + --hash=sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61 \ + --hash=sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d + # via + # -r requirements.in + # gcp-releasetool + # google-api-core + # google-cloud-storage +rsa==4.9 \ + --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ + --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 + # via + # -r requirements.in + # google-auth +secretstorage==3.3.3 \ + --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ + --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 + # via keyring +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via + # -r requirements.in + # gcp-docuploader + # google-auth + # python-dateutil +typing-extensions==4.1.1 \ + --hash=sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42 \ + --hash=sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2 + # via -r requirements.in +urllib3==1.26.12 \ + --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ + --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 + # via + # -r requirements.in + # requests +zipp==3.6.0 \ + --hash=sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832 \ + --hash=sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc + # via + # -r requirements.in + # importlib-metadata diff --git a/CHANGELOG.md b/CHANGELOG.md index e87c65ac8d9..4d1c59ecaeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [6.31.0](https://github.com/googleapis/java-spanner/compare/v6.30.2...v6.31.0) (2022-09-29) + + +### Features + +* Support customer managed instance configurations ([#1742](https://github.com/googleapis/java-spanner/issues/1742)) ([c1c805c](https://github.com/googleapis/java-spanner/commit/c1c805cf6e9c00f2d6796627d919338be1a0599a)) + + +### Dependencies + +* Update dependency com.google.cloud:google-cloud-trace to v2.3.4 ([#2027](https://github.com/googleapis/java-spanner/issues/2027)) ([14890ed](https://github.com/googleapis/java-spanner/commit/14890ed8e0df99eba7c2521a196132c78054b6ed)) +* Update dependency com.google.cloud:google-cloud-trace to v2.3.5 ([#2083](https://github.com/googleapis/java-spanner/issues/2083)) ([cef4e0a](https://github.com/googleapis/java-spanner/commit/cef4e0ada98ab65020f32836fc0c8ab1ee0c7eed)) +* Update dependency org.graalvm.buildtools:junit-platform-native to v0.9.14 ([#2030](https://github.com/googleapis/java-spanner/issues/2030)) ([04b59ff](https://github.com/googleapis/java-spanner/commit/04b59ff8a1efaa32082aa4e9567d90b5956810c6)) +* Update dependency org.json:json to v20220924 ([#2035](https://github.com/googleapis/java-spanner/issues/2035)) ([a26a14a](https://github.com/googleapis/java-spanner/commit/a26a14a94ac3ca6cd7eabce6826cce3dde27ea66)) + ## [6.30.2](https://github.com/googleapis/java-spanner/compare/v6.30.1...v6.30.2) (2022-09-21) diff --git a/README.md b/README.md index b62f05b32ef..8c32e569dee 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ If you are using Maven without BOM, add this to your dependencies: com.google.cloud google-cloud-spanner - 6.30.1 + 6.30.2 ``` @@ -56,13 +56,13 @@ implementation 'com.google.cloud:google-cloud-spanner' If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-spanner:6.30.1' +implementation 'com.google.cloud:google-cloud-spanner:6.30.2' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.30.1" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.30.2" ``` ## Authentication diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 97d753ff4fd..e34c8a09e57 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 6.30.2 + 6.31.0 pom com.google.cloud @@ -53,43 +53,43 @@ com.google.cloud google-cloud-spanner - 6.30.2 + 6.31.0 com.google.cloud google-cloud-spanner test-jar - 6.30.2 + 6.31.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.30.2 + 6.31.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.30.2 + 6.31.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.30.2 + 6.31.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.30.2 + 6.31.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.30.2 + 6.31.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.30.2 + 6.31.0 diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index 8d597d29b3f..039278a6436 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -35,6 +35,46 @@ com/google/cloud/spanner/connection/ConnectionOptions com.google.cloud.spanner.Dialect getDialect() + + 7012 + com/google/cloud/spanner/InstanceAdminClient + com.google.api.gax.longrunning.OperationFuture createInstanceConfig(com.google.cloud.spanner.InstanceConfigInfo, com.google.cloud.spanner.Options$CreateAdminApiOption[]) + + + 7012 + com/google/cloud/spanner/InstanceAdminClient + com.google.api.gax.longrunning.OperationFuture updateInstanceConfig(com.google.cloud.spanner.InstanceConfigInfo, java.lang.Iterable, com.google.cloud.spanner.Options$UpdateAdminApiOption[]) + + + 7012 + com/google/cloud/spanner/InstanceAdminClient + void deleteInstanceConfig(java.lang.String, com.google.cloud.spanner.Options$DeleteAdminApiOption[]) + + + 7012 + com/google/cloud/spanner/InstanceAdminClient + com.google.api.gax.paging.Page listInstanceConfigOperations(com.google.cloud.spanner.Options$ListOption[]) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + com.google.api.gax.longrunning.OperationFuture createInstanceConfig(java.lang.String, java.lang.String, com.google.spanner.admin.instance.v1.InstanceConfig, java.lang.Boolean) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + com.google.api.gax.longrunning.OperationFuture updateInstanceConfig(com.google.spanner.admin.instance.v1.InstanceConfig, java.lang.Boolean, com.google.protobuf.FieldMask) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + void deleteInstanceConfig(java.lang.String, java.lang.String, java.lang.Boolean) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + com.google.cloud.spanner.spi.v1.SpannerRpc$Paginated listInstanceConfigOperations(int, java.lang.String, java.lang.String) + 7013 com/google/cloud/spanner/BackupInfo$Builder @@ -152,4 +192,14 @@ com/google/cloud/spanner/StructReader java.util.List getPgJsonbList(java.lang.String) + + 7012 + com/google/cloud/spanner/BatchClient + java.lang.String getDatabaseRole() + + + 7012 + com/google/cloud/spanner/DatabaseClient + java.lang.String getDatabaseRole() + diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index b792879c383..f29a641be3e 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 6.30.2 + 6.31.0 jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 6.30.2 + 6.31.0 google-cloud-spanner @@ -359,7 +359,7 @@ org.json json - 20220320 + 20220924 test diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClient.java index 9b53d815c4d..45e38989be6 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClient.java @@ -59,4 +59,13 @@ public interface BatchClient { * successive read/query. */ BatchReadOnlyTransaction batchReadOnlyTransaction(BatchTransactionId batchTransactionId); + + /** + * Returns the {@link DatabaseRole} used by the client connection. The database role that is used + * determines the access permissions that a connection has. This can for example be used to create + * connections that are only permitted to access certain tables. + */ + default String getDatabaseRole() { + throw new UnsupportedOperationException("method should be overwritten"); + }; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java index 5a164d52490..0191a11be1c 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java @@ -33,6 +33,7 @@ import io.opencensus.trace.Tracing; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; /** Default implementation for Batch Client interface. */ public class BatchClientImpl implements BatchClient { @@ -42,6 +43,12 @@ public class BatchClientImpl implements BatchClient { this.sessionClient = checkNotNull(sessionClient); } + @Override + @Nullable + public String getDatabaseRole() { + return this.sessionClient.getSpanner().getOptions().getDatabaseRole(); + } + @Override public BatchReadOnlyTransaction batchReadOnlyTransaction(TimestampBound bound) { SessionImpl session = sessionClient.createSession(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java index a09c06bcbe2..a82225d5f44 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java @@ -36,6 +36,17 @@ default Dialect getDialect() { throw new UnsupportedOperationException("method should be overwritten"); } + /** + * Returns the {@link DatabaseRole} used by the client connection. The database role that is used + * determines the access permissions that a connection has. This can for example be used to create + * connections that are only permitted to access certain tables. + * + * @return the {@link DatabaseRole} used by the client connection. + */ + default String getDatabaseRole() { + throw new UnsupportedOperationException("method should be overwritten"); + } + /** * Writes the given mutations atomically to the database. * diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java index d0ee29ada17..a2a46b5a198 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java @@ -28,6 +28,7 @@ import io.opencensus.trace.Span; import io.opencensus.trace.Tracer; import io.opencensus.trace.Tracing; +import javax.annotation.Nullable; class DatabaseClientImpl implements DatabaseClient { private static final String READ_WRITE_TRANSACTION = "CloudSpanner.ReadWriteTransaction"; @@ -58,6 +59,12 @@ public Dialect getDialect() { return pool.getDialect(); } + @Override + @Nullable + public String getDatabaseRole() { + return pool.getDatabaseRole(); + } + @Override public Timestamp write(final Iterable mutations) throws SpannerException { return writeWithOptions(mutations).getCommitTimestamp(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClient.java index a84bf04aac2..702b9c40598 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClient.java @@ -19,14 +19,141 @@ import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.paging.Page; import com.google.cloud.Policy; +import com.google.cloud.spanner.Options.CreateAdminApiOption; +import com.google.cloud.spanner.Options.DeleteAdminApiOption; import com.google.cloud.spanner.Options.ListOption; +import com.google.cloud.spanner.Options.UpdateAdminApiOption; import com.google.longrunning.Operation; +import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata; import com.google.spanner.admin.instance.v1.CreateInstanceMetadata; +import com.google.spanner.admin.instance.v1.UpdateInstanceConfigMetadata; import com.google.spanner.admin.instance.v1.UpdateInstanceMetadata; /** Client to do admin operations on Cloud Spanner Instance and Instance Configs. */ public interface InstanceAdminClient { + /** + * Creates an instance config and begins preparing it to be used. The returned {@code Operation} + * can be used to track the progress of preparing the new instance config. The instance config + * name is assigned by the caller and must start with the string 'custom'. If the named instance + * config already exists, a SpannerException is thrown. + * + *

Immediately after the request returns: + * + *

    + *
  • The instance config is readable via the API, with all requested attributes. + *
  • The instance config's {@code reconciling} field is set to true. Its state is {@code + * CREATING}. + *
+ * + * While the operation is pending: + * + *
    + *
  • Cancelling the operation renders the instance config immediately unreadable via the API. + *
  • Except for deleting the creating resource, all other attempts to modify the instance + * config are rejected. + *
+ * + * Upon completion of the returned operation: + * + *
    + *
  • Instances can be created using the instance configuration. + *
  • The instance config's {@code reconciling} field becomes false. + *
  • Its state becomes {@code READY}. + *
+ * + * + * + *
{@code
+   * String projectId = "my-project";
+   * String baseInstanceConfig = "my-base-config";
+   * String instanceConfigId = "custom-user-config";
+   *
+   * final InstanceConfig baseConfig = instanceAdminClient.getInstanceConfig(baseInstanceConfig);
+   *
+   * List readOnlyReplicas = ImmutableList.of(baseConfig.getOptionalReplicas().get(0));
+   *
+   * InstanceConfigInfo instanceConfigInfo =
+   *     InstanceConfigInfo.newBuilder(InstanceConfigId.of(projectId, instanceConfigId), baseConfig)
+   *         .setDisplayName(instanceConfigId)
+   *         .addReadOnlyReplicas(readOnlyReplicas)
+   *         .build();
+   *
+   * final OperationFuture operation =
+   *     instanceAdminClient.createInstanceConfig(instanceConfigInfo);
+   *
+   * InstanceConfig instanceConfig = op.get(5, TimeUnit.MINUTES)
+   * }
+ * + * + */ + default OperationFuture createInstanceConfig( + InstanceConfigInfo instanceConfig, CreateAdminApiOption... options) throws SpannerException { + throw new UnsupportedOperationException("Not implemented"); + } + + /** + * Updates a custom instance config. This can not be used to update a Google managed instance + * config. The returned {@code Operation} can be used to track the progress of updating the + * instance. If the named instance config does not exist, a SpannerException is thrown. The + * request must include at least one field to update. + * + *

Only user managed configurations can be updated. + * + *

Immediately after the request returns: + * + *

    + *
  • The instance config's {@code reconciling} field is set to true. + *
+ * + * While the operation is pending: + * + *
    + *
  • Cancelling the operation sets its metadata's cancel_time. + *
  • The operation is guaranteed to succeed at undoing all changes, after which point it + * terminates with a `CANCELLED` status. + *
  • All other attempts to modify the instance config are rejected. + *
  • Reading the instance config via the API continues to give the pre-request values. + *
+ * + * Upon completion of the returned operation: + * + *
    + *
  • Creating instances using the instance configuration uses the new values. + *
  • The instance config's new values are readable via the API. + *
  • The instance config's {@code reconciling} field becomes false. + *
+ * + * + * + *
{@code
+   * String projectId = "my-project";
+   * String instanceConfigId = "custom-user-config";
+   * String displayName = "my-display-name";
+   *
+   * InstanceConfigInfo instanceConfigInfo =
+   *     InstanceConfigInfo.newBuilder(InstanceConfigId.of(projectId, instanceConfigId))
+   *         .setDisplayName(displayName)
+   *         .build();
+   *
+   * // Only update display name.
+   * final OperationFuture operation =
+   *     instanceAdminClient.updateInstanceConfig(
+   *         instanceConfigInfo, ImmutableList.of(InstanceConfigField.DISPLAY_NAME));
+   *
+   * InstanceConfig instanceConfig = operation.get(5, TimeUnit.MINUTES);
+   * }
+ * + * + */ + default OperationFuture updateInstanceConfig( + InstanceConfigInfo instanceConfig, + Iterable fieldsToUpdate, + UpdateAdminApiOption... options) + throws SpannerException { + throw new UnsupportedOperationException("Not implemented"); + } + /** Gets an instance config. */ /* *
{@code
@@ -37,6 +164,28 @@ public interface InstanceAdminClient {
    */
   InstanceConfig getInstanceConfig(String configId) throws SpannerException;
 
+  /**
+   * Deletes a custom instance config. Deletion is only allowed for custom instance configs and when
+   * no instances are using the configuration. If any instances are using the config, a
+   * SpannerException is thrown.
+   *
+   * 

Only user managed configurations can be deleted. + * + * + *

{@code
+   * String projectId = "my-project";
+   * String instanceConfigId = "custom-user-config";
+   *
+   * instanceAdminClient.deleteInstanceConfig(instanceConfigId);
+   * }
+ * + * + */ + default void deleteInstanceConfig(String instanceConfigId, DeleteAdminApiOption... options) + throws SpannerException { + throw new UnsupportedOperationException("Not implemented"); + } + /** Lists the supported instance configs for current project. */ /* *
{@code
@@ -47,6 +196,11 @@ public interface InstanceAdminClient {
    */
   Page listInstanceConfigs(ListOption... options) throws SpannerException;
 
+  /** Lists long-running instance config operations. */
+  default Page listInstanceConfigOperations(ListOption... options) {
+    throw new UnsupportedOperationException("Not implemented");
+  }
+
   /**
    * Creates an instance and begins preparing it to begin serving. The returned {@code Operation}
    * can be used to track the progress of preparing the new instance. The instance name is assigned
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClientImpl.java
index 142540af667..195de83382a 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClientImpl.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClientImpl.java
@@ -23,14 +23,19 @@
 import com.google.api.pathtemplate.PathTemplate;
 import com.google.cloud.Policy;
 import com.google.cloud.Policy.DefaultMarshaller;
+import com.google.cloud.spanner.Options.CreateAdminApiOption;
+import com.google.cloud.spanner.Options.DeleteAdminApiOption;
 import com.google.cloud.spanner.Options.ListOption;
+import com.google.cloud.spanner.Options.UpdateAdminApiOption;
 import com.google.cloud.spanner.SpannerImpl.PageFetcher;
 import com.google.cloud.spanner.spi.v1.SpannerRpc;
 import com.google.cloud.spanner.spi.v1.SpannerRpc.Paginated;
 import com.google.common.base.Preconditions;
 import com.google.longrunning.Operation;
 import com.google.protobuf.FieldMask;
+import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata;
 import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
+import com.google.spanner.admin.instance.v1.UpdateInstanceConfigMetadata;
 import com.google.spanner.admin.instance.v1.UpdateInstanceMetadata;
 
 /** Default implementation of {@link InstanceAdminClient} */
@@ -60,6 +65,64 @@ protected com.google.iam.v1.Policy toPb(Policy policy) {
     this.dbClient = dbClient;
   }
 
+  @Override
+  public OperationFuture createInstanceConfig(
+      InstanceConfigInfo instanceConfig, CreateAdminApiOption... options) throws SpannerException {
+    final Options createAdminApiOptions = Options.fromAdminApiOptions(options);
+    String projectName = PROJECT_NAME_TEMPLATE.instantiate("project", projectId);
+    OperationFuture<
+            com.google.spanner.admin.instance.v1.InstanceConfig, CreateInstanceConfigMetadata>
+        rawOperationFuture =
+            rpc.createInstanceConfig(
+                projectName,
+                instanceConfig.getId().getInstanceConfig(),
+                instanceConfig.toProto(),
+                createAdminApiOptions.validateOnly());
+
+    return new OperationFutureImpl<>(
+        rawOperationFuture.getPollingFuture(),
+        rawOperationFuture.getInitialFuture(),
+        snapshot ->
+            InstanceConfig.fromProto(
+                ProtoOperationTransformers.ResponseTransformer.create(
+                        com.google.spanner.admin.instance.v1.InstanceConfig.class)
+                    .apply(snapshot),
+                InstanceAdminClientImpl.this),
+        ProtoOperationTransformers.MetadataTransformer.create(CreateInstanceConfigMetadata.class),
+        e -> {
+          throw SpannerExceptionFactory.newSpannerException(e);
+        });
+  }
+
+  @Override
+  public OperationFuture updateInstanceConfig(
+      InstanceConfigInfo instanceConfig,
+      Iterable fieldsToUpdate,
+      UpdateAdminApiOption... options)
+      throws SpannerException {
+    final Options deleteAdminApiOptions = Options.fromAdminApiOptions(options);
+    FieldMask fieldMask = InstanceConfigInfo.InstanceConfigField.toFieldMask(fieldsToUpdate);
+
+    OperationFuture<
+            com.google.spanner.admin.instance.v1.InstanceConfig, UpdateInstanceConfigMetadata>
+        rawOperationFuture =
+            rpc.updateInstanceConfig(
+                instanceConfig.toProto(), deleteAdminApiOptions.validateOnly(), fieldMask);
+    return new OperationFutureImpl<>(
+        rawOperationFuture.getPollingFuture(),
+        rawOperationFuture.getInitialFuture(),
+        snapshot ->
+            InstanceConfig.fromProto(
+                ProtoOperationTransformers.ResponseTransformer.create(
+                        com.google.spanner.admin.instance.v1.InstanceConfig.class)
+                    .apply(snapshot),
+                InstanceAdminClientImpl.this),
+        ProtoOperationTransformers.MetadataTransformer.create(UpdateInstanceConfigMetadata.class),
+        e -> {
+          throw SpannerExceptionFactory.newSpannerException(e);
+        });
+  }
+
   @Override
   public InstanceConfig getInstanceConfig(String configId) throws SpannerException {
     String instanceConfigName = new InstanceConfigId(projectId, configId).getName();
@@ -67,6 +130,16 @@ public InstanceConfig getInstanceConfig(String configId) throws SpannerException
         rpc.getInstanceConfig(instanceConfigName), InstanceAdminClientImpl.this);
   }
 
+  @Override
+  public void deleteInstanceConfig(final String instanceConfigId, DeleteAdminApiOption... options)
+      throws SpannerException {
+    final Options deleteAdminApiOptions = Options.fromAdminApiOptions(options);
+    rpc.deleteInstanceConfig(
+        new InstanceConfigId(projectId, instanceConfigId).getName(),
+        deleteAdminApiOptions.etag(),
+        deleteAdminApiOptions.validateOnly());
+  }
+
   @Override
   public Page listInstanceConfigs(ListOption... options) {
     final Options listOptions = Options.fromListOptions(options);
@@ -93,6 +166,30 @@ public InstanceConfig fromProto(
     return pageFetcher.getNextPage();
   }
 
+  @Override
+  public final Page listInstanceConfigOperations(ListOption... options) {
+    final Options listOptions = Options.fromListOptions(options);
+    final int pageSize = listOptions.hasPageSize() ? listOptions.pageSize() : 0;
+    final String filter = listOptions.hasFilter() ? listOptions.filter() : null;
+
+    PageFetcher pageFetcher =
+        new PageFetcher() {
+          @Override
+          public Paginated getNextPage(String nextPageToken) {
+            return rpc.listInstanceConfigOperations(pageSize, filter, nextPageToken);
+          }
+
+          @Override
+          public Operation fromProto(Operation proto) {
+            return proto;
+          }
+        };
+    if (listOptions.hasPageToken()) {
+      pageFetcher.setNextPageToken(listOptions.pageToken());
+    }
+    return pageFetcher.getNextPage();
+  }
+
   @Override
   public OperationFuture createInstance(InstanceInfo instance)
       throws SpannerException {
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceConfig.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceConfig.java
index 6afbc028e19..9b96dda4df7 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceConfig.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceConfig.java
@@ -18,7 +18,7 @@
 
 import java.util.Collections;
 import java.util.List;
-import java.util.stream.Collectors;
+import java.util.Map;
 
 /**
  * Represents a Cloud Spanner instance config.{@code InstanceConfig} adds a layer of service related
@@ -28,10 +28,114 @@ public class InstanceConfig extends InstanceConfigInfo {
 
   private final InstanceAdminClient client;
 
+  /** Builder of {@code InstanceConfig}. */
+  public static class Builder extends InstanceConfigInfo.BuilderImpl {
+    private final InstanceAdminClient client;
+
+    Builder(InstanceConfig instanceConfig) {
+      super(instanceConfig);
+      this.client = instanceConfig.client;
+    }
+
+    Builder(InstanceAdminClient client, InstanceConfigId id) {
+      super(id);
+      this.client = client;
+    }
+
+    @Override
+    public Builder setDisplayName(String displayName) {
+      super.setDisplayName(displayName);
+      return this;
+    }
+
+    @Override
+    protected Builder setReplicas(List replicas) {
+      super.setReplicas(replicas);
+      return this;
+    }
+
+    @Override
+    public Builder setLeaderOptions(List leaderOptions) {
+      super.setLeaderOptions(leaderOptions);
+      return this;
+    }
+
+    @Override
+    protected Builder setOptionalReplicas(List optionalReplicas) {
+      super.setOptionalReplicas(optionalReplicas);
+      return this;
+    }
+
+    @Override
+    protected Builder setBaseConfig(InstanceConfigInfo baseConfig) {
+      super.setBaseConfig(baseConfig);
+      return this;
+    }
+
+    @Override
+    protected Builder setConfigType(Type configType) {
+      super.setConfigType(configType);
+      return this;
+    }
+
+    @Override
+    protected Builder setState(State state) {
+      super.setState(state);
+      return this;
+    }
+
+    @Override
+    public Builder setEtag(String etag) {
+      super.setEtag(etag);
+      return this;
+    }
+
+    @Override
+    protected Builder setReconciling(boolean reconciling) {
+      super.setReconciling(reconciling);
+      return this;
+    }
+
+    @Override
+    public Builder addLabel(String key, String value) {
+      super.addLabel(key, value);
+      return this;
+    }
+
+    @Override
+    public Builder putAllLabels(Map labels) {
+      super.putAllLabels(labels);
+      return this;
+    }
+
+    @Override
+    public Builder addReadOnlyReplicas(List readOnlyReplicas) {
+      super.addReadOnlyReplicas(readOnlyReplicas);
+      return this;
+    }
+
+    @Override
+    public InstanceConfig build() {
+      return new InstanceConfig(this);
+    }
+  }
+
+  public static Builder newBuilder(InstanceConfig instanceConfig) {
+    return new Builder(instanceConfig);
+  }
+
+  public static Builder newBuilder(InstanceAdminClient client, InstanceConfigId instanceConfigId) {
+    return new Builder(client, instanceConfigId);
+  }
+
+  /** Use {@link #newBuilder} instead */
+  @Deprecated
   public InstanceConfig(InstanceConfigId id, String displayName, InstanceAdminClient client) {
     this(id, displayName, Collections.emptyList(), Collections.emptyList(), client);
   }
 
+  /** Use {@link #newBuilder} instead */
+  @Deprecated
   public InstanceConfig(
       InstanceConfigId id,
       String displayName,
@@ -42,18 +146,18 @@ public InstanceConfig(
     this.client = client;
   }
 
+  InstanceConfig(Builder builder) {
+    super(builder);
+    this.client = builder.client;
+  }
+
   /** Gets the current state of this instance config. */
   public InstanceConfig reload() {
     return client.getInstanceConfig(getId().getInstanceConfig());
   }
 
-  static InstanceConfig fromProto(
-      com.google.spanner.admin.instance.v1.InstanceConfig proto, InstanceAdminClient client) {
-    return new InstanceConfig(
-        InstanceConfigId.of(proto.getName()),
-        proto.getDisplayName(),
-        proto.getReplicasList().stream().map(ReplicaInfo::fromProto).collect(Collectors.toList()),
-        proto.getLeaderOptionsList(),
-        client);
+  @Override
+  public Builder toBuilder() {
+    return new Builder(this);
   }
 }
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceConfigInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceConfigInfo.java
index 43d4fbf9535..f2b256fff40 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceConfigInfo.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceConfigInfo.java
@@ -16,33 +16,72 @@
 
 package com.google.cloud.spanner;
 
-import java.util.Collections;
+import com.google.cloud.FieldSelector;
+import com.google.common.collect.ImmutableMap;
+import com.google.protobuf.FieldMask;
+import com.google.spanner.admin.instance.v1.InstanceConfig;
+import com.google.spanner.admin.instance.v1.InstanceConfig.State;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /** Represents a Cloud Spanner instance config resource. */
 public class InstanceConfigInfo {
 
-  private final InstanceConfigId id;
-  private final String displayName;
-  private final List replicas;
-  private final List leaderOptions;
+  /** Represent an updatable field in Cloud Spanner InstanceConfig. */
+  public enum InstanceConfigField implements FieldSelector {
+    DISPLAY_NAME("display_name"),
+    LABELS("labels");
 
-  public InstanceConfigInfo(InstanceConfigId id, String displayName) {
-    this(id, displayName, Collections.emptyList(), Collections.emptyList());
+    private final String selector;
+
+    InstanceConfigField(String selector) {
+      this.selector = selector;
+    }
+
+    @Override
+    public String getSelector() {
+      return selector;
+    }
+
+    static FieldMask toFieldMask(Iterable fields) {
+      FieldMask.Builder builder = FieldMask.newBuilder();
+      for (InstanceConfigField field : fields) {
+        builder.addPaths(field.getSelector());
+      }
+      return builder.build();
+    }
   }
 
-  public InstanceConfigInfo(
-      InstanceConfigId id,
-      String displayName,
-      List replicas,
-      List leaderOptions) {
-    this.id = id;
-    this.displayName = displayName;
-    this.replicas = replicas;
-    this.leaderOptions = leaderOptions;
+  /** Type of the Instance config. */
+  public enum Type {
+    TYPE_UNSPECIFIED,
+    GOOGLE_MANAGED,
+    USER_MANAGED
+  }
+
+  /** Type of the Instance config. */
+  public enum State {
+    STATE_UNSPECIFIED,
+    CREATING,
+    READY
   }
 
+  private final InstanceConfigId id;
+  private final String displayName;
+  private final List replicas;
+  private final List leaderOptions;
+  private final List optionalReplicas;
+  private final InstanceConfigInfo baseConfig;
+  private final Type configType;
+  private final String etag;
+  private final boolean reconciling;
+  private final State state;
+  private final Map labels;
+
   /** Returns the id of this instance config. */
   public InstanceConfigId getId() {
     return id;
@@ -69,6 +108,254 @@ public List getLeaderOptions() {
     return leaderOptions;
   }
 
+  /**
+   * The available optional replicas to choose from for user managed configurations. Populated for
+   * Google managed configurations.
+   */
+  public List getOptionalReplicas() {
+    return optionalReplicas;
+  }
+
+  /**
+   * Base configuration, e.g. projects//instanceConfigs/nam3, based on which this
+   * configuration is created. Only set for user managed configurations. The base config must refer
+   * to a configuration of type GOOGLE_MANAGED.
+   */
+  public InstanceConfigInfo getBaseConfig() {
+    return baseConfig;
+  }
+
+  /**
+   * Config type, indicates whether this instance config is a Google or User Managed Configuration.
+   */
+  public Type getConfigType() {
+    return configType;
+  }
+
+  /**
+   * etag, which is used for optimistic concurrency control as a way to help prevent simultaneous
+   * updates of an instance config from overwriting each other.
+   */
+  public String getEtag() {
+    return etag;
+  }
+
+  /**
+   * If true, the instance config is being created or updated. If false, there are no ongoing
+   * operations for the instance config.
+   */
+  public boolean getReconciling() {
+    return reconciling;
+  }
+
+  /** The current instance config state. */
+  public State getState() {
+    return state;
+  }
+
+  /**
+   * Cloud Labels, which can be used to filter collections of resources. They can be used to control
+   * how resource metrics are aggregated.
+   */
+  public Map getLabels() {
+    return labels;
+  }
+
+  /** Builder for {@code InstanceConfigInfo}. */
+  public abstract static class Builder {
+    public abstract Builder setDisplayName(String displayName);
+
+    protected abstract Builder setReplicas(List replicas);
+
+    protected abstract Builder setOptionalReplicas(List optionalReplicas);
+
+    protected abstract Builder setBaseConfig(InstanceConfigInfo baseConfig);
+
+    /**
+     * Sets the allowed values of the "default_leader" schema option for databases in instances that
+     * use this instance configuration.
+     */
+    public abstract Builder setLeaderOptions(List leaderOptions);
+
+    protected abstract Builder setConfigType(Type configType);
+
+    protected abstract Builder setState(State state);
+
+    public abstract Builder setEtag(String etag);
+
+    protected abstract Builder setReconciling(boolean reconciling);
+
+    public abstract Builder addLabel(String key, String value);
+
+    public abstract Builder putAllLabels(Map labels);
+
+    /**
+     * Adds the read only replicas to the set of replicas for a custom instance config. Called with
+     * one or more of the optional replicas of the base config.
+     */
+    public abstract Builder addReadOnlyReplicas(List readOnlyReplicas);
+
+    public abstract InstanceConfigInfo build();
+  }
+
+  static class BuilderImpl extends Builder {
+    private InstanceConfigId id;
+    private String displayName = "";
+    private List replicas = new ArrayList<>();
+    private List leaderOptions = new ArrayList<>();
+    private List optionalReplicas = new ArrayList<>();
+    private InstanceConfigInfo baseConfig;
+    private Type configType = Type.TYPE_UNSPECIFIED;
+    private String etag = "";
+    private boolean reconciling = false;
+    private State state = State.STATE_UNSPECIFIED;
+    private Map labels = new HashMap<>();
+
+    BuilderImpl(InstanceConfigId id) {
+      this.id = id;
+    }
+
+    BuilderImpl(InstanceConfigId id, InstanceConfigInfo baseConfig) {
+      this.id = id;
+      this.baseConfig = baseConfig;
+      this.replicas = new ArrayList<>(baseConfig.replicas);
+    }
+
+    BuilderImpl(InstanceConfigInfo instanceConfigInfo) {
+      this.id = instanceConfigInfo.id;
+      this.displayName = instanceConfigInfo.displayName;
+      this.replicas = new ArrayList<>(instanceConfigInfo.replicas);
+      this.leaderOptions = new ArrayList<>(instanceConfigInfo.leaderOptions);
+      this.optionalReplicas = new ArrayList<>(instanceConfigInfo.optionalReplicas);
+      this.baseConfig = instanceConfigInfo.baseConfig;
+      this.configType = instanceConfigInfo.configType;
+      this.etag = instanceConfigInfo.etag;
+      this.reconciling = instanceConfigInfo.reconciling;
+      this.state = instanceConfigInfo.state;
+      this.labels = new HashMap<>(instanceConfigInfo.labels);
+    }
+
+    @Override
+    public Builder setDisplayName(String displayName) {
+      this.displayName = displayName;
+      return this;
+    }
+
+    @Override
+    protected Builder setReplicas(List replicas) {
+      this.replicas = replicas;
+      return this;
+    }
+
+    @Override
+    public Builder setLeaderOptions(List leaderOptions) {
+      this.leaderOptions = leaderOptions;
+      return this;
+    }
+
+    @Override
+    protected Builder setOptionalReplicas(List optionalReplicas) {
+      this.optionalReplicas = optionalReplicas;
+      return this;
+    }
+
+    @Override
+    protected Builder setBaseConfig(InstanceConfigInfo baseConfig) {
+      this.baseConfig = baseConfig;
+      return this;
+    }
+
+    @Override
+    protected Builder setConfigType(Type configType) {
+      this.configType = configType;
+      return this;
+    }
+
+    @Override
+    protected Builder setState(State state) {
+      this.state = state;
+      return this;
+    }
+
+    @Override
+    public Builder setEtag(String etag) {
+      this.etag = etag;
+      return this;
+    }
+
+    @Override
+    protected Builder setReconciling(boolean reconciling) {
+      this.reconciling = reconciling;
+      return this;
+    }
+
+    @Override
+    public Builder addLabel(String key, String value) {
+      this.labels.put(key, value);
+      return this;
+    }
+
+    @Override
+    public Builder putAllLabels(Map labels) {
+      this.labels.putAll(labels);
+      return this;
+    }
+
+    @Override
+    public Builder addReadOnlyReplicas(List readOnlyReplicas) {
+      this.replicas.addAll(readOnlyReplicas);
+      return this;
+    }
+
+    @Override
+    public InstanceConfigInfo build() {
+      return new InstanceConfigInfo(this);
+    }
+  }
+
+  /** Use {@link #newBuilder} instead */
+  @Deprecated
+  public InstanceConfigInfo(InstanceConfigId id, String displayName) {
+    this((BuilderImpl) newBuilder(id).setDisplayName(displayName));
+  }
+
+  public static Builder newBuilder(InstanceConfigId id) {
+    return new BuilderImpl(id);
+  }
+
+  public static Builder newBuilder(InstanceConfigId id, InstanceConfigInfo baseConfig) {
+    return new BuilderImpl(id, baseConfig);
+  }
+
+  /** Use {@link #newBuilder} instead */
+  @Deprecated
+  public InstanceConfigInfo(
+      InstanceConfigId id,
+      String displayName,
+      List replicas,
+      List leaderOptions) {
+    this(
+        (BuilderImpl)
+            newBuilder(id)
+                .setDisplayName(displayName)
+                .setReplicas(replicas)
+                .setLeaderOptions(leaderOptions));
+  }
+
+  InstanceConfigInfo(BuilderImpl builder) {
+    this.id = builder.id;
+    this.displayName = builder.displayName;
+    this.replicas = new ArrayList<>(builder.replicas);
+    this.leaderOptions = new ArrayList<>(builder.leaderOptions);
+    this.baseConfig = builder.baseConfig;
+    this.optionalReplicas = new ArrayList<>(builder.optionalReplicas);
+    this.configType = builder.configType;
+    this.etag = builder.etag;
+    this.reconciling = builder.reconciling;
+    this.state = builder.state;
+    this.labels = ImmutableMap.copyOf(builder.labels);
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -81,17 +368,157 @@ public boolean equals(Object o) {
     return Objects.equals(id, that.id)
         && Objects.equals(displayName, that.displayName)
         && Objects.equals(replicas, that.replicas)
-        && Objects.equals(leaderOptions, that.leaderOptions);
+        && Objects.equals(leaderOptions, that.leaderOptions)
+        && Objects.equals(optionalReplicas, that.optionalReplicas)
+        && Objects.equals(baseConfig, that.baseConfig)
+        && Objects.equals(configType, that.configType)
+        && Objects.equals(etag, that.etag)
+        && Objects.equals(reconciling, that.reconciling)
+        && Objects.equals(state, that.state)
+        && Objects.equals(labels, that.labels);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(id, displayName, replicas, leaderOptions);
+    return Objects.hash(
+        id,
+        displayName,
+        replicas,
+        leaderOptions,
+        optionalReplicas,
+        baseConfig,
+        configType,
+        etag,
+        reconciling,
+        state,
+        labels);
+  }
+
+  public Builder toBuilder() {
+    return new BuilderImpl(this);
   }
 
   @Override
   public String toString() {
     return String.format(
-        "Instance Config[%s, %s, %s, %s]", id, displayName, replicas, leaderOptions);
+        "Instance Config[%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s]",
+        id,
+        displayName,
+        replicas,
+        leaderOptions,
+        optionalReplicas,
+        baseConfig,
+        configType,
+        etag,
+        reconciling,
+        state,
+        labels);
+  }
+
+  com.google.spanner.admin.instance.v1.InstanceConfig toProto() {
+    InstanceConfig.Builder builder =
+        com.google.spanner.admin.instance.v1.InstanceConfig.newBuilder()
+            .setName(getId().getName())
+            .setDisplayName(getDisplayName())
+            .addAllReplicas(
+                getReplicas().stream().map(ReplicaInfo::getProto).collect(Collectors.toList()))
+            .addAllLeaderOptions(getLeaderOptions())
+            .setEtag(getEtag())
+            .setReconciling(getReconciling())
+            .putAllLabels(getLabels())
+            .addAllOptionalReplicas(
+                getOptionalReplicas().stream()
+                    .map(ReplicaInfo::getProto)
+                    .collect(Collectors.toList()))
+            .setConfigType(toProtoConfigType(getConfigType()))
+            .setState(toProtoState(getState()));
+
+    if (getBaseConfig() != null) {
+      builder.setBaseConfig(getBaseConfig().getId().getName());
+    }
+
+    return builder.build();
+  }
+
+  private static InstanceConfig.Type toProtoConfigType(Type type) {
+    switch (type) {
+      case TYPE_UNSPECIFIED:
+        return com.google.spanner.admin.instance.v1.InstanceConfig.Type.TYPE_UNSPECIFIED;
+      case GOOGLE_MANAGED:
+        return com.google.spanner.admin.instance.v1.InstanceConfig.Type.GOOGLE_MANAGED;
+      case USER_MANAGED:
+        return InstanceConfig.Type.USER_MANAGED;
+      default:
+        throw new IllegalArgumentException("Unknown config type:" + type);
+    }
+  }
+
+  private static InstanceConfig.State toProtoState(State state) {
+    switch (state) {
+      case STATE_UNSPECIFIED:
+        return com.google.spanner.admin.instance.v1.InstanceConfig.State.STATE_UNSPECIFIED;
+      case CREATING:
+        return com.google.spanner.admin.instance.v1.InstanceConfig.State.CREATING;
+      case READY:
+        return com.google.spanner.admin.instance.v1.InstanceConfig.State.READY;
+      default:
+        throw new IllegalArgumentException("Unknown state:" + state);
+    }
+  }
+
+  static com.google.cloud.spanner.InstanceConfig fromProto(
+      com.google.spanner.admin.instance.v1.InstanceConfig proto, InstanceAdminClient client) {
+    com.google.cloud.spanner.InstanceConfig.Builder builder =
+        com.google.cloud.spanner.InstanceConfig.newBuilder(
+                client, InstanceConfigId.of(proto.getName()))
+            .setReconciling(proto.getReconciling())
+            .setReplicas(
+                proto.getReplicasList().stream()
+                    .map(ReplicaInfo::fromProto)
+                    .collect(Collectors.toList()))
+            .setDisplayName(proto.getDisplayName())
+            .putAllLabels(proto.getLabelsMap())
+            .setEtag(proto.getEtag())
+            .setLeaderOptions(proto.getLeaderOptionsList())
+            .setOptionalReplicas(
+                proto.getOptionalReplicasList().stream()
+                    .map(ReplicaInfo::fromProto)
+                    .collect(Collectors.toList()))
+            .setState(fromProtoState(proto.getState()))
+            .setConfigType(fromProtoConfigType(proto.getConfigType()));
+
+    if (!proto.getBaseConfig().isEmpty()) {
+      builder.setBaseConfig(newBuilder(InstanceConfigId.of(proto.getBaseConfig())).build());
+    }
+
+    return builder.build();
+  }
+
+  private static State fromProtoState(
+      com.google.spanner.admin.instance.v1.InstanceConfig.State state) {
+    switch (state) {
+      case STATE_UNSPECIFIED:
+        return State.STATE_UNSPECIFIED;
+      case CREATING:
+        return State.CREATING;
+      case READY:
+        return State.READY;
+      default:
+        throw new IllegalArgumentException("Unknown state:" + state);
+    }
+  }
+
+  private static Type fromProtoConfigType(
+      com.google.spanner.admin.instance.v1.InstanceConfig.Type type) {
+    switch (type) {
+      case TYPE_UNSPECIFIED:
+        return Type.TYPE_UNSPECIFIED;
+      case GOOGLE_MANAGED:
+        return Type.GOOGLE_MANAGED;
+      case USER_MANAGED:
+        return Type.USER_MANAGED;
+      default:
+        throw new IllegalArgumentException("Unknown config type:" + type);
+    }
   }
 }
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java
index fa2cd2526e4..7b411b4caa0 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java
@@ -51,6 +51,22 @@ public interface ReadOption {}
   public interface ReadQueryUpdateTransactionOption
       extends ReadOption, QueryOption, UpdateOption, TransactionOption {}
 
+  /**
+   * Marker interface to mark options applicable to Create, Update and Delete operations in admin
+   * API.
+   */
+  public interface CreateUpdateDeleteAdminApiOption
+      extends CreateAdminApiOption, UpdateAdminApiOption, DeleteAdminApiOption {}
+
+  /** Marker interface to mark options applicable to Create operations in admin API. */
+  public interface CreateAdminApiOption extends AdminApiOption {}
+
+  /** Marker interface to mark options applicable to Delete operations in admin API. */
+  public interface DeleteAdminApiOption extends AdminApiOption {}
+
+  /** Marker interface to mark options applicable to Update operations in admin API. */
+  public interface UpdateAdminApiOption extends AdminApiOption {}
+
   /** Marker interface to mark options applicable to query operation. */
   public interface QueryOption {}
 
@@ -63,6 +79,9 @@ public interface UpdateOption {}
   /** Marker interface to mark options applicable to list operations in admin API. */
   public interface ListOption {}
 
+  /** Marker interface to mark options applicable to operations in admin API. */
+  public interface AdminApiOption {}
+
   /** Specifying this instructs the transaction to request {@link CommitStats} from the backend. */
   public static TransactionOption commitStats() {
     return COMMIT_STATS_OPTION;
@@ -151,6 +170,33 @@ public static ListOption filter(String filter) {
     return new FilterOption(filter);
   }
 
+  /**
+   * Specifying this will help in optimistic concurrency control as a way to help prevent
+   * simultaneous deletes of an instance config from overwriting each other. Operations that support
+   * this option are:
+   *
+   * 
    + *
  • {@link InstanceAdminClient#deleteInstanceConfig} + *
+ */ + public static DeleteAdminApiOption etag(String etag) { + return new EtagOption(etag); + } + + /** + * Specifying this will not actually execute a request, and provide the same response. Operations + * that support this option are: + * + *
    + *
  • {@link InstanceAdminClient#createInstanceConfig} + *
  • {@link InstanceAdminClient#updateInstanceConfig} + *
  • {@link InstanceAdminClient#deleteInstanceConfig} + *
+ */ + public static CreateUpdateDeleteAdminApiOption validateOnly(Boolean validateOnly) { + return new ValidateOnlyOption(validateOnly); + } + /** Option to request {@link CommitStats} for read/write transactions. */ static final class CommitStatsOption extends InternalOption implements TransactionOption { @Override @@ -215,6 +261,33 @@ void appendToOptions(Options options) { } } + static final class EtagOption extends InternalOption implements DeleteAdminApiOption { + private final String etag; + + EtagOption(String etag) { + this.etag = etag; + } + + @Override + void appendToOptions(Options options) { + options.etag = etag; + } + } + + static final class ValidateOnlyOption extends InternalOption + implements CreateUpdateDeleteAdminApiOption { + private final Boolean validateOnly; + + ValidateOnlyOption(Boolean validateOnly) { + this.validateOnly = validateOnly; + } + + @Override + void appendToOptions(Options options) { + options.validateOnly = validateOnly; + } + } + private boolean withCommitStats; private Long limit; private Integer prefetchChunks; @@ -224,6 +297,8 @@ void appendToOptions(Options options) { private String filter; private RpcPriority priority; private String tag; + private String etag; + private Boolean validateOnly; // Construction is via factory methods below. private Options() {} @@ -296,6 +371,22 @@ String tag() { return tag; } + boolean hasEtag() { + return etag != null; + } + + String etag() { + return etag; + } + + boolean hasValidateOnly() { + return validateOnly != null; + } + + Boolean validateOnly() { + return validateOnly; + } + @Override public String toString() { StringBuilder b = new StringBuilder(); @@ -323,6 +414,12 @@ public String toString() { if (tag != null) { b.append("tag: ").append(tag).append(' '); } + if (etag != null) { + b.append("etag: ").append(etag).append(' '); + } + if (validateOnly != null) { + b.append("validateOnly: ").append(validateOnly).append(' '); + } return b.toString(); } @@ -354,7 +451,9 @@ public boolean equals(Object o) { && Objects.equals(pageToken(), that.pageToken()) && Objects.equals(filter(), that.filter()) && Objects.equals(priority(), that.priority()) - && Objects.equals(tag(), that.tag()); + && Objects.equals(tag(), that.tag()) + && Objects.equals(etag(), that.etag()) + && Objects.equals(validateOnly(), that.validateOnly()); } @Override @@ -387,6 +486,12 @@ public int hashCode() { if (tag != null) { result = 31 * result + tag.hashCode(); } + if (etag != null) { + result = 31 * result + etag.hashCode(); + } + if (validateOnly != null) { + result = 31 * result + validateOnly.hashCode(); + } return result; } @@ -440,6 +545,16 @@ static Options fromListOptions(ListOption... options) { return listOptions; } + static Options fromAdminApiOptions(AdminApiOption... options) { + Options adminApiOptions = new Options(); + for (AdminApiOption option : options) { + if (option instanceof InternalOption) { + ((InternalOption) option).appendToOptions(adminApiOptions); + } + } + return adminApiOptions; + } + private abstract static class InternalOption { abstract void appendToOptions(Options options); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java index 05340b4f177..5502648b599 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java @@ -1784,6 +1784,7 @@ private enum Position { private final SessionPoolOptions options; private final SettableFuture dialect = SettableFuture.create(); + private final String databaseRole; private final SessionClient sessionClient; private final ScheduledExecutorService executor; private final ExecutorFactory executorFactory; @@ -1858,6 +1859,7 @@ static SessionPool createPool( SpannerOptions spannerOptions, SessionClient sessionClient, List labelValues) { return createPool( spannerOptions.getSessionPoolOptions(), + spannerOptions.getDatabaseRole(), ((GrpcTransportOptions) spannerOptions.getTransportOptions()).getExecutorFactory(), sessionClient, new Clock(), @@ -1879,6 +1881,7 @@ static SessionPool createPool( Clock clock) { return createPool( poolOptions, + null, executorFactory, sessionClient, clock, @@ -1888,6 +1891,7 @@ static SessionPool createPool( static SessionPool createPool( SessionPoolOptions poolOptions, + String databaseRole, ExecutorFactory executorFactory, SessionClient sessionClient, Clock clock, @@ -1896,6 +1900,7 @@ static SessionPool createPool( SessionPool pool = new SessionPool( poolOptions, + databaseRole, executorFactory, executorFactory.get(), sessionClient, @@ -1908,6 +1913,7 @@ static SessionPool createPool( private SessionPool( SessionPoolOptions options, + String databaseRole, ExecutorFactory executorFactory, ScheduledExecutorService executor, SessionClient sessionClient, @@ -1915,6 +1921,7 @@ private SessionPool( MetricRegistry metricRegistry, List labelValues) { this.options = options; + this.databaseRole = databaseRole; this.executorFactory = executorFactory; this.executor = executor; this.sessionClient = sessionClient; @@ -1956,6 +1963,11 @@ Dialect getDialect() { } } + @Nullable + public String getDatabaseRole() { + return databaseRole; + } + @VisibleForTesting int getNumberOfSessionsInUse() { synchronized (lock) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 937da7e8d2a..3f28d46c1c2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -133,18 +133,25 @@ import com.google.spanner.admin.database.v1.UpdateBackupRequest; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlRequest; +import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata; +import com.google.spanner.admin.instance.v1.CreateInstanceConfigRequest; import com.google.spanner.admin.instance.v1.CreateInstanceMetadata; import com.google.spanner.admin.instance.v1.CreateInstanceRequest; +import com.google.spanner.admin.instance.v1.DeleteInstanceConfigRequest; import com.google.spanner.admin.instance.v1.DeleteInstanceRequest; import com.google.spanner.admin.instance.v1.GetInstanceConfigRequest; import com.google.spanner.admin.instance.v1.GetInstanceRequest; import com.google.spanner.admin.instance.v1.Instance; import com.google.spanner.admin.instance.v1.InstanceAdminGrpc; import com.google.spanner.admin.instance.v1.InstanceConfig; +import com.google.spanner.admin.instance.v1.ListInstanceConfigOperationsRequest; +import com.google.spanner.admin.instance.v1.ListInstanceConfigOperationsResponse; import com.google.spanner.admin.instance.v1.ListInstanceConfigsRequest; import com.google.spanner.admin.instance.v1.ListInstanceConfigsResponse; import com.google.spanner.admin.instance.v1.ListInstancesRequest; import com.google.spanner.admin.instance.v1.ListInstancesResponse; +import com.google.spanner.admin.instance.v1.UpdateInstanceConfigMetadata; +import com.google.spanner.admin.instance.v1.UpdateInstanceConfigRequest; import com.google.spanner.admin.instance.v1.UpdateInstanceMetadata; import com.google.spanner.admin.instance.v1.UpdateInstanceRequest; import com.google.spanner.v1.BatchCreateSessionsRequest; @@ -879,6 +886,48 @@ public Paginated listInstanceConfigs(int pageSize, @Nullable Str return new Paginated<>(response.getInstanceConfigsList(), response.getNextPageToken()); } + @Override + public OperationFuture createInstanceConfig( + String parent, + String instanceConfigId, + InstanceConfig instanceConfig, + @Nullable Boolean validateOnly) + throws SpannerException { + CreateInstanceConfigRequest.Builder builder = + CreateInstanceConfigRequest.newBuilder() + .setParent(parent) + .setInstanceConfigId(instanceConfigId) + .setInstanceConfig(instanceConfig); + if (validateOnly != null) { + builder.setValidateOnly(validateOnly); + } + CreateInstanceConfigRequest request = builder.build(); + GrpcCallContext context = + newCallContext(null, parent, request, InstanceAdminGrpc.getCreateInstanceConfigMethod()); + return instanceAdminStub.createInstanceConfigOperationCallable().futureCall(request, context); + } + + @Override + public OperationFuture updateInstanceConfig( + InstanceConfig instanceConfig, @Nullable Boolean validateOnly, FieldMask fieldMask) + throws SpannerException { + UpdateInstanceConfigRequest.Builder builder = + UpdateInstanceConfigRequest.newBuilder() + .setInstanceConfig(instanceConfig) + .setUpdateMask(fieldMask); + if (validateOnly != null) { + builder.setValidateOnly(validateOnly); + } + UpdateInstanceConfigRequest request = builder.build(); + GrpcCallContext context = + newCallContext( + null, + instanceConfig.getName(), + request, + InstanceAdminGrpc.getUpdateInstanceConfigMethod()); + return instanceAdminStub.updateInstanceConfigOperationCallable().futureCall(request, context); + } + @Override public InstanceConfig getInstanceConfig(String instanceConfigName) throws SpannerException { GetInstanceConfigRequest request = @@ -889,6 +938,55 @@ public InstanceConfig getInstanceConfig(String instanceConfigName) throws Spanne return get(instanceAdminStub.getInstanceConfigCallable().futureCall(request, context)); } + @Override + public void deleteInstanceConfig( + String instanceConfigName, @Nullable String etag, @Nullable Boolean validateOnly) + throws SpannerException { + DeleteInstanceConfigRequest.Builder requestBuilder = + DeleteInstanceConfigRequest.newBuilder().setName(instanceConfigName); + + if (etag != null) { + requestBuilder.setEtag(etag); + } + if (validateOnly != null) { + requestBuilder.setValidateOnly(validateOnly); + } + DeleteInstanceConfigRequest request = requestBuilder.build(); + GrpcCallContext context = + newCallContext( + null, instanceConfigName, request, InstanceAdminGrpc.getDeleteInstanceConfigMethod()); + get(instanceAdminStub.deleteInstanceConfigCallable().futureCall(request, context)); + } + + @Override + public Paginated listInstanceConfigOperations( + int pageSize, @Nullable String filter, @Nullable String pageToken) { + acquireAdministrativeRequestsRateLimiter(); + ListInstanceConfigOperationsRequest.Builder requestBuilder = + ListInstanceConfigOperationsRequest.newBuilder() + .setParent(projectName) + .setPageSize(pageSize); + if (filter != null) { + requestBuilder.setFilter(filter); + } + if (pageToken != null) { + requestBuilder.setPageToken(pageToken); + } + final ListInstanceConfigOperationsRequest request = requestBuilder.build(); + + final GrpcCallContext context = + newCallContext( + null, projectName, request, InstanceAdminGrpc.getListInstanceConfigOperationsMethod()); + ListInstanceConfigOperationsResponse response = + runWithRetryOnAdministrativeRequestsExceeded( + () -> + get( + instanceAdminStub + .listInstanceConfigOperationsCallable() + .futureCall(request, context))); + return new Paginated<>(response.getOperationsList(), response.getNextPageToken()); + } + @Override public Paginated listInstances( int pageSize, @Nullable String pageToken, @Nullable String filter) throws SpannerException { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index 189af2fb55c..2f68b9c1df2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -34,10 +34,19 @@ import com.google.longrunning.Operation; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; -import com.google.spanner.admin.database.v1.*; +import com.google.spanner.admin.database.v1.Backup; +import com.google.spanner.admin.database.v1.CopyBackupMetadata; +import com.google.spanner.admin.database.v1.CreateBackupMetadata; +import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; +import com.google.spanner.admin.database.v1.Database; +import com.google.spanner.admin.database.v1.DatabaseRole; +import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; +import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; +import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata; import com.google.spanner.admin.instance.v1.CreateInstanceMetadata; import com.google.spanner.admin.instance.v1.Instance; import com.google.spanner.admin.instance.v1.InstanceConfig; +import com.google.spanner.admin.instance.v1.UpdateInstanceConfigMetadata; import com.google.spanner.admin.instance.v1.UpdateInstanceMetadata; import com.google.spanner.v1.*; import java.util.List; @@ -162,8 +171,35 @@ interface StreamingCall { Paginated listInstanceConfigs(int pageSize, @Nullable String pageToken) throws SpannerException; + default OperationFuture createInstanceConfig( + String parent, + String instanceConfigId, + InstanceConfig instanceConfig, + @Nullable Boolean validateOnly) + throws SpannerException { + throw new UnsupportedOperationException("Not implemented"); + } + + default OperationFuture updateInstanceConfig( + InstanceConfig instanceConfig, @Nullable Boolean validateOnly, FieldMask fieldMask) + throws SpannerException { + throw new UnsupportedOperationException("Not implemented"); + } + InstanceConfig getInstanceConfig(String instanceConfigName) throws SpannerException; + default void deleteInstanceConfig( + String instanceConfigName, @Nullable String etag, @Nullable Boolean validateOnly) + throws SpannerException { + throw new UnsupportedOperationException("Not implemented"); + } + + /** List all long-running instance config operations on the given project. */ + default Paginated listInstanceConfigOperations( + int pageSize, @Nullable String filter, @Nullable String pageToken) { + throw new UnsupportedOperationException("Not implemented"); + } + Paginated listInstances( int pageSize, @Nullable String pageToken, @Nullable String filter) throws SpannerException; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchClientImplTest.java index 211f3969cc6..2c29b87f86b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchClientImplTest.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.anyMap; import static org.mockito.Mockito.eq; @@ -115,4 +116,9 @@ public void testBatchReadOnlyTxnWithTxnId() { assertThat(batchTxn.getReadTimestamp()) .isEqualTo(batchTxn.getBatchTransactionId().getTimestamp()); } + + @Test + public void testGetDatabaseRole() { + assertEquals(client.getDatabaseRole(), "role"); + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java index c11016fea29..69888fa96ba 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java @@ -94,6 +94,7 @@ public class DatabaseClientImplTest { private static final String TEST_PROJECT = "my-project"; private static final String TEST_INSTANCE = "my-instance"; private static final String TEST_DATABASE = "my-database"; + private static final String TEST_DATABASE_ROLE = "my-role"; private static final String INSTANCE_NAME = String.format("projects/%s/instances/%s", TEST_PROJECT, TEST_INSTANCE); private static final String DATABASE_NAME = @@ -149,6 +150,7 @@ public void setUp() { spanner = SpannerOptions.newBuilder() .setProjectId(TEST_PROJECT) + .setDatabaseRole(TEST_DATABASE_ROLE) .setChannelProvider(channelProvider) .setCredentials(NoCredentials.getInstance()) .setSessionPoolOption(SessionPoolOptions.newBuilder().setFailOnSessionLeak().build()) @@ -2318,4 +2320,11 @@ public void testUntypedNullParameters() { assertNotNull(updateCount); assertEquals(1L, updateCount.longValue()); } + + @Test + public void testGetDatabaseRole() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + assertEquals(TEST_DATABASE_ROLE, client.getDatabaseRole()); + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminClientImplTest.java index 0df869de676..d8134ef29d6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminClientImplTest.java @@ -27,6 +27,7 @@ import com.google.api.gax.longrunning.OperationFuture; import com.google.cloud.Identity; import com.google.cloud.Role; +import com.google.cloud.spanner.InstanceConfigInfo.InstanceConfigField; import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.cloud.spanner.spi.v1.SpannerRpc.Paginated; import com.google.common.collect.ImmutableList; @@ -36,10 +37,14 @@ import com.google.iam.v1.Binding; import com.google.iam.v1.Policy; import com.google.iam.v1.TestIamPermissionsResponse; +import com.google.longrunning.Operation; +import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.FieldMask; +import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata; import com.google.spanner.admin.instance.v1.CreateInstanceMetadata; import com.google.spanner.admin.instance.v1.InstanceConfig; +import com.google.spanner.admin.instance.v1.UpdateInstanceConfigMetadata; import com.google.spanner.admin.instance.v1.UpdateInstanceMetadata; import java.util.Arrays; import java.util.List; @@ -59,6 +64,7 @@ public class InstanceAdminClientImplTest { private static final String CONFIG_ID = "my-config"; private static final String CONFIG_NAME = "projects/my-project/instanceConfigs/my-config"; private static final String CONFIG_NAME2 = "projects/my-project/instanceConfigs/my-config2"; + private static final String BASE_CONFIG = "projects/my-project/instanceConfigs/my-base-config"; @Mock SpannerRpc rpc; @Mock DatabaseAdminClient dbClient; @@ -70,6 +76,84 @@ public void setUp() { client = new InstanceAdminClientImpl(PROJECT_ID, rpc, dbClient); } + private List getAllReplicas() { + return Arrays.asList( + com.google.spanner.admin.instance.v1.ReplicaInfo.newBuilder() + .setLocation("Replica Location 1") + .setType(com.google.spanner.admin.instance.v1.ReplicaInfo.ReplicaType.READ_WRITE) + .setDefaultLeaderLocation(true) + .build(), + com.google.spanner.admin.instance.v1.ReplicaInfo.newBuilder() + .setLocation("Replica Location 2") + .setType(com.google.spanner.admin.instance.v1.ReplicaInfo.ReplicaType.READ_ONLY) + .setDefaultLeaderLocation(false) + .build(), + com.google.spanner.admin.instance.v1.ReplicaInfo.newBuilder() + .setLocation("Replica Location 3") + .setType(com.google.spanner.admin.instance.v1.ReplicaInfo.ReplicaType.WITNESS) + .setDefaultLeaderLocation(false) + .build()); + } + + private com.google.spanner.admin.instance.v1.InstanceConfig getInstanceConfigProto() { + return com.google.spanner.admin.instance.v1.InstanceConfig.newBuilder() + .setName(CONFIG_NAME) + .setBaseConfig(BASE_CONFIG) + .addAllReplicas(getAllReplicas()) + .build(); + } + + @Test + public void createInstanceConfig() { + OperationFuture< + com.google.spanner.admin.instance.v1.InstanceConfig, CreateInstanceConfigMetadata> + rawOperationFuture = + OperationFutureUtil.immediateOperationFuture( + "createInstanceConfig", + getInstanceConfigProto(), + CreateInstanceConfigMetadata.getDefaultInstance()); + when(rpc.createInstanceConfig( + "projects/" + PROJECT_ID, CONFIG_ID, getInstanceConfigProto(), false)) + .thenReturn(rawOperationFuture); + + InstanceConfigInfo instanceConfigInfo = + InstanceConfigInfo.fromProto(getInstanceConfigProto(), client); + + OperationFuture op = + client.createInstanceConfig(instanceConfigInfo, Options.validateOnly(false)); + assertThat(op.isDone()).isTrue(); + } + + @Test + public void updateInstanceConfig() throws Exception { + com.google.spanner.admin.instance.v1.InstanceConfig instanceConfig = + com.google.spanner.admin.instance.v1.InstanceConfig.newBuilder() + .setName(CONFIG_NAME) + .setDisplayName(CONFIG_NAME) + .build(); + OperationFuture< + com.google.spanner.admin.instance.v1.InstanceConfig, UpdateInstanceConfigMetadata> + rawOperationFuture = + OperationFutureUtil.immediateOperationFuture( + "updateInstanceConfig", + getInstanceConfigProto(), + UpdateInstanceConfigMetadata.getDefaultInstance()); + when(rpc.updateInstanceConfig( + instanceConfig, false, FieldMask.newBuilder().addPaths("display_name").build())) + .thenReturn(rawOperationFuture); + InstanceConfigInfo instanceConfigInfo = + InstanceConfigInfo.newBuilder(InstanceConfigId.of(CONFIG_NAME)) + .setDisplayName(CONFIG_NAME) + .build(); + OperationFuture op = + client.updateInstanceConfig( + instanceConfigInfo, + ImmutableList.of(InstanceConfigField.DISPLAY_NAME), + Options.validateOnly(false)); + assertThat(op.isDone()).isTrue(); + assertThat(op.get().getId().getName()).isEqualTo(CONFIG_NAME); + } + @Test public void getInstanceConfig() { when(rpc.getInstanceConfig(CONFIG_NAME)) @@ -77,6 +161,51 @@ public void getInstanceConfig() { assertThat(client.getInstanceConfig(CONFIG_ID).getId().getName()).isEqualTo(CONFIG_NAME); } + @Test + public void dropInstanceConfig() { + client.deleteInstanceConfig(CONFIG_ID); + verify(rpc).deleteInstanceConfig(CONFIG_NAME, null, null); + } + + public Operation getInstanceConfigOperation(String instanceConfigId, Integer operationId) { + InstanceConfig instanceConfig = + com.google.spanner.admin.instance.v1.InstanceConfig.newBuilder() + .setName(instanceConfigId) + .setBaseConfig(BASE_CONFIG) + .addAllReplicas(getAllReplicas()) + .build(); + + CreateInstanceConfigMetadata metadata = + CreateInstanceConfigMetadata.newBuilder().setInstanceConfig(instanceConfig).build(); + + final String operationName = + String.format( + "projects/%s/instanceConfigs/%s/operations/%d", + PROJECT_ID, instanceConfigId, operationId); + return com.google.longrunning.Operation.newBuilder() + .setMetadata(Any.pack(metadata)) + .setResponse(Any.pack(instanceConfig)) + .setDone(false) + .setName(operationName) + .build(); + } + + @Test + public void listInstanceConfigOperations() { + String nextToken = "token"; + Operation operation1 = getInstanceConfigOperation("custom-instance-config-1", 1); + Operation operation2 = getInstanceConfigOperation("custom-instance-config-2", 2); + when(rpc.listInstanceConfigOperations(1, null, null)) + .thenReturn(new Paginated<>(ImmutableList.of(operation1), nextToken)); + when(rpc.listInstanceConfigOperations(1, null, nextToken)) + .thenReturn(new Paginated<>(ImmutableList.of(operation2), "")); + List operations = + Lists.newArrayList(client.listInstanceConfigOperations(Options.pageSize(1)).iterateAll()); + assertThat(operations.get(0).getName()).isEqualTo(operation1.getName()); + assertThat(operations.get(1).getName()).isEqualTo(operation2.getName()); + assertThat(operations.size()).isEqualTo(2); + } + @Test public void listInstanceConfigs() { String nextToken = "token"; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceConfigTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceConfigTest.java index 3b0f56c0889..234c322f762 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceConfigTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceConfigTest.java @@ -40,6 +40,19 @@ public void testInstanceConfigFromProto() { com.google.spanner.admin.instance.v1.InstanceConfig.newBuilder() .setDisplayName("Display Name") .setName("projects/my-project/instanceConfigs/my-instance-config") + .setBaseConfig("projects/my-project/instanceConfigs/custom-base-config") + .addAllOptionalReplicas( + Arrays.asList( + com.google.spanner.admin.instance.v1.ReplicaInfo.newBuilder() + .setLocation("Optional Replica Location 1") + .setType(ReplicaType.READ_ONLY) + .setDefaultLeaderLocation(true) + .build(), + com.google.spanner.admin.instance.v1.ReplicaInfo.newBuilder() + .setLocation("Optional Replica Location 2") + .setType(ReplicaType.READ_ONLY) + .setDefaultLeaderLocation(false) + .build())) .addAllLeaderOptions(Arrays.asList("Leader Option 1", "Leader Option 2")) .addAllReplicas( Arrays.asList( @@ -63,26 +76,43 @@ public void testInstanceConfigFromProto() { assertEquals( new InstanceConfig( - InstanceConfigId.of("my-project", "my-instance-config"), - "Display Name", - Arrays.asList( - ReplicaInfo.newBuilder() - .setLocation("Replica Location 1") - .setType(ReplicaInfo.ReplicaType.READ_WRITE) - .setDefaultLeaderLocation(true) - .build(), - ReplicaInfo.newBuilder() - .setLocation("Replica Location 2") - .setType(ReplicaInfo.ReplicaType.READ_ONLY) - .setDefaultLeaderLocation(false) - .build(), - ReplicaInfo.newBuilder() - .setLocation("Replica Location 3") - .setType(ReplicaInfo.ReplicaType.WITNESS) - .setDefaultLeaderLocation(false) - .build()), - Arrays.asList("Leader Option 1", "Leader Option 2"), - client), + new InstanceConfig.Builder( + client, InstanceConfigId.of("my-project", "my-instance-config")) + .setDisplayName("Display Name") + .setReplicas( + Arrays.asList( + ReplicaInfo.newBuilder() + .setLocation("Replica Location 1") + .setType(ReplicaInfo.ReplicaType.READ_WRITE) + .setDefaultLeaderLocation(true) + .build(), + ReplicaInfo.newBuilder() + .setLocation("Replica Location 2") + .setType(ReplicaInfo.ReplicaType.READ_ONLY) + .setDefaultLeaderLocation(false) + .build(), + ReplicaInfo.newBuilder() + .setLocation("Replica Location 3") + .setType(ReplicaInfo.ReplicaType.WITNESS) + .setDefaultLeaderLocation(false) + .build())) + .setLeaderOptions(Arrays.asList("Leader Option 1", "Leader Option 2")) + .setOptionalReplicas( + Arrays.asList( + ReplicaInfo.newBuilder() + .setLocation("Optional Replica Location 1") + .setType(ReplicaInfo.ReplicaType.READ_ONLY) + .setDefaultLeaderLocation(true) + .build(), + ReplicaInfo.newBuilder() + .setLocation("Optional Replica Location 2") + .setType(ReplicaInfo.ReplicaType.READ_ONLY) + .setDefaultLeaderLocation(false) + .build())) + .setBaseConfig( + new InstanceConfigInfo.BuilderImpl( + InstanceConfigId.of("my-project", "custom-base-config")) + .build())), instanceConfig); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java index 3f018e382d2..8da8683cf0c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java @@ -20,6 +20,7 @@ import static com.google.cloud.spanner.MetricRegistryConstants.NUM_READ_SESSIONS; import static com.google.cloud.spanner.MetricRegistryConstants.NUM_SESSIONS_BEING_PREPARED; import static com.google.cloud.spanner.MetricRegistryConstants.NUM_WRITE_SESSIONS; +import static com.google.cloud.spanner.MetricRegistryConstants.SPANNER_DEFAULT_LABEL_VALUES; import static com.google.cloud.spanner.MetricRegistryConstants.SPANNER_LABEL_KEYS; import static com.google.cloud.spanner.MetricRegistryConstants.SPANNER_LABEL_KEYS_WITH_TYPE; import static com.google.common.truth.Truth.assertThat; @@ -108,6 +109,7 @@ public class SessionPoolTest extends BaseSessionPoolTest { SessionPool pool; SessionPoolOptions options; private String sessionName = String.format("%s/sessions/s", db.getName()); + private String TEST_DATABASE_ROLE = "my-role"; @Parameters(name = "min sessions = {0}") public static Collection data() { @@ -127,6 +129,7 @@ private SessionPool createPool( Clock clock, MetricRegistry metricRegistry, List labelValues) { return SessionPool.createPool( options, + TEST_DATABASE_ROLE, new TestExecutorFactory(), client.getSessionClient(db), clock, @@ -1178,6 +1181,13 @@ public void testSessionMetrics() throws Exception { assertThat(writePreparedSessions.value()).isEqualTo(0L); } + @Test + public void testGetDatabaseRole() throws Exception { + setupMockSessionCreation(); + pool = createPool(new FakeClock(), new FakeMetricRegistry(), SPANNER_DEFAULT_LABEL_VALUES); + assertEquals(TEST_DATABASE_ROLE, pool.getDatabaseRole()); + } + private void mockKeepAlive(Session session) { ReadContext context = mock(ReadContext.class); ResultSet resultSet = mock(ResultSet.class); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java index 84074787655..4d13829a857 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java @@ -110,8 +110,15 @@ public static void startStaticServer() throws Exception { // This is not possible in Java 12 and later. java.lang.reflect.Field field = Tracing.class.getDeclaredField("traceComponent"); field.setAccessible(true); - java.lang.reflect.Field modifiersField = - java.lang.reflect.Field.class.getDeclaredField("modifiers"); + java.lang.reflect.Field modifiersField = null; + try { + modifiersField = java.lang.reflect.Field.class.getDeclaredField("modifiers"); + } catch (NoSuchFieldException e) { + // Halt the test and ignore it. + Assume.assumeTrue( + "Skipping test as reflection is not allowed on reflection class in this JDK build", + false); + } modifiersField.setAccessible(true); // Remove the final modifier from the 'traceComponent' field. modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseRolePermissionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseRolePermissionTest.java index 410ed0d17e6..c23cd1d0fbe 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseRolePermissionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseRolePermissionTest.java @@ -110,6 +110,7 @@ public void grantAndRevokeDatabaseRolePermissions() throws Exception { try (ResultSet rs = dbClient.singleUse().executeQuery(Statement.of("SELECT COUNT(*) as cnt FROM T"))) { assertTrue(rs.next()); + assertEquals(dbClient.getDatabaseRole(), dbRoleParent); } catch (PermissionDeniedException e) { // This is not expected fail("Got PermissionDeniedException when it should not have occurred."); diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/it/valid/y_90_nested.json b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/it/valid/y_80_nested.json similarity index 71% rename from google-cloud-spanner/src/test/resources/com/google/cloud/spanner/it/valid/y_90_nested.json rename to google-cloud-spanner/src/test/resources/com/google/cloud/spanner/it/valid/y_80_nested.json index 5d1bd8e16cc..f32ea97ccd3 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/it/valid/y_90_nested.json +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/it/valid/y_80_nested.json @@ -1 +1 @@ -{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} +{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{"nest":{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 8c51214f921..f23b04ae73c 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.30.2 + 6.31.0 grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 6.30.2 + 6.31.0 diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 3fbb1257136..358fa2ac4a7 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.30.2 + 6.31.0 grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 6.30.2 + 6.31.0 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index d5f67b52c17..16c0338a583 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.30.2 + 6.31.0 grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.30.2 + 6.31.0 diff --git a/pom.xml b/pom.xml index 3ba4915a6b0..1bcf2ec5264 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 6.30.2 + 6.31.0 Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -62,37 +62,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.30.2 + 6.31.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.30.2 + 6.31.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.30.2 + 6.31.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.30.2 + 6.31.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.30.2 + 6.31.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.30.2 + 6.31.0 com.google.cloud google-cloud-spanner - 6.30.2 + 6.31.0 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index f9e1b9231d4..d707485840b 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.30.2 + 6.31.0 proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 6.30.2 + 6.31.0 diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index db504059c5a..3c3484faf86 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.30.2 + 6.31.0 proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 6.30.2 + 6.31.0 diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 540dbad6487..0e9ee080955 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.30.2 + 6.31.0 proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.30.2 + 6.31.0 diff --git a/renovate.json b/renovate.json index 6c98729fcab..077ed87c15d 100644 --- a/renovate.json +++ b/renovate.json @@ -10,6 +10,7 @@ ":maintainLockFilesDisabled", ":autodetectPinVersions" ], + "ignorePaths": [".kokoro/requirements.txt"], "packageRules": [ { "packagePatterns": [ diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 54c0a1c97e4..121e5d58f1b 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -22,7 +22,7 @@ 1.8 UTF-8 0.31.1 - 2.3.3 + 2.3.5 3.4.5 @@ -32,7 +32,7 @@ com.google.cloud google-cloud-spanner - 6.30.1 + 6.30.2 diff --git a/samples/native-image/pom.xml b/samples/native-image/pom.xml index bc99087a8a7..4dc023db144 100644 --- a/samples/native-image/pom.xml +++ b/samples/native-image/pom.xml @@ -109,7 +109,7 @@ org.graalvm.buildtools junit-platform-native - 0.9.13 + 0.9.14 test diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 79100663d57..9f503b73f0c 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -22,7 +22,7 @@ 1.8 UTF-8 0.31.1 - 2.3.3 + 2.3.5 3.4.5 @@ -31,7 +31,7 @@ com.google.cloud google-cloud-spanner - 6.30.2 + 6.31.0 diff --git a/versions.txt b/versions.txt index 24033553c32..7316c9c5de8 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:6.30.2:6.30.2 -proto-google-cloud-spanner-v1:6.30.2:6.30.2 -proto-google-cloud-spanner-admin-database-v1:6.30.2:6.30.2 -grpc-google-cloud-spanner-v1:6.30.2:6.30.2 -grpc-google-cloud-spanner-admin-instance-v1:6.30.2:6.30.2 -grpc-google-cloud-spanner-admin-database-v1:6.30.2:6.30.2 -google-cloud-spanner:6.30.2:6.30.2 +proto-google-cloud-spanner-admin-instance-v1:6.31.0:6.31.0 +proto-google-cloud-spanner-v1:6.31.0:6.31.0 +proto-google-cloud-spanner-admin-database-v1:6.31.0:6.31.0 +grpc-google-cloud-spanner-v1:6.31.0:6.31.0 +grpc-google-cloud-spanner-admin-instance-v1:6.31.0:6.31.0 +grpc-google-cloud-spanner-admin-database-v1:6.31.0:6.31.0 +google-cloud-spanner:6.31.0:6.31.0