summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/js/app/yarn.lock165
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java5
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java3
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java39
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TermsOfServiceApproval.java30
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java20
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java25
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java24
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java6
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentdbconfigmanager.cpp15
-rw-r--r--searchlib/src/tests/query/querybuilder_test.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/common/bitvector.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/common/bitvector.h76
-rw-r--r--searchlib/src/vespa/searchlib/parsequery/parse.h2
-rw-r--r--storage/src/vespa/storage/storageserver/mergethrottler.cpp4
22 files changed, 306 insertions, 142 deletions
diff --git a/client/js/app/yarn.lock b/client/js/app/yarn.lock
index b812a8b8e37..7341cdc6132 100644
--- a/client/js/app/yarn.lock
+++ b/client/js/app/yarn.lock
@@ -24,9 +24,9 @@
chalk "^2.4.2"
"@babel/compat-data@^7.22.9":
- version "7.22.20"
- resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0"
- integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.2.tgz#6a12ced93455827037bfb5ed8492820d60fc32cc"
+ integrity sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==
"@babel/core@^7.1.0", "@babel/core@^7.12.17":
version "7.22.9"
@@ -70,22 +70,22 @@
json5 "^2.2.3"
semver "^6.3.1"
-"@babel/core@^7.22.20":
- version "7.22.20"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.20.tgz#e3d0eed84c049e2a2ae0a64d27b6a37edec385b7"
- integrity sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==
+"@babel/core@^7.23.2":
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.2.tgz#ed10df0d580fff67c5f3ee70fd22e2e4c90a9f94"
+ integrity sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.22.13"
- "@babel/generator" "^7.22.15"
+ "@babel/generator" "^7.23.0"
"@babel/helper-compilation-targets" "^7.22.15"
- "@babel/helper-module-transforms" "^7.22.20"
- "@babel/helpers" "^7.22.15"
- "@babel/parser" "^7.22.16"
+ "@babel/helper-module-transforms" "^7.23.0"
+ "@babel/helpers" "^7.23.2"
+ "@babel/parser" "^7.23.0"
"@babel/template" "^7.22.15"
- "@babel/traverse" "^7.22.20"
- "@babel/types" "^7.22.19"
- convert-source-map "^1.7.0"
+ "@babel/traverse" "^7.23.2"
+ "@babel/types" "^7.23.0"
+ convert-source-map "^2.0.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.3"
@@ -188,17 +188,6 @@
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/helper-validator-identifier" "^7.22.15"
-"@babel/helper-module-transforms@^7.22.20":
- version "7.22.20"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz#da9edc14794babbe7386df438f3768067132f59e"
- integrity sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==
- dependencies:
- "@babel/helper-environment-visitor" "^7.22.20"
- "@babel/helper-module-imports" "^7.22.15"
- "@babel/helper-simple-access" "^7.22.5"
- "@babel/helper-split-export-declaration" "^7.22.6"
- "@babel/helper-validator-identifier" "^7.22.20"
-
"@babel/helper-module-transforms@^7.22.5":
version "7.22.9"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129"
@@ -210,6 +199,17 @@
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/helper-validator-identifier" "^7.22.5"
+"@babel/helper-module-transforms@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e"
+ integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-module-imports" "^7.22.15"
+ "@babel/helper-simple-access" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/helper-validator-identifier" "^7.22.20"
+
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
@@ -262,6 +262,15 @@
"@babel/traverse" "^7.22.11"
"@babel/types" "^7.22.11"
+"@babel/helpers@^7.23.2":
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.2.tgz#2832549a6e37d484286e15ba36a5330483cac767"
+ integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/traverse" "^7.23.2"
+ "@babel/types" "^7.23.0"
+
"@babel/highlight@^7.22.13":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
@@ -271,7 +280,12 @@
chalk "^2.4.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.22.16":
+"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
+ integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
+
+"@babel/parser@^7.14.7", "@babel/parser@^7.22.16":
version "7.22.16"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95"
integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==
@@ -281,11 +295,6 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.13.tgz#23fb17892b2be7afef94f573031c2f4b42839a2b"
integrity sha512-3l6+4YOvc9wx7VlCSw4yQfcBo01ECA8TicQfbnCPuCEpRQrf+gTUyGdxNw+pyTUyywp6JRD1w0YQs9TpBXYlkw==
-"@babel/parser@^7.23.0":
- version "7.23.0"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
- integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
-
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@@ -430,7 +439,7 @@
"@babel/parser" "^7.22.15"
"@babel/types" "^7.22.15"
-"@babel/traverse@^7.22.11", "@babel/traverse@^7.22.15", "@babel/traverse@^7.22.17", "@babel/traverse@^7.22.20", "@babel/traverse@^7.22.8":
+"@babel/traverse@^7.22.11", "@babel/traverse@^7.22.15", "@babel/traverse@^7.22.17", "@babel/traverse@^7.22.8", "@babel/traverse@^7.23.2":
version "7.23.2"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
@@ -446,13 +455,13 @@
debug "^4.1.0"
globals "^11.1.0"
-"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.17", "@babel/types@^7.22.19", "@babel/types@^7.22.5":
- version "7.22.19"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684"
- integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
+ integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
- "@babel/helper-validator-identifier" "^7.22.19"
+ "@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
"@babel/types@^7.22.10", "@babel/types@^7.22.11", "@babel/types@^7.3.3":
@@ -464,13 +473,13 @@
"@babel/helper-validator-identifier" "^7.22.15"
to-fast-properties "^2.0.0"
-"@babel/types@^7.23.0":
- version "7.23.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
- integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+"@babel/types@^7.22.17":
+ version "7.22.19"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684"
+ integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
- "@babel/helper-validator-identifier" "^7.22.20"
+ "@babel/helper-validator-identifier" "^7.22.19"
to-fast-properties "^2.0.0"
"@bcoe/v8-coverage@^0.2.3":
@@ -1068,7 +1077,7 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
-"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9":
+"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18":
version "0.3.19"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811"
integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==
@@ -1076,6 +1085,14 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
+"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
+ version "0.3.20"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
+ integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
"@mantine/core@^6.0.0":
version "6.0.21"
resolved "https://registry.yarnpkg.com/@mantine/core/-/core-6.0.21.tgz#6e3a1b8d0f6869518a644d5f5e3d55a5db7e1e51"
@@ -1272,10 +1289,10 @@
"@types/babel__template" "*"
"@types/babel__traverse" "*"
-"@types/babel__core@^7.20.2":
- version "7.20.2"
- resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.2.tgz#215db4f4a35d710256579784a548907237728756"
- integrity sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==
+"@types/babel__core@^7.20.3":
+ version "7.20.3"
+ resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.3.tgz#d5625a50b6f18244425a1359a858c73d70340778"
+ integrity sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==
dependencies:
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
@@ -1284,24 +1301,24 @@
"@types/babel__traverse" "*"
"@types/babel__generator@*":
- version "7.6.5"
- resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.5.tgz#281f4764bcbbbc51fdded0f25aa587b4ce14da95"
- integrity sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==
+ version "7.6.6"
+ resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.6.tgz#676f89f67dc8ddaae923f70ebc5f1fa800c031a8"
+ integrity sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==
dependencies:
"@babel/types" "^7.0.0"
"@types/babel__template@*":
- version "7.4.2"
- resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.2.tgz#843e9f1f47c957553b0c374481dc4772921d6a6b"
- integrity sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==
+ version "7.4.3"
+ resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.3.tgz#db9ac539a2fe05cfe9e168b24f360701bde41f5f"
+ integrity sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==
dependencies:
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
"@types/babel__traverse@*":
- version "7.20.2"
- resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.2.tgz#4ddf99d95cfdd946ff35d2b65c978d9c9bf2645d"
- integrity sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==
+ version "7.20.3"
+ resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.3.tgz#a971aa47441b28ef17884ff945d0551265a2d058"
+ integrity sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==
dependencies:
"@babel/types" "^7.20.7"
@@ -1388,14 +1405,14 @@
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
"@vitejs/plugin-react@^4":
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz#e4f56f46fd737c5d386bb1f1ade86ba275fe09bd"
- integrity sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.1.1.tgz#a10254dc76778027407d01b6ddbca53b23852a72"
+ integrity sha512-Jie2HERK+uh27e+ORXXwEP5h0Y2lS9T2PRGbfebiHGlwzDO0dEnd2aNtOR/qjBlPb1YgxwAONeblL1xqLikLag==
dependencies:
- "@babel/core" "^7.22.20"
+ "@babel/core" "^7.23.2"
"@babel/plugin-transform-react-jsx-self" "^7.22.5"
"@babel/plugin-transform-react-jsx-source" "^7.22.5"
- "@types/babel__core" "^7.20.2"
+ "@types/babel__core" "^7.20.3"
react-refresh "^0.14.0"
acorn-jsx@^5.3.2:
@@ -1809,12 +1826,12 @@ braces@^3.0.2:
fill-range "^7.0.1"
browserslist@^4.21.9:
- version "4.21.11"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.11.tgz#35f74a3e51adc4d193dcd76ea13858de7b8fecb8"
- integrity sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==
+ version "4.22.1"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619"
+ integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==
dependencies:
- caniuse-lite "^1.0.30001538"
- electron-to-chromium "^1.4.526"
+ caniuse-lite "^1.0.30001541"
+ electron-to-chromium "^1.4.535"
node-releases "^2.0.13"
update-browserslist-db "^1.0.13"
@@ -1876,10 +1893,10 @@ camelcase@^6.2.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-caniuse-lite@^1.0.30001538:
- version "1.0.30001539"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz#325a387ab1ed236df2c12dc6cd43a4fff9903a44"
- integrity sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA==
+caniuse-lite@^1.0.30001541:
+ version "1.0.30001559"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz#95a982440d3d314c471db68d02664fb7536c5a30"
+ integrity sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA==
capture-exit@^2.0.0:
version "2.0.0"
@@ -2219,10 +2236,10 @@ dom-helpers@^5.0.1:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
-electron-to-chromium@^1.4.526:
- version "1.4.528"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz#7c900fd73d9d2e8bb0dab0e301f25f0f4776ef2c"
- integrity sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==
+electron-to-chromium@^1.4.535:
+ version "1.4.574"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.574.tgz#6de04d7c6e244e5ffcae76d2e2a33b02cab66781"
+ integrity sha512-bg1m8L0n02xRzx4LsTTMbBPiUd9yIR+74iPtS/Ao65CuXvhVZHP0ym1kSdDG3yHFDXqHQQBKujlN1AQ8qZnyFg==
emittery@^0.13.1:
version "0.13.1"
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java
index 82cddb46d9a..e741fb8d203 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java
@@ -7,6 +7,7 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.Bill;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import java.net.URI;
@@ -25,6 +26,8 @@ public class ConsoleUrls {
this.root = root.toString().replaceFirst("/$", ""); // Remove trailing slash
}
+ public ConsoleUrls(String hostname) { this(URI.create("https://" + hostname)); }
+
public String root() {
return root;
}
@@ -40,6 +43,8 @@ public class ConsoleUrls {
public String tenantBilling(TenantName t) { return "%s/tenant/%s/account/billing".formatted(root, t.value()); }
+ public String tenantBilling(TenantName t, Bill.Id id) { return "%s/bill/%s".formatted(tenantBilling(t), id.value()); }
+
public String prodApplicationOverview(TenantName tenantName, ApplicationName applicationName) {
return "%s/tenant/%s/application/%s/prod/instance".formatted(root, tenantName.value(), applicationName.value());
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
index 54f53d64f76..9a3ea71660b 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
@@ -253,7 +253,9 @@ enum PathGroup {
emailVerification("/user/v1/email/verify"),
/** Path used for dataplane token */
- dataplaneToken(Matcher.tenant,"/application/v4/tenant/{tenant}/token", "/application/v4/tenant/{tenant}/token/{ignored}");
+ dataplaneToken(Matcher.tenant,"/application/v4/tenant/{tenant}/token", "/application/v4/tenant/{tenant}/token/{ignored}"),
+
+ termsOfService(Matcher.tenant, "/application/v4/tenant/{tenant}/terms-of-service");
final List<String> pathSpecs;
final List<Matcher> matchers;
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java
index d1a8b2ef0c3..44f6386e9bc 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java
@@ -191,6 +191,10 @@ enum Policy {
dataplaneToken(Privilege.grant(Action.all())
.on(PathGroup.dataplaneToken)
+ .in(SystemName.PublicCd, SystemName.Public)),
+
+ termsOfService(Privilege.grant(Action.create)
+ .on(PathGroup.termsOfService)
.in(SystemName.PublicCd, SystemName.Public));
private final Set<Privilege> privileges;
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java
index 31c8560c908..0b5359ac826 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java
@@ -69,7 +69,8 @@ public enum RoleDefinition {
Policy.applicationManager,
Policy.keyRevokal,
Policy.billingInformationRead,
- Policy.accessRequests
+ Policy.accessRequests,
+ Policy.termsOfService
),
/** Headless — the application specific role identified by deployment keys for production */
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java
index 6e3b26661e5..1db84240fe2 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java
@@ -13,17 +13,21 @@ public class TenantBilling {
private final TaxId taxId;
private final PurchaseOrder purchaseOrder;
private final Email invoiceEmail;
+ private final TermsOfServiceApproval tosApproval;
- public TenantBilling(TenantContact contact, TenantAddress address, TaxId taxId, PurchaseOrder purchaseOrder, Email invoiceEmail) {
+ public TenantBilling(TenantContact contact, TenantAddress address, TaxId taxId, PurchaseOrder purchaseOrder,
+ Email invoiceEmail, TermsOfServiceApproval tosApproval) {
this.contact = Objects.requireNonNull(contact);
this.address = Objects.requireNonNull(address);
this.taxId = Objects.requireNonNull(taxId);
this.purchaseOrder = Objects.requireNonNull(purchaseOrder);
this.invoiceEmail = Objects.requireNonNull(invoiceEmail);
+ this.tosApproval = Objects.requireNonNull(tosApproval);
}
public static TenantBilling empty() {
- return new TenantBilling(TenantContact.empty(), TenantAddress.empty(), TaxId.empty(), PurchaseOrder.empty(), Email.empty());
+ return new TenantBilling(TenantContact.empty(), TenantAddress.empty(), TaxId.empty(), PurchaseOrder.empty(),
+ Email.empty(), TermsOfServiceApproval.empty());
}
public TenantContact contact() {
@@ -46,24 +50,30 @@ public class TenantBilling {
return invoiceEmail;
}
+ public TermsOfServiceApproval getToSApproval() { return tosApproval; }
+
public TenantBilling withContact(TenantContact updatedContact) {
- return new TenantBilling(updatedContact, this.address, this.taxId, this.purchaseOrder, this.invoiceEmail);
+ return new TenantBilling(updatedContact, this.address, this.taxId, this.purchaseOrder, this.invoiceEmail, tosApproval);
}
public TenantBilling withAddress(TenantAddress updatedAddress) {
- return new TenantBilling(this.contact, updatedAddress, this.taxId, this.purchaseOrder, this.invoiceEmail);
+ return new TenantBilling(this.contact, updatedAddress, this.taxId, this.purchaseOrder, this.invoiceEmail, tosApproval);
}
public TenantBilling withTaxId(TaxId updatedTaxId) {
- return new TenantBilling(this.contact, this.address, updatedTaxId, this.purchaseOrder, this.invoiceEmail);
+ return new TenantBilling(this.contact, this.address, updatedTaxId, this.purchaseOrder, this.invoiceEmail, tosApproval);
}
public TenantBilling withPurchaseOrder(PurchaseOrder updatedPurchaseOrder) {
- return new TenantBilling(this.contact, this.address, this.taxId, updatedPurchaseOrder, this.invoiceEmail);
+ return new TenantBilling(this.contact, this.address, this.taxId, updatedPurchaseOrder, this.invoiceEmail, tosApproval);
}
public TenantBilling withInvoiceEmail(Email updatedInvoiceEmail) {
- return new TenantBilling(this.contact, this.address, this.taxId, this.purchaseOrder, updatedInvoiceEmail);
+ return new TenantBilling(this.contact, this.address, this.taxId, this.purchaseOrder, updatedInvoiceEmail, tosApproval);
+ }
+
+ public TenantBilling withToSApproval(TermsOfServiceApproval approval) {
+ return new TenantBilling(contact, address, taxId, purchaseOrder, invoiceEmail, approval);
}
public boolean isEmpty() {
@@ -75,16 +85,14 @@ public class TenantBilling {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TenantBilling that = (TenantBilling) o;
- return Objects.equals(contact, that.contact) &&
- Objects.equals(address, that.address) &&
- Objects.equals(taxId, that.taxId) &&
- Objects.equals(purchaseOrder, that.purchaseOrder) &&
- Objects.equals(invoiceEmail, that.invoiceEmail);
+ return Objects.equals(contact, that.contact) && Objects.equals(address, that.address)
+ && Objects.equals(taxId, that.taxId) && Objects.equals(purchaseOrder, that.purchaseOrder)
+ && Objects.equals(invoiceEmail, that.invoiceEmail) && Objects.equals(tosApproval, that.tosApproval);
}
@Override
public int hashCode() {
- return Objects.hash(contact, address, taxId, purchaseOrder, invoiceEmail);
+ return Objects.hash(contact, address, taxId, purchaseOrder, invoiceEmail, tosApproval);
}
@Override
@@ -92,9 +100,10 @@ public class TenantBilling {
return "TenantBilling{" +
"contact=" + contact +
", address=" + address +
- ", taxId='" + taxId + '\'' +
- ", purchaseOrder='" + purchaseOrder + '\'' +
+ ", taxId=" + taxId +
+ ", purchaseOrder=" + purchaseOrder +
", invoiceEmail=" + invoiceEmail +
+ ", tosApproval=" + tosApproval +
'}';
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TermsOfServiceApproval.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TermsOfServiceApproval.java
new file mode 100644
index 00000000000..61fba17c473
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TermsOfServiceApproval.java
@@ -0,0 +1,30 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+package com.yahoo.vespa.hosted.controller.tenant;
+
+import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal;
+
+import java.time.Instant;
+import java.util.Optional;
+
+/**
+ * @author bjorncs
+ */
+public record TermsOfServiceApproval(Instant approvedAt, Optional<SimplePrincipal> approvedBy) {
+
+ public TermsOfServiceApproval(Instant at, SimplePrincipal by) { this(at, Optional.of(by)); }
+
+ public TermsOfServiceApproval(String at, String by) {
+ this(at.isBlank() ? Instant.EPOCH : Instant.parse(at), by.isBlank() ? Optional.empty() : Optional.of(new SimplePrincipal(by)));
+ }
+
+ public TermsOfServiceApproval {
+ if (approvedBy.isEmpty() && !Instant.EPOCH.equals(approvedAt))
+ throw new IllegalArgumentException("Missing approver");
+ }
+
+ public static TermsOfServiceApproval empty() { return new TermsOfServiceApproval(Instant.EPOCH, Optional.empty()); }
+
+ public boolean hasApproved() { return approvedBy.isPresent(); }
+ public boolean isEmpty() { return approvedBy.isEmpty() && Instant.EPOCH.equals(approvedAt); }
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
index 7801efe504b..961925cf620 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
@@ -36,6 +36,7 @@ import com.yahoo.vespa.hosted.controller.tenant.TenantBilling;
import com.yahoo.vespa.hosted.controller.tenant.TenantContact;
import com.yahoo.vespa.hosted.controller.tenant.TenantContacts;
import com.yahoo.vespa.hosted.controller.tenant.TenantInfo;
+import com.yahoo.vespa.hosted.controller.tenant.TermsOfServiceApproval;
import java.net.URI;
import java.security.Principal;
@@ -101,6 +102,9 @@ public class TenantSerializer {
private static final String taxIdCodeField = "code";
private static final String purchaseOrderField = "purchaseOrder";
private static final String invoiceEmailField = "invoiceEmail";
+ private static final String tosApprovalField = "tosApproval";
+ private static final String tosApprovalAtField = "at";
+ private static final String tosApprovalByField = "by";
private static final String awsIdField = "awsId";
private static final String roleField = "role";
@@ -292,6 +296,7 @@ public class TenantSerializer {
private TenantBilling tenantInfoBillingContactFromSlime(Inspector billingObject) {
var taxIdInspector = billingObject.field(taxIdField);
var taxId = switch (taxIdInspector.type()) {
+ // TODO(bjorncs, 2023-11-02): Remove legacy tax id format
case STRING -> TaxId.legacy(taxIdInspector.asString());
case OBJECT -> {
var taxIdCountry = taxIdInspector.field(taxIdCountryField).asString();
@@ -304,6 +309,13 @@ public class TenantSerializer {
};
var purchaseOrder = new PurchaseOrder(billingObject.field(purchaseOrderField).asString());
var invoiceEmail = new Email(billingObject.field(invoiceEmailField).asString(), false);
+ var tosApprovalInspector = billingObject.field(tosApprovalField);
+ var tosApproval = switch (tosApprovalInspector.type()) {
+ case OBJECT -> new TermsOfServiceApproval(tosApprovalInspector.field(tosApprovalAtField).asString(),
+ tosApprovalInspector.field(tosApprovalByField).asString());
+ case NIX -> TermsOfServiceApproval.empty();
+ default -> throw new IllegalArgumentException(taxIdInspector.type().name());
+ };
return TenantBilling.empty()
.withContact(TenantContact.from(
@@ -313,7 +325,8 @@ public class TenantSerializer {
.withAddress(tenantInfoAddressFromSlime(billingObject.field("address")))
.withTaxId(taxId)
.withPurchaseOrder(purchaseOrder)
- .withInvoiceEmail(invoiceEmail);
+ .withInvoiceEmail(invoiceEmail)
+ .withToSApproval(tosApproval);
}
private List<TenantSecretStore> secretStoresFromSlime(Inspector secretStoresObject) {
@@ -382,6 +395,11 @@ public class TenantSerializer {
billingCursor.setString(purchaseOrderField, billingContact.getPurchaseOrder().value());
billingCursor.setString(invoiceEmailField, billingContact.getInvoiceEmail().getEmailAddress());
toSlime(billingContact.address(), billingCursor);
+ if (!billingContact.getToSApproval().isEmpty()) {
+ var tosApprovalCursor = billingCursor.setObject(tosApprovalField);
+ tosApprovalCursor.setString(tosApprovalAtField, billingContact.getToSApproval().approvedAt().toString());
+ tosApprovalCursor.setString(tosApprovalByField, billingContact.getToSApproval().approvedBy().get().getName());
+ }
}
private void toSlime(List<TenantSecretStore> tenantSecretStores, Cursor parentCursor) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index 1fd8e7c8f3b..6cf38a1927c 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -87,6 +87,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretSto
import com.yahoo.vespa.hosted.controller.api.role.Role;
import com.yahoo.vespa.hosted.controller.api.role.RoleDefinition;
import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
+import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal;
import com.yahoo.vespa.hosted.controller.application.AssignedRotation;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.Deployment;
@@ -135,6 +136,7 @@ import com.yahoo.vespa.hosted.controller.tenant.TenantBilling;
import com.yahoo.vespa.hosted.controller.tenant.TenantContact;
import com.yahoo.vespa.hosted.controller.tenant.TenantContacts;
import com.yahoo.vespa.hosted.controller.tenant.TenantInfo;
+import com.yahoo.vespa.hosted.controller.tenant.TermsOfServiceApproval;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
import com.yahoo.yolean.Exceptions;
@@ -386,6 +388,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
private HttpResponse handlePOST(Path path, HttpRequest request) {
if (path.matches("/application/v4/tenant/{tenant}")) return createTenant(path.get("tenant"), request);
+ if (path.matches("/application/v4/tenant/{tenant}/terms-of-service")) return approveTermsOfService(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/key")) return addDeveloperKey(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/token/{tokenid}")) return generateToken(path.get("tenant"), path.get("tokenid"), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return createApplication(path.get("tenant"), path.get("application"), request);
@@ -702,6 +705,10 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
taxIdCursor.setString("code", billingContact.getTaxId().code().value());
root.setString("purchaseOrder", billingContact.getPurchaseOrder().value());
root.setString("invoiceEmail", billingContact.getInvoiceEmail().getEmailAddress());
+ var tosApprovalCursor = root.setObject("tosApproval");
+ var tosApproval = billingContact.getToSApproval();
+ tosApprovalCursor.setString("at", !tosApproval.isEmpty() ? tosApproval.approvedAt().toString() : "");
+ tosApprovalCursor.setString("by", !tosApproval.isEmpty() ? tosApproval.approvedBy().get().getName() : "");
toSlime(billingContact.address(), root); // will create "address" on the parent
}
@@ -812,6 +819,10 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
billingCursor.setString("purchaseOrder", billingContact.getPurchaseOrder().value());
billingCursor.setString("invoiceEmail", billingContact.getInvoiceEmail().getEmailAddress());
toSlime(billingContact.address(), billingCursor);
+ var tosApprovalCursor = billingCursor.setObject("tosApproval");
+ var tosApproval = billingContact.getToSApproval();
+ tosApprovalCursor.setString("at", !tosApproval.isEmpty() ? tosApproval.approvedAt().toString() : "");
+ tosApprovalCursor.setString("by", !tosApproval.isEmpty() ? tosApproval.approvedBy().get().getName() : "");
}
private void toSlime(TenantContacts contacts, Cursor parentCursor) {
@@ -1239,6 +1250,20 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
return new SlimeJsonResponse(slime);
}
+ private HttpResponse approveTermsOfService(String tenant, HttpRequest req) {
+ if (controller.tenants().require(TenantName.from(tenant)).type() != Tenant.Type.cloud)
+ throw new IllegalArgumentException("Tenant '" + tenant + "' is not a cloud tenant");
+ var approvedBy = SimplePrincipal.of(req.getJDiscRequest().getUserPrincipal());
+ var approvedAt = controller.clock().instant();
+
+ controller.tenants().lockOrThrow(TenantName.from(tenant), LockedTenant.Cloud.class, t -> {
+ var updatedTenant = t.withInfo(t.get().info().withBilling(t.get().info().billingContact().withToSApproval(
+ new TermsOfServiceApproval(approvedAt, approvedBy))));
+ controller.tenants().store(updatedTenant);
+ });
+ return new MessageResponse("Terms of service approved by %s".formatted(approvedBy.getName()));
+ }
+
private HttpResponse addDeveloperKey(String tenantName, HttpRequest request) {
if (controller.tenants().require(TenantName.from(tenantName)).type() != Tenant.Type.cloud)
throw new IllegalArgumentException("Tenant '" + tenantName + "' is not a cloud tenant");
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
index f2fc43933df..493d4df90a9 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
@@ -31,6 +31,7 @@ import com.yahoo.vespa.hosted.controller.tenant.TenantBilling;
import com.yahoo.vespa.hosted.controller.tenant.TenantContact;
import com.yahoo.vespa.hosted.controller.tenant.TenantContacts;
import com.yahoo.vespa.hosted.controller.tenant.TenantInfo;
+import com.yahoo.vespa.hosted.controller.tenant.TermsOfServiceApproval;
import org.junit.jupiter.api.Test;
import java.net.URI;
@@ -240,6 +241,7 @@ public class TenantSerializerTest {
.withPurchaseOrder(new PurchaseOrder("PO42"))
.withTaxId(new TaxId("NO", "no_vat", "123456789MVA"))
.withInvoiceEmail(new Email("billing@mycomp.any", false))
+ .withToSApproval(new TermsOfServiceApproval(Instant.ofEpochMilli(1234L), new SimplePrincipal("ceo@mycomp.any")))
);
Slime slime = new Slime();
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
index f8ae7c8ea50..3c57f812a48 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
@@ -112,7 +112,11 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
"code": ""
},
"purchaseOrder":"",
- "invoiceEmail":""
+ "invoiceEmail":"",
+ "tosApproval": {
+ "at": "",
+ "by": ""
+ }
}
""";
var request = request("/application/v4/tenant/scoober/info/billing", GET)
@@ -143,6 +147,10 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
.roles(Set.of(Role.administrator(tenantName)));
tester.assertResponse(updateRequest, "{\"message\":\"Tenant info updated\"}", 200);
+ var approveToSRequest = request("/application/v4/tenant/scoober/terms-of-service", POST)
+ .data("{}").roles(Set.of(Role.administrator(tenantName)));
+ tester.assertResponse(approveToSRequest, "{\"message\":\"Terms of service approved by user@test\"}", 200);
+
expectedResponse = """
{
"contact": {
@@ -158,6 +166,10 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
},
"purchaseOrder":"PO9001",
"invoiceEmail":"billing@mycomp.any",
+ "tosApproval": {
+ "at": "2020-09-13T12:26:40Z",
+ "by": "user@test"
+ },
"address": {
"addressLines":"addressLines",
"postalCodeOrZip":"postalCodeOrZip",
@@ -245,7 +257,11 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
"code": ""
},
"purchaseOrder":"",
- "invoiceEmail":""
+ "invoiceEmail":"",
+ "tosApproval": {
+ "at": "",
+ "by": ""
+ }
},
"contacts": [
{"audiences":["tenant"],"email":"contact1@example.com","emailVerified":false}
@@ -287,6 +303,10 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
"city":"city",
"stateRegionProvince":"stateRegionProvince",
"country":"country"
+ },
+ "tosApproval": {
+ "at": "",
+ "by": ""
}
},
"contacts": [
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java
index 3f6b20ccfa4..66356d979a4 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java
@@ -41,9 +41,16 @@ public class SharedHost {
return resources.isEmpty() ? null : resources;
}
+ /** Whether there are any shared hosts specifically for the given cluster type, or without a cluster type restriction. */
@JsonIgnore
- public boolean isEnabled(String clusterType) {
- return resources.stream().anyMatch(hr -> hr.satisfiesClusterType(clusterType));
+ public boolean supportsClusterType(String clusterType) {
+ return resources.stream().anyMatch(resource -> resource.clusterType().map(clusterType::equalsIgnoreCase).orElse(true));
+ }
+
+ /** Whether there are any shared hosts specifically for the given cluster type. */
+ @JsonIgnore
+ public boolean hasClusterType(String clusterType) {
+ return resources.stream().anyMatch(resource -> resource.clusterType().map(clusterType::equalsIgnoreCase).orElse(false));
}
@JsonIgnore
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
index 449e1c07bf8..dfbe41e31d7 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
@@ -201,6 +201,11 @@ public class NodeRepository extends AbstractComponent {
/** The number of nodes we should ensure has free capacity for node failures whenever possible */
public int spareCount() { return spareCount; }
+ /** Returns whether nodes must be allocated to hosts that are exclusive to the cluster type. */
+ public boolean exclusiveClusterType(ClusterSpec cluster) {
+ return sharedHosts.value().hasClusterType(cluster.type().name());
+ }
+
/**
* Returns whether nodes are allocated exclusively in this instance given this cluster spec.
* Exclusive allocation requires that the wanted node resources matches the advertised resources of the node
@@ -209,7 +214,7 @@ public class NodeRepository extends AbstractComponent {
public boolean exclusiveAllocation(ClusterSpec clusterSpec) {
return clusterSpec.isExclusive() ||
( clusterSpec.type().isContainer() && zone.system().isPublic() && !zone.environment().isTest() ) ||
- ( !zone().cloud().allowHostSharing() && !sharedHosts.value().isEnabled(clusterSpec.type().name()));
+ ( !zone().cloud().allowHostSharing() && !sharedHosts.value().supportsClusterType(clusterSpec.type().name()));
}
/** Whether the nodes of this cluster must be running on hosts that are specifically provisioned for the application. */
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java
index 3c42972ee0b..108f8d77837 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java
@@ -301,6 +301,7 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer {
.stream()
.filter(node -> node.violatesExclusivity(cluster,
application,
+ nodeRepository().exclusiveClusterType(cluster),
nodeRepository().exclusiveAllocation(cluster),
false,
nodeRepository().zone().cloud().allowHostSharing(),
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
index e1be5b48e2d..21340baf273 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
@@ -198,6 +198,7 @@ class NodeAllocation {
private NodeCandidate.ExclusivityViolation violatesExclusivity(NodeCandidate candidate) {
return candidate.violatesExclusivity(cluster, application,
+ nodeRepository.exclusiveClusterType(cluster),
nodeRepository.exclusiveAllocation(cluster),
nodeRepository.exclusiveProvisioning(cluster),
nodeRepository.zone().cloud().allowHostSharing(), allNodes, makeExclusive);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
index 1547a266e15..8c29b40bc26 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
@@ -595,7 +595,7 @@ public abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidat
}
public ExclusivityViolation violatesExclusivity(ClusterSpec cluster, ApplicationId application,
- boolean exclusiveAllocation, boolean exclusiveProvisioning,
+ boolean exclusiveClusterType, boolean exclusiveAllocation, boolean exclusiveProvisioning,
boolean hostSharing, NodeList allNodes, boolean makeExclusive) {
if (parentHostname().isEmpty()) return ExclusivityViolation.NONE;
if (type() != NodeType.tenant) return ExclusivityViolation.NONE;
@@ -614,6 +614,10 @@ public abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidat
if ( ! emptyOrEqual(parent.flatMap(Node::exclusiveToClusterType), cluster.type()))
return ExclusivityViolation.YES;
+ // this cluster requires a parent that was provisioned exclusively for this cluster type
+ if (exclusiveClusterType && parent.flatMap(Node::exclusiveToClusterType).isEmpty() && makeExclusive)
+ return ExclusivityViolation.YES;
+
// the parent is provisioned for another application
if ( ! emptyOrEqual(parent.flatMap(Node::provisionedForApplicationId), application))
return ExclusivityViolation.YES;
diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdbconfigmanager.cpp b/searchcore/src/vespa/searchcore/proton/server/documentdbconfigmanager.cpp
index 9a734168260..150de1c9cec 100644
--- a/searchcore/src/vespa/searchcore/proton/server/documentdbconfigmanager.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/documentdbconfigmanager.cpp
@@ -21,6 +21,7 @@
#include <vespa/searchsummary/config/config-juniperrc.h>
#include <vespa/config/retriever/configsnapshot.hpp>
#include <vespa/vespalib/util/hw_info.h>
+#include <vespa/config.h>
#include <thread>
#include <cassert>
#include <cinttypes>
@@ -222,6 +223,18 @@ find_document_db_config_entry(const ProtonConfig::DocumentdbVector& document_dbs
return default_document_db_config_entry;
}
+[[nodiscard]] bool
+use_hw_memory_presized_target_num_docs([[maybe_unused]] ProtonConfig::Documentdb::Mode mode) noexcept {
+ // If sanitizers are enabled, mmap-allocations may be intercepted and allocated pages
+ // may be implicitly touched+committed. This tends to explode when testing locally, so
+ // fall back to configured initial num-docs if this is the case.
+#ifndef VESPA_USE_SANITIZER
+ return (mode != ProtonConfig::Documentdb::Mode::INDEX);
+#else
+ return false;
+#endif
+}
+
AllocConfig
build_alloc_config(const vespalib::HwInfo & hwInfo, const ProtonConfig& proton_config, const vespalib::string& doc_type_name)
{
@@ -230,7 +243,7 @@ build_alloc_config(const vespalib::HwInfo & hwInfo, const ProtonConfig& proton_c
auto& document_db_config_entry = find_document_db_config_entry(proton_config.documentdb, doc_type_name);
auto& alloc_config = document_db_config_entry.allocation;
- uint32_t target_numdocs = (document_db_config_entry.mode != ProtonConfig::Documentdb::Mode::INDEX)
+ uint32_t target_numdocs = use_hw_memory_presized_target_num_docs(document_db_config_entry.mode)
? (hwInfo.memory().sizeBytes() / (MIN_MEMORY_COST_PER_DOCUMENT * proton_config.distribution.searchablecopies))
: alloc_config.initialnumdocs;
auto& distribution_config = proton_config.distribution;
diff --git a/searchlib/src/tests/query/querybuilder_test.cpp b/searchlib/src/tests/query/querybuilder_test.cpp
index 189e0f5f0b1..606d6a2474a 100644
--- a/searchlib/src/tests/query/querybuilder_test.cpp
+++ b/searchlib/src/tests/query/querybuilder_test.cpp
@@ -673,7 +673,7 @@ TEST("require that empty intermediate node can be added") {
}
TEST("control size of SimpleQueryStackDumpIterator") {
- EXPECT_EQUAL(128u, sizeof(SimpleQueryStackDumpIterator));
+ EXPECT_EQUAL(120u, sizeof(SimpleQueryStackDumpIterator));
}
TEST("test query parsing error") {
diff --git a/searchlib/src/vespa/searchlib/common/bitvector.cpp b/searchlib/src/vespa/searchlib/common/bitvector.cpp
index c359f433d12..b79703a8e5c 100644
--- a/searchlib/src/vespa/searchlib/common/bitvector.cpp
+++ b/searchlib/src/vespa/searchlib/common/bitvector.cpp
@@ -49,7 +49,7 @@ BitVector::allocatePaddedAndAligned(Index start, Index end, Index capacity, cons
return alloc;
}
-BitVector::BitVector(void * buf, Index start, Index end) :
+BitVector::BitVector(void * buf, Index start, Index end) noexcept :
_words(static_cast<Word *>(buf) - wordNum(start)),
_startOffset(start),
_sz(end),
diff --git a/searchlib/src/vespa/searchlib/common/bitvector.h b/searchlib/src/vespa/searchlib/common/bitvector.h
index af1722e200c..943db5f06ba 100644
--- a/searchlib/src/vespa/searchlib/common/bitvector.h
+++ b/searchlib/src/vespa/searchlib/common/bitvector.h
@@ -40,18 +40,18 @@ public:
BitVector& operator = (const BitVector &) = delete;
virtual ~BitVector() = default;
bool operator == (const BitVector &right) const;
- const void * getStart() const { return _words; }
- void * getStart() { return _words; }
+ const void * getStart() const noexcept { return _words; }
+ void * getStart() noexcept { return _words; }
Range range() const noexcept { return {getStartIndex(), size()}; }
- Index size() const { return vespalib::atomic::load_ref_relaxed(_sz); }
- Index sizeBytes() const { return numBytes(getActiveSize()); }
+ Index size() const noexcept { return vespalib::atomic::load_ref_relaxed(_sz); }
+ Index sizeBytes() const noexcept { return numBytes(getActiveSize()); }
bool testBit(Index idx) const noexcept {
return ((load(_words[wordNum(idx)]) & mask(idx)) != 0);
}
Index getSizeAcquire() const {
return vespalib::atomic::load_ref_acquire(_sz);
}
- bool testBitAcquire(Index idx) const {
+ bool testBitAcquire(Index idx) const noexcept {
auto my_word = vespalib::atomic::load_ref_acquire(_words[wordNum(idx)]);
return (my_word & mask(idx)) != 0;
}
@@ -144,31 +144,31 @@ public:
}
vespalib::atomic::store_ref_release(_sz, sz);
}
- void set_bit_no_range_check(Index idx) {
+ void set_bit_no_range_check(Index idx) noexcept {
store_unchecked(_words[wordNum(idx)], _words[wordNum(idx)] | mask(idx));
}
- void clear_bit_no_range_check(Index idx) {
+ void clear_bit_no_range_check(Index idx) noexcept {
store_unchecked(_words[wordNum(idx)], _words[wordNum(idx)] & ~ mask(idx));
}
- void flip_bit_no_range_check(Index idx) {
+ void flip_bit_no_range_check(Index idx) noexcept {
store_unchecked(_words[wordNum(idx)], _words[wordNum(idx)] ^ mask(idx));
}
- void range_check(Index idx) const {
+ void range_check(Index idx) const noexcept {
#if VESPA_ENABLE_BITVECTOR_RANGE_CHECK
assert(!_enable_range_check || (idx >= _startOffset && idx < _sz));
#else
(void) idx;
#endif
}
- void setBit(Index idx) {
+ void setBit(Index idx) noexcept {
range_check(idx);
set_bit_no_range_check(idx);
}
- void clearBit(Index idx) {
+ void clearBit(Index idx) noexcept {
range_check(idx);
clear_bit_no_range_check(idx);
}
- void flipBit(Index idx) {
+ void flipBit(Index idx) noexcept {
range_check(idx);
flip_bit_no_range_check(idx);
}
@@ -283,20 +283,20 @@ public:
static void consider_enable_range_check();
protected:
using Alloc = vespalib::alloc::Alloc;
- VESPA_DLL_LOCAL BitVector(void * buf, Index start, Index end);
- BitVector(void * buf, Index sz) : BitVector(buf, 0, sz) { }
- BitVector() : BitVector(nullptr, 0) { }
+ VESPA_DLL_LOCAL BitVector(void * buf, Index start, Index end) noexcept;
+ BitVector(void * buf, Index sz) noexcept : BitVector(buf, 0, sz) { }
+ BitVector() noexcept : BitVector(nullptr, 0) { }
void init(void * buf, Index start, Index end);
- void updateCount() const { _numTrueBits.store(count(), std::memory_order_relaxed); }
- void setTrueBits(Index numTrueBits) { _numTrueBits.store(numTrueBits, std::memory_order_relaxed); }
+ void updateCount() const noexcept { _numTrueBits.store(count(), std::memory_order_relaxed); }
+ void setTrueBits(Index numTrueBits) noexcept { _numTrueBits.store(numTrueBits, std::memory_order_relaxed); }
VESPA_DLL_LOCAL void clearIntervalNoInvalidation(Range range);
- bool isValidCount() const { return isValidCount(_numTrueBits.load(std::memory_order_relaxed)); }
- static bool isValidCount(Index v) { return v != invalidCount(); }
- static Index numWords(Index bits) { return wordNum(bits + 1 + (WordLen - 1)); }
- static Index numBytes(Index bits) { return numWords(bits) * sizeof(Word); }
- size_t numWords() const { return numWords(size()); }
- static size_t getAlignment() { return 0x40u; }
- static size_t numActiveBytes(Index start, Index end) { return numActiveWords(start, end) * sizeof(Word); }
+ bool isValidCount() const noexcept { return isValidCount(_numTrueBits.load(std::memory_order_relaxed)); }
+ static bool isValidCount(Index v) noexcept { return v != invalidCount(); }
+ static Index numWords(Index bits) noexcept { return wordNum(bits + 1 + (WordLen - 1)); }
+ static Index numBytes(Index bits) noexcept { return numWords(bits) * sizeof(Word); }
+ size_t numWords() const noexcept { return numWords(size()); }
+ static constexpr size_t getAlignment() noexcept { return 0x40u; }
+ static size_t numActiveBytes(Index start, Index end) noexcept { return numActiveWords(start, end) * sizeof(Word); }
static Alloc allocatePaddedAndAligned(Index sz) {
return allocatePaddedAndAligned(0, sz);
}
@@ -308,29 +308,29 @@ protected:
private:
static Word load(const Word &word) noexcept { return vespalib::atomic::load_ref_relaxed(word); }
VESPA_DLL_LOCAL void store(Word &word, Word value);
- static void store_unchecked(Word &word, Word value) {
+ static void store_unchecked(Word &word, Word value) noexcept {
return vespalib::atomic::store_ref_relaxed(word, value);
}
friend PartialBitVector;
- const Word * getWordIndex(Index index) const { return static_cast<const Word *>(getStart()) + wordNum(index); }
- Word * getWordIndex(Index index) { return static_cast<Word *>(getStart()) + wordNum(index); }
- const Word * getActiveStart() const { return getWordIndex(getStartIndex()); }
- Word * getActiveStart() { return getWordIndex(getStartIndex()); }
- Index getStartWordNum() const { return wordNum(getStartIndex()); }
- Index getActiveSize() const { return size() - getStartIndex(); }
- size_t getActiveBytes() const { return numActiveBytes(getStartIndex(), size()); }
- size_t numActiveWords() const { return numActiveWords(getStartIndex(), size()); }
- static size_t numActiveWords(Index start, Index end) {
+ const Word * getWordIndex(Index index) const noexcept { return static_cast<const Word *>(getStart()) + wordNum(index); }
+ Word * getWordIndex(Index index) noexcept { return static_cast<Word *>(getStart()) + wordNum(index); }
+ const Word * getActiveStart() const noexcept { return getWordIndex(getStartIndex()); }
+ Word * getActiveStart() noexcept { return getWordIndex(getStartIndex()); }
+ Index getStartWordNum() const noexcept { return wordNum(getStartIndex()); }
+ Index getActiveSize() const noexcept { return size() - getStartIndex(); }
+ size_t getActiveBytes() const noexcept { return numActiveBytes(getStartIndex(), size()); }
+ size_t numActiveWords() const noexcept { return numActiveWords(getStartIndex(), size()); }
+ static size_t numActiveWords(Index start, Index end) noexcept {
return (end >= start) ? (numWords(end) - wordNum(start)) : 0;
}
- static Index invalidCount() { return std::numeric_limits<Index>::max(); }
- void setGuardBit() { set_bit_no_range_check(size()); }
- void incNumBits() {
+ static constexpr Index invalidCount() noexcept { return std::numeric_limits<Index>::max(); }
+ void setGuardBit() noexcept { set_bit_no_range_check(size()); }
+ void incNumBits() noexcept {
if ( isValidCount() ) {
_numTrueBits.store(_numTrueBits.load(std::memory_order_relaxed) + 1, std::memory_order_relaxed);
}
}
- void decNumBits() {
+ void decNumBits() noexcept {
if ( isValidCount() ) {
_numTrueBits.store(_numTrueBits.load(std::memory_order_relaxed) - 1, std::memory_order_relaxed);
diff --git a/searchlib/src/vespa/searchlib/parsequery/parse.h b/searchlib/src/vespa/searchlib/parsequery/parse.h
index bb0b7b88caa..7029a3d4e12 100644
--- a/searchlib/src/vespa/searchlib/parsequery/parse.h
+++ b/searchlib/src/vespa/searchlib/parsequery/parse.h
@@ -25,7 +25,7 @@ class ParseItem
public:
/** The type of the item is from this set of values.
It is important that these defines match those in container-search/src/main/java/com/yahoo/prelude/query/Item.java */
- enum ItemType {
+ enum ItemType : uint8_t {
ITEM_OR = 0,
ITEM_AND = 1,
ITEM_NOT = 2,
diff --git a/storage/src/vespa/storage/storageserver/mergethrottler.cpp b/storage/src/vespa/storage/storageserver/mergethrottler.cpp
index 82bd5ff7ace..b341c676fc9 100644
--- a/storage/src/vespa/storage/storageserver/mergethrottler.cpp
+++ b/storage/src/vespa/storage/storageserver/mergethrottler.cpp
@@ -68,8 +68,8 @@ MergeThrottler::Metrics::Metrics(metrics::MetricSet* owner)
queueSize("queuesize", {}, "Length of merge queue", this),
active_window_size("active_window_size", {}, "Number of merges active within the pending window size", this),
estimated_merge_memory_usage("estimated_merge_memory_usage", {}, "An estimated upper bound of the "
- "memory usage of the merges currently in the active window", this),
- merge_memory_limit("merge_memory_limit", {}, "The active soft limit for memory used by merge operations on this node", this),
+ "memory usage (in bytes) of the merges currently in the active window", this),
+ merge_memory_limit("merge_memory_limit", {}, "The active soft limit (in bytes) for memory used by merge operations on this node", this),
bounced_due_to_back_pressure("bounced_due_to_back_pressure", {}, "Number of merges bounced due to resource exhaustion back-pressure", this),
chaining("mergechains", this),
local("locallyexecutedmerges", this)