mirror of
https://github.com/neondatabase/neon.git
synced 2026-06-02 04:50:38 +00:00
Compare commits
505 Commits
release-co
...
erik/commu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6761760a2 | ||
|
|
0bce818d5e | ||
|
|
48be1da6ef | ||
|
|
d2efc80e40 | ||
|
|
958c2577f5 | ||
|
|
175c2e11e3 | ||
|
|
efdb07e7b6 | ||
|
|
b0970b415c | ||
|
|
7429dd711c | ||
|
|
88ac1e356b | ||
|
|
c3cb1ab98d | ||
|
|
8e216a3a59 | ||
|
|
81ac4ef43a | ||
|
|
d0a4ae3e8f | ||
|
|
a384d7d501 | ||
|
|
66f53d9d34 | ||
|
|
a5b0fc560c | ||
|
|
2af9380962 | ||
|
|
620d50432c | ||
|
|
67b04f8ab3 | ||
|
|
1d43f3bee8 | ||
|
|
c746678bbc | ||
|
|
9d9e3cd08a | ||
|
|
9bb4688c54 | ||
|
|
97a8f4ef85 | ||
|
|
39f31957e3 | ||
|
|
924c6a6fdf | ||
|
|
7020476bf5 | ||
|
|
80e948db93 | ||
|
|
bfb30d434c | ||
|
|
f3ba201800 | ||
|
|
8b7796cbfa | ||
|
|
fdc7e9c2a4 | ||
|
|
a352d290eb | ||
|
|
8c122a1c98 | ||
|
|
47553dbaf9 | ||
|
|
e50b914a8e | ||
|
|
e33e109403 | ||
|
|
0ee15002fc | ||
|
|
4c7956fa56 | ||
|
|
5a82182c48 | ||
|
|
37e181af8a | ||
|
|
6f4198c78a | ||
|
|
cc1664ef93 | ||
|
|
ebb6e26a64 | ||
|
|
ebc12a388c | ||
|
|
abc1efd5a6 | ||
|
|
6fa1562b57 | ||
|
|
10afac87e7 | ||
|
|
72b3c9cd11 | ||
|
|
232f2447d4 | ||
|
|
a2d2108e6a | ||
|
|
33c0d5e2f4 | ||
|
|
605fb04f89 | ||
|
|
fd1e8ec257 | ||
|
|
e3ecdfbecc | ||
|
|
d08e553835 | ||
|
|
7fffb5b4df | ||
|
|
be23eae3b6 | ||
|
|
6f70885e11 | ||
|
|
f755979102 | ||
|
|
1d49eefbbb | ||
|
|
6c77638ea1 | ||
|
|
517a3d0d86 | ||
|
|
27ca1e21be | ||
|
|
1dc01c9bed | ||
|
|
7c4c36f5ac | ||
|
|
a2d623696c | ||
|
|
aa75722010 | ||
|
|
6c6de6382a | ||
|
|
158d84ea30 | ||
|
|
4dd9ca7b04 | ||
|
|
552249607d | ||
|
|
a29772bf6e | ||
|
|
0efff1db26 | ||
|
|
5eecde461d | ||
|
|
85164422d0 | ||
|
|
46b5c0be0b | ||
|
|
6c3aba7c44 | ||
|
|
68a175d545 | ||
|
|
2d913ff125 | ||
|
|
e90be06d46 | ||
|
|
356ba67607 | ||
|
|
5e2c444525 | ||
|
|
8d711229c1 | ||
|
|
0e490f3be7 | ||
|
|
7e41ef1bec | ||
|
|
7916aa26e0 | ||
|
|
52ab8f3e65 | ||
|
|
3d822dbbde | ||
|
|
af46b5286f | ||
|
|
47f7efee06 | ||
|
|
868c38f522 | ||
|
|
c8b2ac93cf | ||
|
|
b2954d16ff | ||
|
|
79485e7c3a | ||
|
|
eaf1ab21c4 | ||
|
|
6508f4e5c1 | ||
|
|
a298d2c29b | ||
|
|
8b197de7ff | ||
|
|
15d079cd41 | ||
|
|
dc1625cd8e | ||
|
|
a6d4de25cd | ||
|
|
ec1452a559 | ||
|
|
1950ccfe33 | ||
|
|
2ca6665f4a | ||
|
|
fa954671b2 | ||
|
|
6f4ffdb48b | ||
|
|
3f676df3d5 | ||
|
|
20f4febce1 | ||
|
|
762905cf8d | ||
|
|
830ef35ed3 | ||
|
|
1847f4de54 | ||
|
|
d8d62fb7cb | ||
|
|
e6a404c66d | ||
|
|
7e711ede44 | ||
|
|
e95f2f9a67 | ||
|
|
5a045e7d52 | ||
|
|
67fbc0582e | ||
|
|
3af6b3a2bf | ||
|
|
04013929cb | ||
|
|
83069f6ca1 | ||
|
|
7d4f662fbf | ||
|
|
a5cac52e26 | ||
|
|
dfa055f4be | ||
|
|
a4c76740c0 | ||
|
|
f2e96b2323 | ||
|
|
dee73f0cb4 | ||
|
|
edf51688bc | ||
|
|
4a8f3508f9 | ||
|
|
48052477b4 | ||
|
|
d81353b2d1 | ||
|
|
143500dc4f | ||
|
|
1a5f7ce6ad | ||
|
|
01ccb34118 | ||
|
|
e8af3a2811 | ||
|
|
b603e3dddb | ||
|
|
83007782fd | ||
|
|
f669e18477 | ||
|
|
632cde7f13 | ||
|
|
118e13438d | ||
|
|
fc136eec8f | ||
|
|
818e5130f1 | ||
|
|
782062014e | ||
|
|
c243521ae5 | ||
|
|
d0b3629412 | ||
|
|
5303c71589 | ||
|
|
d146897415 | ||
|
|
d63815fa40 | ||
|
|
385324ee8a | ||
|
|
8a68d463f6 | ||
|
|
3046c307da | ||
|
|
e83f1d8ba5 | ||
|
|
8917676e86 | ||
|
|
43acabd4c2 | ||
|
|
db24ba95d1 | ||
|
|
1dce65308d | ||
|
|
ad88ec9257 | ||
|
|
60dfdf39c7 | ||
|
|
3d5e2bf685 | ||
|
|
54fdcfdfa8 | ||
|
|
28e882a80f | ||
|
|
24038033bf | ||
|
|
1b935b1958 | ||
|
|
3f16ca2c18 | ||
|
|
67b94c5992 | ||
|
|
e38193c530 | ||
|
|
21949137ed | ||
|
|
02f94edb60 | ||
|
|
58327ef74d | ||
|
|
73be6bb736 | ||
|
|
40d7583906 | ||
|
|
7a68699abb | ||
|
|
f42d44342d | ||
|
|
f4d51c0f5c | ||
|
|
ec17ae0658 | ||
|
|
9ecce60ded | ||
|
|
d759fcb8bd | ||
|
|
76f95f06d8 | ||
|
|
7efd4554ab | ||
|
|
3c7235669a | ||
|
|
e74a957045 | ||
|
|
396a16a3b2 | ||
|
|
6dd84041a1 | ||
|
|
df7e301a54 | ||
|
|
470c7d5e0e | ||
|
|
4d99b6ff4d | ||
|
|
590301df08 | ||
|
|
c511786548 | ||
|
|
fe31baf985 | ||
|
|
b23e75ebfe | ||
|
|
7140a50225 | ||
|
|
68f18ccacf | ||
|
|
24d7c37e6e | ||
|
|
786888d93f | ||
|
|
255537dda1 | ||
|
|
8b494f6a24 | ||
|
|
28a61741b3 | ||
|
|
2fb6164bf8 | ||
|
|
328f28dfe5 | ||
|
|
95838056da | ||
|
|
6d451654f1 | ||
|
|
f64eb0cbaf | ||
|
|
37c58522a2 | ||
|
|
6ae4b89000 | ||
|
|
f7ec7668a2 | ||
|
|
038e967daf | ||
|
|
6a43f23eca | ||
|
|
868f194a3b | ||
|
|
9c6c780201 | ||
|
|
6123fe2d5e | ||
|
|
1577665c20 | ||
|
|
d8ebd1d771 | ||
|
|
c8a96cf722 | ||
|
|
56d505bce6 | ||
|
|
dae203ef69 | ||
|
|
1fb1315aed | ||
|
|
838622c594 | ||
|
|
3fd5a94a85 | ||
|
|
e7d6f525b3 | ||
|
|
e4ca3ac745 | ||
|
|
b69d103b90 | ||
|
|
208cbd52d4 | ||
|
|
4b6f02e47d | ||
|
|
c567ed0de0 | ||
|
|
c698cee19a | ||
|
|
4a3f32bf4a | ||
|
|
a963aab14b | ||
|
|
8202c6172f | ||
|
|
5bdba70f7d | ||
|
|
25fffd3a55 | ||
|
|
e00fd45bba | ||
|
|
69a47d789d | ||
|
|
b36f880710 | ||
|
|
745b750f33 | ||
|
|
3b8be98b67 | ||
|
|
3e72edede5 | ||
|
|
a650f7f5af | ||
|
|
fc3994eb71 | ||
|
|
781bf4945d | ||
|
|
a21c1174ed | ||
|
|
8d7ed2a4ee | ||
|
|
5b62749c42 | ||
|
|
af5bb67f08 | ||
|
|
589bfdfd02 | ||
|
|
87179e26b3 | ||
|
|
f05df409bd | ||
|
|
f6c0f6c4ec | ||
|
|
62cd3b8d3d | ||
|
|
8d26978ed9 | ||
|
|
35372a8f12 | ||
|
|
6d95a3fe2d | ||
|
|
99726495c7 | ||
|
|
4a4a457312 | ||
|
|
e78d1e2ec6 | ||
|
|
af429b4a62 | ||
|
|
3b4d4eb535 | ||
|
|
f060537a31 | ||
|
|
8a6fc6fd8c | ||
|
|
f06bb2bbd8 | ||
|
|
51639cd6af | ||
|
|
529d661532 | ||
|
|
9e4cf52949 | ||
|
|
b3c25418a6 | ||
|
|
33549bad1d | ||
|
|
831f2a4ba7 | ||
|
|
eadabeddb8 | ||
|
|
009168d711 | ||
|
|
67ddf1de28 | ||
|
|
541fcd8d2f | ||
|
|
e77961c1c6 | ||
|
|
cdfa06caad | ||
|
|
f0bb93a9c9 | ||
|
|
30adf8e2bd | ||
|
|
5d538a9503 | ||
|
|
f3976e5c60 | ||
|
|
9657fbc194 | ||
|
|
dd501554c9 | ||
|
|
fe1513ca57 | ||
|
|
3e86008e66 | ||
|
|
23fc611461 | ||
|
|
7c9bd542a6 | ||
|
|
dc953de85d | ||
|
|
014823b305 | ||
|
|
af9379ccf6 | ||
|
|
841517ee37 | ||
|
|
1369d73dcd | ||
|
|
7cd0defaf0 | ||
|
|
a082f9814a | ||
|
|
bb28109ffa | ||
|
|
ec991877f4 | ||
|
|
abc6c84262 | ||
|
|
6768a71c86 | ||
|
|
87fc0a0374 | ||
|
|
06ce704041 | ||
|
|
d5023f2b89 | ||
|
|
8ff25dca8e | ||
|
|
cf81330fbc | ||
|
|
e69ae739ff | ||
|
|
136eaeb74a | ||
|
|
211b824d62 | ||
|
|
f9fdbc9618 | ||
|
|
95a5f749c8 | ||
|
|
5db20af8a7 | ||
|
|
136cf1979b | ||
|
|
08bb72e516 | ||
|
|
6f4f3691a5 | ||
|
|
a2b756843e | ||
|
|
f3c9d0adf4 | ||
|
|
2e3dc9a8c2 | ||
|
|
568779fa8a | ||
|
|
e94acbc816 | ||
|
|
f4150614d0 | ||
|
|
60a0bec1c0 | ||
|
|
31fa7a545d | ||
|
|
ac464c5f2c | ||
|
|
0dddb1e373 | ||
|
|
3acb263e62 | ||
|
|
38dbc5f67f | ||
|
|
3685ad606d | ||
|
|
76a7d37f7e | ||
|
|
cdb6479c8a | ||
|
|
81c557d87e | ||
|
|
e963129678 | ||
|
|
4f0a9fc569 | ||
|
|
81c6a5a796 | ||
|
|
8e05639dbf | ||
|
|
deed46015d | ||
|
|
532d9b646e | ||
|
|
55f91cf10b | ||
|
|
baafcc5d41 | ||
|
|
aa22572d8c | ||
|
|
2d247375b3 | ||
|
|
a7ce323949 | ||
|
|
31026d5a3c | ||
|
|
2621ce2daf | ||
|
|
a703cd342b | ||
|
|
42e4cf18c9 | ||
|
|
9e5a41a342 | ||
|
|
48b870bc07 | ||
|
|
32a12783fd | ||
|
|
1e83398cdd | ||
|
|
be8ed81532 | ||
|
|
68120cfa31 | ||
|
|
a8e652d47e | ||
|
|
81fd652151 | ||
|
|
d47e88e353 | ||
|
|
12b08c4b82 | ||
|
|
045ae13e06 | ||
|
|
234c882a07 | ||
|
|
290369061f | ||
|
|
25ab16ee24 | ||
|
|
cfbef4d586 | ||
|
|
34a42b00ca | ||
|
|
a9979620c5 | ||
|
|
a113c48c43 | ||
|
|
827358dd03 | ||
|
|
d367273000 | ||
|
|
e2bad5d9e9 | ||
|
|
9971fba584 | ||
|
|
a77919f4b2 | ||
|
|
5623e4665b | ||
|
|
a618056770 | ||
|
|
307e1e64c8 | ||
|
|
a537b2ffd0 | ||
|
|
8abb4dab6d | ||
|
|
731667ac37 | ||
|
|
6a1374d106 | ||
|
|
f7c908f2f0 | ||
|
|
86671e3a0b | ||
|
|
319cd74f73 | ||
|
|
64353b48db | ||
|
|
79ddc803af | ||
|
|
0efefbf77c | ||
|
|
e6a4171fa1 | ||
|
|
f5070f6aa4 | ||
|
|
3b7cc4234c | ||
|
|
0c25ea9e31 | ||
|
|
33abfc2b74 | ||
|
|
93b964f829 | ||
|
|
d0aaec2abb | ||
|
|
d0dc65da12 | ||
|
|
03d635b916 | ||
|
|
5cd7f936f9 | ||
|
|
101e115b38 | ||
|
|
b37bb7d7ed | ||
|
|
bef5954fd7 | ||
|
|
8477d15f95 | ||
|
|
622b3b2993 | ||
|
|
659366060d | ||
|
|
42d93031a1 | ||
|
|
d22377c754 | ||
|
|
6c70789cfd | ||
|
|
7e55497e13 | ||
|
|
40f32ea326 | ||
|
|
1d1502bc16 | ||
|
|
7eb85c56ac | ||
|
|
24d62c647f | ||
|
|
4d2e4b19c3 | ||
|
|
0691b73f53 | ||
|
|
3cf5e1386c | ||
|
|
608afc3055 | ||
|
|
0ef6851219 | ||
|
|
5c356c63eb | ||
|
|
384e3df2ad | ||
|
|
f9b3a2e059 | ||
|
|
79ee78ea32 | ||
|
|
6692321026 | ||
|
|
0e0ad073bf | ||
|
|
791df28755 | ||
|
|
d20da994f4 | ||
|
|
6dbbdaae73 | ||
|
|
977bc09d2a | ||
|
|
44269fcd5e | ||
|
|
44cc648dc8 | ||
|
|
884e028a4a | ||
|
|
42df3e5453 | ||
|
|
fc743e284f | ||
|
|
d02f9a2139 | ||
|
|
083118e98e | ||
|
|
54cd2272f1 | ||
|
|
e40193e3c8 | ||
|
|
6827f2f58c | ||
|
|
ce9f7bacc1 | ||
|
|
c82e363ed9 | ||
|
|
b7891f8fe8 | ||
|
|
50dc2fae77 | ||
|
|
62ac5b94b3 | ||
|
|
f0e7b3e0ef | ||
|
|
c6ff18affc | ||
|
|
16ca74a3f4 | ||
|
|
cb67f9a651 | ||
|
|
baf425a2cd | ||
|
|
0b243242df | ||
|
|
6131d86ec9 | ||
|
|
4b9087651c | ||
|
|
5f2adaa9ad | ||
|
|
3e5e396c8d | ||
|
|
9d781c6fda | ||
|
|
79699aebc8 | ||
|
|
cf5d038472 | ||
|
|
22290eb7ba | ||
|
|
d785100c02 | ||
|
|
bbc35e10b8 | ||
|
|
ae2c3ac12f | ||
|
|
16d594b7b3 | ||
|
|
f999632327 | ||
|
|
5bd850d15a | ||
|
|
1b789e8d7c | ||
|
|
bec7427d9e | ||
|
|
e2db76b9be | ||
|
|
6b4b8e0d8b | ||
|
|
2c0d930e3d | ||
|
|
66171a117b | ||
|
|
df2806e7a0 | ||
|
|
1d68577fbd | ||
|
|
60f63c076f | ||
|
|
8da4ec9740 | ||
|
|
b48404952d | ||
|
|
07631692db | ||
|
|
4c77397943 | ||
|
|
7bb58be546 | ||
|
|
1d06172d59 | ||
|
|
a08c1a23eb | ||
|
|
b5373de208 | ||
|
|
a2adc7dbd3 | ||
|
|
b86c610f42 | ||
|
|
768a580373 | ||
|
|
0f520d79ab | ||
|
|
09247de8d5 | ||
|
|
0b35929211 | ||
|
|
93eb7bb6b8 | ||
|
|
b3db7f66ac | ||
|
|
498d852bde | ||
|
|
7f8b1d79c0 | ||
|
|
d15f2ff57a | ||
|
|
e58d0fece1 | ||
|
|
3593356c10 | ||
|
|
9e8ab2ab4f | ||
|
|
c1ff7db187 | ||
|
|
6d6b83e737 | ||
|
|
0482690534 | ||
|
|
a750026c2e | ||
|
|
998d2c2ce9 | ||
|
|
b1fa68f659 | ||
|
|
84bc3380cc | ||
|
|
11f6044338 | ||
|
|
692c0f3fb8 | ||
|
|
2b1d2a55d6 | ||
|
|
60b9fb1baf | ||
|
|
606f14034e | ||
|
|
32393b4393 | ||
|
|
1a29f5672a | ||
|
|
b8d47b5acf | ||
|
|
97e01ae6fd | ||
|
|
459d51974c | ||
|
|
902d361107 | ||
|
|
ef53a76434 | ||
|
|
6f0046b688 | ||
|
|
2b0248cd76 | ||
|
|
7b03216dca | ||
|
|
992aa91075 | ||
|
|
afe9b27983 | ||
|
|
5d91d4e843 | ||
|
|
2465e9141f |
@@ -4,6 +4,7 @@
|
|||||||
!Cargo.lock
|
!Cargo.lock
|
||||||
!Cargo.toml
|
!Cargo.toml
|
||||||
!Makefile
|
!Makefile
|
||||||
|
!postgres.mk
|
||||||
!rust-toolchain.toml
|
!rust-toolchain.toml
|
||||||
!scripts/ninstall.sh
|
!scripts/ninstall.sh
|
||||||
!docker-compose/run-tests.sh
|
!docker-compose/run-tests.sh
|
||||||
|
|||||||
5
.github/actionlint.yml
vendored
5
.github/actionlint.yml
vendored
@@ -33,9 +33,14 @@ config-variables:
|
|||||||
- REMOTE_STORAGE_AZURE_CONTAINER
|
- REMOTE_STORAGE_AZURE_CONTAINER
|
||||||
- REMOTE_STORAGE_AZURE_REGION
|
- REMOTE_STORAGE_AZURE_REGION
|
||||||
- SLACK_CICD_CHANNEL_ID
|
- SLACK_CICD_CHANNEL_ID
|
||||||
|
- SLACK_COMPUTE_CHANNEL_ID
|
||||||
- SLACK_ON_CALL_DEVPROD_STREAM
|
- SLACK_ON_CALL_DEVPROD_STREAM
|
||||||
- SLACK_ON_CALL_QA_STAGING_STREAM
|
- SLACK_ON_CALL_QA_STAGING_STREAM
|
||||||
- SLACK_ON_CALL_STORAGE_STAGING_STREAM
|
- SLACK_ON_CALL_STORAGE_STAGING_STREAM
|
||||||
|
- SLACK_ONCALL_COMPUTE_GROUP
|
||||||
|
- SLACK_ONCALL_PROXY_GROUP
|
||||||
|
- SLACK_ONCALL_STORAGE_GROUP
|
||||||
|
- SLACK_PROXY_CHANNEL_ID
|
||||||
- SLACK_RUST_CHANNEL_ID
|
- SLACK_RUST_CHANNEL_ID
|
||||||
- SLACK_STORAGE_CHANNEL_ID
|
- SLACK_STORAGE_CHANNEL_ID
|
||||||
- SLACK_UPCOMING_RELEASE_CHANNEL_ID
|
- SLACK_UPCOMING_RELEASE_CHANNEL_ID
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ inputs:
|
|||||||
type: boolean
|
type: boolean
|
||||||
required: false
|
required: false
|
||||||
default: false
|
default: false
|
||||||
aws-oicd-role-arn:
|
aws-oidc-role-arn:
|
||||||
description: 'OIDC role arn to interract with S3'
|
description: 'OIDC role arn to interract with S3'
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ runs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
with:
|
with:
|
||||||
aws-region: eu-central-1
|
aws-region: eu-central-1
|
||||||
role-to-assume: ${{ inputs.aws-oicd-role-arn }}
|
role-to-assume: ${{ inputs.aws-oidc-role-arn }}
|
||||||
role-duration-seconds: 3600 # 1 hour should be more than enough to upload report
|
role-duration-seconds: 3600 # 1 hour should be more than enough to upload report
|
||||||
|
|
||||||
# Potentially we could have several running build for the same key (for example, for the main branch), so we use improvised lock for this
|
# Potentially we could have several running build for the same key (for example, for the main branch), so we use improvised lock for this
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ inputs:
|
|||||||
unique-key:
|
unique-key:
|
||||||
description: 'string to distinguish different results in the same run'
|
description: 'string to distinguish different results in the same run'
|
||||||
required: true
|
required: true
|
||||||
aws-oicd-role-arn:
|
aws-oidc-role-arn:
|
||||||
description: 'OIDC role arn to interract with S3'
|
description: 'OIDC role arn to interract with S3'
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ runs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
with:
|
with:
|
||||||
aws-region: eu-central-1
|
aws-region: eu-central-1
|
||||||
role-to-assume: ${{ inputs.aws-oicd-role-arn }}
|
role-to-assume: ${{ inputs.aws-oidc-role-arn }}
|
||||||
role-duration-seconds: 3600 # 1 hour should be more than enough to upload report
|
role-duration-seconds: 3600 # 1 hour should be more than enough to upload report
|
||||||
|
|
||||||
- name: Upload test results
|
- name: Upload test results
|
||||||
|
|||||||
4
.github/actions/download/action.yml
vendored
4
.github/actions/download/action.yml
vendored
@@ -15,7 +15,7 @@ inputs:
|
|||||||
prefix:
|
prefix:
|
||||||
description: "S3 prefix. Default is '${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}'"
|
description: "S3 prefix. Default is '${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}'"
|
||||||
required: false
|
required: false
|
||||||
aws-oicd-role-arn:
|
aws-oidc-role-arn:
|
||||||
description: 'OIDC role arn to interract with S3'
|
description: 'OIDC role arn to interract with S3'
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ runs:
|
|||||||
- uses: aws-actions/configure-aws-credentials@v4
|
- uses: aws-actions/configure-aws-credentials@v4
|
||||||
with:
|
with:
|
||||||
aws-region: eu-central-1
|
aws-region: eu-central-1
|
||||||
role-to-assume: ${{ inputs.aws-oicd-role-arn }}
|
role-to-assume: ${{ inputs.aws-oidc-role-arn }}
|
||||||
role-duration-seconds: 3600
|
role-duration-seconds: 3600
|
||||||
|
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
|
|||||||
14
.github/actions/neon-project-create/action.yml
vendored
14
.github/actions/neon-project-create/action.yml
vendored
@@ -66,9 +66,9 @@ runs:
|
|||||||
# A shell without `set -x` to not to expose password/dsn in logs
|
# A shell without `set -x` to not to expose password/dsn in logs
|
||||||
shell: bash -euo pipefail {0}
|
shell: bash -euo pipefail {0}
|
||||||
run: |
|
run: |
|
||||||
project=$(curl \
|
res=$(curl \
|
||||||
"https://${API_HOST}/api/v2/projects" \
|
"https://${API_HOST}/api/v2/projects" \
|
||||||
--fail \
|
-w "%{http_code}" \
|
||||||
--header "Accept: application/json" \
|
--header "Accept: application/json" \
|
||||||
--header "Content-Type: application/json" \
|
--header "Content-Type: application/json" \
|
||||||
--header "Authorization: Bearer ${API_KEY}" \
|
--header "Authorization: Bearer ${API_KEY}" \
|
||||||
@@ -83,6 +83,15 @@ runs:
|
|||||||
\"settings\": ${PROJECT_SETTINGS}
|
\"settings\": ${PROJECT_SETTINGS}
|
||||||
}
|
}
|
||||||
}")
|
}")
|
||||||
|
|
||||||
|
code=${res: -3}
|
||||||
|
if [[ ${code} -ge 400 ]]; then
|
||||||
|
echo Request failed with error code ${code}
|
||||||
|
echo ${res::-3}
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
project=${res::-3}
|
||||||
|
fi
|
||||||
|
|
||||||
# Mask password
|
# Mask password
|
||||||
echo "::add-mask::$(echo $project | jq --raw-output '.roles[] | select(.name != "web_access") | .password')"
|
echo "::add-mask::$(echo $project | jq --raw-output '.roles[] | select(.name != "web_access") | .password')"
|
||||||
@@ -126,6 +135,7 @@ runs:
|
|||||||
-H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: Bearer ${ADMIN_API_KEY}" \
|
-H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: Bearer ${ADMIN_API_KEY}" \
|
||||||
-d "{\"scheduling\": \"Essential\"}"
|
-d "{\"scheduling\": \"Essential\"}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
API_HOST: ${{ inputs.api_host }}
|
API_HOST: ${{ inputs.api_host }}
|
||||||
|
|||||||
14
.github/actions/run-python-test-set/action.yml
vendored
14
.github/actions/run-python-test-set/action.yml
vendored
@@ -53,7 +53,7 @@ inputs:
|
|||||||
description: 'benchmark durations JSON'
|
description: 'benchmark durations JSON'
|
||||||
required: false
|
required: false
|
||||||
default: '{}'
|
default: '{}'
|
||||||
aws-oicd-role-arn:
|
aws-oidc-role-arn:
|
||||||
description: 'OIDC role arn to interract with S3'
|
description: 'OIDC role arn to interract with S3'
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ runs:
|
|||||||
with:
|
with:
|
||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build_type }}${{ inputs.sanitizers == 'enabled' && '-sanitized' || '' }}-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build_type }}${{ inputs.sanitizers == 'enabled' && '-sanitized' || '' }}-artifact
|
||||||
path: /tmp/neon
|
path: /tmp/neon
|
||||||
aws-oicd-role-arn: ${{ inputs.aws-oicd-role-arn }}
|
aws-oidc-role-arn: ${{ inputs.aws-oidc-role-arn }}
|
||||||
|
|
||||||
- name: Download Neon binaries for the previous release
|
- name: Download Neon binaries for the previous release
|
||||||
if: inputs.build_type != 'remote'
|
if: inputs.build_type != 'remote'
|
||||||
@@ -75,7 +75,7 @@ runs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build_type }}-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build_type }}-artifact
|
||||||
path: /tmp/neon-previous
|
path: /tmp/neon-previous
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ inputs.aws-oicd-role-arn }}
|
aws-oidc-role-arn: ${{ inputs.aws-oidc-role-arn }}
|
||||||
|
|
||||||
- name: Download compatibility snapshot
|
- name: Download compatibility snapshot
|
||||||
if: inputs.build_type != 'remote'
|
if: inputs.build_type != 'remote'
|
||||||
@@ -87,7 +87,7 @@ runs:
|
|||||||
# The lack of compatibility snapshot (for example, for the new Postgres version)
|
# The lack of compatibility snapshot (for example, for the new Postgres version)
|
||||||
# shouldn't fail the whole job. Only relevant test should fail.
|
# shouldn't fail the whole job. Only relevant test should fail.
|
||||||
skip-if-does-not-exist: true
|
skip-if-does-not-exist: true
|
||||||
aws-oicd-role-arn: ${{ inputs.aws-oicd-role-arn }}
|
aws-oidc-role-arn: ${{ inputs.aws-oidc-role-arn }}
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
if: inputs.needs_postgres_source == 'true'
|
if: inputs.needs_postgres_source == 'true'
|
||||||
@@ -228,13 +228,13 @@ runs:
|
|||||||
# The lack of compatibility snapshot shouldn't fail the job
|
# The lack of compatibility snapshot shouldn't fail the job
|
||||||
# (for example if we didn't run the test for non build-and-test workflow)
|
# (for example if we didn't run the test for non build-and-test workflow)
|
||||||
skip-if-does-not-exist: true
|
skip-if-does-not-exist: true
|
||||||
aws-oicd-role-arn: ${{ inputs.aws-oicd-role-arn }}
|
aws-oidc-role-arn: ${{ inputs.aws-oidc-role-arn }}
|
||||||
|
|
||||||
- uses: aws-actions/configure-aws-credentials@v4
|
- uses: aws-actions/configure-aws-credentials@v4
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
with:
|
with:
|
||||||
aws-region: eu-central-1
|
aws-region: eu-central-1
|
||||||
role-to-assume: ${{ inputs.aws-oicd-role-arn }}
|
role-to-assume: ${{ inputs.aws-oidc-role-arn }}
|
||||||
role-duration-seconds: 3600 # 1 hour should be more than enough to upload report
|
role-duration-seconds: 3600 # 1 hour should be more than enough to upload report
|
||||||
|
|
||||||
- name: Upload test results
|
- name: Upload test results
|
||||||
@@ -243,4 +243,4 @@ runs:
|
|||||||
with:
|
with:
|
||||||
report-dir: /tmp/test_output/allure/results
|
report-dir: /tmp/test_output/allure/results
|
||||||
unique-key: ${{ inputs.build_type }}-${{ inputs.pg_version }}-${{ runner.arch }}
|
unique-key: ${{ inputs.build_type }}-${{ inputs.pg_version }}-${{ runner.arch }}
|
||||||
aws-oicd-role-arn: ${{ inputs.aws-oicd-role-arn }}
|
aws-oidc-role-arn: ${{ inputs.aws-oidc-role-arn }}
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ runs:
|
|||||||
name: coverage-data-artifact
|
name: coverage-data-artifact
|
||||||
path: /tmp/coverage
|
path: /tmp/coverage
|
||||||
skip-if-does-not-exist: true # skip if there's no previous coverage to download
|
skip-if-does-not-exist: true # skip if there's no previous coverage to download
|
||||||
aws-oicd-role-arn: ${{ inputs.aws-oicd-role-arn }}
|
aws-oidc-role-arn: ${{ inputs.aws-oidc-role-arn }}
|
||||||
|
|
||||||
- name: Upload coverage data
|
- name: Upload coverage data
|
||||||
uses: ./.github/actions/upload
|
uses: ./.github/actions/upload
|
||||||
with:
|
with:
|
||||||
name: coverage-data-artifact
|
name: coverage-data-artifact
|
||||||
path: /tmp/coverage
|
path: /tmp/coverage
|
||||||
aws-oicd-role-arn: ${{ inputs.aws-oicd-role-arn }}
|
aws-oidc-role-arn: ${{ inputs.aws-oidc-role-arn }}
|
||||||
|
|||||||
4
.github/actions/upload/action.yml
vendored
4
.github/actions/upload/action.yml
vendored
@@ -14,7 +14,7 @@ inputs:
|
|||||||
prefix:
|
prefix:
|
||||||
description: "S3 prefix. Default is '${GITHUB_SHA}/${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}'"
|
description: "S3 prefix. Default is '${GITHUB_SHA}/${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}'"
|
||||||
required: false
|
required: false
|
||||||
aws-oicd-role-arn:
|
aws-oidc-role-arn:
|
||||||
description: "the OIDC role arn for aws auth"
|
description: "the OIDC role arn for aws auth"
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
@@ -61,7 +61,7 @@ runs:
|
|||||||
uses: aws-actions/configure-aws-credentials@v4
|
uses: aws-actions/configure-aws-credentials@v4
|
||||||
with:
|
with:
|
||||||
aws-region: eu-central-1
|
aws-region: eu-central-1
|
||||||
role-to-assume: ${{ inputs.aws-oicd-role-arn }}
|
role-to-assume: ${{ inputs.aws-oidc-role-arn }}
|
||||||
role-duration-seconds: 3600
|
role-duration-seconds: 3600
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
|
|||||||
2
.github/scripts/lint-release-pr.sh
vendored
2
.github/scripts/lint-release-pr.sh
vendored
@@ -41,7 +41,7 @@ echo "Merge base of ${MAIN_BRANCH} and ${RELEASE_BRANCH}: ${MERGE_BASE}"
|
|||||||
LAST_COMMIT=$(git rev-parse HEAD)
|
LAST_COMMIT=$(git rev-parse HEAD)
|
||||||
|
|
||||||
MERGE_COMMIT_MESSAGE=$(git log -1 --format=%s "${LAST_COMMIT}")
|
MERGE_COMMIT_MESSAGE=$(git log -1 --format=%s "${LAST_COMMIT}")
|
||||||
EXPECTED_MESSAGE_REGEX="^$COMPONENT release [0-9]{4}-[0-9]{2}-[0-9]{2}$"
|
EXPECTED_MESSAGE_REGEX="^$COMPONENT release [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2} UTC$"
|
||||||
|
|
||||||
if ! [[ "${MERGE_COMMIT_MESSAGE}" =~ ${EXPECTED_MESSAGE_REGEX} ]]; then
|
if ! [[ "${MERGE_COMMIT_MESSAGE}" =~ ${EXPECTED_MESSAGE_REGEX} ]]; then
|
||||||
report_error "Merge commit message does not match expected pattern: '<component> release YYYY-MM-DD'
|
report_error "Merge commit message does not match expected pattern: '<component> release YYYY-MM-DD'
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
# we create a table that has one row for each database that we want to restore with the status whether the restore is done
|
# we create a table that has one row for each database that we want to restore with the status whether the restore is done
|
||||||
- name: Create benchmark_restore_status table if it does not exist
|
- name: Create benchmark_restore_status table if it does not exist
|
||||||
|
|||||||
113
.github/workflows/_build-and-test-locally.yml
vendored
113
.github/workflows/_build-and-test-locally.yml
vendored
@@ -28,6 +28,21 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
default: 'disabled'
|
default: 'disabled'
|
||||||
type: string
|
type: string
|
||||||
|
test-selection:
|
||||||
|
description: 'specification of selected test(s) to run'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
test-run-count:
|
||||||
|
description: 'number of runs to perform for selected tests'
|
||||||
|
required: false
|
||||||
|
default: 1
|
||||||
|
type: number
|
||||||
|
rerun-failed:
|
||||||
|
description: 'rerun failed tests to ignore flaky tests'
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -89,11 +104,10 @@ jobs:
|
|||||||
|
|
||||||
# Set some environment variables used by all the steps.
|
# Set some environment variables used by all the steps.
|
||||||
#
|
#
|
||||||
# CARGO_FLAGS is extra options to pass to "cargo build", "cargo test" etc.
|
# CARGO_FLAGS is extra options to pass to all "cargo" subcommands.
|
||||||
# It also includes --features, if any
|
|
||||||
#
|
#
|
||||||
# CARGO_FEATURES is passed to "cargo metadata". It is separate from CARGO_FLAGS,
|
# CARGO_PROFILE is passed to "cargo build", "cargo test" etc, but not to
|
||||||
# because "cargo metadata" doesn't accept --release or --debug options
|
# "cargo metadata", because it doesn't accept --release or --debug options.
|
||||||
#
|
#
|
||||||
# We run tests with addtional features, that are turned off by default (e.g. in release builds), see
|
# We run tests with addtional features, that are turned off by default (e.g. in release builds), see
|
||||||
# corresponding Cargo.toml files for their descriptions.
|
# corresponding Cargo.toml files for their descriptions.
|
||||||
@@ -102,16 +116,16 @@ jobs:
|
|||||||
ARCH: ${{ inputs.arch }}
|
ARCH: ${{ inputs.arch }}
|
||||||
SANITIZERS: ${{ inputs.sanitizers }}
|
SANITIZERS: ${{ inputs.sanitizers }}
|
||||||
run: |
|
run: |
|
||||||
CARGO_FEATURES="--features testing"
|
CARGO_FLAGS="--locked --features testing"
|
||||||
if [[ $BUILD_TYPE == "debug" && $ARCH == 'x64' ]]; then
|
if [[ $BUILD_TYPE == "debug" && $ARCH == 'x64' ]]; then
|
||||||
cov_prefix="scripts/coverage --profraw-prefix=$GITHUB_JOB --dir=/tmp/coverage run"
|
cov_prefix="scripts/coverage --profraw-prefix=$GITHUB_JOB --dir=/tmp/coverage run"
|
||||||
CARGO_FLAGS="--locked"
|
CARGO_PROFILE=""
|
||||||
elif [[ $BUILD_TYPE == "debug" ]]; then
|
elif [[ $BUILD_TYPE == "debug" ]]; then
|
||||||
cov_prefix=""
|
cov_prefix=""
|
||||||
CARGO_FLAGS="--locked"
|
CARGO_PROFILE=""
|
||||||
elif [[ $BUILD_TYPE == "release" ]]; then
|
elif [[ $BUILD_TYPE == "release" ]]; then
|
||||||
cov_prefix=""
|
cov_prefix=""
|
||||||
CARGO_FLAGS="--locked --release"
|
CARGO_PROFILE="--release"
|
||||||
fi
|
fi
|
||||||
if [[ $SANITIZERS == 'enabled' ]]; then
|
if [[ $SANITIZERS == 'enabled' ]]; then
|
||||||
make_vars="WITH_SANITIZERS=yes"
|
make_vars="WITH_SANITIZERS=yes"
|
||||||
@@ -121,8 +135,8 @@ jobs:
|
|||||||
{
|
{
|
||||||
echo "cov_prefix=${cov_prefix}"
|
echo "cov_prefix=${cov_prefix}"
|
||||||
echo "make_vars=${make_vars}"
|
echo "make_vars=${make_vars}"
|
||||||
echo "CARGO_FEATURES=${CARGO_FEATURES}"
|
|
||||||
echo "CARGO_FLAGS=${CARGO_FLAGS}"
|
echo "CARGO_FLAGS=${CARGO_FLAGS}"
|
||||||
|
echo "CARGO_PROFILE=${CARGO_PROFILE}"
|
||||||
echo "CARGO_HOME=${GITHUB_WORKSPACE}/.cargo"
|
echo "CARGO_HOME=${GITHUB_WORKSPACE}/.cargo"
|
||||||
} >> $GITHUB_ENV
|
} >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -174,34 +188,18 @@ jobs:
|
|||||||
path: pg_install/v17
|
path: pg_install/v17
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build-type }}-pg-${{ steps.pg_v17_rev.outputs.pg_rev }}-bookworm-${{ hashFiles('Makefile', 'build-tools.Dockerfile') }}
|
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build-type }}-pg-${{ steps.pg_v17_rev.outputs.pg_rev }}-bookworm-${{ hashFiles('Makefile', 'build-tools.Dockerfile') }}
|
||||||
|
|
||||||
- name: Build postgres v14
|
- name: Build all
|
||||||
if: steps.cache_pg_14.outputs.cache-hit != 'true'
|
# Note: the Makefile picks up BUILD_TYPE and CARGO_PROFILE from the env variables
|
||||||
run: mold -run make ${make_vars} postgres-v14 -j$(nproc)
|
run: mold -run make ${make_vars} all -j$(nproc) CARGO_BUILD_FLAGS="$CARGO_FLAGS"
|
||||||
|
|
||||||
- name: Build postgres v15
|
|
||||||
if: steps.cache_pg_15.outputs.cache-hit != 'true'
|
|
||||||
run: mold -run make ${make_vars} postgres-v15 -j$(nproc)
|
|
||||||
|
|
||||||
- name: Build postgres v16
|
|
||||||
if: steps.cache_pg_16.outputs.cache-hit != 'true'
|
|
||||||
run: mold -run make ${make_vars} postgres-v16 -j$(nproc)
|
|
||||||
|
|
||||||
- name: Build postgres v17
|
|
||||||
if: steps.cache_pg_17.outputs.cache-hit != 'true'
|
|
||||||
run: mold -run make ${make_vars} postgres-v17 -j$(nproc)
|
|
||||||
|
|
||||||
- name: Build neon extensions
|
|
||||||
run: mold -run make ${make_vars} neon-pg-ext -j$(nproc)
|
|
||||||
|
|
||||||
- name: Build walproposer-lib
|
- name: Build walproposer-lib
|
||||||
run: mold -run make ${make_vars} walproposer-lib -j$(nproc)
|
run: mold -run make ${make_vars} walproposer-lib -j$(nproc)
|
||||||
|
|
||||||
- name: Run cargo build
|
- name: Build unit tests
|
||||||
env:
|
if: inputs.sanitizers != 'enabled'
|
||||||
WITH_TESTS: ${{ inputs.sanitizers != 'enabled' && '--tests' || '' }}
|
|
||||||
run: |
|
run: |
|
||||||
export ASAN_OPTIONS=detect_leaks=0
|
export ASAN_OPTIONS=detect_leaks=0
|
||||||
${cov_prefix} mold -run cargo build $CARGO_FLAGS $CARGO_FEATURES --bins ${WITH_TESTS}
|
${cov_prefix} mold -run cargo build $CARGO_FLAGS $CARGO_PROFILE --tests
|
||||||
|
|
||||||
# Do install *before* running rust tests because they might recompile the
|
# Do install *before* running rust tests because they might recompile the
|
||||||
# binaries with different features/flags.
|
# binaries with different features/flags.
|
||||||
@@ -213,7 +211,7 @@ jobs:
|
|||||||
# Install target binaries
|
# Install target binaries
|
||||||
mkdir -p /tmp/neon/bin/
|
mkdir -p /tmp/neon/bin/
|
||||||
binaries=$(
|
binaries=$(
|
||||||
${cov_prefix} cargo metadata $CARGO_FEATURES --format-version=1 --no-deps |
|
${cov_prefix} cargo metadata $CARGO_FLAGS --format-version=1 --no-deps |
|
||||||
jq -r '.packages[].targets[] | select(.kind | index("bin")) | .name'
|
jq -r '.packages[].targets[] | select(.kind | index("bin")) | .name'
|
||||||
)
|
)
|
||||||
for bin in $binaries; do
|
for bin in $binaries; do
|
||||||
@@ -230,7 +228,7 @@ jobs:
|
|||||||
mkdir -p /tmp/neon/test_bin/
|
mkdir -p /tmp/neon/test_bin/
|
||||||
|
|
||||||
test_exe_paths=$(
|
test_exe_paths=$(
|
||||||
${cov_prefix} cargo test $CARGO_FLAGS $CARGO_FEATURES --message-format=json --no-run |
|
${cov_prefix} cargo test $CARGO_FLAGS $CARGO_PROFILE --message-format=json --no-run |
|
||||||
jq -r '.executable | select(. != null)'
|
jq -r '.executable | select(. != null)'
|
||||||
)
|
)
|
||||||
for bin in $test_exe_paths; do
|
for bin in $test_exe_paths; do
|
||||||
@@ -264,29 +262,25 @@ jobs:
|
|||||||
export LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
#nextest does not yet support running doctests
|
#nextest does not yet support running doctests
|
||||||
${cov_prefix} cargo test --doc $CARGO_FLAGS $CARGO_FEATURES
|
${cov_prefix} cargo test --doc $CARGO_FLAGS $CARGO_PROFILE
|
||||||
|
|
||||||
# run all non-pageserver tests
|
# run all non-pageserver tests
|
||||||
${cov_prefix} cargo nextest run $CARGO_FLAGS $CARGO_FEATURES -E '!package(pageserver)'
|
${cov_prefix} cargo nextest run $CARGO_FLAGS $CARGO_PROFILE -E '!package(pageserver)'
|
||||||
|
|
||||||
# run pageserver tests with different settings
|
# run pageserver tests
|
||||||
for get_vectored_concurrent_io in sequential sidecar-task; do
|
# (When developing new pageserver features gated by config fields, we commonly make the rust
|
||||||
for io_engine in std-fs tokio-epoll-uring ; do
|
# unit tests sensitive to an environment variable NEON_PAGESERVER_UNIT_TEST_FEATURENAME.
|
||||||
for io_mode in buffered direct direct-rw ; do
|
# Then run the nextest invocation below for all relevant combinations. Singling out the
|
||||||
NEON_PAGESERVER_UNIT_TEST_GET_VECTORED_CONCURRENT_IO=$get_vectored_concurrent_io \
|
# pageserver tests from non-pageserver tests cuts down the time it takes for this CI step.)
|
||||||
NEON_PAGESERVER_UNIT_TEST_VIRTUAL_FILE_IOENGINE=$io_engine \
|
NEON_PAGESERVER_UNIT_TEST_VIRTUAL_FILE_IOENGINE=tokio-epoll-uring \
|
||||||
NEON_PAGESERVER_UNIT_TEST_VIRTUAL_FILE_IO_MODE=$io_mode \
|
${cov_prefix} \
|
||||||
${cov_prefix} \
|
cargo nextest run $CARGO_FLAGS $CARGO_PROFILE -E 'package(pageserver)'
|
||||||
cargo nextest run $CARGO_FLAGS $CARGO_FEATURES -E 'package(pageserver)'
|
|
||||||
done
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# Run separate tests for real S3
|
# Run separate tests for real S3
|
||||||
export ENABLE_REAL_S3_REMOTE_STORAGE=nonempty
|
export ENABLE_REAL_S3_REMOTE_STORAGE=nonempty
|
||||||
export REMOTE_STORAGE_S3_BUCKET=neon-github-ci-tests
|
export REMOTE_STORAGE_S3_BUCKET=neon-github-ci-tests
|
||||||
export REMOTE_STORAGE_S3_REGION=eu-central-1
|
export REMOTE_STORAGE_S3_REGION=eu-central-1
|
||||||
${cov_prefix} cargo nextest run $CARGO_FLAGS $CARGO_FEATURES -E 'package(remote_storage)' -E 'test(test_real_s3)'
|
${cov_prefix} cargo nextest run $CARGO_FLAGS $CARGO_PROFILE -E 'package(remote_storage)' -E 'test(test_real_s3)'
|
||||||
|
|
||||||
# Run separate tests for real Azure Blob Storage
|
# Run separate tests for real Azure Blob Storage
|
||||||
# XXX: replace region with `eu-central-1`-like region
|
# XXX: replace region with `eu-central-1`-like region
|
||||||
@@ -295,17 +289,17 @@ jobs:
|
|||||||
export AZURE_STORAGE_ACCESS_KEY="${{ secrets.AZURE_STORAGE_ACCESS_KEY_DEV }}"
|
export AZURE_STORAGE_ACCESS_KEY="${{ secrets.AZURE_STORAGE_ACCESS_KEY_DEV }}"
|
||||||
export REMOTE_STORAGE_AZURE_CONTAINER="${{ vars.REMOTE_STORAGE_AZURE_CONTAINER }}"
|
export REMOTE_STORAGE_AZURE_CONTAINER="${{ vars.REMOTE_STORAGE_AZURE_CONTAINER }}"
|
||||||
export REMOTE_STORAGE_AZURE_REGION="${{ vars.REMOTE_STORAGE_AZURE_REGION }}"
|
export REMOTE_STORAGE_AZURE_REGION="${{ vars.REMOTE_STORAGE_AZURE_REGION }}"
|
||||||
${cov_prefix} cargo nextest run $CARGO_FLAGS $CARGO_FEATURES -E 'package(remote_storage)' -E 'test(test_real_azure)'
|
${cov_prefix} cargo nextest run $CARGO_FLAGS $CARGO_PROFILE -E 'package(remote_storage)' -E 'test(test_real_azure)'
|
||||||
|
|
||||||
- name: Install postgres binaries
|
- name: Install postgres binaries
|
||||||
run: |
|
run: |
|
||||||
# Use tar to copy files matching the pattern, preserving the paths in the destionation
|
# Use tar to copy files matching the pattern, preserving the paths in the destionation
|
||||||
tar c \
|
tar c \
|
||||||
pg_install/v* \
|
pg_install/v* \
|
||||||
pg_install/build/*/src/test/regress/*.so \
|
build/*/src/test/regress/*.so \
|
||||||
pg_install/build/*/src/test/regress/pg_regress \
|
build/*/src/test/regress/pg_regress \
|
||||||
pg_install/build/*/src/test/isolation/isolationtester \
|
build/*/src/test/isolation/isolationtester \
|
||||||
pg_install/build/*/src/test/isolation/pg_isolation_regress \
|
build/*/src/test/isolation/pg_isolation_regress \
|
||||||
| tar x -C /tmp/neon
|
| tar x -C /tmp/neon
|
||||||
|
|
||||||
- name: Upload Neon artifact
|
- name: Upload Neon artifact
|
||||||
@@ -313,7 +307,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build-type }}${{ inputs.sanitizers == 'enabled' && '-sanitized' || '' }}-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build-type }}${{ inputs.sanitizers == 'enabled' && '-sanitized' || '' }}-artifact
|
||||||
path: /tmp/neon
|
path: /tmp/neon
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Check diesel schema
|
- name: Check diesel schema
|
||||||
if: inputs.build-type == 'release' && inputs.arch == 'x64'
|
if: inputs.build-type == 'release' && inputs.arch == 'x64'
|
||||||
@@ -373,7 +367,7 @@ jobs:
|
|||||||
- name: Pytest regression tests
|
- name: Pytest regression tests
|
||||||
continue-on-error: ${{ matrix.lfc_state == 'with-lfc' && inputs.build-type == 'debug' }}
|
continue-on-error: ${{ matrix.lfc_state == 'with-lfc' && inputs.build-type == 'debug' }}
|
||||||
uses: ./.github/actions/run-python-test-set
|
uses: ./.github/actions/run-python-test-set
|
||||||
timeout-minutes: ${{ inputs.sanitizers != 'enabled' && 75 || 180 }}
|
timeout-minutes: ${{ (inputs.build-type == 'release' && inputs.sanitizers != 'enabled') && 75 || 180 }}
|
||||||
with:
|
with:
|
||||||
build_type: ${{ inputs.build-type }}
|
build_type: ${{ inputs.build-type }}
|
||||||
test_selection: regress
|
test_selection: regress
|
||||||
@@ -381,21 +375,20 @@ jobs:
|
|||||||
run_with_real_s3: true
|
run_with_real_s3: true
|
||||||
real_s3_bucket: neon-github-ci-tests
|
real_s3_bucket: neon-github-ci-tests
|
||||||
real_s3_region: eu-central-1
|
real_s3_region: eu-central-1
|
||||||
rerun_failed: true
|
rerun_failed: ${{ inputs.rerun-failed }}
|
||||||
pg_version: ${{ matrix.pg_version }}
|
pg_version: ${{ matrix.pg_version }}
|
||||||
sanitizers: ${{ inputs.sanitizers }}
|
sanitizers: ${{ inputs.sanitizers }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
# `--session-timeout` is equal to (timeout-minutes - 10 minutes) * 60 seconds.
|
# `--session-timeout` is equal to (timeout-minutes - 10 minutes) * 60 seconds.
|
||||||
# Attempt to stop tests gracefully to generate test reports
|
# Attempt to stop tests gracefully to generate test reports
|
||||||
# until they are forcibly stopped by the stricter `timeout-minutes` limit.
|
# until they are forcibly stopped by the stricter `timeout-minutes` limit.
|
||||||
extra_params: --session-timeout=${{ inputs.sanitizers != 'enabled' && 3000 || 10200 }}
|
extra_params: --session-timeout=${{ (inputs.build-type == 'release' && inputs.sanitizers != 'enabled') && 3000 || 10200 }} --count=${{ inputs.test-run-count }}
|
||||||
|
${{ inputs.test-selection != '' && format('-k "{0}"', inputs.test-selection) || '' }}
|
||||||
env:
|
env:
|
||||||
TEST_RESULT_CONNSTR: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
TEST_RESULT_CONNSTR: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||||
CHECK_ONDISK_DATA_COMPATIBILITY: nonempty
|
CHECK_ONDISK_DATA_COMPATIBILITY: nonempty
|
||||||
BUILD_TAG: ${{ inputs.build-tag }}
|
BUILD_TAG: ${{ inputs.build-tag }}
|
||||||
PAGESERVER_VIRTUAL_FILE_IO_ENGINE: tokio-epoll-uring
|
PAGESERVER_VIRTUAL_FILE_IO_ENGINE: tokio-epoll-uring
|
||||||
PAGESERVER_GET_VECTORED_CONCURRENT_IO: sidecar-task
|
|
||||||
PAGESERVER_VIRTUAL_FILE_IO_MODE: direct-rw
|
|
||||||
USE_LFC: ${{ matrix.lfc_state == 'with-lfc' && 'true' || 'false' }}
|
USE_LFC: ${{ matrix.lfc_state == 'with-lfc' && 'true' || 'false' }}
|
||||||
|
|
||||||
# Temporary disable this step until we figure out why it's so flaky
|
# Temporary disable this step until we figure out why it's so flaky
|
||||||
|
|||||||
103
.github/workflows/_create-release-pr.yml
vendored
103
.github/workflows/_create-release-pr.yml
vendored
@@ -1,103 +0,0 @@
|
|||||||
name: Create Release PR
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
component-name:
|
|
||||||
description: 'Component name'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
source-branch:
|
|
||||||
description: 'Source branch'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
secrets:
|
|
||||||
ci-access-token:
|
|
||||||
description: 'CI access token'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash -euo pipefail {0}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
create-release-branch:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write # for `git push`
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
with:
|
|
||||||
ref: ${{ inputs.source-branch }}
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set variables
|
|
||||||
id: vars
|
|
||||||
env:
|
|
||||||
COMPONENT_NAME: ${{ inputs.component-name }}
|
|
||||||
RELEASE_BRANCH: >-
|
|
||||||
${{
|
|
||||||
false
|
|
||||||
|| inputs.component-name == 'Storage' && 'release'
|
|
||||||
|| inputs.component-name == 'Proxy' && 'release-proxy'
|
|
||||||
|| inputs.component-name == 'Compute' && 'release-compute'
|
|
||||||
}}
|
|
||||||
run: |
|
|
||||||
now_date=$(date -u +'%Y-%m-%d')
|
|
||||||
now_time=$(date -u +'%H-%M-%Z')
|
|
||||||
{
|
|
||||||
echo "title=${COMPONENT_NAME} release ${now_date}"
|
|
||||||
echo "rc-branch=rc/${RELEASE_BRANCH}/${now_date}_${now_time}"
|
|
||||||
echo "release-branch=${RELEASE_BRANCH}"
|
|
||||||
} | tee -a ${GITHUB_OUTPUT}
|
|
||||||
|
|
||||||
- name: Configure git
|
|
||||||
run: |
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
|
|
||||||
- name: Create RC branch
|
|
||||||
env:
|
|
||||||
RELEASE_BRANCH: ${{ steps.vars.outputs.release-branch }}
|
|
||||||
RC_BRANCH: ${{ steps.vars.outputs.rc-branch }}
|
|
||||||
TITLE: ${{ steps.vars.outputs.title }}
|
|
||||||
run: |
|
|
||||||
git switch -c "${RC_BRANCH}"
|
|
||||||
|
|
||||||
# Manually create a merge commit on the current branch, keeping the
|
|
||||||
# tree and setting the parents to the current HEAD and the HEAD of the
|
|
||||||
# release branch. This commit is what we'll fast-forward the release
|
|
||||||
# branch to when merging the release branch.
|
|
||||||
# For details on why, look at
|
|
||||||
# https://docs.neon.build/overview/repositories/neon.html#background-on-commit-history-of-release-prs
|
|
||||||
current_tree=$(git rev-parse 'HEAD^{tree}')
|
|
||||||
release_head=$(git rev-parse "origin/${RELEASE_BRANCH}")
|
|
||||||
current_head=$(git rev-parse HEAD)
|
|
||||||
merge_commit=$(git commit-tree -p "${current_head}" -p "${release_head}" -m "${TITLE}" "${current_tree}")
|
|
||||||
|
|
||||||
# Fast-forward the current branch to the newly created merge_commit
|
|
||||||
git merge --ff-only ${merge_commit}
|
|
||||||
|
|
||||||
git push origin "${RC_BRANCH}"
|
|
||||||
|
|
||||||
- name: Create a PR into ${{ steps.vars.outputs.release-branch }}
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.ci-access-token }}
|
|
||||||
RC_BRANCH: ${{ steps.vars.outputs.rc-branch }}
|
|
||||||
RELEASE_BRANCH: ${{ steps.vars.outputs.release-branch }}
|
|
||||||
TITLE: ${{ steps.vars.outputs.title }}
|
|
||||||
run: |
|
|
||||||
gh pr create --title "${TITLE}" \
|
|
||||||
--body "" \
|
|
||||||
--head "${RC_BRANCH}" \
|
|
||||||
--base "${RELEASE_BRANCH}"
|
|
||||||
129
.github/workflows/benchmarking.yml
vendored
129
.github/workflows/benchmarking.yml
vendored
@@ -53,6 +53,77 @@ concurrency:
|
|||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
cleanup:
|
||||||
|
runs-on: [ self-hosted, us-east-2, x64 ]
|
||||||
|
container:
|
||||||
|
image: ghcr.io/neondatabase/build-tools:pinned-bookworm
|
||||||
|
credentials:
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
options: --init
|
||||||
|
env:
|
||||||
|
ORG_ID: org-solitary-dew-09443886
|
||||||
|
LIMIT: 100
|
||||||
|
SEARCH: "GITHUB_RUN_ID="
|
||||||
|
BASE_URL: https://console-stage.neon.build/api/v2
|
||||||
|
DRY_RUN: "false" # Set to "true" to just test out the workflow
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
|
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Cleanup inactive Neon projects left over from prior runs
|
||||||
|
env:
|
||||||
|
API_KEY: ${{ secrets.NEON_STAGING_API_KEY }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
NOW=$(date -u +%s)
|
||||||
|
DAYS_AGO=$((NOW - 5 * 86400))
|
||||||
|
|
||||||
|
REQUEST_URL="$BASE_URL/projects?limit=$LIMIT&search=$(printf '%s' "$SEARCH" | jq -sRr @uri)&org_id=$ORG_ID"
|
||||||
|
|
||||||
|
echo "Requesting project list from:"
|
||||||
|
echo "$REQUEST_URL"
|
||||||
|
|
||||||
|
response=$(curl -s -X GET "$REQUEST_URL" \
|
||||||
|
--header "Accept: application/json" \
|
||||||
|
--header "Content-Type: application/json" \
|
||||||
|
--header "Authorization: Bearer ${API_KEY}" )
|
||||||
|
|
||||||
|
echo "Response:"
|
||||||
|
echo "$response" | jq .
|
||||||
|
|
||||||
|
projects_to_delete=$(echo "$response" | jq --argjson cutoff "$DAYS_AGO" '
|
||||||
|
.projects[]
|
||||||
|
| select(.compute_last_active_at != null)
|
||||||
|
| select((.compute_last_active_at | fromdateiso8601) < $cutoff)
|
||||||
|
| {id, name, compute_last_active_at}
|
||||||
|
')
|
||||||
|
|
||||||
|
if [ -z "$projects_to_delete" ]; then
|
||||||
|
echo "No projects eligible for deletion."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Projects that will be deleted:"
|
||||||
|
echo "$projects_to_delete" | jq -r '.id'
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = "false" ]; then
|
||||||
|
echo "$projects_to_delete" | jq -r '.id' | while read -r project_id; do
|
||||||
|
echo "Deleting project: $project_id"
|
||||||
|
curl -s -X DELETE "$BASE_URL/projects/$project_id" \
|
||||||
|
--header "Accept: application/json" \
|
||||||
|
--header "Content-Type: application/json" \
|
||||||
|
--header "Authorization: Bearer ${API_KEY}"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "Dry run enabled — no projects were deleted."
|
||||||
|
fi
|
||||||
bench:
|
bench:
|
||||||
if: ${{ github.event.inputs.run_only_pgvector_tests == 'false' || github.event.inputs.run_only_pgvector_tests == null }}
|
if: ${{ github.event.inputs.run_only_pgvector_tests == 'false' || github.event.inputs.run_only_pgvector_tests == null }}
|
||||||
permissions:
|
permissions:
|
||||||
@@ -114,7 +185,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Create Neon Project
|
- name: Create Neon Project
|
||||||
id: create-neon-project
|
id: create-neon-project
|
||||||
@@ -132,7 +203,7 @@ jobs:
|
|||||||
run_in_parallel: false
|
run_in_parallel: false
|
||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
# Set --sparse-ordering option of pytest-order plugin
|
# Set --sparse-ordering option of pytest-order plugin
|
||||||
# to ensure tests are running in order of appears in the file.
|
# to ensure tests are running in order of appears in the file.
|
||||||
# It's important for test_perf_pgbench.py::test_pgbench_remote_* tests
|
# It's important for test_perf_pgbench.py::test_pgbench_remote_* tests
|
||||||
@@ -165,7 +236,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
@@ -222,8 +293,8 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Verify that cumulative statistics are preserved
|
- name: Verify that cumulative statistics are preserved
|
||||||
uses: ./.github/actions/run-python-test-set
|
uses: ./.github/actions/run-python-test-set
|
||||||
with:
|
with:
|
||||||
@@ -233,7 +304,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 3600
|
extra_params: -m remote_cluster --timeout 3600
|
||||||
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
@@ -282,7 +353,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Run Logical Replication benchmarks
|
- name: Run Logical Replication benchmarks
|
||||||
uses: ./.github/actions/run-python-test-set
|
uses: ./.github/actions/run-python-test-set
|
||||||
@@ -293,7 +364,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 5400
|
extra_params: -m remote_cluster --timeout 5400
|
||||||
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
@@ -310,7 +381,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 5400
|
extra_params: -m remote_cluster --timeout 5400
|
||||||
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
@@ -322,7 +393,7 @@ jobs:
|
|||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
store-test-results-into-db: true
|
store-test-results-into-db: true
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||||
|
|
||||||
@@ -505,7 +576,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Create Neon Project
|
- name: Create Neon Project
|
||||||
if: contains(fromJSON('["neonvm-captest-new", "neonvm-captest-new-many-tables", "neonvm-captest-freetier", "neonvm-azure-captest-freetier", "neonvm-azure-captest-new"]'), matrix.platform)
|
if: contains(fromJSON('["neonvm-captest-new", "neonvm-captest-new-many-tables", "neonvm-captest-freetier", "neonvm-azure-captest-freetier", "neonvm-azure-captest-new"]'), matrix.platform)
|
||||||
@@ -557,7 +628,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 21600 -k test_perf_many_relations
|
extra_params: -m remote_cluster --timeout 21600 -k test_perf_many_relations
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
@@ -573,7 +644,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 21600 -k test_pgbench_remote_init
|
extra_params: -m remote_cluster --timeout 21600 -k test_pgbench_remote_init
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
@@ -588,7 +659,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 21600 -k test_pgbench_remote_simple_update
|
extra_params: -m remote_cluster --timeout 21600 -k test_pgbench_remote_simple_update
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
@@ -603,7 +674,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 21600 -k test_pgbench_remote_select_only
|
extra_params: -m remote_cluster --timeout 21600 -k test_pgbench_remote_select_only
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
@@ -621,7 +692,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
@@ -694,7 +765,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Set up Connection String
|
- name: Set up Connection String
|
||||||
id: set-up-connstr
|
id: set-up-connstr
|
||||||
@@ -726,7 +797,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 21600 -k test_pgvector_indexing
|
extra_params: -m remote_cluster --timeout 21600 -k test_pgvector_indexing
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
@@ -741,7 +812,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 21600
|
extra_params: -m remote_cluster --timeout 21600
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
@@ -752,7 +823,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
@@ -828,7 +899,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Set up Connection String
|
- name: Set up Connection String
|
||||||
id: set-up-connstr
|
id: set-up-connstr
|
||||||
@@ -871,7 +942,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 43200 -k test_clickbench
|
extra_params: -m remote_cluster --timeout 43200 -k test_clickbench
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
@@ -885,7 +956,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
@@ -954,7 +1025,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Get Connstring Secret Name
|
- name: Get Connstring Secret Name
|
||||||
run: |
|
run: |
|
||||||
@@ -1003,7 +1074,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 21600 -k test_tpch
|
extra_params: -m remote_cluster --timeout 21600 -k test_tpch
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
@@ -1015,7 +1086,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
@@ -1078,7 +1149,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Set up Connection String
|
- name: Set up Connection String
|
||||||
id: set-up-connstr
|
id: set-up-connstr
|
||||||
@@ -1121,7 +1192,7 @@ jobs:
|
|||||||
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
save_perf_report: ${{ env.SAVE_PERF_REPORT }}
|
||||||
extra_params: -m remote_cluster --timeout 21600 -k test_user_examples
|
extra_params: -m remote_cluster --timeout 21600 -k test_user_examples
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
@@ -1132,7 +1203,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
|
|||||||
197
.github/workflows/build-macos.yml
vendored
197
.github/workflows/build-macos.yml
vendored
@@ -34,11 +34,10 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
build-pgxn:
|
build-pgxn:
|
||||||
if: |
|
if: |
|
||||||
(inputs.pg_versions != '[]' || inputs.rebuild_everything) && (
|
inputs.pg_versions != '[]' || inputs.rebuild_everything ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-extra-build-macos') ||
|
contains(github.event.pull_request.labels.*.name, 'run-extra-build-macos') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-extra-build-*') ||
|
contains(github.event.pull_request.labels.*.name, 'run-extra-build-*') ||
|
||||||
github.ref_name == 'main'
|
github.ref_name == 'main'
|
||||||
)
|
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
runs-on: macos-15
|
runs-on: macos-15
|
||||||
strategy:
|
strategy:
|
||||||
@@ -63,13 +62,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache postgres ${{ matrix.postgres-version }} build
|
- name: Cache postgres ${{ matrix.postgres-version }} build
|
||||||
id: cache_pg
|
id: cache_pg
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: pg_install/${{ matrix.postgres-version }}
|
path: pg_install/${{ matrix.postgres-version }}
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-${{ matrix.postgres-version }}-${{ steps.pg_rev.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-${{ matrix.postgres-version }}-${{ steps.pg_rev.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||||
|
|
||||||
@@ -100,18 +94,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make "neon-pg-ext-${{ matrix.postgres-version }}" -j$(sysctl -n hw.ncpu)
|
make "neon-pg-ext-${{ matrix.postgres-version }}" -j$(sysctl -n hw.ncpu)
|
||||||
|
|
||||||
- name: Get postgres headers ${{ matrix.postgres-version }}
|
- name: Upload "pg_install/${{ matrix.postgres-version }}" artifact
|
||||||
if: steps.cache_pg.outputs.cache-hit != 'true'
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
run: |
|
with:
|
||||||
make postgres-headers-${{ matrix.postgres-version }} -j$(sysctl -n hw.ncpu)
|
name: pg_install--${{ matrix.postgres-version }}
|
||||||
|
path: pg_install/${{ matrix.postgres-version }}
|
||||||
|
# The artifact is supposed to be used by the next job in the same workflow,
|
||||||
|
# so there’s no need to store it for too long.
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
build-walproposer-lib:
|
build-walproposer-lib:
|
||||||
if: |
|
if: |
|
||||||
(inputs.pg_versions != '[]' || inputs.rebuild_everything) && (
|
contains(inputs.pg_versions, 'v17') || inputs.rebuild_everything ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-extra-build-macos') ||
|
contains(github.event.pull_request.labels.*.name, 'run-extra-build-macos') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-extra-build-*') ||
|
contains(github.event.pull_request.labels.*.name, 'run-extra-build-*') ||
|
||||||
github.ref_name == 'main'
|
github.ref_name == 'main'
|
||||||
)
|
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
runs-on: macos-15
|
runs-on: macos-15
|
||||||
needs: [build-pgxn]
|
needs: [build-pgxn]
|
||||||
@@ -132,28 +129,23 @@ jobs:
|
|||||||
id: pg_rev
|
id: pg_rev
|
||||||
run: echo pg_rev=$(git rev-parse HEAD:vendor/postgres-v17) | tee -a "${GITHUB_OUTPUT}"
|
run: echo pg_rev=$(git rev-parse HEAD:vendor/postgres-v17) | tee -a "${GITHUB_OUTPUT}"
|
||||||
|
|
||||||
- name: Cache postgres v17 build
|
- name: Download "pg_install/v17" artifact
|
||||||
id: cache_pg
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
|
||||||
with:
|
with:
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
name: pg_install--v17
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: pg_install/v17
|
path: pg_install/v17
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v17-${{ steps.pg_rev.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
|
||||||
|
# `actions/download-artifact` doesn't preserve permissions:
|
||||||
|
# https://github.com/actions/download-artifact?tab=readme-ov-file#permission-loss
|
||||||
|
- name: Make pg_install/v*/bin/* executable
|
||||||
|
run: |
|
||||||
|
chmod +x pg_install/v*/bin/*
|
||||||
|
|
||||||
- name: Cache walproposer-lib
|
- name: Cache walproposer-lib
|
||||||
id: cache_walproposer_lib
|
id: cache_walproposer_lib
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
path: build/walproposer-lib
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: pg_install/build/walproposer-lib
|
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-walproposer_lib-v17-${{ steps.pg_rev.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-walproposer_lib-v17-${{ steps.pg_rev.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||||
|
|
||||||
- name: Checkout submodule vendor/postgres-v17
|
- name: Checkout submodule vendor/postgres-v17
|
||||||
@@ -176,15 +168,23 @@ jobs:
|
|||||||
- name: Build walproposer-lib (only for v17)
|
- name: Build walproposer-lib (only for v17)
|
||||||
if: steps.cache_walproposer_lib.outputs.cache-hit != 'true'
|
if: steps.cache_walproposer_lib.outputs.cache-hit != 'true'
|
||||||
run:
|
run:
|
||||||
make walproposer-lib -j$(sysctl -n hw.ncpu)
|
make walproposer-lib -j$(sysctl -n hw.ncpu) PG_INSTALL_CACHED=1
|
||||||
|
|
||||||
|
- name: Upload "build/walproposer-lib" artifact
|
||||||
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
|
with:
|
||||||
|
name: build--walproposer-lib
|
||||||
|
path: build/walproposer-lib
|
||||||
|
# The artifact is supposed to be used by the next job in the same workflow,
|
||||||
|
# so there’s no need to store it for too long.
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
cargo-build:
|
cargo-build:
|
||||||
if: |
|
if: |
|
||||||
(inputs.pg_versions != '[]' || inputs.rebuild_rust_code || inputs.rebuild_everything) && (
|
inputs.pg_versions != '[]' || inputs.rebuild_rust_code || inputs.rebuild_everything ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-extra-build-macos') ||
|
contains(github.event.pull_request.labels.*.name, 'run-extra-build-macos') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-extra-build-*') ||
|
contains(github.event.pull_request.labels.*.name, 'run-extra-build-*') ||
|
||||||
github.ref_name == 'main'
|
github.ref_name == 'main'
|
||||||
)
|
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
runs-on: macos-15
|
runs-on: macos-15
|
||||||
needs: [build-pgxn, build-walproposer-lib]
|
needs: [build-pgxn, build-walproposer-lib]
|
||||||
@@ -203,72 +203,45 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- name: Set pg v14 for caching
|
- name: Download "pg_install/v14" artifact
|
||||||
id: pg_rev_v14
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
run: echo pg_rev=$(git rev-parse HEAD:vendor/postgres-v14) | tee -a "${GITHUB_OUTPUT}"
|
|
||||||
- name: Set pg v15 for caching
|
|
||||||
id: pg_rev_v15
|
|
||||||
run: echo pg_rev=$(git rev-parse HEAD:vendor/postgres-v15) | tee -a "${GITHUB_OUTPUT}"
|
|
||||||
- name: Set pg v16 for caching
|
|
||||||
id: pg_rev_v16
|
|
||||||
run: echo pg_rev=$(git rev-parse HEAD:vendor/postgres-v16) | tee -a "${GITHUB_OUTPUT}"
|
|
||||||
- name: Set pg v17 for caching
|
|
||||||
id: pg_rev_v17
|
|
||||||
run: echo pg_rev=$(git rev-parse HEAD:vendor/postgres-v17) | tee -a "${GITHUB_OUTPUT}"
|
|
||||||
|
|
||||||
- name: Cache postgres v14 build
|
|
||||||
id: cache_pg
|
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
|
||||||
with:
|
with:
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
name: pg_install--v14
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: pg_install/v14
|
path: pg_install/v14
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v14-${{ steps.pg_rev_v14.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
|
||||||
- name: Cache postgres v15 build
|
|
||||||
id: cache_pg_v15
|
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
|
||||||
with:
|
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: pg_install/v15
|
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v15-${{ steps.pg_rev_v15.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
|
||||||
- name: Cache postgres v16 build
|
|
||||||
id: cache_pg_v16
|
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
|
||||||
with:
|
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: pg_install/v16
|
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v16-${{ steps.pg_rev_v16.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
|
||||||
- name: Cache postgres v17 build
|
|
||||||
id: cache_pg_v17
|
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
|
||||||
with:
|
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: pg_install/v17
|
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v17-${{ steps.pg_rev_v17.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
|
||||||
|
|
||||||
- name: Cache cargo deps (only for v17)
|
- name: Download "pg_install/v15" artifact
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
|
with:
|
||||||
|
name: pg_install--v15
|
||||||
|
path: pg_install/v15
|
||||||
|
|
||||||
|
- name: Download "pg_install/v16" artifact
|
||||||
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
|
with:
|
||||||
|
name: pg_install--v16
|
||||||
|
path: pg_install/v16
|
||||||
|
|
||||||
|
- name: Download "pg_install/v17" artifact
|
||||||
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
|
with:
|
||||||
|
name: pg_install--v17
|
||||||
|
path: pg_install/v17
|
||||||
|
|
||||||
|
- name: Download "build/walproposer-lib" artifact
|
||||||
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
|
with:
|
||||||
|
name: build--walproposer-lib
|
||||||
|
path: build/walproposer-lib
|
||||||
|
|
||||||
|
# `actions/download-artifact` doesn't preserve permissions:
|
||||||
|
# https://github.com/actions/download-artifact?tab=readme-ov-file#permission-loss
|
||||||
|
- name: Make pg_install/v*/bin/* executable
|
||||||
|
run: |
|
||||||
|
chmod +x pg_install/v*/bin/*
|
||||||
|
|
||||||
|
- name: Cache cargo deps
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
!~/.cargo/registry/src
|
!~/.cargo/registry/src
|
||||||
@@ -276,18 +249,6 @@ jobs:
|
|||||||
target
|
target
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('./Cargo.lock') }}-${{ hashFiles('./rust-toolchain.toml') }}-rust
|
key: v1-${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('./Cargo.lock') }}-${{ hashFiles('./rust-toolchain.toml') }}-rust
|
||||||
|
|
||||||
- name: Cache walproposer-lib
|
|
||||||
id: cache_walproposer_lib
|
|
||||||
uses: tespkg/actions-cache@b7bf5fcc2f98a52ac6080eb0fd282c2f752074b1 # v1.8.0
|
|
||||||
with:
|
|
||||||
endpoint: ${{ vars.HETZNER_CACHE_REGION }}.${{ vars.HETZNER_CACHE_ENDPOINT }}
|
|
||||||
bucket: ${{ vars.HETZNER_CACHE_BUCKET }}
|
|
||||||
accessKey: ${{ secrets.HETZNER_CACHE_ACCESS_KEY }}
|
|
||||||
secretKey: ${{ secrets.HETZNER_CACHE_SECRET_KEY }}
|
|
||||||
use-fallback: false
|
|
||||||
path: pg_install/build/walproposer-lib
|
|
||||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-walproposer_lib-v17-${{ steps.pg_rev_v17.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
|
||||||
|
|
||||||
- name: Install build dependencies
|
- name: Install build dependencies
|
||||||
run: |
|
run: |
|
||||||
brew install flex bison openssl protobuf icu4c
|
brew install flex bison openssl protobuf icu4c
|
||||||
@@ -297,8 +258,8 @@ jobs:
|
|||||||
echo 'LDFLAGS=-L/usr/local/opt/openssl@3/lib' >> $GITHUB_ENV
|
echo 'LDFLAGS=-L/usr/local/opt/openssl@3/lib' >> $GITHUB_ENV
|
||||||
echo 'CPPFLAGS=-I/usr/local/opt/openssl@3/include' >> $GITHUB_ENV
|
echo 'CPPFLAGS=-I/usr/local/opt/openssl@3/include' >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Run cargo build (only for v17)
|
- name: Run cargo build
|
||||||
run: cargo build --all --release -j$(sysctl -n hw.ncpu)
|
run: cargo build --all --release -j$(sysctl -n hw.ncpu)
|
||||||
|
|
||||||
- name: Check that no warnings are produced (only for v17)
|
- name: Check that no warnings are produced
|
||||||
run: ./run_clippy.sh
|
run: ./run_clippy.sh
|
||||||
|
|||||||
121
.github/workflows/build_and_run_selected_test.yml
vendored
Normal file
121
.github/workflows/build_and_run_selected_test.yml
vendored
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
name: Build and Run Selected Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
test-selection:
|
||||||
|
description: 'Specification of selected test(s), as accepted by pytest -k'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
run-count:
|
||||||
|
description: 'Number of test runs to perform'
|
||||||
|
required: true
|
||||||
|
type: number
|
||||||
|
archs:
|
||||||
|
description: 'Archs to run tests on, e. g.: ["x64", "arm64"]'
|
||||||
|
default: '["x64"]'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
build-types:
|
||||||
|
description: 'Build types to run tests on, e. g.: ["debug", "release"]'
|
||||||
|
default: '["release"]'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
pg-versions:
|
||||||
|
description: 'Postgres versions to use for testing, e.g,: [{"pg_version":"v16"}, {"pg_version":"v17"}])'
|
||||||
|
default: '[{"pg_version":"v17"}]'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
COPT: '-Werror'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
meta:
|
||||||
|
uses: ./.github/workflows/_meta.yml
|
||||||
|
with:
|
||||||
|
github-event-name: ${{ github.event_name }}
|
||||||
|
github-event-json: ${{ toJSON(github.event) }}
|
||||||
|
|
||||||
|
build-and-test-locally:
|
||||||
|
needs: [ meta ]
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
arch: ${{ fromJson(inputs.archs) }}
|
||||||
|
build-type: ${{ fromJson(inputs.build-types) }}
|
||||||
|
uses: ./.github/workflows/_build-and-test-locally.yml
|
||||||
|
with:
|
||||||
|
arch: ${{ matrix.arch }}
|
||||||
|
build-tools-image: ghcr.io/neondatabase/build-tools:pinned-bookworm
|
||||||
|
build-tag: ${{ needs.meta.outputs.build-tag }}
|
||||||
|
build-type: ${{ matrix.build-type }}
|
||||||
|
test-cfg: ${{ inputs.pg-versions }}
|
||||||
|
test-selection: ${{ inputs.test-selection }}
|
||||||
|
test-run-count: ${{ fromJson(inputs.run-count) }}
|
||||||
|
rerun-failed: false
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
create-test-report:
|
||||||
|
needs: [ build-and-test-locally ]
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
permissions:
|
||||||
|
id-token: write # aws-actions/configure-aws-credentials
|
||||||
|
statuses: write
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
outputs:
|
||||||
|
report-url: ${{ steps.create-allure-report.outputs.report-url }}
|
||||||
|
|
||||||
|
runs-on: [ self-hosted, small ]
|
||||||
|
container:
|
||||||
|
image: ghcr.io/neondatabase/build-tools:pinned-bookworm
|
||||||
|
credentials:
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
options: --init
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
|
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Create Allure report
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
id: create-allure-report
|
||||||
|
uses: ./.github/actions/allure-report-generate
|
||||||
|
with:
|
||||||
|
store-test-results-into-db: true
|
||||||
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
env:
|
||||||
|
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_DEV }}
|
||||||
|
|
||||||
|
- uses: actions/github-script@v7
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
with:
|
||||||
|
# Retry script for 5XX server errors: https://github.com/actions/github-script#retries
|
||||||
|
retries: 5
|
||||||
|
script: |
|
||||||
|
const report = {
|
||||||
|
reportUrl: "${{ steps.create-allure-report.outputs.report-url }}",
|
||||||
|
reportJsonUrl: "${{ steps.create-allure-report.outputs.report-json-url }}",
|
||||||
|
}
|
||||||
|
|
||||||
|
const coverage = {}
|
||||||
|
|
||||||
|
const script = require("./scripts/comment-test-report.js")
|
||||||
|
await script({
|
||||||
|
github,
|
||||||
|
context,
|
||||||
|
fetch,
|
||||||
|
report,
|
||||||
|
coverage,
|
||||||
|
})
|
||||||
80
.github/workflows/build_and_test.yml
vendored
80
.github/workflows/build_and_test.yml
vendored
@@ -199,6 +199,28 @@ jobs:
|
|||||||
build-tools-image: ${{ needs.build-build-tools-image.outputs.image }}-bookworm
|
build-tools-image: ${{ needs.build-build-tools-image.outputs.image }}-bookworm
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
validate-compute-manifest:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: [ meta, check-permissions ]
|
||||||
|
# We do need to run this in `.*-rc-pr` because of hotfixes.
|
||||||
|
if: ${{ contains(fromJSON('["pr", "push-main", "storage-rc-pr", "proxy-rc-pr", "compute-rc-pr"]'), needs.meta.outputs.run-kind) }}
|
||||||
|
steps:
|
||||||
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
|
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
|
with:
|
||||||
|
node-version: '24'
|
||||||
|
|
||||||
|
- name: Validate manifest against schema
|
||||||
|
run: |
|
||||||
|
make -C compute manifest-schema-validation
|
||||||
|
|
||||||
build-and-test-locally:
|
build-and-test-locally:
|
||||||
needs: [ meta, build-build-tools-image ]
|
needs: [ meta, build-build-tools-image ]
|
||||||
# We do need to run this in `.*-rc-pr` because of hotfixes.
|
# We do need to run this in `.*-rc-pr` because of hotfixes.
|
||||||
@@ -314,17 +336,16 @@ jobs:
|
|||||||
test_selection: performance
|
test_selection: performance
|
||||||
run_in_parallel: false
|
run_in_parallel: false
|
||||||
save_perf_report: ${{ github.ref_name == 'main' }}
|
save_perf_report: ${{ github.ref_name == 'main' }}
|
||||||
extra_params: --splits 5 --group ${{ matrix.pytest_split_group }}
|
# test_pageserver_max_throughput_getpage_at_latest_lsn is run in separate workflow periodic_pagebench.yml because it needs snapshots
|
||||||
|
extra_params: --splits 5 --group ${{ matrix.pytest_split_group }} --ignore=test_runner/performance/pageserver/pagebench/test_pageserver_max_throughput_getpage_at_latest_lsn.py
|
||||||
benchmark_durations: ${{ needs.get-benchmarks-durations.outputs.json }}
|
benchmark_durations: ${{ needs.get-benchmarks-durations.outputs.json }}
|
||||||
pg_version: v16
|
pg_version: v16
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
TEST_RESULT_CONNSTR: "${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}"
|
TEST_RESULT_CONNSTR: "${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}"
|
||||||
PAGESERVER_VIRTUAL_FILE_IO_ENGINE: tokio-epoll-uring
|
PAGESERVER_VIRTUAL_FILE_IO_ENGINE: tokio-epoll-uring
|
||||||
PAGESERVER_GET_VECTORED_CONCURRENT_IO: sidecar-task
|
|
||||||
PAGESERVER_VIRTUAL_FILE_IO_MODE: direct-rw
|
|
||||||
SYNC_BETWEEN_TESTS: true
|
SYNC_BETWEEN_TESTS: true
|
||||||
# XXX: no coverage data handling here, since benchmarks are run on release builds,
|
# XXX: no coverage data handling here, since benchmarks are run on release builds,
|
||||||
# while coverage is currently collected for the debug ones
|
# while coverage is currently collected for the debug ones
|
||||||
@@ -384,7 +405,7 @@ jobs:
|
|||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
store-test-results-into-db: true
|
store-test-results-into-db: true
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||||
|
|
||||||
@@ -451,14 +472,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-${{ matrix.build_type }}-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-${{ matrix.build_type }}-artifact
|
||||||
path: /tmp/neon
|
path: /tmp/neon
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Get coverage artifact
|
- name: Get coverage artifact
|
||||||
uses: ./.github/actions/download
|
uses: ./.github/actions/download
|
||||||
with:
|
with:
|
||||||
name: coverage-data-artifact
|
name: coverage-data-artifact
|
||||||
path: /tmp/coverage
|
path: /tmp/coverage
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Merge coverage data
|
- name: Merge coverage data
|
||||||
run: scripts/coverage "--profraw-prefix=$GITHUB_JOB" --dir=/tmp/coverage merge
|
run: scripts/coverage "--profraw-prefix=$GITHUB_JOB" --dir=/tmp/coverage merge
|
||||||
@@ -649,7 +670,7 @@ jobs:
|
|||||||
ghcr.io/neondatabase/neon:${{ needs.meta.outputs.build-tag }}-bookworm-arm64
|
ghcr.io/neondatabase/neon:${{ needs.meta.outputs.build-tag }}-bookworm-arm64
|
||||||
|
|
||||||
compute-node-image-arch:
|
compute-node-image-arch:
|
||||||
needs: [ check-permissions, build-build-tools-image, meta ]
|
needs: [ check-permissions, meta ]
|
||||||
if: ${{ contains(fromJSON('["push-main", "pr", "compute-rc-pr"]'), needs.meta.outputs.run-kind) }}
|
if: ${{ contains(fromJSON('["push-main", "pr", "compute-rc-pr"]'), needs.meta.outputs.run-kind) }}
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # aws-actions/configure-aws-credentials
|
id-token: write # aws-actions/configure-aws-credentials
|
||||||
@@ -722,7 +743,6 @@ jobs:
|
|||||||
GIT_VERSION=${{ github.event.pull_request.head.sha || github.sha }}
|
GIT_VERSION=${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
PG_VERSION=${{ matrix.version.pg }}
|
PG_VERSION=${{ matrix.version.pg }}
|
||||||
BUILD_TAG=${{ needs.meta.outputs.release-tag || needs.meta.outputs.build-tag }}
|
BUILD_TAG=${{ needs.meta.outputs.release-tag || needs.meta.outputs.build-tag }}
|
||||||
TAG=${{ needs.build-build-tools-image.outputs.image-tag }}-${{ matrix.version.debian }}
|
|
||||||
DEBIAN_VERSION=${{ matrix.version.debian }}
|
DEBIAN_VERSION=${{ matrix.version.debian }}
|
||||||
provenance: false
|
provenance: false
|
||||||
push: true
|
push: true
|
||||||
@@ -742,7 +762,6 @@ jobs:
|
|||||||
GIT_VERSION=${{ github.event.pull_request.head.sha || github.sha }}
|
GIT_VERSION=${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
PG_VERSION=${{ matrix.version.pg }}
|
PG_VERSION=${{ matrix.version.pg }}
|
||||||
BUILD_TAG=${{ needs.meta.outputs.release-tag || needs.meta.outputs.build-tag }}
|
BUILD_TAG=${{ needs.meta.outputs.release-tag || needs.meta.outputs.build-tag }}
|
||||||
TAG=${{ needs.build-build-tools-image.outputs.image-tag }}-${{ matrix.version.debian }}
|
|
||||||
DEBIAN_VERSION=${{ matrix.version.debian }}
|
DEBIAN_VERSION=${{ matrix.version.debian }}
|
||||||
provenance: false
|
provenance: false
|
||||||
push: true
|
push: true
|
||||||
@@ -824,7 +843,7 @@ jobs:
|
|||||||
- pg: v17
|
- pg: v17
|
||||||
debian: bookworm
|
debian: bookworm
|
||||||
env:
|
env:
|
||||||
VM_BUILDER_VERSION: v0.42.2
|
VM_BUILDER_VERSION: v0.46.0
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
@@ -965,7 +984,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Verify docker-compose example and test extensions
|
- name: Verify docker-compose example and test extensions
|
||||||
timeout-minutes: 20
|
timeout-minutes: 60
|
||||||
env:
|
env:
|
||||||
TAG: >-
|
TAG: >-
|
||||||
${{
|
${{
|
||||||
@@ -1434,10 +1453,10 @@ jobs:
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
notify-storage-release-deploy-failure:
|
notify-release-deploy-failure:
|
||||||
needs: [ deploy ]
|
needs: [ meta, deploy ]
|
||||||
# We want this to run even if (transitive) dependencies are skipped, because deploy should really be successful on release branch workflow runs.
|
# We want this to run even if (transitive) dependencies are skipped, because deploy should really be successful on release branch workflow runs.
|
||||||
if: github.ref_name == 'release' && needs.deploy.result != 'success' && always()
|
if: contains(fromJSON('["storage-release", "compute-release", "proxy-release"]'), needs.meta.outputs.run-kind) && needs.deploy.result != 'success' && always()
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
@@ -1445,15 +1464,40 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- name: Post release-deploy failure to team-storage slack channel
|
- name: Post release-deploy failure to team slack channel
|
||||||
uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0
|
uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0
|
||||||
|
env:
|
||||||
|
TEAM_ONCALL: >-
|
||||||
|
${{
|
||||||
|
fromJSON(format('{
|
||||||
|
"storage-release": "<!subteam^{0}|@oncall-storage>",
|
||||||
|
"compute-release": "<!subteam^{1}|@oncall-compute>",
|
||||||
|
"proxy-release": "<!subteam^{2}|@oncall-proxy>"
|
||||||
|
}',
|
||||||
|
vars.SLACK_ONCALL_STORAGE_GROUP,
|
||||||
|
vars.SLACK_ONCALL_COMPUTE_GROUP,
|
||||||
|
vars.SLACK_ONCALL_PROXY_GROUP
|
||||||
|
))[needs.meta.outputs.run-kind]
|
||||||
|
}}
|
||||||
|
CHANNEL: >-
|
||||||
|
${{
|
||||||
|
fromJSON(format('{
|
||||||
|
"storage-release": "{0}",
|
||||||
|
"compute-release": "{1}",
|
||||||
|
"proxy-release": "{2}"
|
||||||
|
}',
|
||||||
|
vars.SLACK_STORAGE_CHANNEL_ID,
|
||||||
|
vars.SLACK_COMPUTE_CHANNEL_ID,
|
||||||
|
vars.SLACK_PROXY_CHANNEL_ID
|
||||||
|
))[needs.meta.outputs.run-kind]
|
||||||
|
}}
|
||||||
with:
|
with:
|
||||||
method: chat.postMessage
|
method: chat.postMessage
|
||||||
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||||
payload: |
|
payload: |
|
||||||
channel: ${{ vars.SLACK_STORAGE_CHANNEL_ID }}
|
channel: ${{ env.CHANNEL }}
|
||||||
text: |
|
text: |
|
||||||
🔴 <!subteam^S06CJ87UMNY|@oncall-storage>: deploy job on release branch had unexpected status "${{ needs.deploy.result }}" <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Run>.
|
🔴 ${{ env.TEAM_ONCALL }}: deploy job on release branch had unexpected status "${{ needs.deploy.result }}" <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Run>.
|
||||||
|
|
||||||
# The job runs on `release` branch and copies compatibility data and Neon artifact from the last *release PR* to the latest directory
|
# The job runs on `release` branch and copies compatibility data and Neon artifact from the last *release PR* to the latest directory
|
||||||
promote-compatibility-data:
|
promote-compatibility-data:
|
||||||
|
|||||||
151
.github/workflows/build_and_test_fully.yml
vendored
Normal file
151
.github/workflows/build_and_test_fully.yml
vendored
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
name: Build and Test Fully
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# * is a special character in YAML so you have to quote this string
|
||||||
|
# ┌───────────── minute (0 - 59)
|
||||||
|
# │ ┌───────────── hour (0 - 23)
|
||||||
|
# │ │ ┌───────────── day of the month (1 - 31)
|
||||||
|
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||||
|
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||||
|
- cron: '0 3 * * *' # run once a day, timezone is utc
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
# Allow only one workflow per any non-`main` branch.
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
COPT: '-Werror'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tag:
|
||||||
|
runs-on: [ self-hosted, small ]
|
||||||
|
container: ${{ vars.NEON_DEV_AWS_ACCOUNT_ID }}.dkr.ecr.${{ vars.AWS_ECR_REGION }}.amazonaws.com/base:pinned
|
||||||
|
outputs:
|
||||||
|
build-tag: ${{steps.build-tag.outputs.tag}}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Need `fetch-depth: 0` to count the number of commits in the branch
|
||||||
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
|
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get build tag
|
||||||
|
run: |
|
||||||
|
echo run:$GITHUB_RUN_ID
|
||||||
|
echo ref:$GITHUB_REF_NAME
|
||||||
|
echo rev:$(git rev-list --count HEAD)
|
||||||
|
if [[ "$GITHUB_REF_NAME" == "main" ]]; then
|
||||||
|
echo "tag=$(git rev-list --count HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "$GITHUB_REF_NAME" == "release" ]]; then
|
||||||
|
echo "tag=release-$(git rev-list --count HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "$GITHUB_REF_NAME" == "release-proxy" ]]; then
|
||||||
|
echo "tag=release-proxy-$(git rev-list --count HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "$GITHUB_REF_NAME" == "release-compute" ]]; then
|
||||||
|
echo "tag=release-compute-$(git rev-list --count HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "GITHUB_REF_NAME (value '$GITHUB_REF_NAME') is not set to either 'main' or 'release', 'release-proxy', 'release-compute'"
|
||||||
|
echo "tag=$GITHUB_RUN_ID" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
id: build-tag
|
||||||
|
|
||||||
|
build-build-tools-image:
|
||||||
|
uses: ./.github/workflows/build-build-tools-image.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
build-and-test-locally:
|
||||||
|
needs: [ tag, build-build-tools-image ]
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
arch: [ x64, arm64 ]
|
||||||
|
build-type: [ debug, release ]
|
||||||
|
uses: ./.github/workflows/_build-and-test-locally.yml
|
||||||
|
with:
|
||||||
|
arch: ${{ matrix.arch }}
|
||||||
|
build-tools-image: ${{ needs.build-build-tools-image.outputs.image }}-bookworm
|
||||||
|
build-tag: ${{ needs.tag.outputs.build-tag }}
|
||||||
|
build-type: ${{ matrix.build-type }}
|
||||||
|
rerun-failed: false
|
||||||
|
test-cfg: '[{"pg_version":"v14", "lfc_state": "with-lfc"},
|
||||||
|
{"pg_version":"v15", "lfc_state": "with-lfc"},
|
||||||
|
{"pg_version":"v16", "lfc_state": "with-lfc"},
|
||||||
|
{"pg_version":"v17", "lfc_state": "with-lfc"},
|
||||||
|
{"pg_version":"v14", "lfc_state": "without-lfc"},
|
||||||
|
{"pg_version":"v15", "lfc_state": "without-lfc"},
|
||||||
|
{"pg_version":"v16", "lfc_state": "without-lfc"},
|
||||||
|
{"pg_version":"v17", "lfc_state": "withouts-lfc"}]'
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
|
||||||
|
create-test-report:
|
||||||
|
needs: [ build-and-test-locally, build-build-tools-image ]
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
permissions:
|
||||||
|
id-token: write # aws-actions/configure-aws-credentials
|
||||||
|
statuses: write
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
outputs:
|
||||||
|
report-url: ${{ steps.create-allure-report.outputs.report-url }}
|
||||||
|
|
||||||
|
runs-on: [ self-hosted, small ]
|
||||||
|
container:
|
||||||
|
image: ${{ needs.build-build-tools-image.outputs.image }}-bookworm
|
||||||
|
credentials:
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
options: --init
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
|
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Create Allure report
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
id: create-allure-report
|
||||||
|
uses: ./.github/actions/allure-report-generate
|
||||||
|
with:
|
||||||
|
store-test-results-into-db: true
|
||||||
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
env:
|
||||||
|
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||||
|
|
||||||
|
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
with:
|
||||||
|
# Retry script for 5XX server errors: https://github.com/actions/github-script#retries
|
||||||
|
retries: 5
|
||||||
|
script: |
|
||||||
|
const report = {
|
||||||
|
reportUrl: "${{ steps.create-allure-report.outputs.report-url }}",
|
||||||
|
reportJsonUrl: "${{ steps.create-allure-report.outputs.report-json-url }}",
|
||||||
|
}
|
||||||
|
|
||||||
|
const coverage = {}
|
||||||
|
|
||||||
|
const script = require("./scripts/comment-test-report.js")
|
||||||
|
await script({
|
||||||
|
github,
|
||||||
|
context,
|
||||||
|
fetch,
|
||||||
|
report,
|
||||||
|
coverage,
|
||||||
|
})
|
||||||
@@ -79,6 +79,7 @@ jobs:
|
|||||||
build-tools-image: ${{ needs.build-build-tools-image.outputs.image }}-bookworm
|
build-tools-image: ${{ needs.build-build-tools-image.outputs.image }}-bookworm
|
||||||
build-tag: ${{ needs.tag.outputs.build-tag }}
|
build-tag: ${{ needs.tag.outputs.build-tag }}
|
||||||
build-type: ${{ matrix.build-type }}
|
build-type: ${{ matrix.build-type }}
|
||||||
|
rerun-failed: false
|
||||||
test-cfg: '[{"pg_version":"v17"}]'
|
test-cfg: '[{"pg_version":"v17"}]'
|
||||||
sanitizers: enabled
|
sanitizers: enabled
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
@@ -117,7 +118,7 @@ jobs:
|
|||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
store-test-results-into-db: true
|
store-test-results-into-db: true
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/check-permissions.yml
vendored
2
.github/workflows/check-permissions.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
uses: step-security/harden-runner@v2
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
uses: step-security/harden-runner@v2
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|||||||
99
.github/workflows/cloud-extensions.yml
vendored
Normal file
99
.github/workflows/cloud-extensions.yml
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
name: Cloud Extensions Test
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# * is a special character in YAML so you have to quote this string
|
||||||
|
# ┌───────────── minute (0 - 59)
|
||||||
|
# │ ┌───────────── hour (0 - 23)
|
||||||
|
# │ │ ┌───────────── day of the month (1 - 31)
|
||||||
|
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||||
|
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||||
|
- cron: '45 1 * * *' # run once a day, timezone is utc
|
||||||
|
workflow_dispatch: # adds ability to run this manually
|
||||||
|
inputs:
|
||||||
|
region_id:
|
||||||
|
description: 'Project region id. If not set, the default region will be used'
|
||||||
|
required: false
|
||||||
|
default: 'aws-us-east-2'
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
id-token: write # aws-actions/configure-aws-credentials
|
||||||
|
statuses: write
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
regress:
|
||||||
|
env:
|
||||||
|
POSTGRES_DISTRIB_DIR: /tmp/neon/pg_install
|
||||||
|
TEST_OUTPUT: /tmp/test_output
|
||||||
|
BUILD_TYPE: remote
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
pg-version: [16, 17]
|
||||||
|
|
||||||
|
runs-on: us-east-2
|
||||||
|
container:
|
||||||
|
# We use the neon-test-extensions image here as it contains the source code for the extensions.
|
||||||
|
image: ghcr.io/neondatabase/neon-test-extensions-v${{ matrix.pg-version }}:latest
|
||||||
|
credentials:
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
options: --init
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
|
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Evaluate the settings
|
||||||
|
id: project-settings
|
||||||
|
run: |
|
||||||
|
if [[ $((${{ matrix.pg-version }})) -lt 17 ]]; then
|
||||||
|
ULID=ulid
|
||||||
|
else
|
||||||
|
ULID=pgx_ulid
|
||||||
|
fi
|
||||||
|
LIBS=timescaledb:rag_bge_small_en_v15,rag_jina_reranker_v1_tiny_en:$ULID
|
||||||
|
settings=$(jq -c -n --arg libs $LIBS '{preload_libraries:{use_defaults:false,enabled_libraries:($libs| split(":"))}}')
|
||||||
|
echo settings=$settings >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create Neon Project
|
||||||
|
id: create-neon-project
|
||||||
|
uses: ./.github/actions/neon-project-create
|
||||||
|
with:
|
||||||
|
region_id: ${{ inputs.region_id || 'aws-us-east-2' }}
|
||||||
|
postgres_version: ${{ matrix.pg-version }}
|
||||||
|
project_settings: ${{ steps.project-settings.outputs.settings }}
|
||||||
|
api_key: ${{ secrets.NEON_STAGING_API_KEY }}
|
||||||
|
|
||||||
|
- name: Run the regression tests
|
||||||
|
run: /run-tests.sh -r /ext-src
|
||||||
|
env:
|
||||||
|
BENCHMARK_CONNSTR: ${{ steps.create-neon-project.outputs.dsn }}
|
||||||
|
SKIP: "pg_hint_plan-src,pg_repack-src,pg_cron-src,plpgsql_check-src"
|
||||||
|
|
||||||
|
- name: Delete Neon Project
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: ./.github/actions/neon-project-delete
|
||||||
|
with:
|
||||||
|
project_id: ${{ steps.create-neon-project.outputs.project_id }}
|
||||||
|
api_key: ${{ secrets.NEON_STAGING_API_KEY }}
|
||||||
|
|
||||||
|
- name: Post to a Slack channel
|
||||||
|
if: ${{ github.event.schedule && failure() }}
|
||||||
|
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||||
|
with:
|
||||||
|
channel-id: ${{ vars.SLACK_ON_CALL_QA_STAGING_STREAM }}
|
||||||
|
slack-message: |
|
||||||
|
Periodic extensions test on staging: ${{ job.status }}
|
||||||
|
<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Run>
|
||||||
|
env:
|
||||||
|
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||||
|
|
||||||
6
.github/workflows/cloud-regress.yml
vendored
6
.github/workflows/cloud-regress.yml
vendored
@@ -89,7 +89,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Create a new branch
|
- name: Create a new branch
|
||||||
id: create-branch
|
id: create-branch
|
||||||
@@ -105,7 +105,7 @@ jobs:
|
|||||||
test_selection: cloud_regress
|
test_selection: cloud_regress
|
||||||
pg_version: ${{matrix.pg-version}}
|
pg_version: ${{matrix.pg-version}}
|
||||||
extra_params: -m remote_cluster
|
extra_params: -m remote_cluster
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{steps.create-branch.outputs.dsn}}
|
BENCHMARK_CONNSTR: ${{steps.create-branch.outputs.dsn}}
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
|
|||||||
2
.github/workflows/fast-forward.yml
vendored
2
.github/workflows/fast-forward.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
uses: step-security/harden-runner@v2
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|||||||
10
.github/workflows/ingest_benchmark.yml
vendored
10
.github/workflows/ingest_benchmark.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
fail-fast: false # allow other variants to continue even if one fails
|
fail-fast: false # allow other variants to continue even if one fails
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- target_project: new_empty_project_stripe_size_2048
|
- target_project: new_empty_project_stripe_size_2048
|
||||||
stripe_size: 2048 # 16 MiB
|
stripe_size: 2048 # 16 MiB
|
||||||
postgres_version: 16
|
postgres_version: 16
|
||||||
disable_sharding: false
|
disable_sharding: false
|
||||||
@@ -98,7 +98,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Create Neon Project
|
- name: Create Neon Project
|
||||||
if: ${{ startsWith(matrix.target_project, 'new_empty_project') }}
|
if: ${{ startsWith(matrix.target_project, 'new_empty_project') }}
|
||||||
@@ -110,10 +110,10 @@ jobs:
|
|||||||
compute_units: '[7, 7]' # we want to test large compute here to avoid compute-side bottleneck
|
compute_units: '[7, 7]' # we want to test large compute here to avoid compute-side bottleneck
|
||||||
api_key: ${{ secrets.NEON_STAGING_API_KEY }}
|
api_key: ${{ secrets.NEON_STAGING_API_KEY }}
|
||||||
shard_split_project: ${{ matrix.stripe_size != null && 'true' || 'false' }}
|
shard_split_project: ${{ matrix.stripe_size != null && 'true' || 'false' }}
|
||||||
admin_api_key: ${{ secrets.NEON_STAGING_ADMIN_API_KEY }}
|
admin_api_key: ${{ secrets.NEON_STAGING_ADMIN_API_KEY }}
|
||||||
shard_count: 8
|
shard_count: 8
|
||||||
stripe_size: ${{ matrix.stripe_size }}
|
stripe_size: ${{ matrix.stripe_size }}
|
||||||
disable_sharding: ${{ matrix.disable_sharding }}
|
disable_sharding: ${{ matrix.disable_sharding }}
|
||||||
|
|
||||||
- name: Initialize Neon project
|
- name: Initialize Neon project
|
||||||
if: ${{ startsWith(matrix.target_project, 'new_empty_project') }}
|
if: ${{ startsWith(matrix.target_project, 'new_empty_project') }}
|
||||||
@@ -171,7 +171,7 @@ jobs:
|
|||||||
extra_params: -s -m remote_cluster --timeout 86400 -k test_ingest_performance_using_pgcopydb
|
extra_params: -s -m remote_cluster --timeout 86400 -k test_ingest_performance_using_pgcopydb
|
||||||
pg_version: v${{ matrix.postgres_version }}
|
pg_version: v${{ matrix.postgres_version }}
|
||||||
save_perf_report: true
|
save_perf_report: true
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_INGEST_SOURCE_CONNSTR: ${{ secrets.BENCHMARK_INGEST_SOURCE_CONNSTR }}
|
BENCHMARK_INGEST_SOURCE_CONNSTR: ${{ secrets.BENCHMARK_INGEST_SOURCE_CONNSTR }}
|
||||||
TARGET_PROJECT_TYPE: ${{ matrix.target_project }}
|
TARGET_PROJECT_TYPE: ${{ matrix.target_project }}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
uses: step-security/harden-runner@v2
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
uses: step-security/harden-runner@v2
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|||||||
29
.github/workflows/large_oltp_benchmark.yml
vendored
29
.github/workflows/large_oltp_benchmark.yml
vendored
@@ -33,17 +33,25 @@ jobs:
|
|||||||
fail-fast: false # allow other variants to continue even if one fails
|
fail-fast: false # allow other variants to continue even if one fails
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- target: new_branch
|
# test only read-only custom scripts in new branch without database maintenance
|
||||||
|
- target: new_branch
|
||||||
|
custom_scripts: select_any_webhook_with_skew.sql@300 select_recent_webhook.sql@397 select_prefetch_webhook.sql@3
|
||||||
|
test_maintenance: false
|
||||||
|
# test all custom scripts in new branch with database maintenance
|
||||||
|
- target: new_branch
|
||||||
custom_scripts: insert_webhooks.sql@200 select_any_webhook_with_skew.sql@300 select_recent_webhook.sql@397 select_prefetch_webhook.sql@3 IUD_one_transaction.sql@100
|
custom_scripts: insert_webhooks.sql@200 select_any_webhook_with_skew.sql@300 select_recent_webhook.sql@397 select_prefetch_webhook.sql@3 IUD_one_transaction.sql@100
|
||||||
- target: reuse_branch
|
test_maintenance: true
|
||||||
|
# test all custom scripts in reuse branch with database maintenance
|
||||||
|
- target: reuse_branch
|
||||||
custom_scripts: insert_webhooks.sql@200 select_any_webhook_with_skew.sql@300 select_recent_webhook.sql@397 select_prefetch_webhook.sql@3 IUD_one_transaction.sql@100
|
custom_scripts: insert_webhooks.sql@200 select_any_webhook_with_skew.sql@300 select_recent_webhook.sql@397 select_prefetch_webhook.sql@3 IUD_one_transaction.sql@100
|
||||||
max-parallel: 1 # we want to run each stripe size sequentially to be able to compare the results
|
test_maintenance: true
|
||||||
|
max-parallel: 1 # we want to run each benchmark sequentially to not have noisy neighbors on shared storage (PS, SK)
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
statuses: write
|
statuses: write
|
||||||
id-token: write # aws-actions/configure-aws-credentials
|
id-token: write # aws-actions/configure-aws-credentials
|
||||||
env:
|
env:
|
||||||
TEST_PG_BENCH_DURATIONS_MATRIX: "1h" # todo update to > 1 h
|
TEST_PG_BENCH_DURATIONS_MATRIX: "1h" # todo update to > 1 h
|
||||||
TEST_PGBENCH_CUSTOM_SCRIPTS: ${{ matrix.custom_scripts }}
|
TEST_PGBENCH_CUSTOM_SCRIPTS: ${{ matrix.custom_scripts }}
|
||||||
POSTGRES_DISTRIB_DIR: /tmp/neon/pg_install
|
POSTGRES_DISTRIB_DIR: /tmp/neon/pg_install
|
||||||
PG_VERSION: 16 # pre-determined by pre-determined project
|
PG_VERSION: 16 # pre-determined by pre-determined project
|
||||||
@@ -85,7 +93,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Create Neon Branch for large tenant
|
- name: Create Neon Branch for large tenant
|
||||||
if: ${{ matrix.target == 'new_branch' }}
|
if: ${{ matrix.target == 'new_branch' }}
|
||||||
@@ -129,7 +137,7 @@ jobs:
|
|||||||
${PSQL} "${BENCHMARK_CONNSTR}" -c "SET statement_timeout = 0; DELETE FROM webhook.incoming_webhooks WHERE created_at > '2025-02-27 23:59:59+00';"
|
${PSQL} "${BENCHMARK_CONNSTR}" -c "SET statement_timeout = 0; DELETE FROM webhook.incoming_webhooks WHERE created_at > '2025-02-27 23:59:59+00';"
|
||||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - Finished deleting rows in table webhook.incoming_webhooks from prior runs"
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - Finished deleting rows in table webhook.incoming_webhooks from prior runs"
|
||||||
|
|
||||||
- name: Benchmark pgbench with custom-scripts
|
- name: Benchmark pgbench with custom-scripts
|
||||||
uses: ./.github/actions/run-python-test-set
|
uses: ./.github/actions/run-python-test-set
|
||||||
with:
|
with:
|
||||||
build_type: ${{ env.BUILD_TYPE }}
|
build_type: ${{ env.BUILD_TYPE }}
|
||||||
@@ -138,13 +146,14 @@ jobs:
|
|||||||
save_perf_report: true
|
save_perf_report: true
|
||||||
extra_params: -m remote_cluster --timeout 7200 -k test_perf_oltp_large_tenant_pgbench
|
extra_params: -m remote_cluster --timeout 7200 -k test_perf_oltp_large_tenant_pgbench
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
|
|
||||||
- name: Benchmark database maintenance
|
- name: Benchmark database maintenance
|
||||||
|
if: ${{ matrix.test_maintenance }}
|
||||||
uses: ./.github/actions/run-python-test-set
|
uses: ./.github/actions/run-python-test-set
|
||||||
with:
|
with:
|
||||||
build_type: ${{ env.BUILD_TYPE }}
|
build_type: ${{ env.BUILD_TYPE }}
|
||||||
@@ -153,7 +162,7 @@ jobs:
|
|||||||
save_perf_report: true
|
save_perf_report: true
|
||||||
extra_params: -m remote_cluster --timeout 172800 -k test_perf_oltp_large_tenant_maintenance
|
extra_params: -m remote_cluster --timeout 172800 -k test_perf_oltp_large_tenant_maintenance
|
||||||
pg_version: ${{ env.PG_VERSION }}
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr_without_pooler }}
|
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr_without_pooler }}
|
||||||
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
@@ -179,8 +188,8 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||||
|
|||||||
175
.github/workflows/large_oltp_growth.yml
vendored
Normal file
175
.github/workflows/large_oltp_growth.yml
vendored
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
name: large oltp growth
|
||||||
|
# workflow to grow the reuse branch of large oltp benchmark continuously (about 16 GB per run)
|
||||||
|
|
||||||
|
on:
|
||||||
|
# uncomment to run on push for debugging your PR
|
||||||
|
# push:
|
||||||
|
# branches: [ bodobolero/increase_large_oltp_workload ]
|
||||||
|
|
||||||
|
schedule:
|
||||||
|
# * is a special character in YAML so you have to quote this string
|
||||||
|
# ┌───────────── minute (0 - 59)
|
||||||
|
# │ ┌───────────── hour (0 - 23)
|
||||||
|
# │ │ ┌───────────── day of the month (1 - 31)
|
||||||
|
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||||
|
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||||
|
- cron: '0 6 * * *' # 06:00 UTC
|
||||||
|
- cron: '0 8 * * *' # 08:00 UTC
|
||||||
|
- cron: '0 10 * * *' # 10:00 UTC
|
||||||
|
- cron: '0 12 * * *' # 12:00 UTC
|
||||||
|
- cron: '0 14 * * *' # 14:00 UTC
|
||||||
|
- cron: '0 16 * * *' # 16:00 UTC
|
||||||
|
workflow_dispatch: # adds ability to run this manually
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
# Allow only one workflow globally because we need dedicated resources which only exist once
|
||||||
|
group: large-oltp-growth
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
oltp:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false # allow other variants to continue even if one fails
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# for now only grow the reuse branch, not the other branches.
|
||||||
|
- target: reuse_branch
|
||||||
|
custom_scripts:
|
||||||
|
- grow_action_blocks.sql
|
||||||
|
- grow_action_kwargs.sql
|
||||||
|
- grow_device_fingerprint_event.sql
|
||||||
|
- grow_edges.sql
|
||||||
|
- grow_hotel_rate_mapping.sql
|
||||||
|
- grow_ocr_pipeline_results_version.sql
|
||||||
|
- grow_priceline_raw_response.sql
|
||||||
|
- grow_relabled_transactions.sql
|
||||||
|
- grow_state_values.sql
|
||||||
|
- grow_values.sql
|
||||||
|
- grow_vertices.sql
|
||||||
|
- update_accounting_coding_body_tracking_category_selection.sql
|
||||||
|
- update_action_blocks.sql
|
||||||
|
- update_action_kwargs.sql
|
||||||
|
- update_denormalized_approval_workflow.sql
|
||||||
|
- update_device_fingerprint_event.sql
|
||||||
|
- update_edges.sql
|
||||||
|
- update_heron_transaction_enriched_log.sql
|
||||||
|
- update_heron_transaction_enrichment_requests.sql
|
||||||
|
- update_hotel_rate_mapping.sql
|
||||||
|
- update_incoming_webhooks.sql
|
||||||
|
- update_manual_transaction.sql
|
||||||
|
- update_ml_receipt_matching_log.sql
|
||||||
|
- update_ocr_pipeine_results_version.sql
|
||||||
|
- update_orc_pipeline_step_results.sql
|
||||||
|
- update_orc_pipeline_step_results_version.sql
|
||||||
|
- update_priceline_raw_response.sql
|
||||||
|
- update_quickbooks_transactions.sql
|
||||||
|
- update_raw_finicity_transaction.sql
|
||||||
|
- update_relabeled_transactions.sql
|
||||||
|
- update_state_values.sql
|
||||||
|
- update_stripe_authorization_event_log.sql
|
||||||
|
- update_transaction.sql
|
||||||
|
- update_values.sql
|
||||||
|
- update_vertices.sql
|
||||||
|
max-parallel: 1 # we want to run each growth workload sequentially (for now there is just one)
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
statuses: write
|
||||||
|
id-token: write # aws-actions/configure-aws-credentials
|
||||||
|
env:
|
||||||
|
TEST_PG_BENCH_DURATIONS_MATRIX: "1h"
|
||||||
|
TEST_PGBENCH_CUSTOM_SCRIPTS: ${{ join(matrix.custom_scripts, ' ') }}
|
||||||
|
POSTGRES_DISTRIB_DIR: /tmp/neon/pg_install
|
||||||
|
PG_VERSION: 16 # pre-determined by pre-determined project
|
||||||
|
TEST_OUTPUT: /tmp/test_output
|
||||||
|
BUILD_TYPE: remote
|
||||||
|
PLATFORM: ${{ matrix.target }}
|
||||||
|
|
||||||
|
runs-on: [ self-hosted, us-east-2, x64 ]
|
||||||
|
container:
|
||||||
|
image: ghcr.io/neondatabase/build-tools:pinned-bookworm
|
||||||
|
credentials:
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
options: --init
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
|
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Configure AWS credentials # necessary to download artefacts
|
||||||
|
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||||
|
with:
|
||||||
|
aws-region: eu-central-1
|
||||||
|
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
role-duration-seconds: 18000 # 5 hours is currently max associated with IAM role
|
||||||
|
|
||||||
|
- name: Download Neon artifact
|
||||||
|
uses: ./.github/actions/download
|
||||||
|
with:
|
||||||
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
|
path: /tmp/neon/
|
||||||
|
prefix: latest
|
||||||
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
|
- name: Set up Connection String
|
||||||
|
id: set-up-connstr
|
||||||
|
run: |
|
||||||
|
case "${{ matrix.target }}" in
|
||||||
|
reuse_branch)
|
||||||
|
CONNSTR=${{ secrets.BENCHMARK_LARGE_OLTP_REUSE_CONNSTR }}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo >&2 "Unknown target=${{ matrix.target }}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CONNSTR_WITHOUT_POOLER="${CONNSTR//-pooler/}"
|
||||||
|
|
||||||
|
echo "connstr=${CONNSTR}" >> $GITHUB_OUTPUT
|
||||||
|
echo "connstr_without_pooler=${CONNSTR_WITHOUT_POOLER}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: pgbench with custom-scripts
|
||||||
|
uses: ./.github/actions/run-python-test-set
|
||||||
|
with:
|
||||||
|
build_type: ${{ env.BUILD_TYPE }}
|
||||||
|
test_selection: performance
|
||||||
|
run_in_parallel: false
|
||||||
|
save_perf_report: true
|
||||||
|
extra_params: -m remote_cluster --timeout 7200 -k test_perf_oltp_large_tenant_growth
|
||||||
|
pg_version: ${{ env.PG_VERSION }}
|
||||||
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
env:
|
||||||
|
BENCHMARK_CONNSTR: ${{ steps.set-up-connstr.outputs.connstr }}
|
||||||
|
VIP_VAP_ACCESS_TOKEN: "${{ secrets.VIP_VAP_ACCESS_TOKEN }}"
|
||||||
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
|
|
||||||
|
- name: Create Allure report
|
||||||
|
id: create-allure-report
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
uses: ./.github/actions/allure-report-generate
|
||||||
|
with:
|
||||||
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
|
- name: Post to a Slack channel
|
||||||
|
if: ${{ github.event.schedule && failure() }}
|
||||||
|
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||||
|
with:
|
||||||
|
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||||
|
slack-message: |
|
||||||
|
Periodic large oltp tenant growth increase: ${{ job.status }}
|
||||||
|
<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Run>
|
||||||
|
<${{ steps.create-allure-report.outputs.report-url }}|Allure report>
|
||||||
|
env:
|
||||||
|
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||||
8
.github/workflows/neon_extra_builds.yml
vendored
8
.github/workflows/neon_extra_builds.yml
vendored
@@ -63,16 +63,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Filter out only v-string for build matrix
|
- name: Filter out only v-string for build matrix
|
||||||
id: postgres_changes
|
id: postgres_changes
|
||||||
|
env:
|
||||||
|
CHANGES: ${{ steps.files_changed.outputs.changes }}
|
||||||
run: |
|
run: |
|
||||||
v_strings_only_as_json_array=$(echo ${{ steps.files_changed.outputs.chnages }} | jq '.[]|select(test("v\\d+"))' | jq --slurp -c)
|
v_strings_only_as_json_array=$(echo ${CHANGES} | jq '.[]|select(test("v\\d+"))' | jq --slurp -c)
|
||||||
echo "changes=${v_strings_only_as_json_array}" | tee -a "${GITHUB_OUTPUT}"
|
echo "changes=${v_strings_only_as_json_array}" | tee -a "${GITHUB_OUTPUT}"
|
||||||
|
|
||||||
check-macos-build:
|
check-macos-build:
|
||||||
needs: [ check-permissions, files-changed ]
|
needs: [ check-permissions, files-changed ]
|
||||||
if: |
|
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-extra-build-macos') ||
|
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-extra-build-*') ||
|
|
||||||
github.ref_name == 'main'
|
|
||||||
uses: ./.github/workflows/build-macos.yml
|
uses: ./.github/workflows/build-macos.yml
|
||||||
with:
|
with:
|
||||||
pg_versions: ${{ needs.files-changed.outputs.postgres_changes }}
|
pg_versions: ${{ needs.files-changed.outputs.postgres_changes }}
|
||||||
|
|||||||
283
.github/workflows/periodic_pagebench.yml
vendored
283
.github/workflows/periodic_pagebench.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Periodic pagebench performance test on dedicated EC2 machine in eu-central-1 region
|
name: Periodic pagebench performance test on unit-perf hetzner runner
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
@@ -8,7 +8,7 @@ on:
|
|||||||
# │ │ ┌───────────── day of the month (1 - 31)
|
# │ │ ┌───────────── day of the month (1 - 31)
|
||||||
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||||
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||||
- cron: '0 */3 * * *' # Runs every 3 hours
|
- cron: '0 */4 * * *' # Runs every 4 hours
|
||||||
workflow_dispatch: # Allows manual triggering of the workflow
|
workflow_dispatch: # Allows manual triggering of the workflow
|
||||||
inputs:
|
inputs:
|
||||||
commit_hash:
|
commit_hash:
|
||||||
@@ -16,6 +16,11 @@ on:
|
|||||||
description: 'The long neon repo commit hash for the system under test (pageserver) to be tested.'
|
description: 'The long neon repo commit hash for the system under test (pageserver) to be tested.'
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
|
recreate_snapshots:
|
||||||
|
type: boolean
|
||||||
|
description: 'Recreate snapshots - !!!WARNING!!! We should only recreate snapshots if the previous ones are no longer compatible. Otherwise benchmarking results are not comparable across runs.'
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -29,13 +34,13 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
trigger_bench_on_ec2_machine_in_eu_central_1:
|
run_periodic_pagebench_test:
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # aws-actions/configure-aws-credentials
|
id-token: write # aws-actions/configure-aws-credentials
|
||||||
statuses: write
|
statuses: write
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: [ self-hosted, small ]
|
runs-on: [ self-hosted, unit-perf ]
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/neondatabase/build-tools:pinned-bookworm
|
image: ghcr.io/neondatabase/build-tools:pinned-bookworm
|
||||||
credentials:
|
credentials:
|
||||||
@@ -44,10 +49,13 @@ jobs:
|
|||||||
options: --init
|
options: --init
|
||||||
timeout-minutes: 360 # Set the timeout to 6 hours
|
timeout-minutes: 360 # Set the timeout to 6 hours
|
||||||
env:
|
env:
|
||||||
API_KEY: ${{ secrets.PERIODIC_PAGEBENCH_EC2_RUNNER_API_KEY }}
|
|
||||||
RUN_ID: ${{ github.run_id }}
|
RUN_ID: ${{ github.run_id }}
|
||||||
AWS_DEFAULT_REGION : "eu-central-1"
|
DEFAULT_PG_VERSION: 16
|
||||||
AWS_INSTANCE_ID : "i-02a59a3bf86bc7e74"
|
BUILD_TYPE: release
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
# NEON_ENV_BUILDER_USE_OVERLAYFS_FOR_SNAPSHOTS: 1 - doesn't work without root in container
|
||||||
|
S3_BUCKET: neon-github-public-dev
|
||||||
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PERF_TEST_RESULT_CONNSTR }}"
|
||||||
steps:
|
steps:
|
||||||
# we don't need the neon source code because we run everything remotely
|
# we don't need the neon source code because we run everything remotely
|
||||||
# however we still need the local github actions to run the allure step below
|
# however we still need the local github actions to run the allure step below
|
||||||
@@ -56,98 +64,193 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- name: Set up the environment which depends on $RUNNER_TEMP on nvme drive
|
||||||
|
id: set-env
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
run: |
|
||||||
|
{
|
||||||
|
echo "NEON_DIR=${RUNNER_TEMP}/neon"
|
||||||
|
echo "NEON_BIN=${RUNNER_TEMP}/neon/bin"
|
||||||
|
echo "POSTGRES_DISTRIB_DIR=${RUNNER_TEMP}/neon/pg_install"
|
||||||
|
echo "LD_LIBRARY_PATH=${RUNNER_TEMP}/neon/pg_install/v${DEFAULT_PG_VERSION}/lib"
|
||||||
|
echo "BACKUP_DIR=${RUNNER_TEMP}/instance_store/saved_snapshots"
|
||||||
|
echo "TEST_OUTPUT=${RUNNER_TEMP}/neon/test_output"
|
||||||
|
echo "PERF_REPORT_DIR=${RUNNER_TEMP}/neon/test_output/perf-report-local"
|
||||||
|
echo "ALLURE_DIR=${RUNNER_TEMP}/neon/test_output/allure-results"
|
||||||
|
echo "ALLURE_RESULTS_DIR=${RUNNER_TEMP}/neon/test_output/allure-results/results"
|
||||||
|
} >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Show my own (github runner) external IP address - usefull for IP allowlisting
|
echo "allure_results_dir=${RUNNER_TEMP}/neon/test_output/allure-results/results" >> "$GITHUB_OUTPUT"
|
||||||
run: curl https://ifconfig.me
|
|
||||||
|
|
||||||
- name: Assume AWS OIDC role that allows to manage (start/stop/describe... EC machine)
|
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
|
||||||
with:
|
with:
|
||||||
aws-region: eu-central-1
|
aws-region: eu-central-1
|
||||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_MANAGE_BENCHMARK_EC2_VMS_ARN }}
|
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
role-duration-seconds: 3600
|
role-duration-seconds: 18000 # max 5 hours (needed in case commit hash is still being built)
|
||||||
|
|
||||||
- name: Start EC2 instance and wait for the instance to boot up
|
|
||||||
run: |
|
|
||||||
aws ec2 start-instances --instance-ids $AWS_INSTANCE_ID
|
|
||||||
aws ec2 wait instance-running --instance-ids $AWS_INSTANCE_ID
|
|
||||||
sleep 60 # sleep some time to allow cloudinit and our API server to start up
|
|
||||||
|
|
||||||
- name: Determine public IP of the EC2 instance and set env variable EC2_MACHINE_URL_US
|
|
||||||
run: |
|
|
||||||
public_ip=$(aws ec2 describe-instances --instance-ids $AWS_INSTANCE_ID --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
|
|
||||||
echo "Public IP of the EC2 instance: $public_ip"
|
|
||||||
echo "EC2_MACHINE_URL_US=https://${public_ip}:8443" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Determine commit hash
|
- name: Determine commit hash
|
||||||
|
id: commit_hash
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
env:
|
env:
|
||||||
INPUT_COMMIT_HASH: ${{ github.event.inputs.commit_hash }}
|
INPUT_COMMIT_HASH: ${{ github.event.inputs.commit_hash }}
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$INPUT_COMMIT_HASH" ]; then
|
if [[ -z "${INPUT_COMMIT_HASH}" ]]; then
|
||||||
echo "COMMIT_HASH=$(curl -s https://api.github.com/repos/neondatabase/neon/commits/main | jq -r '.sha')" >> $GITHUB_ENV
|
COMMIT_HASH=$(curl -s https://api.github.com/repos/neondatabase/neon/commits/main | jq -r '.sha')
|
||||||
|
echo "COMMIT_HASH=$COMMIT_HASH" >> $GITHUB_ENV
|
||||||
|
echo "commit_hash=$COMMIT_HASH" >> "$GITHUB_OUTPUT"
|
||||||
echo "COMMIT_HASH_TYPE=latest" >> $GITHUB_ENV
|
echo "COMMIT_HASH_TYPE=latest" >> $GITHUB_ENV
|
||||||
else
|
else
|
||||||
echo "COMMIT_HASH=$INPUT_COMMIT_HASH" >> $GITHUB_ENV
|
COMMIT_HASH="${INPUT_COMMIT_HASH}"
|
||||||
|
echo "COMMIT_HASH=$COMMIT_HASH" >> $GITHUB_ENV
|
||||||
|
echo "commit_hash=$COMMIT_HASH" >> "$GITHUB_OUTPUT"
|
||||||
echo "COMMIT_HASH_TYPE=manual" >> $GITHUB_ENV
|
echo "COMMIT_HASH_TYPE=manual" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
|
- name: Checkout the neon repository at given commit hash
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
with:
|
||||||
|
ref: ${{ steps.commit_hash.outputs.commit_hash }}
|
||||||
|
|
||||||
- name: Start Bench with run_id
|
# does not reuse ./.github/actions/download because we need to download the artifact for the given commit hash
|
||||||
|
# example artifact
|
||||||
|
# s3://neon-github-public-dev/artifacts/48b870bc078bd2c450eb7b468e743b9c118549bf/15036827400/1/neon-Linux-X64-release-artifact.tar.zst /instance_store/artifacts/neon-Linux-release-artifact.tar.zst
|
||||||
|
- name: Determine artifact S3_KEY for given commit hash and download and extract artifact
|
||||||
|
id: artifact_prefix
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
env:
|
||||||
|
ARCHIVE: ${{ runner.temp }}/downloads/neon-${{ runner.os }}-${{ runner.arch }}-release-artifact.tar.zst
|
||||||
|
COMMIT_HASH: ${{ env.COMMIT_HASH }}
|
||||||
|
COMMIT_HASH_TYPE: ${{ env.COMMIT_HASH_TYPE }}
|
||||||
run: |
|
run: |
|
||||||
curl -k -X 'POST' \
|
attempt=0
|
||||||
"${EC2_MACHINE_URL_US}/start_test/${GITHUB_RUN_ID}" \
|
max_attempts=24 # 5 minutes * 24 = 2 hours
|
||||||
-H 'accept: application/json' \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-H "Authorization: Bearer $API_KEY" \
|
|
||||||
-d "{\"neonRepoCommitHash\": \"${COMMIT_HASH}\", \"neonRepoCommitHashType\": \"${COMMIT_HASH_TYPE}\"}"
|
|
||||||
|
|
||||||
- name: Poll Test Status
|
while [[ $attempt -lt $max_attempts ]]; do
|
||||||
id: poll_step
|
# the following command will fail until the artifacts are available ...
|
||||||
run: |
|
S3_KEY=$(aws s3api list-objects-v2 --bucket "$S3_BUCKET" --prefix "artifacts/$COMMIT_HASH/" \
|
||||||
status=""
|
| jq -r '.Contents[]?.Key' \
|
||||||
while [[ "$status" != "failure" && "$status" != "success" ]]; do
|
| grep "neon-${{ runner.os }}-${{ runner.arch }}-release-artifact.tar.zst" \
|
||||||
response=$(curl -k -X 'GET' \
|
| sort --version-sort \
|
||||||
"${EC2_MACHINE_URL_US}/test_status/${GITHUB_RUN_ID}" \
|
| tail -1) || true # ... thus ignore errors from the command
|
||||||
-H 'accept: application/json' \
|
if [[ -n "${S3_KEY}" ]]; then
|
||||||
-H "Authorization: Bearer $API_KEY")
|
echo "Artifact found: $S3_KEY"
|
||||||
echo "Response: $response"
|
echo "S3_KEY=$S3_KEY" >> $GITHUB_ENV
|
||||||
set +x
|
|
||||||
status=$(echo $response | jq -r '.status')
|
|
||||||
echo "Test status: $status"
|
|
||||||
if [[ "$status" == "failure" ]]; then
|
|
||||||
echo "Test failed"
|
|
||||||
exit 1 # Fail the job step if status is failure
|
|
||||||
elif [[ "$status" == "success" || "$status" == "null" ]]; then
|
|
||||||
break
|
break
|
||||||
elif [[ "$status" == "too_many_runs" ]]; then
|
|
||||||
echo "Too many runs already running"
|
|
||||||
echo "too_many_runs=true" >> "$GITHUB_OUTPUT"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sleep 60 # Poll every 60 seconds
|
# Increment attempt counter and sleep for 5 minutes
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
echo "Attempt $attempt of $max_attempts to find artifacts in S3 bucket s3://$S3_BUCKET/artifacts/$COMMIT_HASH failed. Retrying in 5 minutes..."
|
||||||
|
sleep 300 # Sleep for 5 minutes
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Retrieve Test Logs
|
if [[ -z "${S3_KEY}" ]]; then
|
||||||
if: always() && steps.poll_step.outputs.too_many_runs != 'true'
|
echo "Error: artifact not found in S3 bucket s3://$S3_BUCKET/artifacts/$COMMIT_HASH" after 2 hours
|
||||||
run: |
|
else
|
||||||
curl -k -X 'GET' \
|
mkdir -p $(dirname $ARCHIVE)
|
||||||
"${EC2_MACHINE_URL_US}/test_log/${GITHUB_RUN_ID}" \
|
time aws s3 cp --only-show-errors s3://$S3_BUCKET/${S3_KEY} ${ARCHIVE}
|
||||||
-H 'accept: application/gzip' \
|
mkdir -p ${NEON_DIR}
|
||||||
-H "Authorization: Bearer $API_KEY" \
|
time tar -xf ${ARCHIVE} -C ${NEON_DIR}
|
||||||
--output "test_log_${GITHUB_RUN_ID}.gz"
|
rm -f ${ARCHIVE}
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Unzip Test Log and Print it into this job's log
|
- name: Download snapshots from S3
|
||||||
if: always() && steps.poll_step.outputs.too_many_runs != 'true'
|
if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.recreate_snapshots == 'false' || github.event.inputs.recreate_snapshots == '' }}
|
||||||
|
id: download_snapshots
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
run: |
|
run: |
|
||||||
gzip -d "test_log_${GITHUB_RUN_ID}.gz"
|
# Download the snapshots from S3
|
||||||
cat "test_log_${GITHUB_RUN_ID}"
|
mkdir -p ${TEST_OUTPUT}
|
||||||
|
mkdir -p $BACKUP_DIR
|
||||||
|
cd $BACKUP_DIR
|
||||||
|
mkdir parts
|
||||||
|
cd parts
|
||||||
|
PART=$(aws s3api list-objects-v2 --bucket $S3_BUCKET --prefix performance/pagebench/ \
|
||||||
|
| jq -r '.Contents[]?.Key' \
|
||||||
|
| grep -E 'shared-snapshots-[0-9]{4}-[0-9]{2}-[0-9]{2}' \
|
||||||
|
| sort \
|
||||||
|
| tail -1)
|
||||||
|
echo "Latest PART: $PART"
|
||||||
|
if [[ -z "$PART" ]]; then
|
||||||
|
echo "ERROR: No matching S3 key found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
S3_KEY=$(dirname $PART)
|
||||||
|
time aws s3 cp --only-show-errors --recursive s3://${S3_BUCKET}/$S3_KEY/ .
|
||||||
|
cd $TEST_OUTPUT
|
||||||
|
time cat $BACKUP_DIR/parts/* | zstdcat | tar --extract --preserve-permissions
|
||||||
|
rm -rf ${BACKUP_DIR}
|
||||||
|
|
||||||
|
- name: Cache poetry deps
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pypoetry/virtualenvs
|
||||||
|
key: v2-${{ runner.os }}-${{ runner.arch }}-python-deps-bookworm-${{ hashFiles('poetry.lock') }}
|
||||||
|
|
||||||
|
- name: Install Python deps
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
run: ./scripts/pysync
|
||||||
|
|
||||||
|
# we need high number of open files for pagebench
|
||||||
|
- name: show ulimits
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
run: |
|
||||||
|
ulimit -a
|
||||||
|
|
||||||
|
- name: Run pagebench testcase
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
env:
|
||||||
|
CI: false # need to override this env variable set by github to enforce using snapshots
|
||||||
|
run: |
|
||||||
|
export PLATFORM=hetzner-unit-perf-${COMMIT_HASH_TYPE}
|
||||||
|
# report the commit hash of the neon repository in the revision of the test results
|
||||||
|
export GITHUB_SHA=${COMMIT_HASH}
|
||||||
|
rm -rf ${PERF_REPORT_DIR}
|
||||||
|
rm -rf ${ALLURE_RESULTS_DIR}
|
||||||
|
mkdir -p ${PERF_REPORT_DIR}
|
||||||
|
mkdir -p ${ALLURE_RESULTS_DIR}
|
||||||
|
PARAMS="--alluredir=${ALLURE_RESULTS_DIR} --tb=short --verbose -rA"
|
||||||
|
EXTRA_PARAMS="--out-dir ${PERF_REPORT_DIR} --durations-path $TEST_OUTPUT/benchmark_durations.json"
|
||||||
|
# run only two selected tests
|
||||||
|
# environment set by parent:
|
||||||
|
# RUST_BACKTRACE=1 DEFAULT_PG_VERSION=16 BUILD_TYPE=release
|
||||||
|
./scripts/pytest ${PARAMS} test_runner/performance/pageserver/pagebench/test_pageserver_max_throughput_getpage_at_latest_lsn.py::test_pageserver_characterize_throughput_with_n_tenants ${EXTRA_PARAMS}
|
||||||
|
./scripts/pytest ${PARAMS} test_runner/performance/pageserver/pagebench/test_pageserver_max_throughput_getpage_at_latest_lsn.py::test_pageserver_characterize_latencies_with_1_client_and_throughput_with_many_clients_one_tenant ${EXTRA_PARAMS}
|
||||||
|
|
||||||
|
- name: upload the performance metrics to the Neon performance database which is used by grafana dashboards to display the results
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
run: |
|
||||||
|
export REPORT_FROM="$PERF_REPORT_DIR"
|
||||||
|
export GITHUB_SHA=${COMMIT_HASH}
|
||||||
|
time ./scripts/generate_and_push_perf_report.sh
|
||||||
|
|
||||||
|
- name: Upload test results
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
uses: ./.github/actions/allure-report-store
|
||||||
|
with:
|
||||||
|
report-dir: ${{ steps.set-env.outputs.allure_results_dir }}
|
||||||
|
unique-key: ${{ env.BUILD_TYPE }}-${{ env.DEFAULT_PG_VERSION }}-${{ runner.arch }}
|
||||||
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Create Allure report
|
- name: Create Allure report
|
||||||
|
id: create-allure-report
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
|
- name: Upload snapshots
|
||||||
|
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.recreate_snapshots != 'false' && github.event.inputs.recreate_snapshots != '' }}
|
||||||
|
id: upload_snapshots
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
run: |
|
||||||
|
mkdir -p $BACKUP_DIR
|
||||||
|
cd $TEST_OUTPUT
|
||||||
|
tar --create --preserve-permissions --file - shared-snapshots | zstd -o $BACKUP_DIR/shared_snapshots.tar.zst
|
||||||
|
cd $BACKUP_DIR
|
||||||
|
mkdir parts
|
||||||
|
split -b 1G shared_snapshots.tar.zst ./parts/shared_snapshots.tar.zst.part.
|
||||||
|
SNAPSHOT_DATE=$(date +%F) # YYYY-MM-DD
|
||||||
|
cd parts
|
||||||
|
time aws s3 cp --recursive . s3://${S3_BUCKET}/performance/pagebench/shared-snapshots-${SNAPSHOT_DATE}/
|
||||||
|
|
||||||
- name: Post to a Slack channel
|
- name: Post to a Slack channel
|
||||||
if: ${{ github.event.schedule && failure() }}
|
if: ${{ github.event.schedule && failure() }}
|
||||||
@@ -157,26 +260,22 @@ jobs:
|
|||||||
slack-message: "Periodic pagebench testing on dedicated hardware: ${{ job.status }}\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
slack-message: "Periodic pagebench testing on dedicated hardware: ${{ job.status }}\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
env:
|
env:
|
||||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||||
|
|
||||||
- name: Cleanup Test Resources
|
- name: Cleanup Test Resources
|
||||||
if: always()
|
if: always()
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
env:
|
||||||
|
ARCHIVE: ${{ runner.temp }}/downloads/neon-${{ runner.os }}-${{ runner.arch }}-release-artifact.tar.zst
|
||||||
run: |
|
run: |
|
||||||
curl -k -X 'POST' \
|
# Cleanup the test resources
|
||||||
"${EC2_MACHINE_URL_US}/cleanup_test/${GITHUB_RUN_ID}" \
|
if [[ -d "${BACKUP_DIR}" ]]; then
|
||||||
-H 'accept: application/json' \
|
rm -rf ${BACKUP_DIR}
|
||||||
-H "Authorization: Bearer $API_KEY" \
|
fi
|
||||||
-d ''
|
if [[ -d "${TEST_OUTPUT}" ]]; then
|
||||||
|
rm -rf ${TEST_OUTPUT}
|
||||||
|
fi
|
||||||
|
if [[ -d "${NEON_DIR}" ]]; then
|
||||||
|
rm -rf ${NEON_DIR}
|
||||||
|
fi
|
||||||
|
rm -rf $(dirname $ARCHIVE)
|
||||||
|
|
||||||
- name: Assume AWS OIDC role that allows to manage (start/stop/describe... EC machine)
|
|
||||||
if: always() && steps.poll_step.outputs.too_many_runs != 'true'
|
|
||||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
|
||||||
with:
|
|
||||||
aws-region: eu-central-1
|
|
||||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_MANAGE_BENCHMARK_EC2_VMS_ARN }}
|
|
||||||
role-duration-seconds: 3600
|
|
||||||
|
|
||||||
- name: Stop EC2 instance and wait for the instance to be stopped
|
|
||||||
if: always() && steps.poll_step.outputs.too_many_runs != 'true'
|
|
||||||
run: |
|
|
||||||
aws ec2 stop-instances --instance-ids $AWS_INSTANCE_ID
|
|
||||||
aws ec2 wait instance-stopped --instance-ids $AWS_INSTANCE_ID
|
|
||||||
|
|||||||
12
.github/workflows/pg-clients.yml
vendored
12
.github/workflows/pg-clients.yml
vendored
@@ -103,7 +103,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Create Neon Project
|
- name: Create Neon Project
|
||||||
id: create-neon-project
|
id: create-neon-project
|
||||||
@@ -122,7 +122,7 @@ jobs:
|
|||||||
run_in_parallel: false
|
run_in_parallel: false
|
||||||
extra_params: -m remote_cluster
|
extra_params: -m remote_cluster
|
||||||
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.create-neon-project.outputs.dsn }}
|
BENCHMARK_CONNSTR: ${{ steps.create-neon-project.outputs.dsn }}
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ jobs:
|
|||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
store-test-results-into-db: true
|
store-test-results-into-db: true
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Create Neon Project
|
- name: Create Neon Project
|
||||||
id: create-neon-project
|
id: create-neon-project
|
||||||
@@ -195,7 +195,7 @@ jobs:
|
|||||||
run_in_parallel: false
|
run_in_parallel: false
|
||||||
extra_params: -m remote_cluster
|
extra_params: -m remote_cluster
|
||||||
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
pg_version: ${{ env.DEFAULT_PG_VERSION }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
BENCHMARK_CONNSTR: ${{ steps.create-neon-project.outputs.dsn }}
|
BENCHMARK_CONNSTR: ${{ steps.create-neon-project.outputs.dsn }}
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ jobs:
|
|||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
store-test-results-into-db: true
|
store-test-results-into-db: true
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/pin-build-tools-image.yml
vendored
2
.github/workflows/pin-build-tools-image.yml
vendored
@@ -41,7 +41,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
uses: step-security/harden-runner@v2
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/pre-merge-checks.yml
vendored
4
.github/workflows/pre-merge-checks.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1
|
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
|
||||||
id: python-src
|
id: python-src
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
poetry.lock
|
poetry.lock
|
||||||
pyproject.toml
|
pyproject.toml
|
||||||
|
|
||||||
- uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1
|
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
|
||||||
id: rust-src
|
id: rust-src
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
|
|||||||
84
.github/workflows/proxy-benchmark.yml
vendored
Normal file
84
.github/workflows/proxy-benchmark.yml
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
name: Periodic proxy performance test on unit-perf hetzner runner
|
||||||
|
|
||||||
|
on:
|
||||||
|
push: # TODO: remove after testing
|
||||||
|
branches:
|
||||||
|
- test-proxy-bench # Runs on pushes to branches starting with test-proxy-bench
|
||||||
|
# schedule:
|
||||||
|
# * is a special character in YAML so you have to quote this string
|
||||||
|
# ┌───────────── minute (0 - 59)
|
||||||
|
# │ ┌───────────── hour (0 - 23)
|
||||||
|
# │ │ ┌───────────── day of the month (1 - 31)
|
||||||
|
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||||
|
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||||
|
# - cron: '0 5 * * *' # Runs at 5 UTC once a day
|
||||||
|
workflow_dispatch: # adds an ability to run this manually
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash -euo pipefail {0}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run_periodic_proxybench_test:
|
||||||
|
permissions:
|
||||||
|
id-token: write # aws-actions/configure-aws-credentials
|
||||||
|
statuses: write
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
runs-on: [self-hosted, unit-perf]
|
||||||
|
timeout-minutes: 60 # 1h timeout
|
||||||
|
container:
|
||||||
|
image: ghcr.io/neondatabase/build-tools:pinned-bookworm
|
||||||
|
credentials:
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
options: --init
|
||||||
|
steps:
|
||||||
|
- name: Checkout proxy-bench Repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: neondatabase/proxy-bench
|
||||||
|
path: proxy-bench
|
||||||
|
|
||||||
|
- name: Set up the environment which depends on $RUNNER_TEMP on nvme drive
|
||||||
|
id: set-env
|
||||||
|
shell: bash -euxo pipefail {0}
|
||||||
|
run: |
|
||||||
|
PROXY_BENCH_PATH=$(realpath ./proxy-bench)
|
||||||
|
{
|
||||||
|
echo "PROXY_BENCH_PATH=$PROXY_BENCH_PATH"
|
||||||
|
echo "NEON_DIR=${RUNNER_TEMP}/neon"
|
||||||
|
echo "TEST_OUTPUT=${PROXY_BENCH_PATH}/test_output"
|
||||||
|
echo ""
|
||||||
|
} >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Run proxy-bench
|
||||||
|
run: ${PROXY_BENCH_PATH}/run.sh
|
||||||
|
|
||||||
|
- name: Ingest Bench Results # neon repo script
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
mkdir -p $TEST_OUTPUT
|
||||||
|
python $NEON_DIR/scripts/proxy_bench_results_ingest.py --out $TEST_OUTPUT
|
||||||
|
|
||||||
|
- name: Push Metrics to Proxy perf database
|
||||||
|
if: always()
|
||||||
|
env:
|
||||||
|
PERF_TEST_RESULT_CONNSTR: "${{ secrets.PROXY_TEST_RESULT_CONNSTR }}"
|
||||||
|
REPORT_FROM: $TEST_OUTPUT
|
||||||
|
run: $NEON_DIR/scripts/generate_and_push_perf_report.sh
|
||||||
|
|
||||||
|
- name: Docker cleanup
|
||||||
|
if: always()
|
||||||
|
run: docker compose down
|
||||||
|
|
||||||
|
- name: Notify Failure
|
||||||
|
if: failure()
|
||||||
|
run: echo "Proxy bench job failed" && exit 1
|
||||||
6
.github/workflows/random-ops-test.yml
vendored
6
.github/workflows/random-ops-test.yml
vendored
@@ -66,7 +66,7 @@ jobs:
|
|||||||
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
name: neon-${{ runner.os }}-${{ runner.arch }}-release-artifact
|
||||||
path: /tmp/neon/
|
path: /tmp/neon/
|
||||||
prefix: latest
|
prefix: latest
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
uses: ./.github/actions/run-python-test-set
|
uses: ./.github/actions/run-python-test-set
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
run_in_parallel: false
|
run_in_parallel: false
|
||||||
extra_params: -m remote_cluster
|
extra_params: -m remote_cluster
|
||||||
pg_version: ${{ matrix.pg-version }}
|
pg_version: ${{ matrix.pg-version }}
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
NEON_API_KEY: ${{ secrets.NEON_STAGING_API_KEY }}
|
NEON_API_KEY: ${{ secrets.NEON_STAGING_API_KEY }}
|
||||||
RANDOM_SEED: ${{ inputs.random_seed }}
|
RANDOM_SEED: ${{ inputs.random_seed }}
|
||||||
@@ -88,6 +88,6 @@ jobs:
|
|||||||
uses: ./.github/actions/allure-report-generate
|
uses: ./.github/actions/allure-report-generate
|
||||||
with:
|
with:
|
||||||
store-test-results-into-db: true
|
store-test-results-into-db: true
|
||||||
aws-oicd-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
aws-oidc-role-arn: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||||
env:
|
env:
|
||||||
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||||
|
|||||||
12
.github/workflows/release-compute.yml
vendored
Normal file
12
.github/workflows/release-compute.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
name: Create compute release PR
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 7 * * FRI'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
create-release-pr:
|
||||||
|
uses: ./.github/workflows/release.yml
|
||||||
|
with:
|
||||||
|
component: compute
|
||||||
|
secrets: inherit
|
||||||
12
.github/workflows/release-proxy.yml
vendored
Normal file
12
.github/workflows/release-proxy.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
name: Create proxy release PR
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 6 * * TUE'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
create-release-pr:
|
||||||
|
uses: ./.github/workflows/release.yml
|
||||||
|
with:
|
||||||
|
component: proxy
|
||||||
|
secrets: inherit
|
||||||
12
.github/workflows/release-storage.yml
vendored
Normal file
12
.github/workflows/release-storage.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
name: Create storage release PR
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 6 * * FRI'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
create-release-pr:
|
||||||
|
uses: ./.github/workflows/release.yml
|
||||||
|
with:
|
||||||
|
component: storage
|
||||||
|
secrets: inherit
|
||||||
93
.github/workflows/release.yml
vendored
93
.github/workflows/release.yml
vendored
@@ -1,25 +1,34 @@
|
|||||||
name: Create Release Branch
|
name: Create release PR
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
|
||||||
# It should be kept in sync with if-condition in jobs
|
|
||||||
- cron: '0 6 * * TUE' # Proxy release
|
|
||||||
- cron: '0 6 * * FRI' # Storage release
|
|
||||||
- cron: '0 7 * * FRI' # Compute release
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
create-storage-release-branch:
|
component:
|
||||||
type: boolean
|
description: "Component to release"
|
||||||
description: 'Create Storage release PR'
|
required: true
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- compute
|
||||||
|
- proxy
|
||||||
|
- storage
|
||||||
|
cherry-pick:
|
||||||
|
description: "Commits to cherry-pick (space separated, makes this a hotfix based on previous release)"
|
||||||
required: false
|
required: false
|
||||||
create-proxy-release-branch:
|
type: string
|
||||||
type: boolean
|
default: ''
|
||||||
description: 'Create Proxy release PR'
|
|
||||||
required: false
|
workflow_call:
|
||||||
create-compute-release-branch:
|
inputs:
|
||||||
type: boolean
|
component:
|
||||||
description: 'Create Compute release PR'
|
description: "Component to release"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
cherry-pick:
|
||||||
|
description: "Commits to cherry-pick (space separated, makes this a hotfix based on previous release)"
|
||||||
required: false
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
|
||||||
|
|
||||||
# No permission for GITHUB_TOKEN by default; the **minimal required** set of permissions should be granted in each job.
|
# No permission for GITHUB_TOKEN by default; the **minimal required** set of permissions should be granted in each job.
|
||||||
permissions: {}
|
permissions: {}
|
||||||
@@ -29,41 +38,31 @@ defaults:
|
|||||||
shell: bash -euo pipefail {0}
|
shell: bash -euo pipefail {0}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
create-storage-release-branch:
|
create-release-pr:
|
||||||
if: ${{ github.event.schedule == '0 6 * * FRI' || inputs.create-storage-release-branch }}
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
uses: ./.github/workflows/_create-release-pr.yml
|
steps:
|
||||||
with:
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
component-name: 'Storage'
|
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||||
source-branch: ${{ github.ref_name }}
|
with:
|
||||||
secrets:
|
egress-policy: audit
|
||||||
ci-access-token: ${{ secrets.CI_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
create-proxy-release-branch:
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
if: ${{ github.event.schedule == '0 6 * * TUE' || inputs.create-proxy-release-branch }}
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
permissions:
|
- name: Configure git
|
||||||
contents: write
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
uses: ./.github/workflows/_create-release-pr.yml
|
- name: Create release PR
|
||||||
with:
|
uses: neondatabase/dev-actions/release-pr@290dec821d86fa8a93f019e8c69720f5865b5677
|
||||||
component-name: 'Proxy'
|
with:
|
||||||
source-branch: ${{ github.ref_name }}
|
component: ${{ inputs.component }}
|
||||||
secrets:
|
cherry-pick: ${{ inputs.cherry-pick }}
|
||||||
ci-access-token: ${{ secrets.CI_ACCESS_TOKEN }}
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||||
create-compute-release-branch:
|
|
||||||
if: ${{ github.event.schedule == '0 7 * * FRI' || inputs.create-compute-release-branch }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
uses: ./.github/workflows/_create-release-pr.yml
|
|
||||||
with:
|
|
||||||
component-name: 'Compute'
|
|
||||||
source-branch: ${{ github.ref_name }}
|
|
||||||
secrets:
|
|
||||||
ci-access-token: ${{ secrets.CI_ACCESS_TOKEN }}
|
|
||||||
|
|||||||
4
.github/workflows/trigger-e2e-tests.yml
vendored
4
.github/workflows/trigger-e2e-tests.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
uses: step-security/harden-runner@v2
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ jobs:
|
|||||||
}}
|
}}
|
||||||
steps:
|
steps:
|
||||||
- name: Harden the runner (Audit all outbound calls)
|
- name: Harden the runner (Audit all outbound calls)
|
||||||
uses: step-security/harden-runner@v2
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
/artifact_cache
|
/artifact_cache
|
||||||
|
/build
|
||||||
/pg_install
|
/pg_install
|
||||||
/target
|
/target
|
||||||
/tmp_check
|
/tmp_check
|
||||||
@@ -13,6 +14,7 @@ neon.iml
|
|||||||
/.neon
|
/.neon
|
||||||
/integration_tests/.neon
|
/integration_tests/.neon
|
||||||
compaction-suite-results.*
|
compaction-suite-results.*
|
||||||
|
pgxn/neon/communicator/communicator_bindings.h
|
||||||
|
|
||||||
# Coverage
|
# Coverage
|
||||||
*.profraw
|
*.profraw
|
||||||
|
|||||||
790
Cargo.lock
generated
790
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
47
Cargo.toml
47
Cargo.toml
@@ -8,7 +8,9 @@ members = [
|
|||||||
"pageserver/compaction",
|
"pageserver/compaction",
|
||||||
"pageserver/ctl",
|
"pageserver/ctl",
|
||||||
"pageserver/client",
|
"pageserver/client",
|
||||||
|
"pageserver/client_grpc",
|
||||||
"pageserver/pagebench",
|
"pageserver/pagebench",
|
||||||
|
"pageserver/page_api",
|
||||||
"proxy",
|
"proxy",
|
||||||
"safekeeper",
|
"safekeeper",
|
||||||
"safekeeper/client",
|
"safekeeper/client",
|
||||||
@@ -21,14 +23,19 @@ members = [
|
|||||||
"libs/http-utils",
|
"libs/http-utils",
|
||||||
"libs/pageserver_api",
|
"libs/pageserver_api",
|
||||||
"libs/postgres_ffi",
|
"libs/postgres_ffi",
|
||||||
|
"libs/postgres_ffi_types",
|
||||||
|
"libs/postgres_versioninfo",
|
||||||
"libs/safekeeper_api",
|
"libs/safekeeper_api",
|
||||||
"libs/desim",
|
"libs/desim",
|
||||||
|
"libs/neon-shmem",
|
||||||
"libs/utils",
|
"libs/utils",
|
||||||
"libs/consumption_metrics",
|
"libs/consumption_metrics",
|
||||||
"libs/postgres_backend",
|
"libs/postgres_backend",
|
||||||
|
"libs/posthog_client_lite",
|
||||||
"libs/pq_proto",
|
"libs/pq_proto",
|
||||||
"libs/tenant_size_model",
|
"libs/tenant_size_model",
|
||||||
"libs/metrics",
|
"libs/metrics",
|
||||||
|
"libs/neonart",
|
||||||
"libs/postgres_connection",
|
"libs/postgres_connection",
|
||||||
"libs/remote_storage",
|
"libs/remote_storage",
|
||||||
"libs/tracing-utils",
|
"libs/tracing-utils",
|
||||||
@@ -41,6 +48,7 @@ members = [
|
|||||||
"libs/proxy/postgres-types2",
|
"libs/proxy/postgres-types2",
|
||||||
"libs/proxy/tokio-postgres2",
|
"libs/proxy/tokio-postgres2",
|
||||||
"endpoint_storage",
|
"endpoint_storage",
|
||||||
|
"pgxn/neon/communicator",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
@@ -68,8 +76,8 @@ aws-credential-types = "1.2.0"
|
|||||||
aws-sigv4 = { version = "1.2", features = ["sign-http"] }
|
aws-sigv4 = { version = "1.2", features = ["sign-http"] }
|
||||||
aws-types = "1.3"
|
aws-types = "1.3"
|
||||||
axum = { version = "0.8.1", features = ["ws"] }
|
axum = { version = "0.8.1", features = ["ws"] }
|
||||||
axum-extra = { version = "0.10.0", features = ["typed-header"] }
|
axum-extra = { version = "0.10.0", features = ["typed-header", "query"] }
|
||||||
base64 = "0.13.0"
|
base64 = "0.22"
|
||||||
bincode = "1.3"
|
bincode = "1.3"
|
||||||
bindgen = "0.71"
|
bindgen = "0.71"
|
||||||
bit_field = "0.10.2"
|
bit_field = "0.10.2"
|
||||||
@@ -84,6 +92,7 @@ clap = { version = "4.0", features = ["derive", "env"] }
|
|||||||
clashmap = { version = "1.0", features = ["raw-api"] }
|
clashmap = { version = "1.0", features = ["raw-api"] }
|
||||||
comfy-table = "7.1"
|
comfy-table = "7.1"
|
||||||
const_format = "0.2"
|
const_format = "0.2"
|
||||||
|
crossbeam-utils = "0.8.21"
|
||||||
crc32c = "0.6"
|
crc32c = "0.6"
|
||||||
diatomic-waker = { version = "0.2.3" }
|
diatomic-waker = { version = "0.2.3" }
|
||||||
either = "1.8"
|
either = "1.8"
|
||||||
@@ -126,7 +135,7 @@ md5 = "0.7.0"
|
|||||||
measured = { version = "0.0.22", features=["lasso"] }
|
measured = { version = "0.0.22", features=["lasso"] }
|
||||||
measured-process = { version = "0.0.22" }
|
measured-process = { version = "0.0.22" }
|
||||||
memoffset = "0.9"
|
memoffset = "0.9"
|
||||||
nix = { version = "0.27", features = ["dir", "fs", "process", "socket", "signal", "poll"] }
|
nix = { version = "0.30.1", features = ["dir", "fs", "mman", "process", "socket", "signal", "poll"] }
|
||||||
# Do not update to >= 7.0.0, at least. The update will have a significant impact
|
# Do not update to >= 7.0.0, at least. The update will have a significant impact
|
||||||
# on compute startup metrics (start_postgres_ms), >= 25% degradation.
|
# on compute startup metrics (start_postgres_ms), >= 25% degradation.
|
||||||
notify = "6.0.0"
|
notify = "6.0.0"
|
||||||
@@ -142,11 +151,13 @@ parquet = { version = "53", default-features = false, features = ["zstd"] }
|
|||||||
parquet_derive = "53"
|
parquet_derive = "53"
|
||||||
pbkdf2 = { version = "0.12.1", features = ["simple", "std"] }
|
pbkdf2 = { version = "0.12.1", features = ["simple", "std"] }
|
||||||
pem = "3.0.3"
|
pem = "3.0.3"
|
||||||
|
peekable = "0.3.0"
|
||||||
pin-project-lite = "0.2"
|
pin-project-lite = "0.2"
|
||||||
pprof = { version = "0.14", features = ["criterion", "flamegraph", "frame-pointer", "prost-codec"] }
|
pprof = { version = "0.14", features = ["criterion", "flamegraph", "frame-pointer", "prost-codec"] }
|
||||||
procfs = "0.16"
|
procfs = "0.16"
|
||||||
prometheus = {version = "0.13", default-features=false, features = ["process"]} # removes protobuf dependency
|
prometheus = {version = "0.13", default-features=false, features = ["process"]} # removes protobuf dependency
|
||||||
prost = "0.13"
|
prost = "0.13.5"
|
||||||
|
prost-types = "0.13.5"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
redis = { version = "0.29.2", features = ["tokio-rustls-comp", "keep-alive"] }
|
redis = { version = "0.29.2", features = ["tokio-rustls-comp", "keep-alive"] }
|
||||||
regex = "1.10.2"
|
regex = "1.10.2"
|
||||||
@@ -168,14 +179,16 @@ sentry = { version = "0.37", default-features = false, features = ["backtrace",
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
serde_path_to_error = "0.1"
|
serde_path_to_error = "0.1"
|
||||||
serde_with = { version = "2.0", features = [ "base64" ] }
|
serde_with = { version = "3", features = [ "base64" ] }
|
||||||
serde_assert = "0.5.0"
|
serde_assert = "0.5.0"
|
||||||
|
serde_repr = "0.1.20"
|
||||||
sha2 = "0.10.2"
|
sha2 = "0.10.2"
|
||||||
signal-hook = "0.3"
|
signal-hook = "0.3"
|
||||||
smallvec = "1.11"
|
smallvec = "1.11"
|
||||||
smol_str = { version = "0.2.0", features = ["serde"] }
|
smol_str = { version = "0.2.0", features = ["serde"] }
|
||||||
socket2 = "0.5"
|
socket2 = "0.5"
|
||||||
spki = "0.7.3"
|
spki = "0.7.3"
|
||||||
|
spin = "0.9.8"
|
||||||
strum = "0.26"
|
strum = "0.26"
|
||||||
strum_macros = "0.26"
|
strum_macros = "0.26"
|
||||||
"subtle" = "2.5.0"
|
"subtle" = "2.5.0"
|
||||||
@@ -187,16 +200,16 @@ thiserror = "1.0"
|
|||||||
tikv-jemallocator = { version = "0.6", features = ["profiling", "stats", "unprefixed_malloc_on_supported_platforms"] }
|
tikv-jemallocator = { version = "0.6", features = ["profiling", "stats", "unprefixed_malloc_on_supported_platforms"] }
|
||||||
tikv-jemalloc-ctl = { version = "0.6", features = ["stats"] }
|
tikv-jemalloc-ctl = { version = "0.6", features = ["stats"] }
|
||||||
tokio = { version = "1.43.1", features = ["macros"] }
|
tokio = { version = "1.43.1", features = ["macros"] }
|
||||||
tokio-epoll-uring = { git = "https://github.com/neondatabase/tokio-epoll-uring.git" , branch = "main" }
|
|
||||||
tokio-io-timeout = "1.2.0"
|
tokio-io-timeout = "1.2.0"
|
||||||
tokio-postgres-rustls = "0.12.0"
|
tokio-postgres-rustls = "0.12.0"
|
||||||
tokio-rustls = { version = "0.26.0", default-features = false, features = ["tls12", "ring"]}
|
tokio-rustls = { version = "0.26.0", default-features = false, features = ["tls12", "ring"]}
|
||||||
tokio-stream = "0.1"
|
tokio-stream = "0.1"
|
||||||
tokio-tar = "0.3"
|
tokio-tar = "0.3"
|
||||||
tokio-util = { version = "0.7.10", features = ["io", "rt"] }
|
tokio-util = { version = "0.7.10", features = ["io", "io-util", "rt"] }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
toml_edit = "0.22"
|
toml_edit = "0.22"
|
||||||
tonic = {version = "0.12.3", default-features = false, features = ["channel", "tls", "tls-roots"]}
|
tonic = { version = "0.13.1", default-features = false, features = ["channel", "codegen", "gzip", "prost", "router", "server", "tls-ring", "tls-native-roots", "zstd"] }
|
||||||
|
tonic-reflection = { version = "0.13.1", features = ["server"] }
|
||||||
tower = { version = "0.5.2", default-features = false }
|
tower = { version = "0.5.2", default-features = false }
|
||||||
tower-http = { version = "0.6.2", features = ["auth", "request-id", "trace"] }
|
tower-http = { version = "0.6.2", features = ["auth", "request-id", "trace"] }
|
||||||
|
|
||||||
@@ -228,6 +241,9 @@ x509-cert = { version = "0.2.5" }
|
|||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
|
tokio-epoll-uring = { git = "https://github.com/neondatabase/tokio-epoll-uring.git" , branch = "main" }
|
||||||
|
uring-common = { git = "https://github.com/neondatabase/tokio-epoll-uring.git" , branch = "main" }
|
||||||
|
|
||||||
## Libraries from neondatabase/ git forks, ideally with changes to be upstreamed
|
## Libraries from neondatabase/ git forks, ideally with changes to be upstreamed
|
||||||
postgres = { git = "https://github.com/neondatabase/rust-postgres.git", branch = "neon" }
|
postgres = { git = "https://github.com/neondatabase/rust-postgres.git", branch = "neon" }
|
||||||
postgres-protocol = { git = "https://github.com/neondatabase/rust-postgres.git", branch = "neon" }
|
postgres-protocol = { git = "https://github.com/neondatabase/rust-postgres.git", branch = "neon" }
|
||||||
@@ -243,39 +259,48 @@ azure_storage_blobs = { git = "https://github.com/neondatabase/azure-sdk-for-rus
|
|||||||
## Local libraries
|
## Local libraries
|
||||||
compute_api = { version = "0.1", path = "./libs/compute_api/" }
|
compute_api = { version = "0.1", path = "./libs/compute_api/" }
|
||||||
consumption_metrics = { version = "0.1", path = "./libs/consumption_metrics/" }
|
consumption_metrics = { version = "0.1", path = "./libs/consumption_metrics/" }
|
||||||
|
desim = { version = "0.1", path = "./libs/desim" }
|
||||||
|
endpoint_storage = { version = "0.0.1", path = "./endpoint_storage/" }
|
||||||
http-utils = { version = "0.1", path = "./libs/http-utils/" }
|
http-utils = { version = "0.1", path = "./libs/http-utils/" }
|
||||||
metrics = { version = "0.1", path = "./libs/metrics/" }
|
metrics = { version = "0.1", path = "./libs/metrics/" }
|
||||||
|
neonart = { version = "0.1", path = "./libs/neonart/" }
|
||||||
|
neon-shmem = { version = "0.1", path = "./libs/neon-shmem/" }
|
||||||
pageserver = { path = "./pageserver" }
|
pageserver = { path = "./pageserver" }
|
||||||
pageserver_api = { version = "0.1", path = "./libs/pageserver_api/" }
|
pageserver_api = { version = "0.1", path = "./libs/pageserver_api/" }
|
||||||
pageserver_client = { path = "./pageserver/client" }
|
pageserver_client = { path = "./pageserver/client" }
|
||||||
|
pageserver_client_grpc = { path = "./pageserver/client_grpc" }
|
||||||
pageserver_compaction = { version = "0.1", path = "./pageserver/compaction/" }
|
pageserver_compaction = { version = "0.1", path = "./pageserver/compaction/" }
|
||||||
|
pageserver_page_api = { path = "./pageserver/page_api" }
|
||||||
postgres_backend = { version = "0.1", path = "./libs/postgres_backend/" }
|
postgres_backend = { version = "0.1", path = "./libs/postgres_backend/" }
|
||||||
postgres_connection = { version = "0.1", path = "./libs/postgres_connection/" }
|
postgres_connection = { version = "0.1", path = "./libs/postgres_connection/" }
|
||||||
postgres_ffi = { version = "0.1", path = "./libs/postgres_ffi/" }
|
postgres_ffi = { version = "0.1", path = "./libs/postgres_ffi/" }
|
||||||
|
postgres_ffi_types = { version = "0.1", path = "./libs/postgres_ffi_types/" }
|
||||||
|
postgres_versioninfo = { version = "0.1", path = "./libs/postgres_versioninfo/" }
|
||||||
postgres_initdb = { path = "./libs/postgres_initdb" }
|
postgres_initdb = { path = "./libs/postgres_initdb" }
|
||||||
|
posthog_client_lite = { version = "0.1", path = "./libs/posthog_client_lite" }
|
||||||
pq_proto = { version = "0.1", path = "./libs/pq_proto/" }
|
pq_proto = { version = "0.1", path = "./libs/pq_proto/" }
|
||||||
remote_storage = { version = "0.1", path = "./libs/remote_storage/" }
|
remote_storage = { version = "0.1", path = "./libs/remote_storage/" }
|
||||||
safekeeper_api = { version = "0.1", path = "./libs/safekeeper_api" }
|
safekeeper_api = { version = "0.1", path = "./libs/safekeeper_api" }
|
||||||
safekeeper_client = { path = "./safekeeper/client" }
|
safekeeper_client = { path = "./safekeeper/client" }
|
||||||
desim = { version = "0.1", path = "./libs/desim" }
|
|
||||||
storage_broker = { version = "0.1", path = "./storage_broker/" } # Note: main broker code is inside the binary crate, so linking with the library shouldn't be heavy.
|
storage_broker = { version = "0.1", path = "./storage_broker/" } # Note: main broker code is inside the binary crate, so linking with the library shouldn't be heavy.
|
||||||
storage_controller_client = { path = "./storage_controller/client" }
|
storage_controller_client = { path = "./storage_controller/client" }
|
||||||
tenant_size_model = { version = "0.1", path = "./libs/tenant_size_model/" }
|
tenant_size_model = { version = "0.1", path = "./libs/tenant_size_model/" }
|
||||||
tracing-utils = { version = "0.1", path = "./libs/tracing-utils/" }
|
tracing-utils = { version = "0.1", path = "./libs/tracing-utils/" }
|
||||||
utils = { version = "0.1", path = "./libs/utils/" }
|
utils = { version = "0.1", path = "./libs/utils/" }
|
||||||
vm_monitor = { version = "0.1", path = "./libs/vm_monitor/" }
|
vm_monitor = { version = "0.1", path = "./libs/vm_monitor/" }
|
||||||
walproposer = { version = "0.1", path = "./libs/walproposer/" }
|
|
||||||
wal_decoder = { version = "0.1", path = "./libs/wal_decoder" }
|
wal_decoder = { version = "0.1", path = "./libs/wal_decoder" }
|
||||||
|
walproposer = { version = "0.1", path = "./libs/walproposer/" }
|
||||||
|
|
||||||
## Common library dependency
|
## Common library dependency
|
||||||
workspace_hack = { version = "0.1", path = "./workspace_hack/" }
|
workspace_hack = { version = "0.1", path = "./workspace_hack/" }
|
||||||
|
|
||||||
## Build dependencies
|
## Build dependencies
|
||||||
|
cbindgen = "0.28.0"
|
||||||
criterion = "0.5.1"
|
criterion = "0.5.1"
|
||||||
rcgen = "0.13"
|
rcgen = "0.13"
|
||||||
rstest = "0.18"
|
rstest = "0.18"
|
||||||
camino-tempfile = "1.0.2"
|
camino-tempfile = "1.0.2"
|
||||||
tonic-build = "0.12"
|
tonic-build = "0.13.1"
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
|
||||||
|
|||||||
23
Dockerfile
23
Dockerfile
@@ -5,8 +5,6 @@
|
|||||||
ARG REPOSITORY=ghcr.io/neondatabase
|
ARG REPOSITORY=ghcr.io/neondatabase
|
||||||
ARG IMAGE=build-tools
|
ARG IMAGE=build-tools
|
||||||
ARG TAG=pinned
|
ARG TAG=pinned
|
||||||
ARG DEFAULT_PG_VERSION=17
|
|
||||||
ARG STABLE_PG_VERSION=16
|
|
||||||
ARG DEBIAN_VERSION=bookworm
|
ARG DEBIAN_VERSION=bookworm
|
||||||
ARG DEBIAN_FLAVOR=${DEBIAN_VERSION}-slim
|
ARG DEBIAN_FLAVOR=${DEBIAN_VERSION}-slim
|
||||||
|
|
||||||
@@ -42,12 +40,12 @@ COPY --chown=nonroot vendor/postgres-v16 vendor/postgres-v16
|
|||||||
COPY --chown=nonroot vendor/postgres-v17 vendor/postgres-v17
|
COPY --chown=nonroot vendor/postgres-v17 vendor/postgres-v17
|
||||||
COPY --chown=nonroot pgxn pgxn
|
COPY --chown=nonroot pgxn pgxn
|
||||||
COPY --chown=nonroot Makefile Makefile
|
COPY --chown=nonroot Makefile Makefile
|
||||||
|
COPY --chown=nonroot postgres.mk postgres.mk
|
||||||
COPY --chown=nonroot scripts/ninstall.sh scripts/ninstall.sh
|
COPY --chown=nonroot scripts/ninstall.sh scripts/ninstall.sh
|
||||||
|
|
||||||
ENV BUILD_TYPE=release
|
ENV BUILD_TYPE=release
|
||||||
RUN set -e \
|
RUN set -e \
|
||||||
&& mold -run make -j $(nproc) -s neon-pg-ext \
|
&& mold -run make -j $(nproc) -s neon-pg-ext \
|
||||||
&& rm -rf pg_install/build \
|
|
||||||
&& tar -C pg_install -czf /home/nonroot/postgres_install.tar.gz .
|
&& tar -C pg_install -czf /home/nonroot/postgres_install.tar.gz .
|
||||||
|
|
||||||
# Prepare cargo-chef recipe
|
# Prepare cargo-chef recipe
|
||||||
@@ -63,14 +61,11 @@ FROM $REPOSITORY/$IMAGE:$TAG AS build
|
|||||||
WORKDIR /home/nonroot
|
WORKDIR /home/nonroot
|
||||||
ARG GIT_VERSION=local
|
ARG GIT_VERSION=local
|
||||||
ARG BUILD_TAG
|
ARG BUILD_TAG
|
||||||
ARG STABLE_PG_VERSION
|
|
||||||
|
|
||||||
COPY --from=pg-build /home/nonroot/pg_install/v14/include/postgresql/server pg_install/v14/include/postgresql/server
|
COPY --from=pg-build /home/nonroot/pg_install/v14/include/postgresql/server pg_install/v14/include/postgresql/server
|
||||||
COPY --from=pg-build /home/nonroot/pg_install/v15/include/postgresql/server pg_install/v15/include/postgresql/server
|
COPY --from=pg-build /home/nonroot/pg_install/v15/include/postgresql/server pg_install/v15/include/postgresql/server
|
||||||
COPY --from=pg-build /home/nonroot/pg_install/v16/include/postgresql/server pg_install/v16/include/postgresql/server
|
COPY --from=pg-build /home/nonroot/pg_install/v16/include/postgresql/server pg_install/v16/include/postgresql/server
|
||||||
COPY --from=pg-build /home/nonroot/pg_install/v17/include/postgresql/server pg_install/v17/include/postgresql/server
|
COPY --from=pg-build /home/nonroot/pg_install/v17/include/postgresql/server pg_install/v17/include/postgresql/server
|
||||||
COPY --from=pg-build /home/nonroot/pg_install/v16/lib pg_install/v16/lib
|
|
||||||
COPY --from=pg-build /home/nonroot/pg_install/v17/lib pg_install/v17/lib
|
|
||||||
COPY --from=plan /home/nonroot/recipe.json recipe.json
|
COPY --from=plan /home/nonroot/recipe.json recipe.json
|
||||||
|
|
||||||
ARG ADDITIONAL_RUSTFLAGS=""
|
ARG ADDITIONAL_RUSTFLAGS=""
|
||||||
@@ -97,7 +92,6 @@ RUN set -e \
|
|||||||
# Build final image
|
# Build final image
|
||||||
#
|
#
|
||||||
FROM $BASE_IMAGE_SHA
|
FROM $BASE_IMAGE_SHA
|
||||||
ARG DEFAULT_PG_VERSION
|
|
||||||
WORKDIR /data
|
WORKDIR /data
|
||||||
|
|
||||||
RUN set -e \
|
RUN set -e \
|
||||||
@@ -107,9 +101,20 @@ RUN set -e \
|
|||||||
libreadline-dev \
|
libreadline-dev \
|
||||||
libseccomp-dev \
|
libseccomp-dev \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
# System postgres for use with client libraries (e.g. in storage controller)
|
|
||||||
postgresql-15 \
|
|
||||||
openssl \
|
openssl \
|
||||||
|
unzip \
|
||||||
|
curl \
|
||||||
|
&& ARCH=$(uname -m) \
|
||||||
|
&& if [ "$ARCH" = "x86_64" ]; then \
|
||||||
|
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"; \
|
||||||
|
elif [ "$ARCH" = "aarch64" ]; then \
|
||||||
|
curl "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o "awscliv2.zip"; \
|
||||||
|
else \
|
||||||
|
echo "Unsupported architecture: $ARCH" && exit 1; \
|
||||||
|
fi \
|
||||||
|
&& unzip awscliv2.zip \
|
||||||
|
&& ./aws/install \
|
||||||
|
&& rm -rf aws awscliv2.zip \
|
||||||
&& rm -f /etc/apt/apt.conf.d/80-retries \
|
&& rm -f /etc/apt/apt.conf.d/80-retries \
|
||||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
|
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
|
||||||
&& useradd -d /data neon \
|
&& useradd -d /data neon \
|
||||||
|
|||||||
256
Makefile
256
Makefile
@@ -1,8 +1,21 @@
|
|||||||
ROOT_PROJECT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
ROOT_PROJECT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
|
||||||
# Where to install Postgres, default is ./pg_install, maybe useful for package managers
|
# Where to install Postgres, default is ./pg_install, maybe useful for package
|
||||||
|
# managers.
|
||||||
POSTGRES_INSTALL_DIR ?= $(ROOT_PROJECT_DIR)/pg_install/
|
POSTGRES_INSTALL_DIR ?= $(ROOT_PROJECT_DIR)/pg_install/
|
||||||
|
|
||||||
|
# Supported PostgreSQL versions
|
||||||
|
POSTGRES_VERSIONS = v17 v16 v15 v14
|
||||||
|
|
||||||
|
# CARGO_BUILD_FLAGS: Extra flags to pass to `cargo build`. `--locked`
|
||||||
|
# and `--features testing` are popular examples.
|
||||||
|
#
|
||||||
|
# CARGO_PROFILE: Set to override the cargo profile to use. By default,
|
||||||
|
# it is derived from BUILD_TYPE.
|
||||||
|
|
||||||
|
# All intermediate build artifacts are stored here.
|
||||||
|
BUILD_DIR := build
|
||||||
|
|
||||||
ICU_PREFIX_DIR := /usr/local/icu
|
ICU_PREFIX_DIR := /usr/local/icu
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -16,12 +29,19 @@ ifeq ($(BUILD_TYPE),release)
|
|||||||
PG_CONFIGURE_OPTS = --enable-debug --with-openssl
|
PG_CONFIGURE_OPTS = --enable-debug --with-openssl
|
||||||
PG_CFLAGS += -O2 -g3 $(CFLAGS)
|
PG_CFLAGS += -O2 -g3 $(CFLAGS)
|
||||||
PG_LDFLAGS = $(LDFLAGS)
|
PG_LDFLAGS = $(LDFLAGS)
|
||||||
# Unfortunately, `--profile=...` is a nightly feature
|
CARGO_PROFILE ?= --profile=release
|
||||||
CARGO_BUILD_FLAGS += --release
|
# NEON_CARGO_ARTIFACT_TARGET_DIR is the directory where `cargo build` places
|
||||||
|
# the final build artifacts. There is unfortunately no easy way of changing
|
||||||
|
# it to a fully predictable path, nor to extract the path with a simple
|
||||||
|
# command. See https://github.com/rust-lang/cargo/issues/9661 and
|
||||||
|
# https://github.com/rust-lang/cargo/issues/6790.
|
||||||
|
NEON_CARGO_ARTIFACT_TARGET_DIR = $(ROOT_PROJECT_DIR)/target/release
|
||||||
else ifeq ($(BUILD_TYPE),debug)
|
else ifeq ($(BUILD_TYPE),debug)
|
||||||
PG_CONFIGURE_OPTS = --enable-debug --with-openssl --enable-cassert --enable-depend
|
PG_CONFIGURE_OPTS = --enable-debug --with-openssl --enable-cassert --enable-depend
|
||||||
PG_CFLAGS += -O0 -g3 $(CFLAGS)
|
PG_CFLAGS += -O0 -g3 $(CFLAGS)
|
||||||
PG_LDFLAGS = $(LDFLAGS)
|
PG_LDFLAGS = $(LDFLAGS)
|
||||||
|
CARGO_PROFILE ?= --profile=dev
|
||||||
|
NEON_CARGO_ARTIFACT_TARGET_DIR = $(ROOT_PROJECT_DIR)/target/debug
|
||||||
else
|
else
|
||||||
$(error Bad build type '$(BUILD_TYPE)', see Makefile for options)
|
$(error Bad build type '$(BUILD_TYPE)', see Makefile for options)
|
||||||
endif
|
endif
|
||||||
@@ -85,141 +105,32 @@ CACHEDIR_TAG_CONTENTS := "Signature: 8a477f597d28d172789f06886806bc55"
|
|||||||
# Top level Makefile to build Neon and PostgreSQL
|
# Top level Makefile to build Neon and PostgreSQL
|
||||||
#
|
#
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: neon postgres neon-pg-ext
|
all: neon postgres-install neon-pg-ext
|
||||||
|
|
||||||
### Neon Rust bits
|
### Neon Rust bits
|
||||||
#
|
#
|
||||||
# The 'postgres_ffi' depends on the Postgres headers.
|
# The 'postgres_ffi' depends on the Postgres headers.
|
||||||
.PHONY: neon
|
.PHONY: neon
|
||||||
neon: postgres-headers walproposer-lib cargo-target-dir
|
neon: postgres-headers-install walproposer-lib cargo-target-dir
|
||||||
+@echo "Compiling Neon"
|
+@echo "Compiling Neon"
|
||||||
$(CARGO_CMD_PREFIX) cargo build $(CARGO_BUILD_FLAGS)
|
$(CARGO_CMD_PREFIX) cargo build $(CARGO_BUILD_FLAGS) $(CARGO_PROFILE)
|
||||||
|
|
||||||
.PHONY: cargo-target-dir
|
.PHONY: cargo-target-dir
|
||||||
cargo-target-dir:
|
cargo-target-dir:
|
||||||
# https://github.com/rust-lang/cargo/issues/14281
|
# https://github.com/rust-lang/cargo/issues/14281
|
||||||
mkdir -p target
|
mkdir -p target
|
||||||
test -e target/CACHEDIR.TAG || echo "$(CACHEDIR_TAG_CONTENTS)" > target/CACHEDIR.TAG
|
test -e target/CACHEDIR.TAG || echo "$(CACHEDIR_TAG_CONTENTS)" > target/CACHEDIR.TAG
|
||||||
|
|
||||||
### PostgreSQL parts
|
|
||||||
# Some rules are duplicated for Postgres v14 and 15. We may want to refactor
|
|
||||||
# to avoid the duplication in the future, but it's tolerable for now.
|
|
||||||
#
|
|
||||||
$(POSTGRES_INSTALL_DIR)/build/%/config.status:
|
|
||||||
|
|
||||||
mkdir -p $(POSTGRES_INSTALL_DIR)
|
|
||||||
test -e $(POSTGRES_INSTALL_DIR)/CACHEDIR.TAG || echo "$(CACHEDIR_TAG_CONTENTS)" > $(POSTGRES_INSTALL_DIR)/CACHEDIR.TAG
|
|
||||||
|
|
||||||
+@echo "Configuring Postgres $* build"
|
|
||||||
@test -s $(ROOT_PROJECT_DIR)/vendor/postgres-$*/configure || { \
|
|
||||||
echo "\nPostgres submodule not found in $(ROOT_PROJECT_DIR)/vendor/postgres-$*/, execute "; \
|
|
||||||
echo "'git submodule update --init --recursive --depth 2 --progress .' in project root.\n"; \
|
|
||||||
exit 1; }
|
|
||||||
mkdir -p $(POSTGRES_INSTALL_DIR)/build/$*
|
|
||||||
|
|
||||||
VERSION=$*; \
|
|
||||||
EXTRA_VERSION=$$(cd $(ROOT_PROJECT_DIR)/vendor/postgres-$$VERSION && git rev-parse HEAD); \
|
|
||||||
(cd $(POSTGRES_INSTALL_DIR)/build/$$VERSION && \
|
|
||||||
env PATH="$(EXTRA_PATH_OVERRIDES):$$PATH" $(ROOT_PROJECT_DIR)/vendor/postgres-$$VERSION/configure \
|
|
||||||
CFLAGS='$(PG_CFLAGS)' LDFLAGS='$(PG_LDFLAGS)' \
|
|
||||||
$(PG_CONFIGURE_OPTS) --with-extra-version=" ($$EXTRA_VERSION)" \
|
|
||||||
--prefix=$(abspath $(POSTGRES_INSTALL_DIR))/$$VERSION > configure.log)
|
|
||||||
|
|
||||||
# nicer alias to run 'configure'
|
|
||||||
# Note: I've been unable to use templates for this part of our configuration.
|
|
||||||
# I'm not sure why it wouldn't work, but this is the only place (apart from
|
|
||||||
# the "build-all-versions" entry points) where direct mention of PostgreSQL
|
|
||||||
# versions is used.
|
|
||||||
.PHONY: postgres-configure-v17
|
|
||||||
postgres-configure-v17: $(POSTGRES_INSTALL_DIR)/build/v17/config.status
|
|
||||||
.PHONY: postgres-configure-v16
|
|
||||||
postgres-configure-v16: $(POSTGRES_INSTALL_DIR)/build/v16/config.status
|
|
||||||
.PHONY: postgres-configure-v15
|
|
||||||
postgres-configure-v15: $(POSTGRES_INSTALL_DIR)/build/v15/config.status
|
|
||||||
.PHONY: postgres-configure-v14
|
|
||||||
postgres-configure-v14: $(POSTGRES_INSTALL_DIR)/build/v14/config.status
|
|
||||||
|
|
||||||
# Install the PostgreSQL header files into $(POSTGRES_INSTALL_DIR)/<version>/include
|
|
||||||
.PHONY: postgres-headers-%
|
|
||||||
postgres-headers-%: postgres-configure-%
|
|
||||||
+@echo "Installing PostgreSQL $* headers"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/src/include MAKELEVEL=0 install
|
|
||||||
|
|
||||||
# Compile and install PostgreSQL
|
|
||||||
.PHONY: postgres-%
|
|
||||||
postgres-%: postgres-configure-% \
|
|
||||||
postgres-headers-% # to prevent `make install` conflicts with neon's `postgres-headers`
|
|
||||||
+@echo "Compiling PostgreSQL $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$* MAKELEVEL=0 install
|
|
||||||
+@echo "Compiling libpq $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/src/interfaces/libpq install
|
|
||||||
+@echo "Compiling pg_prewarm $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/pg_prewarm install
|
|
||||||
+@echo "Compiling pg_buffercache $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/pg_buffercache install
|
|
||||||
+@echo "Compiling pg_visibility $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/pg_visibility install
|
|
||||||
+@echo "Compiling pageinspect $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/pageinspect install
|
|
||||||
+@echo "Compiling pg_trgm $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/pg_trgm install
|
|
||||||
+@echo "Compiling amcheck $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/amcheck install
|
|
||||||
+@echo "Compiling test_decoding $*"
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/test_decoding install
|
|
||||||
|
|
||||||
.PHONY: postgres-clean-%
|
|
||||||
postgres-clean-%:
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$* MAKELEVEL=0 clean
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/pg_buffercache clean
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/contrib/pageinspect clean
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/src/interfaces/libpq clean
|
|
||||||
|
|
||||||
.PHONY: postgres-check-%
|
|
||||||
postgres-check-%: postgres-%
|
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$* MAKELEVEL=0 check
|
|
||||||
|
|
||||||
.PHONY: neon-pg-ext-%
|
.PHONY: neon-pg-ext-%
|
||||||
neon-pg-ext-%: postgres-%
|
neon-pg-ext-%: postgres-install-%
|
||||||
+@echo "Compiling neon $*"
|
+@echo "Compiling neon-specific Postgres extensions for $*"
|
||||||
mkdir -p $(POSTGRES_INSTALL_DIR)/build/neon-$*
|
mkdir -p $(BUILD_DIR)/pgxn-$*
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config COPT='$(COPT)' \
|
$(MAKE) PG_CONFIG="$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config" COPT='$(COPT)' \
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-$* \
|
NEON_CARGO_ARTIFACT_TARGET_DIR="$(NEON_CARGO_ARTIFACT_TARGET_DIR)" \
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon/Makefile install
|
CARGO_BUILD_FLAGS="$(CARGO_BUILD_FLAGS)" \
|
||||||
+@echo "Compiling neon_walredo $*"
|
CARGO_PROFILE="$(CARGO_PROFILE)" \
|
||||||
mkdir -p $(POSTGRES_INSTALL_DIR)/build/neon-walredo-$*
|
-C $(BUILD_DIR)/pgxn-$*\
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config COPT='$(COPT)' \
|
-f $(ROOT_PROJECT_DIR)/pgxn/Makefile install
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-walredo-$* \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon_walredo/Makefile install
|
|
||||||
+@echo "Compiling neon_rmgr $*"
|
|
||||||
mkdir -p $(POSTGRES_INSTALL_DIR)/build/neon-rmgr-$*
|
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config COPT='$(COPT)' \
|
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-rmgr-$* \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon_rmgr/Makefile install
|
|
||||||
+@echo "Compiling neon_test_utils $*"
|
|
||||||
mkdir -p $(POSTGRES_INSTALL_DIR)/build/neon-test-utils-$*
|
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config COPT='$(COPT)' \
|
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-test-utils-$* \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon_test_utils/Makefile install
|
|
||||||
+@echo "Compiling neon_utils $*"
|
|
||||||
mkdir -p $(POSTGRES_INSTALL_DIR)/build/neon-utils-$*
|
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config COPT='$(COPT)' \
|
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-utils-$* \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon_utils/Makefile install
|
|
||||||
|
|
||||||
.PHONY: neon-pg-clean-ext-%
|
|
||||||
neon-pg-clean-ext-%:
|
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config \
|
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-$* \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon/Makefile clean
|
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config \
|
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-walredo-$* \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon_walredo/Makefile clean
|
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config \
|
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-test-utils-$* \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon_test_utils/Makefile clean
|
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/$*/bin/pg_config \
|
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-utils-$* \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon_utils/Makefile clean
|
|
||||||
|
|
||||||
# Build walproposer as a static library. walproposer source code is located
|
# Build walproposer as a static library. walproposer source code is located
|
||||||
# in the pgxn/neon directory.
|
# in the pgxn/neon directory.
|
||||||
@@ -233,15 +144,15 @@ neon-pg-clean-ext-%:
|
|||||||
.PHONY: walproposer-lib
|
.PHONY: walproposer-lib
|
||||||
walproposer-lib: neon-pg-ext-v17
|
walproposer-lib: neon-pg-ext-v17
|
||||||
+@echo "Compiling walproposer-lib"
|
+@echo "Compiling walproposer-lib"
|
||||||
mkdir -p $(POSTGRES_INSTALL_DIR)/build/walproposer-lib
|
mkdir -p $(BUILD_DIR)/walproposer-lib
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/v17/bin/pg_config COPT='$(COPT)' \
|
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/v17/bin/pg_config COPT='$(COPT)' \
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/walproposer-lib \
|
-C $(BUILD_DIR)/walproposer-lib \
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon/Makefile walproposer-lib
|
-f $(ROOT_PROJECT_DIR)/pgxn/neon/Makefile walproposer-lib
|
||||||
cp $(POSTGRES_INSTALL_DIR)/v17/lib/libpgport.a $(POSTGRES_INSTALL_DIR)/build/walproposer-lib
|
cp $(POSTGRES_INSTALL_DIR)/v17/lib/libpgport.a $(BUILD_DIR)/walproposer-lib
|
||||||
cp $(POSTGRES_INSTALL_DIR)/v17/lib/libpgcommon.a $(POSTGRES_INSTALL_DIR)/build/walproposer-lib
|
cp $(POSTGRES_INSTALL_DIR)/v17/lib/libpgcommon.a $(BUILD_DIR)/walproposer-lib
|
||||||
$(AR) d $(POSTGRES_INSTALL_DIR)/build/walproposer-lib/libpgport.a \
|
$(AR) d $(BUILD_DIR)/walproposer-lib/libpgport.a \
|
||||||
pg_strong_random.o
|
pg_strong_random.o
|
||||||
$(AR) d $(POSTGRES_INSTALL_DIR)/build/walproposer-lib/libpgcommon.a \
|
$(AR) d $(BUILD_DIR)/walproposer-lib/libpgcommon.a \
|
||||||
checksum_helper.o \
|
checksum_helper.o \
|
||||||
cryptohash_openssl.o \
|
cryptohash_openssl.o \
|
||||||
hmac_openssl.o \
|
hmac_openssl.o \
|
||||||
@@ -249,69 +160,18 @@ walproposer-lib: neon-pg-ext-v17
|
|||||||
parse_manifest.o \
|
parse_manifest.o \
|
||||||
scram-common.o
|
scram-common.o
|
||||||
ifeq ($(UNAME_S),Linux)
|
ifeq ($(UNAME_S),Linux)
|
||||||
$(AR) d $(POSTGRES_INSTALL_DIR)/build/walproposer-lib/libpgcommon.a \
|
$(AR) d $(BUILD_DIR)/walproposer-lib/libpgcommon.a \
|
||||||
pg_crc32c.o
|
pg_crc32c.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: walproposer-lib-clean
|
# Shorthand to call neon-pg-ext-% target for all Postgres versions
|
||||||
walproposer-lib-clean:
|
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/v17/bin/pg_config \
|
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/walproposer-lib \
|
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon/Makefile clean
|
|
||||||
|
|
||||||
.PHONY: neon-pg-ext
|
.PHONY: neon-pg-ext
|
||||||
neon-pg-ext: \
|
neon-pg-ext: $(foreach pg_version,$(POSTGRES_VERSIONS),neon-pg-ext-$(pg_version))
|
||||||
neon-pg-ext-v14 \
|
|
||||||
neon-pg-ext-v15 \
|
|
||||||
neon-pg-ext-v16 \
|
|
||||||
neon-pg-ext-v17
|
|
||||||
|
|
||||||
.PHONY: neon-pg-clean-ext
|
|
||||||
neon-pg-clean-ext: \
|
|
||||||
neon-pg-clean-ext-v14 \
|
|
||||||
neon-pg-clean-ext-v15 \
|
|
||||||
neon-pg-clean-ext-v16 \
|
|
||||||
neon-pg-clean-ext-v17
|
|
||||||
|
|
||||||
# shorthand to build all Postgres versions
|
|
||||||
.PHONY: postgres
|
|
||||||
postgres: \
|
|
||||||
postgres-v14 \
|
|
||||||
postgres-v15 \
|
|
||||||
postgres-v16 \
|
|
||||||
postgres-v17
|
|
||||||
|
|
||||||
.PHONY: postgres-headers
|
|
||||||
postgres-headers: \
|
|
||||||
postgres-headers-v14 \
|
|
||||||
postgres-headers-v15 \
|
|
||||||
postgres-headers-v16 \
|
|
||||||
postgres-headers-v17
|
|
||||||
|
|
||||||
.PHONY: postgres-clean
|
|
||||||
postgres-clean: \
|
|
||||||
postgres-clean-v14 \
|
|
||||||
postgres-clean-v15 \
|
|
||||||
postgres-clean-v16 \
|
|
||||||
postgres-clean-v17
|
|
||||||
|
|
||||||
.PHONY: postgres-check
|
|
||||||
postgres-check: \
|
|
||||||
postgres-check-v14 \
|
|
||||||
postgres-check-v15 \
|
|
||||||
postgres-check-v16 \
|
|
||||||
postgres-check-v17
|
|
||||||
|
|
||||||
# This doesn't remove the effects of 'configure'.
|
|
||||||
.PHONY: clean
|
|
||||||
clean: postgres-clean neon-pg-clean-ext
|
|
||||||
$(MAKE) -C compute clean
|
|
||||||
$(CARGO_CMD_PREFIX) cargo clean
|
|
||||||
|
|
||||||
# This removes everything
|
# This removes everything
|
||||||
.PHONY: distclean
|
.PHONY: distclean
|
||||||
distclean:
|
distclean:
|
||||||
$(RM) -r $(POSTGRES_INSTALL_DIR)
|
$(RM) -r $(POSTGRES_INSTALL_DIR) $(BUILD_DIR)
|
||||||
$(CARGO_CMD_PREFIX) cargo clean
|
$(CARGO_CMD_PREFIX) cargo clean
|
||||||
|
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
@@ -320,7 +180,7 @@ fmt:
|
|||||||
|
|
||||||
postgres-%-pg-bsd-indent: postgres-%
|
postgres-%-pg-bsd-indent: postgres-%
|
||||||
+@echo "Compiling pg_bsd_indent"
|
+@echo "Compiling pg_bsd_indent"
|
||||||
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/$*/src/tools/pg_bsd_indent/
|
$(MAKE) -C $(BUILD_DIR)/$*/src/tools/pg_bsd_indent/
|
||||||
|
|
||||||
# Create typedef list for the core. Note that generally it should be combined with
|
# Create typedef list for the core. Note that generally it should be combined with
|
||||||
# buildfarm one to cover platform specific stuff.
|
# buildfarm one to cover platform specific stuff.
|
||||||
@@ -339,7 +199,7 @@ postgres-%-pgindent: postgres-%-pg-bsd-indent postgres-%-typedefs.list
|
|||||||
cat $(ROOT_PROJECT_DIR)/vendor/postgres-$*/src/tools/pgindent/typedefs.list |\
|
cat $(ROOT_PROJECT_DIR)/vendor/postgres-$*/src/tools/pgindent/typedefs.list |\
|
||||||
cat - postgres-$*-typedefs.list | sort | uniq > postgres-$*-typedefs-full.list
|
cat - postgres-$*-typedefs.list | sort | uniq > postgres-$*-typedefs-full.list
|
||||||
+@echo note: you might want to run it on selected files/dirs instead.
|
+@echo note: you might want to run it on selected files/dirs instead.
|
||||||
INDENT=$(POSTGRES_INSTALL_DIR)/build/$*/src/tools/pg_bsd_indent/pg_bsd_indent \
|
INDENT=$(BUILD_DIR)/$*/src/tools/pg_bsd_indent/pg_bsd_indent \
|
||||||
$(ROOT_PROJECT_DIR)/vendor/postgres-$*/src/tools/pgindent/pgindent --typedefs postgres-$*-typedefs-full.list \
|
$(ROOT_PROJECT_DIR)/vendor/postgres-$*/src/tools/pgindent/pgindent --typedefs postgres-$*-typedefs-full.list \
|
||||||
$(ROOT_PROJECT_DIR)/vendor/postgres-$*/src/ \
|
$(ROOT_PROJECT_DIR)/vendor/postgres-$*/src/ \
|
||||||
--excludes $(ROOT_PROJECT_DIR)/vendor/postgres-$*/src/tools/pgindent/exclude_file_patterns
|
--excludes $(ROOT_PROJECT_DIR)/vendor/postgres-$*/src/tools/pgindent/exclude_file_patterns
|
||||||
@@ -350,12 +210,28 @@ postgres-%-pgindent: postgres-%-pg-bsd-indent postgres-%-typedefs.list
|
|||||||
neon-pgindent: postgres-v17-pg-bsd-indent neon-pg-ext-v17
|
neon-pgindent: postgres-v17-pg-bsd-indent neon-pg-ext-v17
|
||||||
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/v17/bin/pg_config COPT='$(COPT)' \
|
$(MAKE) PG_CONFIG=$(POSTGRES_INSTALL_DIR)/v17/bin/pg_config COPT='$(COPT)' \
|
||||||
FIND_TYPEDEF=$(ROOT_PROJECT_DIR)/vendor/postgres-v17/src/tools/find_typedef \
|
FIND_TYPEDEF=$(ROOT_PROJECT_DIR)/vendor/postgres-v17/src/tools/find_typedef \
|
||||||
INDENT=$(POSTGRES_INSTALL_DIR)/build/v17/src/tools/pg_bsd_indent/pg_bsd_indent \
|
INDENT=$(BUILD_DIR)/v17/src/tools/pg_bsd_indent/pg_bsd_indent \
|
||||||
PGINDENT_SCRIPT=$(ROOT_PROJECT_DIR)/vendor/postgres-v17/src/tools/pgindent/pgindent \
|
PGINDENT_SCRIPT=$(ROOT_PROJECT_DIR)/vendor/postgres-v17/src/tools/pgindent/pgindent \
|
||||||
-C $(POSTGRES_INSTALL_DIR)/build/neon-v17 \
|
-C $(BUILD_DIR)/neon-v17 \
|
||||||
-f $(ROOT_PROJECT_DIR)/pgxn/neon/Makefile pgindent
|
-f $(ROOT_PROJECT_DIR)/pgxn/neon/Makefile pgindent
|
||||||
|
|
||||||
|
|
||||||
.PHONY: setup-pre-commit-hook
|
.PHONY: setup-pre-commit-hook
|
||||||
setup-pre-commit-hook:
|
setup-pre-commit-hook:
|
||||||
ln -s -f $(ROOT_PROJECT_DIR)/pre-commit.py .git/hooks/pre-commit
|
ln -s -f $(ROOT_PROJECT_DIR)/pre-commit.py .git/hooks/pre-commit
|
||||||
|
|
||||||
|
# Targets for building PostgreSQL are defined in postgres.mk.
|
||||||
|
#
|
||||||
|
# But if the caller has indicated that PostgreSQL is already
|
||||||
|
# installed, by setting the PG_INSTALL_CACHED variable, skip it.
|
||||||
|
ifdef PG_INSTALL_CACHED
|
||||||
|
postgres-install: skip-install
|
||||||
|
$(foreach pg_version,$(POSTGRES_VERSIONS),postgres-install-$(pg_version)): skip-install
|
||||||
|
postgres-headers-install:
|
||||||
|
+@echo "Skipping installation of PostgreSQL headers because PG_INSTALL_CACHED is set"
|
||||||
|
skip-install:
|
||||||
|
+@echo "Skipping PostgreSQL installation because PG_INSTALL_CACHED is set"
|
||||||
|
|
||||||
|
else
|
||||||
|
include postgres.mk
|
||||||
|
endif
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ RUN set -e \
|
|||||||
|
|
||||||
# Keep the version the same as in compute/compute-node.Dockerfile and
|
# Keep the version the same as in compute/compute-node.Dockerfile and
|
||||||
# test_runner/regress/test_compute_metrics.py.
|
# test_runner/regress/test_compute_metrics.py.
|
||||||
ENV SQL_EXPORTER_VERSION=0.17.0
|
ENV SQL_EXPORTER_VERSION=0.17.3
|
||||||
RUN curl -fsSL \
|
RUN curl -fsSL \
|
||||||
"https://github.com/burningalchemist/sql_exporter/releases/download/${SQL_EXPORTER_VERSION}/sql_exporter-${SQL_EXPORTER_VERSION}.linux-$(case "$(uname -m)" in x86_64) echo amd64;; aarch64) echo arm64;; esac).tar.gz" \
|
"https://github.com/burningalchemist/sql_exporter/releases/download/${SQL_EXPORTER_VERSION}/sql_exporter-${SQL_EXPORTER_VERSION}.linux-$(case "$(uname -m)" in x86_64) echo amd64;; aarch64) echo arm64;; esac).tar.gz" \
|
||||||
--output sql_exporter.tar.gz \
|
--output sql_exporter.tar.gz \
|
||||||
@@ -165,6 +165,7 @@ RUN curl -fsSL \
|
|||||||
&& rm sql_exporter.tar.gz
|
&& rm sql_exporter.tar.gz
|
||||||
|
|
||||||
# protobuf-compiler (protoc)
|
# protobuf-compiler (protoc)
|
||||||
|
# Keep the version the same as in compute/compute-node.Dockerfile
|
||||||
ENV PROTOC_VERSION=25.1
|
ENV PROTOC_VERSION=25.1
|
||||||
RUN curl -fsSL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-$(uname -m | sed 's/aarch64/aarch_64/g').zip" -o "protoc.zip" \
|
RUN curl -fsSL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-$(uname -m | sed 's/aarch64/aarch_64/g').zip" -o "protoc.zip" \
|
||||||
&& unzip -q protoc.zip -d protoc \
|
&& unzip -q protoc.zip -d protoc \
|
||||||
@@ -179,7 +180,7 @@ RUN curl -sL "https://github.com/peak/s5cmd/releases/download/v${S5CMD_VERSION}/
|
|||||||
&& mv s5cmd /usr/local/bin/s5cmd
|
&& mv s5cmd /usr/local/bin/s5cmd
|
||||||
|
|
||||||
# LLVM
|
# LLVM
|
||||||
ENV LLVM_VERSION=19
|
ENV LLVM_VERSION=20
|
||||||
RUN curl -fsSL 'https://apt.llvm.org/llvm-snapshot.gpg.key' | apt-key add - \
|
RUN curl -fsSL 'https://apt.llvm.org/llvm-snapshot.gpg.key' | apt-key add - \
|
||||||
&& echo "deb http://apt.llvm.org/${DEBIAN_VERSION}/ llvm-toolchain-${DEBIAN_VERSION}-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.stable.list \
|
&& echo "deb http://apt.llvm.org/${DEBIAN_VERSION}/ llvm-toolchain-${DEBIAN_VERSION}-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.stable.list \
|
||||||
&& apt update \
|
&& apt update \
|
||||||
@@ -292,7 +293,7 @@ WORKDIR /home/nonroot
|
|||||||
|
|
||||||
# Rust
|
# Rust
|
||||||
# Please keep the version of llvm (installed above) in sync with rust llvm (`rustc --version --verbose | grep LLVM`)
|
# Please keep the version of llvm (installed above) in sync with rust llvm (`rustc --version --verbose | grep LLVM`)
|
||||||
ENV RUSTC_VERSION=1.86.0
|
ENV RUSTC_VERSION=1.88.0
|
||||||
ENV RUSTUP_HOME="/home/nonroot/.rustup"
|
ENV RUSTUP_HOME="/home/nonroot/.rustup"
|
||||||
ENV PATH="/home/nonroot/.cargo/bin:${PATH}"
|
ENV PATH="/home/nonroot/.cargo/bin:${PATH}"
|
||||||
ARG RUSTFILT_VERSION=0.2.1
|
ARG RUSTFILT_VERSION=0.2.1
|
||||||
@@ -310,13 +311,13 @@ RUN curl -sSO https://static.rust-lang.org/rustup/dist/$(uname -m)-unknown-linux
|
|||||||
. "$HOME/.cargo/env" && \
|
. "$HOME/.cargo/env" && \
|
||||||
cargo --version && rustup --version && \
|
cargo --version && rustup --version && \
|
||||||
rustup component add llvm-tools rustfmt clippy && \
|
rustup component add llvm-tools rustfmt clippy && \
|
||||||
cargo install rustfilt --version ${RUSTFILT_VERSION} && \
|
cargo install rustfilt --version ${RUSTFILT_VERSION} --locked && \
|
||||||
cargo install cargo-hakari --version ${CARGO_HAKARI_VERSION} && \
|
cargo install cargo-hakari --version ${CARGO_HAKARI_VERSION} --locked && \
|
||||||
cargo install cargo-deny --locked --version ${CARGO_DENY_VERSION} && \
|
cargo install cargo-deny --version ${CARGO_DENY_VERSION} --locked && \
|
||||||
cargo install cargo-hack --version ${CARGO_HACK_VERSION} && \
|
cargo install cargo-hack --version ${CARGO_HACK_VERSION} --locked && \
|
||||||
cargo install cargo-nextest --version ${CARGO_NEXTEST_VERSION} && \
|
cargo install cargo-nextest --version ${CARGO_NEXTEST_VERSION} --locked && \
|
||||||
cargo install cargo-chef --locked --version ${CARGO_CHEF_VERSION} && \
|
cargo install cargo-chef --version ${CARGO_CHEF_VERSION} --locked && \
|
||||||
cargo install diesel_cli --version ${CARGO_DIESEL_CLI_VERSION} \
|
cargo install diesel_cli --version ${CARGO_DIESEL_CLI_VERSION} --locked \
|
||||||
--features postgres-bundled --no-default-features && \
|
--features postgres-bundled --no-default-features && \
|
||||||
rm -rf /home/nonroot/.cargo/registry && \
|
rm -rf /home/nonroot/.cargo/registry && \
|
||||||
rm -rf /home/nonroot/.cargo/git
|
rm -rf /home/nonroot/.cargo/git
|
||||||
|
|||||||
3
compute/.gitignore
vendored
3
compute/.gitignore
vendored
@@ -3,3 +3,6 @@ etc/neon_collector.yml
|
|||||||
etc/neon_collector_autoscaling.yml
|
etc/neon_collector_autoscaling.yml
|
||||||
etc/sql_exporter.yml
|
etc/sql_exporter.yml
|
||||||
etc/sql_exporter_autoscaling.yml
|
etc/sql_exporter_autoscaling.yml
|
||||||
|
|
||||||
|
# Node.js dependencies
|
||||||
|
node_modules/
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ sql_exporter.yml: $(jsonnet_files)
|
|||||||
--output-file etc/$@ \
|
--output-file etc/$@ \
|
||||||
--tla-str collector_name=neon_collector \
|
--tla-str collector_name=neon_collector \
|
||||||
--tla-str collector_file=neon_collector.yml \
|
--tla-str collector_file=neon_collector.yml \
|
||||||
--tla-str 'connection_string=postgresql://cloud_admin@127.0.0.1:5432/postgres?sslmode=disable&application_name=sql_exporter' \
|
--tla-str 'connection_string=postgresql://cloud_admin@127.0.0.1:5432/postgres?sslmode=disable&application_name=sql_exporter&pgaudit.log=none' \
|
||||||
etc/sql_exporter.jsonnet
|
etc/sql_exporter.jsonnet
|
||||||
|
|
||||||
sql_exporter_autoscaling.yml: $(jsonnet_files)
|
sql_exporter_autoscaling.yml: $(jsonnet_files)
|
||||||
@@ -30,7 +30,7 @@ sql_exporter_autoscaling.yml: $(jsonnet_files)
|
|||||||
--output-file etc/$@ \
|
--output-file etc/$@ \
|
||||||
--tla-str collector_name=neon_collector_autoscaling \
|
--tla-str collector_name=neon_collector_autoscaling \
|
||||||
--tla-str collector_file=neon_collector_autoscaling.yml \
|
--tla-str collector_file=neon_collector_autoscaling.yml \
|
||||||
--tla-str 'connection_string=postgresql://cloud_admin@127.0.0.1:5432/postgres?sslmode=disable&application_name=sql_exporter_autoscaling' \
|
--tla-str 'connection_string=postgresql://cloud_admin@127.0.0.1:5432/postgres?sslmode=disable&application_name=sql_exporter_autoscaling&pgaudit.log=none' \
|
||||||
etc/sql_exporter.jsonnet
|
etc/sql_exporter.jsonnet
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
@@ -48,3 +48,11 @@ jsonnetfmt-test:
|
|||||||
.PHONY: jsonnetfmt-format
|
.PHONY: jsonnetfmt-format
|
||||||
jsonnetfmt-format:
|
jsonnetfmt-format:
|
||||||
jsonnetfmt --in-place $(jsonnet_files)
|
jsonnetfmt --in-place $(jsonnet_files)
|
||||||
|
|
||||||
|
.PHONY: manifest-schema-validation
|
||||||
|
manifest-schema-validation: node_modules
|
||||||
|
node_modules/.bin/jsonschema validate -d https://json-schema.org/draft/2020-12/schema manifest.schema.json manifest.yaml
|
||||||
|
|
||||||
|
node_modules: package.json
|
||||||
|
npm install
|
||||||
|
touch node_modules
|
||||||
|
|||||||
@@ -77,9 +77,6 @@
|
|||||||
# build_and_test.yml github workflow for how that's done.
|
# build_and_test.yml github workflow for how that's done.
|
||||||
|
|
||||||
ARG PG_VERSION
|
ARG PG_VERSION
|
||||||
ARG REPOSITORY=ghcr.io/neondatabase
|
|
||||||
ARG IMAGE=build-tools
|
|
||||||
ARG TAG=pinned
|
|
||||||
ARG BUILD_TAG
|
ARG BUILD_TAG
|
||||||
ARG DEBIAN_VERSION=bookworm
|
ARG DEBIAN_VERSION=bookworm
|
||||||
ARG DEBIAN_FLAVOR=${DEBIAN_VERSION}-slim
|
ARG DEBIAN_FLAVOR=${DEBIAN_VERSION}-slim
|
||||||
@@ -118,6 +115,9 @@ ARG EXTENSIONS=all
|
|||||||
FROM $BASE_IMAGE_SHA AS build-deps
|
FROM $BASE_IMAGE_SHA AS build-deps
|
||||||
ARG DEBIAN_VERSION
|
ARG DEBIAN_VERSION
|
||||||
|
|
||||||
|
# Keep in sync with build-tools.Dockerfile
|
||||||
|
ENV PROTOC_VERSION=25.1
|
||||||
|
|
||||||
# Use strict mode for bash to catch errors early
|
# Use strict mode for bash to catch errors early
|
||||||
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
|
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
|
||||||
|
|
||||||
@@ -149,8 +149,17 @@ RUN case $DEBIAN_VERSION in \
|
|||||||
ninja-build git autoconf automake libtool build-essential bison flex libreadline-dev \
|
ninja-build git autoconf automake libtool build-essential bison flex libreadline-dev \
|
||||||
zlib1g-dev libxml2-dev libcurl4-openssl-dev libossp-uuid-dev wget ca-certificates pkg-config libssl-dev \
|
zlib1g-dev libxml2-dev libcurl4-openssl-dev libossp-uuid-dev wget ca-certificates pkg-config libssl-dev \
|
||||||
libicu-dev libxslt1-dev liblz4-dev libzstd-dev zstd curl unzip g++ \
|
libicu-dev libxslt1-dev liblz4-dev libzstd-dev zstd curl unzip g++ \
|
||||||
|
libclang-dev \
|
||||||
|
jsonnet \
|
||||||
$VERSION_INSTALLS \
|
$VERSION_INSTALLS \
|
||||||
&& apt clean && rm -rf /var/lib/apt/lists/*
|
&& apt clean && rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& useradd -ms /bin/bash nonroot -b /home \
|
||||||
|
# Install protoc from binary release, since Debian's versions are too old.
|
||||||
|
&& curl -fsSL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-$(uname -m | sed 's/aarch64/aarch_64/g').zip" -o "protoc.zip" \
|
||||||
|
&& unzip -q protoc.zip -d protoc \
|
||||||
|
&& mv protoc/bin/protoc /usr/local/bin/protoc \
|
||||||
|
&& mv protoc/include/google /usr/local/include/google \
|
||||||
|
&& rm -rf protoc.zip protoc
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
#
|
#
|
||||||
@@ -171,9 +180,6 @@ RUN cd postgres && \
|
|||||||
eval $CONFIGURE_CMD && \
|
eval $CONFIGURE_CMD && \
|
||||||
make MAKELEVEL=0 -j $(getconf _NPROCESSORS_ONLN) -s install && \
|
make MAKELEVEL=0 -j $(getconf _NPROCESSORS_ONLN) -s install && \
|
||||||
make MAKELEVEL=0 -j $(getconf _NPROCESSORS_ONLN) -s -C contrib/ install && \
|
make MAKELEVEL=0 -j $(getconf _NPROCESSORS_ONLN) -s -C contrib/ install && \
|
||||||
# Install headers
|
|
||||||
make MAKELEVEL=0 -j $(getconf _NPROCESSORS_ONLN) -s -C src/include install && \
|
|
||||||
make MAKELEVEL=0 -j $(getconf _NPROCESSORS_ONLN) -s -C src/interfaces/libpq install && \
|
|
||||||
# Enable some of contrib extensions
|
# Enable some of contrib extensions
|
||||||
echo 'trusted = true' >> /usr/local/pgsql/share/extension/autoinc.control && \
|
echo 'trusted = true' >> /usr/local/pgsql/share/extension/autoinc.control && \
|
||||||
echo 'trusted = true' >> /usr/local/pgsql/share/extension/dblink.control && \
|
echo 'trusted = true' >> /usr/local/pgsql/share/extension/dblink.control && \
|
||||||
@@ -297,6 +303,7 @@ RUN ./autogen.sh && \
|
|||||||
./configure --with-sfcgal=/usr/local/bin/sfcgal-config && \
|
./configure --with-sfcgal=/usr/local/bin/sfcgal-config && \
|
||||||
make -j $(getconf _NPROCESSORS_ONLN) && \
|
make -j $(getconf _NPROCESSORS_ONLN) && \
|
||||||
make -j $(getconf _NPROCESSORS_ONLN) install && \
|
make -j $(getconf _NPROCESSORS_ONLN) install && \
|
||||||
|
make staged-install && \
|
||||||
cd extensions/postgis && \
|
cd extensions/postgis && \
|
||||||
make clean && \
|
make clean && \
|
||||||
make -j $(getconf _NPROCESSORS_ONLN) install && \
|
make -j $(getconf _NPROCESSORS_ONLN) install && \
|
||||||
@@ -582,6 +589,38 @@ RUN make -j $(getconf _NPROCESSORS_ONLN) && \
|
|||||||
make -j $(getconf _NPROCESSORS_ONLN) install && \
|
make -j $(getconf _NPROCESSORS_ONLN) install && \
|
||||||
echo 'trusted = true' >> /usr/local/pgsql/share/extension/hypopg.control
|
echo 'trusted = true' >> /usr/local/pgsql/share/extension/hypopg.control
|
||||||
|
|
||||||
|
#########################################################################################
|
||||||
|
#
|
||||||
|
# Layer "online_advisor-build"
|
||||||
|
# compile online_advisor extension
|
||||||
|
#
|
||||||
|
#########################################################################################
|
||||||
|
FROM build-deps AS online_advisor-src
|
||||||
|
ARG PG_VERSION
|
||||||
|
|
||||||
|
# online_advisor supports all Postgres version starting from PG14, but prior to PG17 has to be included in preload_shared_libraries
|
||||||
|
# last release 1.0 - May 15, 2025
|
||||||
|
WORKDIR /ext-src
|
||||||
|
RUN case "${PG_VERSION:?}" in \
|
||||||
|
"v17") \
|
||||||
|
;; \
|
||||||
|
*) \
|
||||||
|
echo "skipping the version of online_advistor for $PG_VERSION" && exit 0 \
|
||||||
|
;; \
|
||||||
|
esac && \
|
||||||
|
wget https://github.com/knizhnik/online_advisor/archive/refs/tags/1.0.tar.gz -O online_advisor.tar.gz && \
|
||||||
|
echo "37dcadf8f7cc8d6cc1f8831276ee245b44f1b0274f09e511e47a67738ba9ed0f online_advisor.tar.gz" | sha256sum --check && \
|
||||||
|
mkdir online_advisor-src && cd online_advisor-src && tar xzf ../online_advisor.tar.gz --strip-components=1 -C .
|
||||||
|
|
||||||
|
FROM pg-build AS online_advisor-build
|
||||||
|
COPY --from=online_advisor-src /ext-src/ /ext-src/
|
||||||
|
WORKDIR /ext-src/
|
||||||
|
RUN if [ -d online_advisor-src ]; then \
|
||||||
|
cd online_advisor-src && \
|
||||||
|
make -j install && \
|
||||||
|
echo 'trusted = true' >> /usr/local/pgsql/share/extension/online_advisor.control; \
|
||||||
|
fi
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
#
|
#
|
||||||
# Layer "pg_hashids-build"
|
# Layer "pg_hashids-build"
|
||||||
@@ -1024,17 +1063,10 @@ RUN make -j $(getconf _NPROCESSORS_ONLN) && \
|
|||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
#
|
#
|
||||||
# Layer "pg build with nonroot user and cargo installed"
|
# Layer "build-deps with Rust toolchain installed"
|
||||||
# This layer is base and common for layers with `pgrx`
|
|
||||||
#
|
#
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
FROM pg-build AS pg-build-nonroot-with-cargo
|
FROM build-deps AS build-deps-with-cargo
|
||||||
ARG PG_VERSION
|
|
||||||
|
|
||||||
RUN apt update && \
|
|
||||||
apt install --no-install-recommends --no-install-suggests -y curl libclang-dev && \
|
|
||||||
apt clean && rm -rf /var/lib/apt/lists/* && \
|
|
||||||
useradd -ms /bin/bash nonroot -b /home
|
|
||||||
|
|
||||||
ENV HOME=/home/nonroot
|
ENV HOME=/home/nonroot
|
||||||
ENV PATH="/home/nonroot/.cargo/bin:$PATH"
|
ENV PATH="/home/nonroot/.cargo/bin:$PATH"
|
||||||
@@ -1049,13 +1081,29 @@ RUN curl -sSO https://static.rust-lang.org/rustup/dist/$(uname -m)-unknown-linux
|
|||||||
./rustup-init -y --no-modify-path --profile minimal --default-toolchain stable && \
|
./rustup-init -y --no-modify-path --profile minimal --default-toolchain stable && \
|
||||||
rm rustup-init
|
rm rustup-init
|
||||||
|
|
||||||
|
#########################################################################################
|
||||||
|
#
|
||||||
|
# Layer "pg-build with Rust toolchain installed"
|
||||||
|
# This layer is base and common for layers with `pgrx`
|
||||||
|
#
|
||||||
|
#########################################################################################
|
||||||
|
FROM pg-build AS pg-build-with-cargo
|
||||||
|
ARG PG_VERSION
|
||||||
|
|
||||||
|
ENV HOME=/home/nonroot
|
||||||
|
ENV PATH="/home/nonroot/.cargo/bin:$PATH"
|
||||||
|
USER nonroot
|
||||||
|
WORKDIR /home/nonroot
|
||||||
|
|
||||||
|
COPY --from=build-deps-with-cargo /home/nonroot /home/nonroot
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
#
|
#
|
||||||
# Layer "rust extensions"
|
# Layer "rust extensions"
|
||||||
# This layer is used to build `pgrx` deps
|
# This layer is used to build `pgrx` deps
|
||||||
#
|
#
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
FROM pg-build-nonroot-with-cargo AS rust-extensions-build
|
FROM pg-build-with-cargo AS rust-extensions-build
|
||||||
ARG PG_VERSION
|
ARG PG_VERSION
|
||||||
|
|
||||||
RUN case "${PG_VERSION:?}" in \
|
RUN case "${PG_VERSION:?}" in \
|
||||||
@@ -1077,7 +1125,7 @@ USER root
|
|||||||
# and eventually get merged with `rust-extensions-build`
|
# and eventually get merged with `rust-extensions-build`
|
||||||
#
|
#
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
FROM pg-build-nonroot-with-cargo AS rust-extensions-build-pgrx12
|
FROM pg-build-with-cargo AS rust-extensions-build-pgrx12
|
||||||
ARG PG_VERSION
|
ARG PG_VERSION
|
||||||
|
|
||||||
RUN cargo install --locked --version 0.12.9 cargo-pgrx && \
|
RUN cargo install --locked --version 0.12.9 cargo-pgrx && \
|
||||||
@@ -1085,6 +1133,23 @@ RUN cargo install --locked --version 0.12.9 cargo-pgrx && \
|
|||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
|
#########################################################################################
|
||||||
|
#
|
||||||
|
# Layer "rust extensions pgrx14"
|
||||||
|
#
|
||||||
|
# Version 14 is now required by a few
|
||||||
|
# This layer should be used as a base for new pgrx extensions,
|
||||||
|
# and eventually get merged with `rust-extensions-build`
|
||||||
|
#
|
||||||
|
#########################################################################################
|
||||||
|
FROM pg-build-with-cargo AS rust-extensions-build-pgrx14
|
||||||
|
ARG PG_VERSION
|
||||||
|
|
||||||
|
RUN cargo install --locked --version 0.14.1 cargo-pgrx && \
|
||||||
|
/bin/bash -c 'cargo pgrx init --pg${PG_VERSION:1}=/usr/local/pgsql/bin/pg_config'
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
#
|
#
|
||||||
# Layers "pg-onnx-build" and "pgrag-build"
|
# Layers "pg-onnx-build" and "pgrag-build"
|
||||||
@@ -1094,17 +1159,19 @@ USER root
|
|||||||
|
|
||||||
FROM build-deps AS pgrag-src
|
FROM build-deps AS pgrag-src
|
||||||
ARG PG_VERSION
|
ARG PG_VERSION
|
||||||
|
|
||||||
WORKDIR /ext-src
|
WORKDIR /ext-src
|
||||||
|
COPY compute/patches/onnxruntime.patch .
|
||||||
|
|
||||||
RUN wget https://github.com/microsoft/onnxruntime/archive/refs/tags/v1.18.1.tar.gz -O onnxruntime.tar.gz && \
|
RUN wget https://github.com/microsoft/onnxruntime/archive/refs/tags/v1.18.1.tar.gz -O onnxruntime.tar.gz && \
|
||||||
mkdir onnxruntime-src && cd onnxruntime-src && tar xzf ../onnxruntime.tar.gz --strip-components=1 -C . && \
|
mkdir onnxruntime-src && cd onnxruntime-src && tar xzf ../onnxruntime.tar.gz --strip-components=1 -C . && \
|
||||||
|
patch -p1 < /ext-src/onnxruntime.patch && \
|
||||||
echo "#nothing to test here" > neon-test.sh
|
echo "#nothing to test here" > neon-test.sh
|
||||||
|
|
||||||
RUN wget https://github.com/neondatabase-labs/pgrag/archive/refs/tags/v0.0.0.tar.gz -O pgrag.tar.gz && \
|
RUN wget https://github.com/neondatabase-labs/pgrag/archive/refs/tags/v0.1.2.tar.gz -O pgrag.tar.gz && \
|
||||||
echo "2cbe394c1e74fc8bcad9b52d5fbbfb783aef834ca3ce44626cfd770573700bb4 pgrag.tar.gz" | sha256sum --check && \
|
echo "7361654ea24f08cbb9db13c2ee1c0fe008f6114076401bb871619690dafc5225 pgrag.tar.gz" | sha256sum --check && \
|
||||||
mkdir pgrag-src && cd pgrag-src && tar xzf ../pgrag.tar.gz --strip-components=1 -C .
|
mkdir pgrag-src && cd pgrag-src && tar xzf ../pgrag.tar.gz --strip-components=1 -C .
|
||||||
|
|
||||||
FROM rust-extensions-build-pgrx12 AS pgrag-build
|
FROM rust-extensions-build-pgrx14 AS pgrag-build
|
||||||
COPY --from=pgrag-src /ext-src/ /ext-src/
|
COPY --from=pgrag-src /ext-src/ /ext-src/
|
||||||
|
|
||||||
# Install build-time dependencies
|
# Install build-time dependencies
|
||||||
@@ -1112,7 +1179,7 @@ COPY --from=pgrag-src /ext-src/ /ext-src/
|
|||||||
# Install it using virtual environment, because Python 3.11 (the default version on Debian 12 (Bookworm)) complains otherwise
|
# Install it using virtual environment, because Python 3.11 (the default version on Debian 12 (Bookworm)) complains otherwise
|
||||||
WORKDIR /ext-src/onnxruntime-src
|
WORKDIR /ext-src/onnxruntime-src
|
||||||
RUN apt update && apt install --no-install-recommends --no-install-suggests -y \
|
RUN apt update && apt install --no-install-recommends --no-install-suggests -y \
|
||||||
python3 python3-pip python3-venv protobuf-compiler && \
|
python3 python3-pip python3-venv && \
|
||||||
apt clean && rm -rf /var/lib/apt/lists/* && \
|
apt clean && rm -rf /var/lib/apt/lists/* && \
|
||||||
python3 -m venv venv && \
|
python3 -m venv venv && \
|
||||||
. venv/bin/activate && \
|
. venv/bin/activate && \
|
||||||
@@ -1124,21 +1191,21 @@ RUN . venv/bin/activate && \
|
|||||||
|
|
||||||
WORKDIR /ext-src/pgrag-src
|
WORKDIR /ext-src/pgrag-src
|
||||||
RUN cd exts/rag && \
|
RUN cd exts/rag && \
|
||||||
sed -i 's/pgrx = "0.12.6"/pgrx = { version = "0.12.9", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
sed -i 's/pgrx = "0.14.1"/pgrx = { version = "0.14.1", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
||||||
cargo pgrx install --release && \
|
cargo pgrx install --release && \
|
||||||
echo "trusted = true" >> /usr/local/pgsql/share/extension/rag.control
|
echo "trusted = true" >> /usr/local/pgsql/share/extension/rag.control
|
||||||
|
|
||||||
RUN cd exts/rag_bge_small_en_v15 && \
|
RUN cd exts/rag_bge_small_en_v15 && \
|
||||||
sed -i 's/pgrx = "0.12.6"/pgrx = { version = "0.12.9", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
sed -i 's/pgrx = "0.14.1"/pgrx = { version = "0.14.1", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
||||||
ORT_LIB_LOCATION=/ext-src/onnxruntime-src/build/Linux \
|
ORT_LIB_LOCATION=/ext-src/onnxruntime-src/build/Linux \
|
||||||
REMOTE_ONNX_URL=http://pg-ext-s3-gateway/pgrag-data/bge_small_en_v15.onnx \
|
REMOTE_ONNX_URL=http://pg-ext-s3-gateway.pg-ext-s3-gateway.svc.cluster.local/pgrag-data/bge_small_en_v15.onnx \
|
||||||
cargo pgrx install --release --features remote_onnx && \
|
cargo pgrx install --release --features remote_onnx && \
|
||||||
echo "trusted = true" >> /usr/local/pgsql/share/extension/rag_bge_small_en_v15.control
|
echo "trusted = true" >> /usr/local/pgsql/share/extension/rag_bge_small_en_v15.control
|
||||||
|
|
||||||
RUN cd exts/rag_jina_reranker_v1_tiny_en && \
|
RUN cd exts/rag_jina_reranker_v1_tiny_en && \
|
||||||
sed -i 's/pgrx = "0.12.6"/pgrx = { version = "0.12.9", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
sed -i 's/pgrx = "0.14.1"/pgrx = { version = "0.14.1", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
||||||
ORT_LIB_LOCATION=/ext-src/onnxruntime-src/build/Linux \
|
ORT_LIB_LOCATION=/ext-src/onnxruntime-src/build/Linux \
|
||||||
REMOTE_ONNX_URL=http://pg-ext-s3-gateway/pgrag-data/jina_reranker_v1_tiny_en.onnx \
|
REMOTE_ONNX_URL=http://pg-ext-s3-gateway.pg-ext-s3-gateway.svc.cluster.local/pgrag-data/jina_reranker_v1_tiny_en.onnx \
|
||||||
cargo pgrx install --release --features remote_onnx && \
|
cargo pgrx install --release --features remote_onnx && \
|
||||||
echo "trusted = true" >> /usr/local/pgsql/share/extension/rag_jina_reranker_v1_tiny_en.control
|
echo "trusted = true" >> /usr/local/pgsql/share/extension/rag_jina_reranker_v1_tiny_en.control
|
||||||
|
|
||||||
@@ -1305,8 +1372,8 @@ ARG PG_VERSION
|
|||||||
# Do not update without approve from proxy team
|
# Do not update without approve from proxy team
|
||||||
# Make sure the version is reflected in proxy/src/serverless/local_conn_pool.rs
|
# Make sure the version is reflected in proxy/src/serverless/local_conn_pool.rs
|
||||||
WORKDIR /ext-src
|
WORKDIR /ext-src
|
||||||
RUN wget https://github.com/neondatabase/pg_session_jwt/archive/refs/tags/v0.3.0.tar.gz -O pg_session_jwt.tar.gz && \
|
RUN wget https://github.com/neondatabase/pg_session_jwt/archive/refs/tags/v0.3.1.tar.gz -O pg_session_jwt.tar.gz && \
|
||||||
echo "19be2dc0b3834d643706ed430af998bb4c2cdf24b3c45e7b102bb3a550e8660c pg_session_jwt.tar.gz" | sha256sum --check && \
|
echo "62fec9e472cb805c53ba24a0765afdb8ea2720cfc03ae7813e61687b36d1b0ad pg_session_jwt.tar.gz" | sha256sum --check && \
|
||||||
mkdir pg_session_jwt-src && cd pg_session_jwt-src && tar xzf ../pg_session_jwt.tar.gz --strip-components=1 -C . && \
|
mkdir pg_session_jwt-src && cd pg_session_jwt-src && tar xzf ../pg_session_jwt.tar.gz --strip-components=1 -C . && \
|
||||||
sed -i 's/pgrx = "0.12.6"/pgrx = { version = "0.12.9", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
sed -i 's/pgrx = "0.12.6"/pgrx = { version = "0.12.9", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
||||||
sed -i 's/version = "0.12.6"/version = "0.12.9"/g' pgrx-tests/Cargo.toml && \
|
sed -i 's/version = "0.12.6"/version = "0.12.9"/g' pgrx-tests/Cargo.toml && \
|
||||||
@@ -1319,6 +1386,40 @@ COPY --from=pg_session_jwt-src /ext-src/ /ext-src/
|
|||||||
WORKDIR /ext-src/pg_session_jwt-src
|
WORKDIR /ext-src/pg_session_jwt-src
|
||||||
RUN cargo pgrx install --release
|
RUN cargo pgrx install --release
|
||||||
|
|
||||||
|
#########################################################################################
|
||||||
|
#
|
||||||
|
# Layer "pg-anon-pg-build"
|
||||||
|
# compile anon extension
|
||||||
|
#
|
||||||
|
#########################################################################################
|
||||||
|
FROM pg-build AS pg_anon-src
|
||||||
|
ARG PG_VERSION
|
||||||
|
COPY --from=pg-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
|
WORKDIR /ext-src
|
||||||
|
COPY compute/patches/anon_v2.patch .
|
||||||
|
|
||||||
|
# This is an experimental extension, never got to real production.
|
||||||
|
# !Do not remove! It can be present in shared_preload_libraries and compute will fail to start if library is not found.
|
||||||
|
ENV PATH="/usr/local/pgsql/bin/:$PATH"
|
||||||
|
RUN wget https://gitlab.com/dalibo/postgresql_anonymizer/-/archive/2.1.0/postgresql_anonymizer-latest.tar.gz -O pg_anon.tar.gz && \
|
||||||
|
echo "48e7f5ae2f1ca516df3da86c5c739d48dd780a4e885705704ccaad0faa89d6c0 pg_anon.tar.gz" | sha256sum --check && \
|
||||||
|
mkdir pg_anon-src && cd pg_anon-src && tar xzf ../pg_anon.tar.gz --strip-components=1 -C . && \
|
||||||
|
find /usr/local/pgsql -type f | sed 's|^/usr/local/pgsql/||' > /before.txt && \
|
||||||
|
sed -i 's/pgrx = "0.14.1"/pgrx = { version = "=0.14.1", features = [ "unsafe-postgres" ] }/g' Cargo.toml && \
|
||||||
|
patch -p1 < /ext-src/anon_v2.patch
|
||||||
|
|
||||||
|
FROM rust-extensions-build-pgrx14 AS pg-anon-pg-build
|
||||||
|
ARG PG_VERSION
|
||||||
|
COPY --from=pg_anon-src /ext-src/ /ext-src/
|
||||||
|
WORKDIR /ext-src
|
||||||
|
RUN cd pg_anon-src && \
|
||||||
|
make -j $(getconf _NPROCESSORS_ONLN) extension PG_CONFIG=/usr/local/pgsql/bin/pg_config PGVER=pg$(echo "$PG_VERSION" | sed 's/^v//') && \
|
||||||
|
make -j $(getconf _NPROCESSORS_ONLN) install PG_CONFIG=/usr/local/pgsql/bin/pg_config PGVER=pg$(echo "$PG_VERSION" | sed 's/^v//') && \
|
||||||
|
chmod -R a+r ../pg_anon-src && \
|
||||||
|
echo 'trusted = true' >> /usr/local/pgsql/share/extension/anon.control;
|
||||||
|
|
||||||
|
########################################################################################
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
#
|
#
|
||||||
# Layer "wal2json-build"
|
# Layer "wal2json-build"
|
||||||
@@ -1473,20 +1574,20 @@ ARG PG_VERSION
|
|||||||
WORKDIR /ext-src
|
WORKDIR /ext-src
|
||||||
RUN case "${PG_VERSION}" in \
|
RUN case "${PG_VERSION}" in \
|
||||||
"v14") \
|
"v14") \
|
||||||
export PGAUDIT_VERSION=1.6.2 \
|
export PGAUDIT_VERSION=1.6.3 \
|
||||||
export PGAUDIT_CHECKSUM=1f350d70a0cbf488c0f2b485e3a5c9b11f78ad9e3cbb95ef6904afa1eb3187eb \
|
export PGAUDIT_CHECKSUM=37a8f5a7cc8d9188e536d15cf0fdc457fcdab2547caedb54442c37f124110919 \
|
||||||
;; \
|
;; \
|
||||||
"v15") \
|
"v15") \
|
||||||
export PGAUDIT_VERSION=1.7.0 \
|
export PGAUDIT_VERSION=1.7.1 \
|
||||||
export PGAUDIT_CHECKSUM=8f4a73e451c88c567e516e6cba7dc1e23bc91686bb6f1f77f8f3126d428a8bd8 \
|
export PGAUDIT_CHECKSUM=e9c8e6e092d82b2f901d72555ce0fe7780552f35f8985573796cd7e64b09d4ec \
|
||||||
;; \
|
;; \
|
||||||
"v16") \
|
"v16") \
|
||||||
export PGAUDIT_VERSION=16.0 \
|
export PGAUDIT_VERSION=16.1 \
|
||||||
export PGAUDIT_CHECKSUM=d53ef985f2d0b15ba25c512c4ce967dce07b94fd4422c95bd04c4c1a055fe738 \
|
export PGAUDIT_CHECKSUM=3bae908ab70ba0c6f51224009dbcfff1a97bd6104c6273297a64292e1b921fee \
|
||||||
;; \
|
;; \
|
||||||
"v17") \
|
"v17") \
|
||||||
export PGAUDIT_VERSION=17.0 \
|
export PGAUDIT_VERSION=17.1 \
|
||||||
export PGAUDIT_CHECKSUM=7d0d08d030275d525f36cd48b38c6455f1023da863385badff0cec44965bfd8c \
|
export PGAUDIT_CHECKSUM=9c5f37504d393486cc75d2ced83f75f5899be64fa85f689d6babb833b4361e6c \
|
||||||
;; \
|
;; \
|
||||||
*) \
|
*) \
|
||||||
echo "pgaudit is not supported on this PostgreSQL version" && exit 1;; \
|
echo "pgaudit is not supported on this PostgreSQL version" && exit 1;; \
|
||||||
@@ -1537,18 +1638,7 @@ FROM pg-build AS neon-ext-build
|
|||||||
ARG PG_VERSION
|
ARG PG_VERSION
|
||||||
|
|
||||||
COPY pgxn/ pgxn/
|
COPY pgxn/ pgxn/
|
||||||
RUN make -j $(getconf _NPROCESSORS_ONLN) \
|
RUN make -j $(getconf _NPROCESSORS_ONLN) -C pgxn -s install-compute
|
||||||
-C pgxn/neon \
|
|
||||||
-s install && \
|
|
||||||
make -j $(getconf _NPROCESSORS_ONLN) \
|
|
||||||
-C pgxn/neon_utils \
|
|
||||||
-s install && \
|
|
||||||
make -j $(getconf _NPROCESSORS_ONLN) \
|
|
||||||
-C pgxn/neon_test_utils \
|
|
||||||
-s install && \
|
|
||||||
make -j $(getconf _NPROCESSORS_ONLN) \
|
|
||||||
-C pgxn/neon_rmgr \
|
|
||||||
-s install
|
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
#
|
#
|
||||||
@@ -1597,6 +1687,7 @@ COPY --from=pg_jsonschema-build /usr/local/pgsql/ /usr/local/pgsql/
|
|||||||
COPY --from=pg_graphql-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pg_graphql-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=pg_tiktoken-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pg_tiktoken-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=hypopg-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=hypopg-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
|
COPY --from=online_advisor-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=pg_hashids-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pg_hashids-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=rum-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=rum-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=pgtap-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pgtap-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
@@ -1615,6 +1706,7 @@ COPY --from=pg_uuidv7-build /usr/local/pgsql/ /usr/local/pgsql/
|
|||||||
COPY --from=pg_roaringbitmap-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pg_roaringbitmap-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=pg_semver-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pg_semver-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=wal2json-build /usr/local/pgsql /usr/local/pgsql
|
COPY --from=wal2json-build /usr/local/pgsql /usr/local/pgsql
|
||||||
|
COPY --from=pg-anon-pg-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=pg_ivm-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pg_ivm-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=pg_partman-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pg_partman-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
COPY --from=pg_mooncake-build /usr/local/pgsql/ /usr/local/pgsql/
|
COPY --from=pg_mooncake-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
@@ -1636,7 +1728,7 @@ FROM extensions-${EXTENSIONS} AS neon-pg-ext-build
|
|||||||
# Compile the Neon-specific `compute_ctl`, `fast_import`, and `local_proxy` binaries
|
# Compile the Neon-specific `compute_ctl`, `fast_import`, and `local_proxy` binaries
|
||||||
#
|
#
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
FROM $REPOSITORY/$IMAGE:$TAG AS compute-tools
|
FROM build-deps-with-cargo AS compute-tools
|
||||||
ARG BUILD_TAG
|
ARG BUILD_TAG
|
||||||
ENV BUILD_TAG=$BUILD_TAG
|
ENV BUILD_TAG=$BUILD_TAG
|
||||||
|
|
||||||
@@ -1646,7 +1738,7 @@ COPY --chown=nonroot . .
|
|||||||
RUN --mount=type=cache,uid=1000,target=/home/nonroot/.cargo/registry \
|
RUN --mount=type=cache,uid=1000,target=/home/nonroot/.cargo/registry \
|
||||||
--mount=type=cache,uid=1000,target=/home/nonroot/.cargo/git \
|
--mount=type=cache,uid=1000,target=/home/nonroot/.cargo/git \
|
||||||
--mount=type=cache,uid=1000,target=/home/nonroot/target \
|
--mount=type=cache,uid=1000,target=/home/nonroot/target \
|
||||||
mold -run cargo build --locked --profile release-line-debug-size-lto --bin compute_ctl --bin fast_import --bin local_proxy && \
|
cargo build --locked --profile release-line-debug-size-lto --bin compute_ctl --bin fast_import --bin local_proxy && \
|
||||||
mkdir target-bin && \
|
mkdir target-bin && \
|
||||||
cp target/release-line-debug-size-lto/compute_ctl \
|
cp target/release-line-debug-size-lto/compute_ctl \
|
||||||
target/release-line-debug-size-lto/fast_import \
|
target/release-line-debug-size-lto/fast_import \
|
||||||
@@ -1699,17 +1791,17 @@ ARG TARGETARCH
|
|||||||
RUN if [ "$TARGETARCH" = "amd64" ]; then\
|
RUN if [ "$TARGETARCH" = "amd64" ]; then\
|
||||||
postgres_exporter_sha256='59aa4a7bb0f7d361f5e05732f5ed8c03cc08f78449cef5856eadec33a627694b';\
|
postgres_exporter_sha256='59aa4a7bb0f7d361f5e05732f5ed8c03cc08f78449cef5856eadec33a627694b';\
|
||||||
pgbouncer_exporter_sha256='c9f7cf8dcff44f0472057e9bf52613d93f3ffbc381ad7547a959daa63c5e84ac';\
|
pgbouncer_exporter_sha256='c9f7cf8dcff44f0472057e9bf52613d93f3ffbc381ad7547a959daa63c5e84ac';\
|
||||||
sql_exporter_sha256='38e439732bbf6e28ca4a94d7bc3686d3fa1abdb0050773d5617a9efdb9e64d08';\
|
sql_exporter_sha256='9a41127a493e8bfebfe692bf78c7ed2872a58a3f961ee534d1b0da9ae584aaab';\
|
||||||
else\
|
else\
|
||||||
postgres_exporter_sha256='d1dedea97f56c6d965837bfd1fbb3e35a3b4a4556f8cccee8bd513d8ee086124';\
|
postgres_exporter_sha256='d1dedea97f56c6d965837bfd1fbb3e35a3b4a4556f8cccee8bd513d8ee086124';\
|
||||||
pgbouncer_exporter_sha256='217c4afd7e6492ae904055bc14fe603552cf9bac458c063407e991d68c519da3';\
|
pgbouncer_exporter_sha256='217c4afd7e6492ae904055bc14fe603552cf9bac458c063407e991d68c519da3';\
|
||||||
sql_exporter_sha256='11918b00be6e2c3a67564adfdb2414fdcbb15a5db76ea17d1d1a944237a893c6';\
|
sql_exporter_sha256='530e6afc77c043497ed965532c4c9dfa873bc2a4f0b3047fad367715c0081d6a';\
|
||||||
fi\
|
fi\
|
||||||
&& curl -sL https://github.com/prometheus-community/postgres_exporter/releases/download/v0.17.1/postgres_exporter-0.17.1.linux-${TARGETARCH}.tar.gz\
|
&& curl -sL https://github.com/prometheus-community/postgres_exporter/releases/download/v0.17.1/postgres_exporter-0.17.1.linux-${TARGETARCH}.tar.gz\
|
||||||
| tar xzf - --strip-components=1 -C.\
|
| tar xzf - --strip-components=1 -C.\
|
||||||
&& curl -sL https://github.com/prometheus-community/pgbouncer_exporter/releases/download/v0.10.2/pgbouncer_exporter-0.10.2.linux-${TARGETARCH}.tar.gz\
|
&& curl -sL https://github.com/prometheus-community/pgbouncer_exporter/releases/download/v0.10.2/pgbouncer_exporter-0.10.2.linux-${TARGETARCH}.tar.gz\
|
||||||
| tar xzf - --strip-components=1 -C.\
|
| tar xzf - --strip-components=1 -C.\
|
||||||
&& curl -sL https://github.com/burningalchemist/sql_exporter/releases/download/0.17.0/sql_exporter-0.17.0.linux-${TARGETARCH}.tar.gz\
|
&& curl -sL https://github.com/burningalchemist/sql_exporter/releases/download/0.17.3/sql_exporter-0.17.3.linux-${TARGETARCH}.tar.gz\
|
||||||
| tar xzf - --strip-components=1 -C.\
|
| tar xzf - --strip-components=1 -C.\
|
||||||
&& echo "${postgres_exporter_sha256} postgres_exporter" | sha256sum -c -\
|
&& echo "${postgres_exporter_sha256} postgres_exporter" | sha256sum -c -\
|
||||||
&& echo "${pgbouncer_exporter_sha256} pgbouncer_exporter" | sha256sum -c -\
|
&& echo "${pgbouncer_exporter_sha256} pgbouncer_exporter" | sha256sum -c -\
|
||||||
@@ -1740,10 +1832,11 @@ RUN rm /usr/local/pgsql/lib/lib*.a
|
|||||||
# Preprocess the sql_exporter configuration files
|
# Preprocess the sql_exporter configuration files
|
||||||
#
|
#
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
FROM $REPOSITORY/$IMAGE:$TAG AS sql_exporter_preprocessor
|
FROM build-deps AS sql_exporter_preprocessor
|
||||||
ARG PG_VERSION
|
ARG PG_VERSION
|
||||||
|
|
||||||
USER nonroot
|
USER nonroot
|
||||||
|
WORKDIR /home/nonroot
|
||||||
|
|
||||||
COPY --chown=nonroot compute compute
|
COPY --chown=nonroot compute compute
|
||||||
|
|
||||||
@@ -1757,12 +1850,27 @@ RUN make PG_VERSION="${PG_VERSION:?}" -C compute
|
|||||||
|
|
||||||
FROM pg-build AS extension-tests
|
FROM pg-build AS extension-tests
|
||||||
ARG PG_VERSION
|
ARG PG_VERSION
|
||||||
|
# This is required for the PostGIS test
|
||||||
|
RUN apt-get update && case $DEBIAN_VERSION in \
|
||||||
|
bullseye) \
|
||||||
|
apt-get install -y libproj19 libgdal28 time; \
|
||||||
|
;; \
|
||||||
|
bookworm) \
|
||||||
|
apt-get install -y libgdal32 libproj25 time; \
|
||||||
|
;; \
|
||||||
|
*) \
|
||||||
|
echo "Unknown Debian version ${DEBIAN_VERSION}" && exit 1 \
|
||||||
|
;; \
|
||||||
|
esac
|
||||||
|
|
||||||
COPY docker-compose/ext-src/ /ext-src/
|
COPY docker-compose/ext-src/ /ext-src/
|
||||||
|
|
||||||
COPY --from=pg-build /postgres /postgres
|
COPY --from=pg-build /postgres /postgres
|
||||||
#COPY --from=postgis-src /ext-src/ /ext-src/
|
COPY --from=postgis-build /usr/local/pgsql/ /usr/local/pgsql/
|
||||||
|
COPY --from=postgis-build /ext-src/postgis-src /ext-src/postgis-src
|
||||||
|
COPY --from=postgis-build /sfcgal/* /usr
|
||||||
COPY --from=plv8-src /ext-src/ /ext-src/
|
COPY --from=plv8-src /ext-src/ /ext-src/
|
||||||
#COPY --from=h3-pg-src /ext-src/ /ext-src/
|
COPY --from=h3-pg-src /ext-src/h3-pg-src /ext-src/h3-pg-src
|
||||||
COPY --from=postgresql-unit-src /ext-src/ /ext-src/
|
COPY --from=postgresql-unit-src /ext-src/ /ext-src/
|
||||||
COPY --from=pgvector-src /ext-src/ /ext-src/
|
COPY --from=pgvector-src /ext-src/ /ext-src/
|
||||||
COPY --from=pgjwt-src /ext-src/ /ext-src/
|
COPY --from=pgjwt-src /ext-src/ /ext-src/
|
||||||
@@ -1771,6 +1879,7 @@ COPY --from=pgjwt-src /ext-src/ /ext-src/
|
|||||||
COPY --from=pg_graphql-src /ext-src/ /ext-src/
|
COPY --from=pg_graphql-src /ext-src/ /ext-src/
|
||||||
#COPY --from=pg_tiktoken-src /ext-src/ /ext-src/
|
#COPY --from=pg_tiktoken-src /ext-src/ /ext-src/
|
||||||
COPY --from=hypopg-src /ext-src/ /ext-src/
|
COPY --from=hypopg-src /ext-src/ /ext-src/
|
||||||
|
COPY --from=online_advisor-src /ext-src/ /ext-src/
|
||||||
COPY --from=pg_hashids-src /ext-src/ /ext-src/
|
COPY --from=pg_hashids-src /ext-src/ /ext-src/
|
||||||
COPY --from=rum-src /ext-src/ /ext-src/
|
COPY --from=rum-src /ext-src/ /ext-src/
|
||||||
COPY --from=pgtap-src /ext-src/ /ext-src/
|
COPY --from=pgtap-src /ext-src/ /ext-src/
|
||||||
@@ -1800,8 +1909,9 @@ COPY compute/patches/pg_repack.patch /ext-src
|
|||||||
RUN cd /ext-src/pg_repack-src && patch -p1 </ext-src/pg_repack.patch && rm -f /ext-src/pg_repack.patch
|
RUN cd /ext-src/pg_repack-src && patch -p1 </ext-src/pg_repack.patch && rm -f /ext-src/pg_repack.patch
|
||||||
|
|
||||||
COPY --chmod=755 docker-compose/run-tests.sh /run-tests.sh
|
COPY --chmod=755 docker-compose/run-tests.sh /run-tests.sh
|
||||||
RUN apt-get update && apt-get install -y libtap-parser-sourcehandler-pgtap-perl\
|
RUN echo /usr/local/pgsql/lib > /etc/ld.so.conf.d/00-neon.conf && /sbin/ldconfig
|
||||||
&& apt clean && rm -rf /ext-src/*.tar.gz /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y libtap-parser-sourcehandler-pgtap-perl jq \
|
||||||
|
&& apt clean && rm -rf /ext-src/*.tar.gz /ext-src/*.patch /var/lib/apt/lists/*
|
||||||
ENV PATH=/usr/local/pgsql/bin:$PATH
|
ENV PATH=/usr/local/pgsql/bin:$PATH
|
||||||
ENV PGHOST=compute
|
ENV PGHOST=compute
|
||||||
ENV PGPORT=55433
|
ENV PGPORT=55433
|
||||||
@@ -1919,7 +2029,8 @@ COPY --from=sql_exporter_preprocessor --chmod=0644 /home/nonroot/compute/etc/sql
|
|||||||
COPY --from=sql_exporter_preprocessor --chmod=0644 /home/nonroot/compute/etc/neon_collector_autoscaling.yml /etc/neon_collector_autoscaling.yml
|
COPY --from=sql_exporter_preprocessor --chmod=0644 /home/nonroot/compute/etc/neon_collector_autoscaling.yml /etc/neon_collector_autoscaling.yml
|
||||||
|
|
||||||
# Make the libraries we built available
|
# Make the libraries we built available
|
||||||
RUN echo '/usr/local/lib' >> /etc/ld.so.conf && /sbin/ldconfig
|
COPY --chmod=0666 compute/etc/ld.so.conf.d/00-neon.conf /etc/ld.so.conf.d/00-neon.conf
|
||||||
|
RUN /sbin/ldconfig
|
||||||
|
|
||||||
# rsyslog config permissions
|
# rsyslog config permissions
|
||||||
# directory for rsyslogd pid file
|
# directory for rsyslogd pid file
|
||||||
|
|||||||
1
compute/etc/ld.so.conf.d/00-neon.conf
Normal file
1
compute/etc/ld.so.conf.d/00-neon.conf
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/usr/local/lib
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
import 'sql_exporter/getpage_prefetch_requests_total.libsonnet',
|
import 'sql_exporter/getpage_prefetch_requests_total.libsonnet',
|
||||||
import 'sql_exporter/getpage_prefetches_buffered.libsonnet',
|
import 'sql_exporter/getpage_prefetches_buffered.libsonnet',
|
||||||
import 'sql_exporter/getpage_sync_requests_total.libsonnet',
|
import 'sql_exporter/getpage_sync_requests_total.libsonnet',
|
||||||
|
import 'sql_exporter/compute_getpage_stuck_requests_total.libsonnet',
|
||||||
|
import 'sql_exporter/compute_getpage_max_inflight_stuck_time_ms.libsonnet',
|
||||||
import 'sql_exporter/getpage_wait_seconds_bucket.libsonnet',
|
import 'sql_exporter/getpage_wait_seconds_bucket.libsonnet',
|
||||||
import 'sql_exporter/getpage_wait_seconds_count.libsonnet',
|
import 'sql_exporter/getpage_wait_seconds_count.libsonnet',
|
||||||
import 'sql_exporter/getpage_wait_seconds_sum.libsonnet',
|
import 'sql_exporter/getpage_wait_seconds_sum.libsonnet',
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ unix_socket_dir=/tmp/
|
|||||||
unix_socket_mode=0777
|
unix_socket_mode=0777
|
||||||
; required for pgbouncer_exporter
|
; required for pgbouncer_exporter
|
||||||
ignore_startup_parameters=extra_float_digits
|
ignore_startup_parameters=extra_float_digits
|
||||||
|
; pidfile for graceful termination
|
||||||
|
pidfile=/tmp/pgbouncer.pid
|
||||||
|
|
||||||
;; Disable connection logging. It produces a lot of logs that no one looks at,
|
;; Disable connection logging. It produces a lot of logs that no one looks at,
|
||||||
;; and we can get similar log entries from the proxy too. We had incidents in
|
;; and we can get similar log entries from the proxy too. We had incidents in
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
metric_name: 'compute_getpage_max_inflight_stuck_time_ms',
|
||||||
|
type: 'gauge',
|
||||||
|
help: 'Max wait time for stuck requests among all backends. Includes only active stuck requests, terminated or disconnected ones are not accounted for',
|
||||||
|
values: [
|
||||||
|
'compute_getpage_max_inflight_stuck_time_ms',
|
||||||
|
],
|
||||||
|
query_ref: 'neon_perf_counters',
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
metric_name: 'compute_getpage_stuck_requests_total',
|
||||||
|
type: 'counter',
|
||||||
|
help: 'Total number of Getpage requests left without an answer for more than pageserver_response_log_timeout but less than pageserver_response_disconnect_timeout',
|
||||||
|
values: [
|
||||||
|
'compute_getpage_stuck_requests_total',
|
||||||
|
],
|
||||||
|
query_ref: 'neon_perf_counters',
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ SELECT d.* FROM pg_catalog.jsonb_to_record((SELECT jb FROM c)) AS d(
|
|||||||
getpage_wait_seconds_sum numeric,
|
getpage_wait_seconds_sum numeric,
|
||||||
getpage_prefetch_requests_total numeric,
|
getpage_prefetch_requests_total numeric,
|
||||||
getpage_sync_requests_total numeric,
|
getpage_sync_requests_total numeric,
|
||||||
|
compute_getpage_stuck_requests_total numeric,
|
||||||
|
compute_getpage_max_inflight_stuck_time_ms numeric,
|
||||||
getpage_prefetch_misses_total numeric,
|
getpage_prefetch_misses_total numeric,
|
||||||
getpage_prefetch_discards_total numeric,
|
getpage_prefetch_discards_total numeric,
|
||||||
getpage_prefetches_buffered numeric,
|
getpage_prefetches_buffered numeric,
|
||||||
|
|||||||
209
compute/manifest.schema.json
Normal file
209
compute/manifest.schema.json
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"title": "Neon Compute Manifest Schema",
|
||||||
|
"description": "Schema for Neon compute node configuration manifest",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"pg_settings": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"common": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"client_connection_check_interval": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Check for client disconnection interval in milliseconds"
|
||||||
|
},
|
||||||
|
"effective_io_concurrency": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Effective IO concurrency setting"
|
||||||
|
},
|
||||||
|
"fsync": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off"],
|
||||||
|
"description": "Whether to force fsync to disk"
|
||||||
|
},
|
||||||
|
"hot_standby": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off"],
|
||||||
|
"description": "Whether hot standby is enabled"
|
||||||
|
},
|
||||||
|
"idle_in_transaction_session_timeout": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Timeout for idle transactions in milliseconds"
|
||||||
|
},
|
||||||
|
"listen_addresses": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Addresses to listen on"
|
||||||
|
},
|
||||||
|
"log_connections": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off"],
|
||||||
|
"description": "Whether to log connections"
|
||||||
|
},
|
||||||
|
"log_disconnections": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off"],
|
||||||
|
"description": "Whether to log disconnections"
|
||||||
|
},
|
||||||
|
"log_temp_files": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Size threshold for logging temporary files in KB"
|
||||||
|
},
|
||||||
|
"log_error_verbosity": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["terse", "verbose", "default"],
|
||||||
|
"description": "Error logging verbosity level"
|
||||||
|
},
|
||||||
|
"log_min_error_statement": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Minimum error level for statement logging"
|
||||||
|
},
|
||||||
|
"maintenance_io_concurrency": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Maintenance IO concurrency setting"
|
||||||
|
},
|
||||||
|
"max_connections": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Maximum number of connections"
|
||||||
|
},
|
||||||
|
"max_replication_flush_lag": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Maximum replication flush lag"
|
||||||
|
},
|
||||||
|
"max_replication_slots": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Maximum number of replication slots"
|
||||||
|
},
|
||||||
|
"max_replication_write_lag": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Maximum replication write lag"
|
||||||
|
},
|
||||||
|
"max_wal_senders": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Maximum number of WAL senders"
|
||||||
|
},
|
||||||
|
"max_wal_size": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Maximum WAL size"
|
||||||
|
},
|
||||||
|
"neon.unstable_extensions": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "List of unstable extensions"
|
||||||
|
},
|
||||||
|
"neon.protocol_version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Neon protocol version"
|
||||||
|
},
|
||||||
|
"password_encryption": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Password encryption method"
|
||||||
|
},
|
||||||
|
"restart_after_crash": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off"],
|
||||||
|
"description": "Whether to restart after crash"
|
||||||
|
},
|
||||||
|
"superuser_reserved_connections": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Number of reserved connections for superuser"
|
||||||
|
},
|
||||||
|
"synchronous_standby_names": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Names of synchronous standby servers"
|
||||||
|
},
|
||||||
|
"wal_keep_size": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "WAL keep size"
|
||||||
|
},
|
||||||
|
"wal_level": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "WAL level"
|
||||||
|
},
|
||||||
|
"wal_log_hints": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off"],
|
||||||
|
"description": "Whether to log hints in WAL"
|
||||||
|
},
|
||||||
|
"wal_sender_timeout": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "WAL sender timeout in milliseconds"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"client_connection_check_interval",
|
||||||
|
"effective_io_concurrency",
|
||||||
|
"fsync",
|
||||||
|
"hot_standby",
|
||||||
|
"idle_in_transaction_session_timeout",
|
||||||
|
"listen_addresses",
|
||||||
|
"log_connections",
|
||||||
|
"log_disconnections",
|
||||||
|
"log_temp_files",
|
||||||
|
"log_error_verbosity",
|
||||||
|
"log_min_error_statement",
|
||||||
|
"maintenance_io_concurrency",
|
||||||
|
"max_connections",
|
||||||
|
"max_replication_flush_lag",
|
||||||
|
"max_replication_slots",
|
||||||
|
"max_replication_write_lag",
|
||||||
|
"max_wal_senders",
|
||||||
|
"max_wal_size",
|
||||||
|
"neon.unstable_extensions",
|
||||||
|
"neon.protocol_version",
|
||||||
|
"password_encryption",
|
||||||
|
"restart_after_crash",
|
||||||
|
"superuser_reserved_connections",
|
||||||
|
"synchronous_standby_names",
|
||||||
|
"wal_keep_size",
|
||||||
|
"wal_level",
|
||||||
|
"wal_log_hints",
|
||||||
|
"wal_sender_timeout"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"replica": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"hot_standby": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off"],
|
||||||
|
"description": "Whether hot standby is enabled for replicas"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["hot_standby"]
|
||||||
|
},
|
||||||
|
"per_version": {
|
||||||
|
"type": "object",
|
||||||
|
"patternProperties": {
|
||||||
|
"^1[4-7]$": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"common": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"io_combine_limit": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "IO combine limit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"replica": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"recovery_prefetch": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off"],
|
||||||
|
"description": "Whether to enable recovery prefetch for PostgreSQL replicas"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["common", "replica", "per_version"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["pg_settings"]
|
||||||
|
}
|
||||||
121
compute/manifest.yaml
Normal file
121
compute/manifest.yaml
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
pg_settings:
|
||||||
|
# Common settings for primaries and replicas of all versions.
|
||||||
|
common:
|
||||||
|
# Check for client disconnection every 1 minute. By default, Postgres will detect the
|
||||||
|
# loss of the connection only at the next interaction with the socket, when it waits
|
||||||
|
# for, receives or sends data, so it will likely waste resources till the end of the
|
||||||
|
# query execution. There should be no drawbacks in setting this for everyone, so enable
|
||||||
|
# it by default. If anyone will complain, we can allow editing it.
|
||||||
|
# https://www.postgresql.org/docs/16/runtime-config-connection.html#GUC-CLIENT-CONNECTION-CHECK-INTERVAL
|
||||||
|
client_connection_check_interval: "60000" # 1 minute
|
||||||
|
# ---- IO ----
|
||||||
|
effective_io_concurrency: "20"
|
||||||
|
maintenance_io_concurrency: "100"
|
||||||
|
fsync: "off"
|
||||||
|
hot_standby: "off"
|
||||||
|
# We allow users to change this if needed, but by default we
|
||||||
|
# just don't want to see long-lasting idle transactions, as they
|
||||||
|
# prevent activity monitor from suspending projects.
|
||||||
|
idle_in_transaction_session_timeout: "300000" # 5 minutes
|
||||||
|
listen_addresses: "*"
|
||||||
|
# --- LOGGING ---- helps investigations
|
||||||
|
log_connections: "on"
|
||||||
|
log_disconnections: "on"
|
||||||
|
# 1GB, unit is KB
|
||||||
|
log_temp_files: "1048576"
|
||||||
|
# Disable dumping customer data to logs, both to increase data privacy
|
||||||
|
# and to reduce the amount the logs.
|
||||||
|
log_error_verbosity: "terse"
|
||||||
|
log_min_error_statement: "panic"
|
||||||
|
max_connections: "100"
|
||||||
|
# --- WAL ---
|
||||||
|
# - flush lag is the max amount of WAL that has been generated but not yet stored
|
||||||
|
# to disk in the page server. A smaller value means less delay after a pageserver
|
||||||
|
# restart, but if you set it too small you might again need to slow down writes if the
|
||||||
|
# pageserver cannot flush incoming WAL to disk fast enough. This must be larger
|
||||||
|
# than the pageserver's checkpoint interval, currently 1 GB! Otherwise you get a
|
||||||
|
# a deadlock where the compute node refuses to generate more WAL before the
|
||||||
|
# old WAL has been uploaded to S3, but the pageserver is waiting for more WAL
|
||||||
|
# to be generated before it is uploaded to S3.
|
||||||
|
max_replication_flush_lag: "10GB"
|
||||||
|
max_replication_slots: "10"
|
||||||
|
# Backpressure configuration:
|
||||||
|
# - write lag is the max amount of WAL that has been generated by Postgres but not yet
|
||||||
|
# processed by the page server. Making this smaller reduces the worst case latency
|
||||||
|
# of a GetPage request, if you request a page that was recently modified. On the other
|
||||||
|
# hand, if this is too small, the compute node might need to wait on a write if there is a
|
||||||
|
# hiccup in the network or page server so that the page server has temporarily fallen
|
||||||
|
# behind.
|
||||||
|
#
|
||||||
|
# Previously it was set to 500 MB, but it caused compute being unresponsive under load
|
||||||
|
# https://github.com/neondatabase/neon/issues/2028
|
||||||
|
max_replication_write_lag: "500MB"
|
||||||
|
max_wal_senders: "10"
|
||||||
|
# A Postgres checkpoint is cheap in storage, as doesn't involve any significant amount
|
||||||
|
# of real I/O. Only the SLRU buffers and some other small files are flushed to disk.
|
||||||
|
# However, as long as we have full_page_writes=on, page updates after a checkpoint
|
||||||
|
# include full-page images which bloats the WAL. So may want to bump max_wal_size to
|
||||||
|
# reduce the WAL bloating, but at the same it will increase pg_wal directory size on
|
||||||
|
# compute and can lead to out of disk error on k8s nodes.
|
||||||
|
max_wal_size: "1024"
|
||||||
|
wal_keep_size: "0"
|
||||||
|
wal_level: "replica"
|
||||||
|
# Reduce amount of WAL generated by default.
|
||||||
|
wal_log_hints: "off"
|
||||||
|
# - without wal_sender_timeout set we don't get feedback messages,
|
||||||
|
# required for backpressure.
|
||||||
|
wal_sender_timeout: "10000"
|
||||||
|
# We have some experimental extensions, which we don't want users to install unconsciously.
|
||||||
|
# To install them, users would need to set the `neon.allow_unstable_extensions` setting.
|
||||||
|
# There are two of them currently:
|
||||||
|
# - `pgrag` - https://github.com/neondatabase-labs/pgrag - extension is actually called just `rag`,
|
||||||
|
# and two dependencies:
|
||||||
|
# - `rag_bge_small_en_v15`
|
||||||
|
# - `rag_jina_reranker_v1_tiny_en`
|
||||||
|
# - `pg_mooncake` - https://github.com/Mooncake-Labs/pg_mooncake/
|
||||||
|
neon.unstable_extensions: "rag,rag_bge_small_en_v15,rag_jina_reranker_v1_tiny_en,pg_mooncake,anon"
|
||||||
|
neon.protocol_version: "3"
|
||||||
|
password_encryption: "scram-sha-256"
|
||||||
|
# This is important to prevent Postgres from trying to perform
|
||||||
|
# a local WAL redo after backend crash. It should exit and let
|
||||||
|
# the systemd or k8s to do a fresh startup with compute_ctl.
|
||||||
|
restart_after_crash: "off"
|
||||||
|
# By default 3. We have the following persistent connections in the VM:
|
||||||
|
# * compute_activity_monitor (from compute_ctl)
|
||||||
|
# * postgres-exporter (metrics collector; it has 2 connections)
|
||||||
|
# * sql_exporter (metrics collector; we have 2 instances [1 for us & users; 1 for autoscaling])
|
||||||
|
# * vm-monitor (to query & change file cache size)
|
||||||
|
# i.e. total of 6. Let's reserve 7, so there's still at least one left over.
|
||||||
|
superuser_reserved_connections: "7"
|
||||||
|
synchronous_standby_names: "walproposer"
|
||||||
|
|
||||||
|
replica:
|
||||||
|
hot_standby: "on"
|
||||||
|
|
||||||
|
per_version:
|
||||||
|
17:
|
||||||
|
common:
|
||||||
|
# PostgreSQL 17 has a new IO system called "read stream", which can combine IOs up to some
|
||||||
|
# size. It still has some issues with readahead, though, so we default to disabled/
|
||||||
|
# "no combining of IOs" to make sure we get the maximum prefetch depth.
|
||||||
|
# See also: https://github.com/neondatabase/neon/pull/9860
|
||||||
|
io_combine_limit: "1"
|
||||||
|
replica:
|
||||||
|
# prefetching of blocks referenced in WAL doesn't make sense for us
|
||||||
|
# Neon hot standby ignores pages that are not in the shared_buffers
|
||||||
|
recovery_prefetch: "off"
|
||||||
|
16:
|
||||||
|
common: {}
|
||||||
|
replica:
|
||||||
|
# prefetching of blocks referenced in WAL doesn't make sense for us
|
||||||
|
# Neon hot standby ignores pages that are not in the shared_buffers
|
||||||
|
recovery_prefetch: "off"
|
||||||
|
15:
|
||||||
|
common: {}
|
||||||
|
replica:
|
||||||
|
# prefetching of blocks referenced in WAL doesn't make sense for us
|
||||||
|
# Neon hot standby ignores pages that are not in the shared_buffers
|
||||||
|
recovery_prefetch: "off"
|
||||||
|
14:
|
||||||
|
common: {}
|
||||||
|
replica: {}
|
||||||
37
compute/package-lock.json
generated
Normal file
37
compute/package-lock.json
generated
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "neon-compute",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "neon-compute",
|
||||||
|
"dependencies": {
|
||||||
|
"@sourcemeta/jsonschema": "9.3.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sourcemeta/jsonschema": {
|
||||||
|
"version": "9.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sourcemeta/jsonschema/-/jsonschema-9.3.4.tgz",
|
||||||
|
"integrity": "sha512-hkujfkZAIGXUs4U//We9faZW8LZ4/H9LqagRYsFSulH/VLcKPNhZyCTGg7AhORuzm27zqENvKpnX4g2FzudYFw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64",
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "AGPL-3.0",
|
||||||
|
"os": [
|
||||||
|
"darwin",
|
||||||
|
"linux",
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"jsonschema": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sourcemeta"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
compute/package.json
Normal file
7
compute/package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "neon-compute",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@sourcemeta/jsonschema": "9.3.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
129
compute/patches/anon_v2.patch
Normal file
129
compute/patches/anon_v2.patch
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
diff --git a/sql/anon.sql b/sql/anon.sql
|
||||||
|
index 0cdc769..f6cc950 100644
|
||||||
|
--- a/sql/anon.sql
|
||||||
|
+++ b/sql/anon.sql
|
||||||
|
@@ -1141,3 +1141,8 @@ $$
|
||||||
|
-- TODO : https://en.wikipedia.org/wiki/L-diversity
|
||||||
|
|
||||||
|
-- TODO : https://en.wikipedia.org/wiki/T-closeness
|
||||||
|
+
|
||||||
|
+-- NEON Patches
|
||||||
|
+
|
||||||
|
+GRANT ALL ON SCHEMA anon to neon_superuser;
|
||||||
|
+GRANT ALL ON ALL TABLES IN SCHEMA anon TO neon_superuser;
|
||||||
|
diff --git a/sql/init.sql b/sql/init.sql
|
||||||
|
index 7da6553..9b6164b 100644
|
||||||
|
--- a/sql/init.sql
|
||||||
|
+++ b/sql/init.sql
|
||||||
|
@@ -74,50 +74,49 @@ $$
|
||||||
|
|
||||||
|
SECURITY LABEL FOR anon ON FUNCTION anon.load_csv IS 'UNTRUSTED';
|
||||||
|
|
||||||
|
--- load fake data from a given path
|
||||||
|
-CREATE OR REPLACE FUNCTION anon.init(
|
||||||
|
- datapath TEXT
|
||||||
|
-)
|
||||||
|
+CREATE OR REPLACE FUNCTION anon.load_fake_data()
|
||||||
|
RETURNS BOOLEAN
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
- datapath_check TEXT;
|
||||||
|
success BOOLEAN;
|
||||||
|
+ sharedir TEXT;
|
||||||
|
+ datapath TEXT;
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
- IF anon.is_initialized() THEN
|
||||||
|
- RAISE NOTICE 'The anon extension is already initialized.';
|
||||||
|
- RETURN TRUE;
|
||||||
|
- END IF;
|
||||||
|
+ datapath := '/extension/anon/';
|
||||||
|
+ -- find the local extension directory
|
||||||
|
+ SELECT setting INTO sharedir
|
||||||
|
+ FROM pg_catalog.pg_config
|
||||||
|
+ WHERE name = 'SHAREDIR';
|
||||||
|
|
||||||
|
SELECT bool_or(results) INTO success
|
||||||
|
FROM unnest(array[
|
||||||
|
- anon.load_csv('anon.identifiers_category',datapath||'/identifiers_category.csv'),
|
||||||
|
- anon.load_csv('anon.identifier',datapath ||'/identifier.csv'),
|
||||||
|
- anon.load_csv('anon.address',datapath ||'/address.csv'),
|
||||||
|
- anon.load_csv('anon.city',datapath ||'/city.csv'),
|
||||||
|
- anon.load_csv('anon.company',datapath ||'/company.csv'),
|
||||||
|
- anon.load_csv('anon.country',datapath ||'/country.csv'),
|
||||||
|
- anon.load_csv('anon.email', datapath ||'/email.csv'),
|
||||||
|
- anon.load_csv('anon.first_name',datapath ||'/first_name.csv'),
|
||||||
|
- anon.load_csv('anon.iban',datapath ||'/iban.csv'),
|
||||||
|
- anon.load_csv('anon.last_name',datapath ||'/last_name.csv'),
|
||||||
|
- anon.load_csv('anon.postcode',datapath ||'/postcode.csv'),
|
||||||
|
- anon.load_csv('anon.siret',datapath ||'/siret.csv'),
|
||||||
|
- anon.load_csv('anon.lorem_ipsum',datapath ||'/lorem_ipsum.csv')
|
||||||
|
+ anon.load_csv('anon.identifiers_category',sharedir || datapath || '/identifiers_category.csv'),
|
||||||
|
+ anon.load_csv('anon.identifier',sharedir || datapath || '/identifier.csv'),
|
||||||
|
+ anon.load_csv('anon.address',sharedir || datapath || '/address.csv'),
|
||||||
|
+ anon.load_csv('anon.city',sharedir || datapath || '/city.csv'),
|
||||||
|
+ anon.load_csv('anon.company',sharedir || datapath || '/company.csv'),
|
||||||
|
+ anon.load_csv('anon.country',sharedir || datapath || '/country.csv'),
|
||||||
|
+ anon.load_csv('anon.email', sharedir || datapath || '/email.csv'),
|
||||||
|
+ anon.load_csv('anon.first_name',sharedir || datapath || '/first_name.csv'),
|
||||||
|
+ anon.load_csv('anon.iban',sharedir || datapath || '/iban.csv'),
|
||||||
|
+ anon.load_csv('anon.last_name',sharedir || datapath || '/last_name.csv'),
|
||||||
|
+ anon.load_csv('anon.postcode',sharedir || datapath || '/postcode.csv'),
|
||||||
|
+ anon.load_csv('anon.siret',sharedir || datapath || '/siret.csv'),
|
||||||
|
+ anon.load_csv('anon.lorem_ipsum',sharedir || datapath || '/lorem_ipsum.csv')
|
||||||
|
]) results;
|
||||||
|
RETURN success;
|
||||||
|
-
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
- LANGUAGE PLPGSQL
|
||||||
|
+ LANGUAGE plpgsql
|
||||||
|
VOLATILE
|
||||||
|
RETURNS NULL ON NULL INPUT
|
||||||
|
- PARALLEL UNSAFE -- because load_csv is unsafe
|
||||||
|
- SECURITY INVOKER
|
||||||
|
+ PARALLEL UNSAFE -- because of the EXCEPTION
|
||||||
|
+ SECURITY DEFINER
|
||||||
|
SET search_path=''
|
||||||
|
;
|
||||||
|
-SECURITY LABEL FOR anon ON FUNCTION anon.init(TEXT) IS 'UNTRUSTED';
|
||||||
|
+
|
||||||
|
+SECURITY LABEL FOR anon ON FUNCTION anon.load_fake_data IS 'UNTRUSTED';
|
||||||
|
|
||||||
|
-- People tend to forget the anon.init() step
|
||||||
|
-- This is a friendly notice for them
|
||||||
|
@@ -144,7 +143,7 @@ SECURITY LABEL FOR anon ON FUNCTION anon.notice_if_not_init IS 'UNTRUSTED';
|
||||||
|
CREATE OR REPLACE FUNCTION anon.load(TEXT)
|
||||||
|
RETURNS BOOLEAN AS
|
||||||
|
$$
|
||||||
|
- SELECT anon.init($1);
|
||||||
|
+ SELECT anon.init();
|
||||||
|
$$
|
||||||
|
LANGUAGE SQL
|
||||||
|
VOLATILE
|
||||||
|
@@ -159,16 +158,16 @@ SECURITY LABEL FOR anon ON FUNCTION anon.load(TEXT) IS 'UNTRUSTED';
|
||||||
|
CREATE OR REPLACE FUNCTION anon.init()
|
||||||
|
RETURNS BOOLEAN
|
||||||
|
AS $$
|
||||||
|
- WITH conf AS (
|
||||||
|
- -- find the local extension directory
|
||||||
|
- SELECT setting AS sharedir
|
||||||
|
- FROM pg_catalog.pg_config
|
||||||
|
- WHERE name = 'SHAREDIR'
|
||||||
|
- )
|
||||||
|
- SELECT anon.init(conf.sharedir || '/extension/anon/')
|
||||||
|
- FROM conf;
|
||||||
|
+BEGIN
|
||||||
|
+ IF anon.is_initialized() THEN
|
||||||
|
+ RAISE NOTICE 'The anon extension is already initialized.';
|
||||||
|
+ RETURN TRUE;
|
||||||
|
+ END IF;
|
||||||
|
+
|
||||||
|
+ RETURN anon.load_fake_data();
|
||||||
|
+END;
|
||||||
|
$$
|
||||||
|
- LANGUAGE SQL
|
||||||
|
+ LANGUAGE plpgsql
|
||||||
|
VOLATILE
|
||||||
|
PARALLEL UNSAFE -- because init is unsafe
|
||||||
|
SECURITY INVOKER
|
||||||
15
compute/patches/onnxruntime.patch
Normal file
15
compute/patches/onnxruntime.patch
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
diff --git a/cmake/deps.txt b/cmake/deps.txt
|
||||||
|
index d213b09034..229de2ebf0 100644
|
||||||
|
--- a/cmake/deps.txt
|
||||||
|
+++ b/cmake/deps.txt
|
||||||
|
@@ -22,7 +22,9 @@ dlpack;https://github.com/dmlc/dlpack/archive/refs/tags/v0.6.zip;4d565dd2e5b3132
|
||||||
|
# it contains changes on top of 3.4.0 which are required to fix build issues.
|
||||||
|
# Until the 3.4.1 release this is the best option we have.
|
||||||
|
# Issue link: https://gitlab.com/libeigen/eigen/-/issues/2744
|
||||||
|
-eigen;https://gitlab.com/libeigen/eigen/-/archive/e7248b26a1ed53fa030c5c459f7ea095dfd276ac/eigen-e7248b26a1ed53fa030c5c459f7ea095dfd276ac.zip;be8be39fdbc6e60e94fa7870b280707069b5b81a
|
||||||
|
+# Moved to github mirror to avoid gitlab issues.Add commentMore actions
|
||||||
|
+# Issue link: https://github.com/bazelbuild/bazel-central-registry/issues/4355
|
||||||
|
+eigen;https://github.com/eigen-mirror/eigen/archive/e7248b26a1ed53fa030c5c459f7ea095dfd276ac/eigen-e7248b26a1ed53fa030c5c459f7ea095dfd276ac.zip;61418a349000ba7744a3ad03cf5071f22ebf860a
|
||||||
|
flatbuffers;https://github.com/google/flatbuffers/archive/refs/tags/v23.5.26.zip;59422c3b5e573dd192fead2834d25951f1c1670c
|
||||||
|
fp16;https://github.com/Maratyszcza/FP16/archive/0a92994d729ff76a58f692d3028ca1b64b145d91.zip;b985f6985a05a1c03ff1bb71190f66d8f98a1494
|
||||||
|
fxdiv;https://github.com/Maratyszcza/FXdiv/archive/63058eff77e11aa15bf531df5dd34395ec3017c8.zip;a5658f4036402dbca7cebee32be57fb8149811e1
|
||||||
@@ -7,7 +7,7 @@ index 255e616..1c6edb7 100644
|
|||||||
RelationGetRelationName(index));
|
RelationGetRelationName(index));
|
||||||
|
|
||||||
+#ifdef NEON_SMGR
|
+#ifdef NEON_SMGR
|
||||||
+ smgr_start_unlogged_build(index->rd_smgr);
|
+ smgr_start_unlogged_build(RelationGetSmgr(index));
|
||||||
+#endif
|
+#endif
|
||||||
+
|
+
|
||||||
initRumState(&buildstate.rumstate, index);
|
initRumState(&buildstate.rumstate, index);
|
||||||
@@ -18,7 +18,7 @@ index 255e616..1c6edb7 100644
|
|||||||
rumUpdateStats(index, &buildstate.buildStats, buildstate.rumstate.isBuild);
|
rumUpdateStats(index, &buildstate.buildStats, buildstate.rumstate.isBuild);
|
||||||
|
|
||||||
+#ifdef NEON_SMGR
|
+#ifdef NEON_SMGR
|
||||||
+ smgr_finish_unlogged_build_phase_1(index->rd_smgr);
|
+ smgr_finish_unlogged_build_phase_1(RelationGetSmgr(index));
|
||||||
+#endif
|
+#endif
|
||||||
+
|
+
|
||||||
/*
|
/*
|
||||||
@@ -29,7 +29,7 @@ index 255e616..1c6edb7 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
+#ifdef NEON_SMGR
|
+#ifdef NEON_SMGR
|
||||||
+ smgr_end_unlogged_build(index->rd_smgr);
|
+ smgr_end_unlogged_build(RelationGetSmgr(index));
|
||||||
+#endif
|
+#endif
|
||||||
+
|
+
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ commands:
|
|||||||
- name: local_proxy
|
- name: local_proxy
|
||||||
user: postgres
|
user: postgres
|
||||||
sysvInitAction: respawn
|
sysvInitAction: respawn
|
||||||
shell: 'RUST_LOG="info,proxy::serverless::sql_over_http=warn" /usr/local/bin/local_proxy --config-path /etc/local_proxy/config.json --pid-path /etc/local_proxy/pid --http 0.0.0.0:10432'
|
shell: 'RUST_LOG="error" /usr/local/bin/local_proxy --config-path /etc/local_proxy/config.json --pid-path /etc/local_proxy/pid --http 0.0.0.0:10432'
|
||||||
- name: postgres-exporter
|
- name: postgres-exporter
|
||||||
user: nobody
|
user: nobody
|
||||||
sysvInitAction: respawn
|
sysvInitAction: respawn
|
||||||
shell: 'DATA_SOURCE_NAME="user=cloud_admin sslmode=disable dbname=postgres application_name=postgres-exporter" /bin/postgres_exporter --config.file=/etc/postgres_exporter.yml'
|
shell: 'DATA_SOURCE_NAME="user=cloud_admin sslmode=disable dbname=postgres application_name=postgres-exporter pgaudit.log=none" /bin/postgres_exporter --config.file=/etc/postgres_exporter.yml'
|
||||||
- name: pgbouncer-exporter
|
- name: pgbouncer-exporter
|
||||||
user: postgres
|
user: postgres
|
||||||
sysvInitAction: respawn
|
sysvInitAction: respawn
|
||||||
@@ -59,7 +59,7 @@ files:
|
|||||||
# the rules use ALL as the hostname. Avoid the pointless lookups and the "unable to
|
# the rules use ALL as the hostname. Avoid the pointless lookups and the "unable to
|
||||||
# resolve host" log messages that they generate.
|
# resolve host" log messages that they generate.
|
||||||
Defaults !fqdn
|
Defaults !fqdn
|
||||||
|
|
||||||
# Allow postgres user (which is what compute_ctl runs as) to run /neonvm/bin/resize-swap
|
# Allow postgres user (which is what compute_ctl runs as) to run /neonvm/bin/resize-swap
|
||||||
# and /neonvm/bin/set-disk-quota as root without requiring entering a password (NOPASSWD),
|
# and /neonvm/bin/set-disk-quota as root without requiring entering a password (NOPASSWD),
|
||||||
# regardless of hostname (ALL)
|
# regardless of hostname (ALL)
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ commands:
|
|||||||
- name: local_proxy
|
- name: local_proxy
|
||||||
user: postgres
|
user: postgres
|
||||||
sysvInitAction: respawn
|
sysvInitAction: respawn
|
||||||
shell: 'RUST_LOG="info,proxy::serverless::sql_over_http=warn" /usr/local/bin/local_proxy --config-path /etc/local_proxy/config.json --pid-path /etc/local_proxy/pid --http 0.0.0.0:10432'
|
shell: 'RUST_LOG="error" /usr/local/bin/local_proxy --config-path /etc/local_proxy/config.json --pid-path /etc/local_proxy/pid --http 0.0.0.0:10432'
|
||||||
- name: postgres-exporter
|
- name: postgres-exporter
|
||||||
user: nobody
|
user: nobody
|
||||||
sysvInitAction: respawn
|
sysvInitAction: respawn
|
||||||
shell: 'DATA_SOURCE_NAME="user=cloud_admin sslmode=disable dbname=postgres application_name=postgres-exporter" /bin/postgres_exporter --config.file=/etc/postgres_exporter.yml'
|
shell: 'DATA_SOURCE_NAME="user=cloud_admin sslmode=disable dbname=postgres application_name=postgres-exporter pgaudit.log=none" /bin/postgres_exporter --config.file=/etc/postgres_exporter.yml'
|
||||||
- name: pgbouncer-exporter
|
- name: pgbouncer-exporter
|
||||||
user: postgres
|
user: postgres
|
||||||
sysvInitAction: respawn
|
sysvInitAction: respawn
|
||||||
@@ -59,7 +59,7 @@ files:
|
|||||||
# the rules use ALL as the hostname. Avoid the pointless lookups and the "unable to
|
# the rules use ALL as the hostname. Avoid the pointless lookups and the "unable to
|
||||||
# resolve host" log messages that they generate.
|
# resolve host" log messages that they generate.
|
||||||
Defaults !fqdn
|
Defaults !fqdn
|
||||||
|
|
||||||
# Allow postgres user (which is what compute_ctl runs as) to run /neonvm/bin/resize-swap
|
# Allow postgres user (which is what compute_ctl runs as) to run /neonvm/bin/resize-swap
|
||||||
# and /neonvm/bin/set-disk-quota as root without requiring entering a password (NOPASSWD),
|
# and /neonvm/bin/set-disk-quota as root without requiring entering a password (NOPASSWD),
|
||||||
# regardless of hostname (ALL)
|
# regardless of hostname (ALL)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ default = []
|
|||||||
testing = ["fail/failpoints"]
|
testing = ["fail/failpoints"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-compression.workspace = true
|
||||||
base64.workspace = true
|
base64.workspace = true
|
||||||
aws-config.workspace = true
|
aws-config.workspace = true
|
||||||
aws-sdk-s3.workspace = true
|
aws-sdk-s3.workspace = true
|
||||||
@@ -27,6 +28,7 @@ flate2.workspace = true
|
|||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
http.workspace = true
|
http.workspace = true
|
||||||
indexmap.workspace = true
|
indexmap.workspace = true
|
||||||
|
itertools.workspace = true
|
||||||
jsonwebtoken.workspace = true
|
jsonwebtoken.workspace = true
|
||||||
metrics.workspace = true
|
metrics.workspace = true
|
||||||
nix.workspace = true
|
nix.workspace = true
|
||||||
@@ -36,6 +38,7 @@ once_cell.workspace = true
|
|||||||
opentelemetry.workspace = true
|
opentelemetry.workspace = true
|
||||||
opentelemetry_sdk.workspace = true
|
opentelemetry_sdk.workspace = true
|
||||||
p256 = { version = "0.13", features = ["pem"] }
|
p256 = { version = "0.13", features = ["pem"] }
|
||||||
|
pageserver_page_api.workspace = true
|
||||||
postgres.workspace = true
|
postgres.workspace = true
|
||||||
regex.workspace = true
|
regex.workspace = true
|
||||||
reqwest = { workspace = true, features = ["json"] }
|
reqwest = { workspace = true, features = ["json"] }
|
||||||
@@ -44,7 +47,6 @@ serde.workspace = true
|
|||||||
serde_with.workspace = true
|
serde_with.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
signal-hook.workspace = true
|
signal-hook.workspace = true
|
||||||
spki = { version = "0.7.3", features = ["std"] }
|
|
||||||
tar.workspace = true
|
tar.workspace = true
|
||||||
tower.workspace = true
|
tower.workspace = true
|
||||||
tower-http.workspace = true
|
tower-http.workspace = true
|
||||||
@@ -52,6 +54,7 @@ tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
|
|||||||
tokio-postgres.workspace = true
|
tokio-postgres.workspace = true
|
||||||
tokio-util.workspace = true
|
tokio-util.workspace = true
|
||||||
tokio-stream.workspace = true
|
tokio-stream.workspace = true
|
||||||
|
tonic.workspace = true
|
||||||
tower-otel.workspace = true
|
tower-otel.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-opentelemetry.workspace = true
|
tracing-opentelemetry.workspace = true
|
||||||
@@ -63,6 +66,7 @@ uuid.workspace = true
|
|||||||
walkdir.workspace = true
|
walkdir.workspace = true
|
||||||
x509-cert.workspace = true
|
x509-cert.workspace = true
|
||||||
|
|
||||||
|
postgres_versioninfo.workspace = true
|
||||||
postgres_initdb.workspace = true
|
postgres_initdb.workspace = true
|
||||||
compute_api.workspace = true
|
compute_api.workspace = true
|
||||||
utils.workspace = true
|
utils.workspace = true
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ use std::sync::mpsc;
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result, bail};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use compute_api::responses::ComputeConfig;
|
use compute_api::responses::ComputeConfig;
|
||||||
use compute_tools::compute::{
|
use compute_tools::compute::{
|
||||||
@@ -57,25 +57,15 @@ use tracing::{error, info};
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
use utils::failpoint_support;
|
use utils::failpoint_support;
|
||||||
|
|
||||||
// Compatibility hack: if the control plane specified any remote-ext-config
|
#[derive(Debug, Parser)]
|
||||||
// use the default value for extension storage proxy gateway.
|
|
||||||
// Remove this once the control plane is updated to pass the gateway URL
|
|
||||||
fn parse_remote_ext_config(arg: &str) -> Result<String> {
|
|
||||||
if arg.starts_with("http") {
|
|
||||||
Ok(arg.trim_end_matches('/').to_string())
|
|
||||||
} else {
|
|
||||||
Ok("http://pg-ext-s3-gateway".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
|
||||||
#[command(rename_all = "kebab-case")]
|
#[command(rename_all = "kebab-case")]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[arg(short = 'b', long, default_value = "postgres", env = "POSTGRES_PATH")]
|
#[arg(short = 'b', long, default_value = "postgres", env = "POSTGRES_PATH")]
|
||||||
pub pgbin: String,
|
pub pgbin: String,
|
||||||
|
|
||||||
#[arg(short = 'r', long, value_parser = parse_remote_ext_config)]
|
/// The base URL for the remote extension storage proxy gateway.
|
||||||
pub remote_ext_config: Option<String>,
|
#[arg(short = 'r', long, value_parser = Self::parse_remote_ext_base_url)]
|
||||||
|
pub remote_ext_base_url: Option<Url>,
|
||||||
|
|
||||||
/// The port to bind the external listening HTTP server to. Clients running
|
/// The port to bind the external listening HTTP server to. Clients running
|
||||||
/// outside the compute will talk to the compute through this port. Keep
|
/// outside the compute will talk to the compute through this port. Keep
|
||||||
@@ -130,6 +120,33 @@ struct Cli {
|
|||||||
requires = "compute-id"
|
requires = "compute-id"
|
||||||
)]
|
)]
|
||||||
pub control_plane_uri: Option<String>,
|
pub control_plane_uri: Option<String>,
|
||||||
|
|
||||||
|
/// Interval in seconds for collecting installed extensions statistics
|
||||||
|
#[arg(long, default_value = "3600")]
|
||||||
|
pub installed_extensions_collection_interval: u64,
|
||||||
|
|
||||||
|
/// Run in development mode, skipping VM-specific operations like process termination
|
||||||
|
#[arg(long, action = clap::ArgAction::SetTrue)]
|
||||||
|
pub dev: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cli {
|
||||||
|
/// Parse a URL from an argument. By default, this isn't necessary, but we
|
||||||
|
/// want to do some sanity checking.
|
||||||
|
fn parse_remote_ext_base_url(value: &str) -> Result<Url> {
|
||||||
|
// Remove extra trailing slashes, and add one. We use Url::join() later
|
||||||
|
// when downloading remote extensions. If the base URL is something like
|
||||||
|
// http://example.com/pg-ext-s3-gateway, and join() is called with
|
||||||
|
// something like "xyz", the resulting URL is http://example.com/xyz.
|
||||||
|
let value = value.trim_end_matches('/').to_owned() + "/";
|
||||||
|
let url = Url::parse(&value)?;
|
||||||
|
|
||||||
|
if url.query_pairs().count() != 0 {
|
||||||
|
bail!("parameters detected in remote extensions base URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
@@ -146,7 +163,7 @@ fn main() -> Result<()> {
|
|||||||
.build()?;
|
.build()?;
|
||||||
let _rt_guard = runtime.enter();
|
let _rt_guard = runtime.enter();
|
||||||
|
|
||||||
runtime.block_on(init())?;
|
runtime.block_on(init(cli.dev))?;
|
||||||
|
|
||||||
// enable core dumping for all child processes
|
// enable core dumping for all child processes
|
||||||
setrlimit(Resource::CORE, rlimit::INFINITY, rlimit::INFINITY)?;
|
setrlimit(Resource::CORE, rlimit::INFINITY, rlimit::INFINITY)?;
|
||||||
@@ -164,7 +181,7 @@ fn main() -> Result<()> {
|
|||||||
pgversion: get_pg_version_string(&cli.pgbin),
|
pgversion: get_pg_version_string(&cli.pgbin),
|
||||||
external_http_port: cli.external_http_port,
|
external_http_port: cli.external_http_port,
|
||||||
internal_http_port: cli.internal_http_port,
|
internal_http_port: cli.internal_http_port,
|
||||||
ext_remote_storage: cli.remote_ext_config.clone(),
|
remote_ext_base_url: cli.remote_ext_base_url.clone(),
|
||||||
resize_swap_on_bind: cli.resize_swap_on_bind,
|
resize_swap_on_bind: cli.resize_swap_on_bind,
|
||||||
set_disk_quota_for_fs: cli.set_disk_quota_for_fs,
|
set_disk_quota_for_fs: cli.set_disk_quota_for_fs,
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@@ -173,6 +190,7 @@ fn main() -> Result<()> {
|
|||||||
cgroup: cli.cgroup,
|
cgroup: cli.cgroup,
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
vm_monitor_addr: cli.vm_monitor_addr,
|
vm_monitor_addr: cli.vm_monitor_addr,
|
||||||
|
installed_extensions_collection_interval: cli.installed_extensions_collection_interval,
|
||||||
},
|
},
|
||||||
config,
|
config,
|
||||||
)?;
|
)?;
|
||||||
@@ -184,13 +202,13 @@ fn main() -> Result<()> {
|
|||||||
deinit_and_exit(exit_code);
|
deinit_and_exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init() -> Result<()> {
|
async fn init(dev_mode: bool) -> Result<()> {
|
||||||
init_tracing_and_logging(DEFAULT_LOG_LEVEL).await?;
|
init_tracing_and_logging(DEFAULT_LOG_LEVEL).await?;
|
||||||
|
|
||||||
let mut signals = Signals::new([SIGINT, SIGTERM, SIGQUIT])?;
|
let mut signals = Signals::new([SIGINT, SIGTERM, SIGQUIT])?;
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
for sig in signals.forever() {
|
for sig in signals.forever() {
|
||||||
handle_exit_signal(sig);
|
handle_exit_signal(sig, dev_mode);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -249,15 +267,16 @@ fn deinit_and_exit(exit_code: Option<i32>) -> ! {
|
|||||||
/// When compute_ctl is killed, send also termination signal to sync-safekeepers
|
/// When compute_ctl is killed, send also termination signal to sync-safekeepers
|
||||||
/// to prevent leakage. TODO: it is better to convert compute_ctl to async and
|
/// to prevent leakage. TODO: it is better to convert compute_ctl to async and
|
||||||
/// wait for termination which would be easy then.
|
/// wait for termination which would be easy then.
|
||||||
fn handle_exit_signal(sig: i32) {
|
fn handle_exit_signal(sig: i32, dev_mode: bool) {
|
||||||
info!("received {sig} termination signal");
|
info!("received {sig} termination signal");
|
||||||
forward_termination_signal();
|
forward_termination_signal(dev_mode);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use clap::CommandFactory;
|
use clap::{CommandFactory, Parser};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use super::Cli;
|
use super::Cli;
|
||||||
|
|
||||||
@@ -265,4 +284,43 @@ mod test {
|
|||||||
fn verify_cli() {
|
fn verify_cli() {
|
||||||
Cli::command().debug_assert()
|
Cli::command().debug_assert()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn verify_remote_ext_base_url() {
|
||||||
|
let cli = Cli::parse_from([
|
||||||
|
"compute_ctl",
|
||||||
|
"--pgdata=test",
|
||||||
|
"--connstr=test",
|
||||||
|
"--compute-id=test",
|
||||||
|
"--remote-ext-base-url",
|
||||||
|
"https://example.com/subpath",
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
cli.remote_ext_base_url.unwrap(),
|
||||||
|
Url::parse("https://example.com/subpath/").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
let cli = Cli::parse_from([
|
||||||
|
"compute_ctl",
|
||||||
|
"--pgdata=test",
|
||||||
|
"--connstr=test",
|
||||||
|
"--compute-id=test",
|
||||||
|
"--remote-ext-base-url",
|
||||||
|
"https://example.com//",
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
cli.remote_ext_base_url.unwrap(),
|
||||||
|
Url::parse("https://example.com").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
Cli::try_parse_from([
|
||||||
|
"compute_ctl",
|
||||||
|
"--pgdata=test",
|
||||||
|
"--connstr=test",
|
||||||
|
"--compute-id=test",
|
||||||
|
"--remote-ext-base-url",
|
||||||
|
"https://example.com?hello=world",
|
||||||
|
])
|
||||||
|
.expect_err("URL parameters are not allowed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ use anyhow::{Context, bail};
|
|||||||
use aws_config::BehaviorVersion;
|
use aws_config::BehaviorVersion;
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use camino::{Utf8Path, Utf8PathBuf};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use compute_tools::extension_server::{PostgresMajorVersion, get_pg_version};
|
use compute_tools::extension_server::get_pg_version;
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
use tracing::{Instrument, error, info, info_span, warn};
|
use tracing::{Instrument, error, info, info_span, warn};
|
||||||
@@ -179,12 +179,8 @@ impl PostgresProcess {
|
|||||||
.await
|
.await
|
||||||
.context("create pgdata directory")?;
|
.context("create pgdata directory")?;
|
||||||
|
|
||||||
let pg_version = match get_pg_version(self.pgbin.as_ref()) {
|
let pg_version = get_pg_version(self.pgbin.as_ref());
|
||||||
PostgresMajorVersion::V14 => 14,
|
|
||||||
PostgresMajorVersion::V15 => 15,
|
|
||||||
PostgresMajorVersion::V16 => 16,
|
|
||||||
PostgresMajorVersion::V17 => 17,
|
|
||||||
};
|
|
||||||
postgres_initdb::do_run_initdb(postgres_initdb::RunInitdbArgs {
|
postgres_initdb::do_run_initdb(postgres_initdb::RunInitdbArgs {
|
||||||
superuser: initdb_user,
|
superuser: initdb_user,
|
||||||
locale: DEFAULT_LOCALE, // XXX: this shouldn't be hard-coded,
|
locale: DEFAULT_LOCALE, // XXX: this shouldn't be hard-coded,
|
||||||
@@ -339,6 +335,8 @@ async fn run_dump_restore(
|
|||||||
destination_connstring: String,
|
destination_connstring: String,
|
||||||
) -> Result<(), anyhow::Error> {
|
) -> Result<(), anyhow::Error> {
|
||||||
let dumpdir = workdir.join("dumpdir");
|
let dumpdir = workdir.join("dumpdir");
|
||||||
|
let num_jobs = num_cpus::get().to_string();
|
||||||
|
info!("using {num_jobs} jobs for dump/restore");
|
||||||
|
|
||||||
let common_args = [
|
let common_args = [
|
||||||
// schema mapping (prob suffices to specify them on one side)
|
// schema mapping (prob suffices to specify them on one side)
|
||||||
@@ -348,12 +346,13 @@ async fn run_dump_restore(
|
|||||||
"--no-security-labels".to_string(),
|
"--no-security-labels".to_string(),
|
||||||
"--no-subscriptions".to_string(),
|
"--no-subscriptions".to_string(),
|
||||||
"--no-tablespaces".to_string(),
|
"--no-tablespaces".to_string(),
|
||||||
|
"--no-event-triggers".to_string(),
|
||||||
// format
|
// format
|
||||||
"--format".to_string(),
|
"--format".to_string(),
|
||||||
"directory".to_string(),
|
"directory".to_string(),
|
||||||
// concurrency
|
// concurrency
|
||||||
"--jobs".to_string(),
|
"--jobs".to_string(),
|
||||||
num_cpus::get().to_string(),
|
num_jobs,
|
||||||
// progress updates
|
// progress updates
|
||||||
"--verbose".to_string(),
|
"--verbose".to_string(),
|
||||||
];
|
];
|
||||||
@@ -483,10 +482,8 @@ async fn cmd_pgdata(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let superuser = "cloud_admin";
|
let superuser = "cloud_admin";
|
||||||
let destination_connstring = format!(
|
let destination_connstring =
|
||||||
"host=localhost port={} user={} dbname=neondb",
|
format!("host=localhost port={pg_port} user={superuser} dbname=neondb");
|
||||||
pg_port, superuser
|
|
||||||
);
|
|
||||||
|
|
||||||
let pgdata_dir = workdir.join("pgdata");
|
let pgdata_dir = workdir.join("pgdata");
|
||||||
let mut proc = PostgresProcess::new(pgdata_dir.clone(), pg_bin_dir.clone(), pg_lib_dir.clone());
|
let mut proc = PostgresProcess::new(pgdata_dir.clone(), pg_bin_dir.clone(), pg_lib_dir.clone());
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ impl clap::builder::TypedValueParser for S3Uri {
|
|||||||
S3Uri::from_str(value_str).map_err(|e| {
|
S3Uri::from_str(value_str).map_err(|e| {
|
||||||
clap::Error::raw(
|
clap::Error::raw(
|
||||||
clap::error::ErrorKind::InvalidValue,
|
clap::error::ErrorKind::InvalidValue,
|
||||||
format!("Failed to parse S3 URI: {}", e),
|
format!("Failed to parse S3 URI: {e}"),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub async fn get_dbs_and_roles(compute: &Arc<ComputeNode>) -> anyhow::Result<Cat
|
|||||||
|
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
if let Err(e) = connection.await {
|
if let Err(e) = connection.await {
|
||||||
eprintln!("connection error: {}", e);
|
eprintln!("connection error: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ pub async fn get_database_schema(
|
|||||||
_ => {
|
_ => {
|
||||||
let mut lines = stderr_reader.lines();
|
let mut lines = stderr_reader.lines();
|
||||||
if let Some(line) = lines.next_line().await? {
|
if let Some(line) = lines.next_line().await? {
|
||||||
if line.contains(&format!("FATAL: database \"{}\" does not exist", dbname)) {
|
if line.contains(&format!("FATAL: database \"{dbname}\" does not exist")) {
|
||||||
return Err(SchemaDumpError::DatabaseDoesNotExist);
|
return Err(SchemaDumpError::DatabaseDoesNotExist);
|
||||||
}
|
}
|
||||||
warn!("pg_dump stderr: {}", line)
|
warn!("pg_dump stderr: {}", line)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
208
compute_tools/src/compute_prewarm.rs
Normal file
208
compute_tools/src/compute_prewarm.rs
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
use crate::compute::ComputeNode;
|
||||||
|
use anyhow::{Context, Result, bail};
|
||||||
|
use async_compression::tokio::bufread::{ZstdDecoder, ZstdEncoder};
|
||||||
|
use compute_api::responses::LfcOffloadState;
|
||||||
|
use compute_api::responses::LfcPrewarmState;
|
||||||
|
use http::StatusCode;
|
||||||
|
use reqwest::Client;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::{io::AsyncReadExt, spawn};
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, Default)]
|
||||||
|
pub struct LfcPrewarmStateWithProgress {
|
||||||
|
#[serde(flatten)]
|
||||||
|
base: LfcPrewarmState,
|
||||||
|
total: i32,
|
||||||
|
prewarmed: i32,
|
||||||
|
skipped: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A pair of url and a token to query endpoint storage for LFC prewarm-related tasks
|
||||||
|
struct EndpointStoragePair {
|
||||||
|
url: String,
|
||||||
|
token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const KEY: &str = "lfc_state";
|
||||||
|
impl EndpointStoragePair {
|
||||||
|
/// endpoint_id is set to None while prewarming from other endpoint, see replica promotion
|
||||||
|
/// If not None, takes precedence over pspec.spec.endpoint_id
|
||||||
|
fn from_spec_and_endpoint(
|
||||||
|
pspec: &crate::compute::ParsedSpec,
|
||||||
|
endpoint_id: Option<String>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let endpoint_id = endpoint_id.as_ref().or(pspec.spec.endpoint_id.as_ref());
|
||||||
|
let Some(ref endpoint_id) = endpoint_id else {
|
||||||
|
bail!("pspec.endpoint_id missing, other endpoint_id not provided")
|
||||||
|
};
|
||||||
|
let Some(ref base_uri) = pspec.endpoint_storage_addr else {
|
||||||
|
bail!("pspec.endpoint_storage_addr missing")
|
||||||
|
};
|
||||||
|
let tenant_id = pspec.tenant_id;
|
||||||
|
let timeline_id = pspec.timeline_id;
|
||||||
|
|
||||||
|
let url = format!("http://{base_uri}/{tenant_id}/{timeline_id}/{endpoint_id}/{KEY}");
|
||||||
|
let Some(ref token) = pspec.endpoint_storage_token else {
|
||||||
|
bail!("pspec.endpoint_storage_token missing")
|
||||||
|
};
|
||||||
|
let token = token.clone();
|
||||||
|
Ok(EndpointStoragePair { url, token })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComputeNode {
|
||||||
|
// If prewarm failed, we want to get overall number of segments as well as done ones.
|
||||||
|
// However, this function should be reliable even if querying postgres failed.
|
||||||
|
pub async fn lfc_prewarm_state(&self) -> LfcPrewarmStateWithProgress {
|
||||||
|
info!("requesting LFC prewarm state from postgres");
|
||||||
|
let mut state = LfcPrewarmStateWithProgress::default();
|
||||||
|
{
|
||||||
|
state.base = self.state.lock().unwrap().lfc_prewarm_state.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
let client = match ComputeNode::get_maintenance_client(&self.tokio_conn_conf).await {
|
||||||
|
Ok(client) => client,
|
||||||
|
Err(err) => {
|
||||||
|
error!(%err, "connecting to postgres");
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let row = match client
|
||||||
|
.query_one("select * from get_prewarm_info()", &[])
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(row) => row,
|
||||||
|
Err(err) => {
|
||||||
|
error!(%err, "querying LFC prewarm status");
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
state.total = row.try_get(0).unwrap_or_default();
|
||||||
|
state.prewarmed = row.try_get(1).unwrap_or_default();
|
||||||
|
state.skipped = row.try_get(2).unwrap_or_default();
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lfc_offload_state(&self) -> LfcOffloadState {
|
||||||
|
self.state.lock().unwrap().lfc_offload_state.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns false if there is a prewarm request ongoing, true otherwise
|
||||||
|
pub fn prewarm_lfc(self: &Arc<Self>, from_endpoint: Option<String>) -> bool {
|
||||||
|
crate::metrics::LFC_PREWARM_REQUESTS.inc();
|
||||||
|
{
|
||||||
|
let state = &mut self.state.lock().unwrap().lfc_prewarm_state;
|
||||||
|
if let LfcPrewarmState::Prewarming =
|
||||||
|
std::mem::replace(state, LfcPrewarmState::Prewarming)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cloned = self.clone();
|
||||||
|
spawn(async move {
|
||||||
|
let Err(err) = cloned.prewarm_impl(from_endpoint).await else {
|
||||||
|
cloned.state.lock().unwrap().lfc_prewarm_state = LfcPrewarmState::Completed;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
error!(%err);
|
||||||
|
cloned.state.lock().unwrap().lfc_prewarm_state = LfcPrewarmState::Failed {
|
||||||
|
error: err.to_string(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// from_endpoint: None for endpoint managed by this compute_ctl
|
||||||
|
fn endpoint_storage_pair(&self, from_endpoint: Option<String>) -> Result<EndpointStoragePair> {
|
||||||
|
let state = self.state.lock().unwrap();
|
||||||
|
EndpointStoragePair::from_spec_and_endpoint(state.pspec.as_ref().unwrap(), from_endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn prewarm_impl(&self, from_endpoint: Option<String>) -> Result<()> {
|
||||||
|
let EndpointStoragePair { url, token } = self.endpoint_storage_pair(from_endpoint)?;
|
||||||
|
info!(%url, "requesting LFC state from endpoint storage");
|
||||||
|
|
||||||
|
let request = Client::new().get(&url).bearer_auth(token);
|
||||||
|
let res = request.send().await.context("querying endpoint storage")?;
|
||||||
|
let status = res.status();
|
||||||
|
if status != StatusCode::OK {
|
||||||
|
bail!("{status} querying endpoint storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut uncompressed = Vec::new();
|
||||||
|
let lfc_state = res
|
||||||
|
.bytes()
|
||||||
|
.await
|
||||||
|
.context("getting request body from endpoint storage")?;
|
||||||
|
ZstdDecoder::new(lfc_state.iter().as_slice())
|
||||||
|
.read_to_end(&mut uncompressed)
|
||||||
|
.await
|
||||||
|
.context("decoding LFC state")?;
|
||||||
|
let uncompressed_len = uncompressed.len();
|
||||||
|
info!(%url, "downloaded LFC state, uncompressed size {uncompressed_len}, loading into postgres");
|
||||||
|
|
||||||
|
ComputeNode::get_maintenance_client(&self.tokio_conn_conf)
|
||||||
|
.await
|
||||||
|
.context("connecting to postgres")?
|
||||||
|
.query_one("select prewarm_local_cache($1)", &[&uncompressed])
|
||||||
|
.await
|
||||||
|
.context("loading LFC state into postgres")
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns false if there is an offload request ongoing, true otherwise
|
||||||
|
pub fn offload_lfc(self: &Arc<Self>) -> bool {
|
||||||
|
crate::metrics::LFC_OFFLOAD_REQUESTS.inc();
|
||||||
|
{
|
||||||
|
let state = &mut self.state.lock().unwrap().lfc_offload_state;
|
||||||
|
if let LfcOffloadState::Offloading =
|
||||||
|
std::mem::replace(state, LfcOffloadState::Offloading)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cloned = self.clone();
|
||||||
|
spawn(async move {
|
||||||
|
let Err(err) = cloned.offload_lfc_impl().await else {
|
||||||
|
cloned.state.lock().unwrap().lfc_offload_state = LfcOffloadState::Completed;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
error!(%err);
|
||||||
|
cloned.state.lock().unwrap().lfc_offload_state = LfcOffloadState::Failed {
|
||||||
|
error: err.to_string(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn offload_lfc_impl(&self) -> Result<()> {
|
||||||
|
let EndpointStoragePair { url, token } = self.endpoint_storage_pair(None)?;
|
||||||
|
info!(%url, "requesting LFC state from postgres");
|
||||||
|
|
||||||
|
let mut compressed = Vec::new();
|
||||||
|
ComputeNode::get_maintenance_client(&self.tokio_conn_conf)
|
||||||
|
.await
|
||||||
|
.context("connecting to postgres")?
|
||||||
|
.query_one("select get_local_cache_state()", &[])
|
||||||
|
.await
|
||||||
|
.context("querying LFC state")?
|
||||||
|
.try_get::<usize, &[u8]>(0)
|
||||||
|
.context("deserializing LFC state")
|
||||||
|
.map(ZstdEncoder::new)?
|
||||||
|
.read_to_end(&mut compressed)
|
||||||
|
.await
|
||||||
|
.context("compressing LFC state")?;
|
||||||
|
let compressed_len = compressed.len();
|
||||||
|
info!(%url, "downloaded LFC state, compressed size {compressed_len}, writing to endpoint storage");
|
||||||
|
|
||||||
|
let request = Client::new().put(url).bearer_auth(token).body(compressed);
|
||||||
|
match request.send().await {
|
||||||
|
Ok(res) if res.status() == StatusCode::OK => Ok(()),
|
||||||
|
Ok(res) => bail!("Error writing to endpoint storage: {}", res.status()),
|
||||||
|
Err(err) => Err(err).context("writing to endpoint storage"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,14 +51,56 @@ pub fn write_postgres_conf(
|
|||||||
|
|
||||||
// Write the postgresql.conf content from the spec file as is.
|
// Write the postgresql.conf content from the spec file as is.
|
||||||
if let Some(conf) = &spec.cluster.postgresql_conf {
|
if let Some(conf) = &spec.cluster.postgresql_conf {
|
||||||
writeln!(file, "{}", conf)?;
|
writeln!(file, "{conf}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add options for connecting to storage
|
// Add options for connecting to storage
|
||||||
writeln!(file, "# Neon storage settings")?;
|
writeln!(file, "# Neon storage settings")?;
|
||||||
if let Some(s) = &spec.pageserver_connstring {
|
|
||||||
writeln!(file, "neon.pageserver_connstring={}", escape_conf_value(s))?;
|
if let Some(conninfo) = &spec.pageserver_connection_info {
|
||||||
|
let mut libpq_urls: Option<Vec<String>> = Some(Vec::new());
|
||||||
|
let mut grpc_urls: Option<Vec<String>> = Some(Vec::new());
|
||||||
|
|
||||||
|
for shardno in 0..conninfo.shards.len() {
|
||||||
|
let info = conninfo.shards.get(&(shardno as u32)).ok_or_else(|| {
|
||||||
|
anyhow::anyhow!("shard {shardno} missing from pageserver_connection_info shard map")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if let Some(url) = &info.libpq_url {
|
||||||
|
if let Some(ref mut urls) = libpq_urls {
|
||||||
|
urls.push(url.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
libpq_urls = None
|
||||||
|
}
|
||||||
|
if let Some(url) = &info.grpc_url {
|
||||||
|
if let Some(ref mut urls) = grpc_urls {
|
||||||
|
urls.push(url.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
grpc_urls = None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(libpq_urls) = libpq_urls {
|
||||||
|
writeln!(
|
||||||
|
file,
|
||||||
|
"neon.pageserver_connstring={}",
|
||||||
|
escape_conf_value(&libpq_urls.join(","))
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
writeln!(file, "# no neon.pageserver_connstring")?;
|
||||||
|
}
|
||||||
|
if let Some(grpc_urls) = grpc_urls {
|
||||||
|
writeln!(
|
||||||
|
file,
|
||||||
|
"neon.pageserver_grpc_urls={}",
|
||||||
|
escape_conf_value(&grpc_urls.join(","))
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
writeln!(file, "# no neon.pageserver_grpc_urls")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(stripe_size) = spec.shard_stripe_size {
|
if let Some(stripe_size) = spec.shard_stripe_size {
|
||||||
writeln!(file, "neon.stripe_size={stripe_size}")?;
|
writeln!(file, "neon.stripe_size={stripe_size}")?;
|
||||||
}
|
}
|
||||||
@@ -70,7 +112,7 @@ pub fn write_postgres_conf(
|
|||||||
);
|
);
|
||||||
// If generation is given, prepend sk list with g#number:
|
// If generation is given, prepend sk list with g#number:
|
||||||
if let Some(generation) = spec.safekeepers_generation {
|
if let Some(generation) = spec.safekeepers_generation {
|
||||||
write!(neon_safekeepers_value, "g#{}:", generation)?;
|
write!(neon_safekeepers_value, "g#{generation}:")?;
|
||||||
}
|
}
|
||||||
neon_safekeepers_value.push_str(&spec.safekeeper_connstrings.join(","));
|
neon_safekeepers_value.push_str(&spec.safekeeper_connstrings.join(","));
|
||||||
writeln!(
|
writeln!(
|
||||||
@@ -109,8 +151,8 @@ pub fn write_postgres_conf(
|
|||||||
tls::update_key_path_blocking(pgdata_path, tls_config);
|
tls::update_key_path_blocking(pgdata_path, tls_config);
|
||||||
|
|
||||||
// these are the default, but good to be explicit.
|
// these are the default, but good to be explicit.
|
||||||
writeln!(file, "ssl_cert_file = '{}'", SERVER_CRT)?;
|
writeln!(file, "ssl_cert_file = '{SERVER_CRT}'")?;
|
||||||
writeln!(file, "ssl_key_file = '{}'", SERVER_KEY)?;
|
writeln!(file, "ssl_key_file = '{SERVER_KEY}'")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locales
|
// Locales
|
||||||
@@ -191,8 +233,7 @@ pub fn write_postgres_conf(
|
|||||||
}
|
}
|
||||||
writeln!(
|
writeln!(
|
||||||
file,
|
file,
|
||||||
"shared_preload_libraries='{}{}'",
|
"shared_preload_libraries='{libs}{extra_shared_preload_libraries}'"
|
||||||
libs, extra_shared_preload_libraries
|
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
// Typically, this should be unreacheable,
|
// Typically, this should be unreacheable,
|
||||||
@@ -223,6 +264,12 @@ pub fn write_postgres_conf(
|
|||||||
// TODO: tune this after performance testing
|
// TODO: tune this after performance testing
|
||||||
writeln!(file, "pgaudit.log_rotation_age=5")?;
|
writeln!(file, "pgaudit.log_rotation_age=5")?;
|
||||||
|
|
||||||
|
// Enable audit logs for pg_session_jwt extension
|
||||||
|
// TODO: Consider a good approach for shipping pg_session_jwt logs to the same sink as
|
||||||
|
// pgAudit - additional context in https://github.com/neondatabase/cloud/issues/28863
|
||||||
|
//
|
||||||
|
// writeln!(file, "pg_session_jwt.audit_log=on")?;
|
||||||
|
|
||||||
// Add audit shared_preload_libraries, if they are not present.
|
// Add audit shared_preload_libraries, if they are not present.
|
||||||
//
|
//
|
||||||
// The caller who sets the flag is responsible for ensuring that the necessary
|
// The caller who sets the flag is responsible for ensuring that the necessary
|
||||||
@@ -238,8 +285,7 @@ pub fn write_postgres_conf(
|
|||||||
}
|
}
|
||||||
writeln!(
|
writeln!(
|
||||||
file,
|
file,
|
||||||
"shared_preload_libraries='{}{}'",
|
"shared_preload_libraries='{libs}{extra_shared_preload_libraries}'"
|
||||||
libs, extra_shared_preload_libraries
|
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
// Typically, this should be unreacheable,
|
// Typically, this should be unreacheable,
|
||||||
@@ -257,7 +303,7 @@ pub fn write_postgres_conf(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(file, "neon.extension_server_port={}", extension_server_port)?;
|
writeln!(file, "neon.extension_server_port={extension_server_port}")?;
|
||||||
|
|
||||||
if spec.drop_subscriptions_before_start {
|
if spec.drop_subscriptions_before_start {
|
||||||
writeln!(file, "neon.disable_logical_replication_subscribers=true")?;
|
writeln!(file, "neon.disable_logical_replication_subscribers=true")?;
|
||||||
@@ -285,7 +331,7 @@ where
|
|||||||
{
|
{
|
||||||
let path = pgdata_path.join("compute_ctl_temp_override.conf");
|
let path = pgdata_path.join("compute_ctl_temp_override.conf");
|
||||||
let mut file = File::create(path)?;
|
let mut file = File::create(path)?;
|
||||||
write!(file, "{}", options)?;
|
write!(file, "{options}")?;
|
||||||
|
|
||||||
let res = exec();
|
let res = exec();
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,24 @@
|
|||||||
module(load="imfile")
|
module(load="imfile")
|
||||||
|
|
||||||
# Input configuration for log files in the specified directory
|
# Input configuration for log files in the specified directory
|
||||||
# Replace {log_directory} with the directory containing the log files
|
# The messages can be multiline. The start of the message is a timestamp
|
||||||
input(type="imfile" File="{log_directory}/*.log" Tag="{tag}" Severity="info" Facility="local0")
|
# in "%Y-%m-%d %H:%M:%S.%3N GMT" (so timezone hardcoded).
|
||||||
|
# Replace log_directory with the directory containing the log files
|
||||||
|
input(type="imfile" File="{log_directory}/*.log"
|
||||||
|
Tag="pgaudit_log" Severity="info" Facility="local5"
|
||||||
|
startmsg.regex="^[[:digit:]]{{4}}-[[:digit:]]{{2}}-[[:digit:]]{{2}} [[:digit:]]{{2}}:[[:digit:]]{{2}}:[[:digit:]]{{2}}.[[:digit:]]{{3}} GMT,")
|
||||||
|
|
||||||
# the directory to store rsyslog state files
|
# the directory to store rsyslog state files
|
||||||
global(workDirectory="/var/log/rsyslog")
|
global(workDirectory="/var/log/rsyslog")
|
||||||
|
|
||||||
# Forward logs to remote syslog server
|
# Construct json, endpoint_id and project_id as additional metadata
|
||||||
*.* @@{remote_endpoint}
|
set $.json_log!endpoint_id = "{endpoint_id}";
|
||||||
|
set $.json_log!project_id = "{project_id}";
|
||||||
|
set $.json_log!msg = $msg;
|
||||||
|
|
||||||
|
# Template suitable for rfc5424 syslog format
|
||||||
|
template(name="PgAuditLog" type="string"
|
||||||
|
string="<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% - - - - %$.json_log%")
|
||||||
|
|
||||||
|
# Forward to remote syslog receiver (@@<hostname>:<port>;format
|
||||||
|
local5.info @@{remote_endpoint};PgAuditLog
|
||||||
|
|||||||
@@ -74,19 +74,20 @@ More specifically, here is an example ext_index.json
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
use crate::metrics::{REMOTE_EXT_REQUESTS_TOTAL, UNKNOWN_HTTP_STATUS};
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use compute_api::spec::RemoteExtSpec;
|
use compute_api::spec::RemoteExtSpec;
|
||||||
|
use postgres_versioninfo::PgMajorVersion;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use remote_storage::*;
|
use remote_storage::*;
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use tar::Archive;
|
use tar::Archive;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use tracing::log::warn;
|
use tracing::log::warn;
|
||||||
|
use url::Url;
|
||||||
use zstd::stream::read::Decoder;
|
use zstd::stream::read::Decoder;
|
||||||
|
|
||||||
use crate::metrics::{REMOTE_EXT_REQUESTS_TOTAL, UNKNOWN_HTTP_STATUS};
|
|
||||||
|
|
||||||
fn get_pg_config(argument: &str, pgbin: &str) -> String {
|
fn get_pg_config(argument: &str, pgbin: &str) -> String {
|
||||||
// gives the result of `pg_config [argument]`
|
// gives the result of `pg_config [argument]`
|
||||||
// where argument is a flag like `--version` or `--sharedir`
|
// where argument is a flag like `--version` or `--sharedir`
|
||||||
@@ -105,7 +106,7 @@ fn get_pg_config(argument: &str, pgbin: &str) -> String {
|
|||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pg_version(pgbin: &str) -> PostgresMajorVersion {
|
pub fn get_pg_version(pgbin: &str) -> PgMajorVersion {
|
||||||
// pg_config --version returns a (platform specific) human readable string
|
// pg_config --version returns a (platform specific) human readable string
|
||||||
// such as "PostgreSQL 15.4". We parse this to v14/v15/v16 etc.
|
// such as "PostgreSQL 15.4". We parse this to v14/v15/v16 etc.
|
||||||
let human_version = get_pg_config("--version", pgbin);
|
let human_version = get_pg_config("--version", pgbin);
|
||||||
@@ -113,25 +114,11 @@ pub fn get_pg_version(pgbin: &str) -> PostgresMajorVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pg_version_string(pgbin: &str) -> String {
|
pub fn get_pg_version_string(pgbin: &str) -> String {
|
||||||
match get_pg_version(pgbin) {
|
get_pg_version(pgbin).v_str()
|
||||||
PostgresMajorVersion::V14 => "v14",
|
|
||||||
PostgresMajorVersion::V15 => "v15",
|
|
||||||
PostgresMajorVersion::V16 => "v16",
|
|
||||||
PostgresMajorVersion::V17 => "v17",
|
|
||||||
}
|
|
||||||
.to_owned()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
fn parse_pg_version(human_version: &str) -> PgMajorVersion {
|
||||||
pub enum PostgresMajorVersion {
|
use PgMajorVersion::*;
|
||||||
V14,
|
|
||||||
V15,
|
|
||||||
V16,
|
|
||||||
V17,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_pg_version(human_version: &str) -> PostgresMajorVersion {
|
|
||||||
use PostgresMajorVersion::*;
|
|
||||||
// Normal releases have version strings like "PostgreSQL 15.4". But there
|
// Normal releases have version strings like "PostgreSQL 15.4". But there
|
||||||
// are also pre-release versions like "PostgreSQL 17devel" or "PostgreSQL
|
// are also pre-release versions like "PostgreSQL 17devel" or "PostgreSQL
|
||||||
// 16beta2" or "PostgreSQL 17rc1". And with the --with-extra-version
|
// 16beta2" or "PostgreSQL 17rc1". And with the --with-extra-version
|
||||||
@@ -142,10 +129,10 @@ fn parse_pg_version(human_version: &str) -> PostgresMajorVersion {
|
|||||||
.captures(human_version)
|
.captures(human_version)
|
||||||
{
|
{
|
||||||
Some(captures) if captures.len() == 2 => match &captures["major"] {
|
Some(captures) if captures.len() == 2 => match &captures["major"] {
|
||||||
"14" => return V14,
|
"14" => return PG14,
|
||||||
"15" => return V15,
|
"15" => return PG15,
|
||||||
"16" => return V16,
|
"16" => return PG16,
|
||||||
"17" => return V17,
|
"17" => return PG17,
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -158,14 +145,14 @@ fn parse_pg_version(human_version: &str) -> PostgresMajorVersion {
|
|||||||
pub async fn download_extension(
|
pub async fn download_extension(
|
||||||
ext_name: &str,
|
ext_name: &str,
|
||||||
ext_path: &RemotePath,
|
ext_path: &RemotePath,
|
||||||
ext_remote_storage: &str,
|
remote_ext_base_url: &Url,
|
||||||
pgbin: &str,
|
pgbin: &str,
|
||||||
) -> Result<u64> {
|
) -> Result<u64> {
|
||||||
info!("Download extension {:?} from {:?}", ext_name, ext_path);
|
info!("Download extension {:?} from {:?}", ext_name, ext_path);
|
||||||
|
|
||||||
// TODO add retry logic
|
// TODO add retry logic
|
||||||
let download_buffer =
|
let download_buffer =
|
||||||
match download_extension_tar(ext_remote_storage, &ext_path.to_string()).await {
|
match download_extension_tar(remote_ext_base_url, &ext_path.to_string()).await {
|
||||||
Ok(buffer) => buffer,
|
Ok(buffer) => buffer,
|
||||||
Err(error_message) => {
|
Err(error_message) => {
|
||||||
return Err(anyhow::anyhow!(
|
return Err(anyhow::anyhow!(
|
||||||
@@ -270,10 +257,14 @@ pub fn create_control_files(remote_extensions: &RemoteExtSpec, pgbin: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do request to extension storage proxy, e.g.,
|
// Do request to extension storage proxy, e.g.,
|
||||||
// curl http://pg-ext-s3-gateway/latest/v15/extensions/anon.tar.zst
|
// curl http://pg-ext-s3-gateway.pg-ext-s3-gateway.svc.cluster.local/latest/v15/extensions/anon.tar.zst
|
||||||
// using HTTP GET and return the response body as bytes.
|
// using HTTP GET and return the response body as bytes.
|
||||||
async fn download_extension_tar(ext_remote_storage: &str, ext_path: &str) -> Result<Bytes> {
|
async fn download_extension_tar(remote_ext_base_url: &Url, ext_path: &str) -> Result<Bytes> {
|
||||||
let uri = format!("{}/{}", ext_remote_storage, ext_path);
|
let uri = remote_ext_base_url.join(ext_path).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"failed to create the remote extension URI for {ext_path} using {remote_ext_base_url}"
|
||||||
|
)
|
||||||
|
})?;
|
||||||
let filename = Path::new(ext_path)
|
let filename = Path::new(ext_path)
|
||||||
.file_name()
|
.file_name()
|
||||||
.unwrap_or_else(|| std::ffi::OsStr::new("unknown"))
|
.unwrap_or_else(|| std::ffi::OsStr::new("unknown"))
|
||||||
@@ -283,7 +274,7 @@ async fn download_extension_tar(ext_remote_storage: &str, ext_path: &str) -> Res
|
|||||||
|
|
||||||
info!("Downloading extension file '{}' from uri {}", filename, uri);
|
info!("Downloading extension file '{}' from uri {}", filename, uri);
|
||||||
|
|
||||||
match do_extension_server_request(&uri).await {
|
match do_extension_server_request(uri).await {
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
info!("Successfully downloaded remote extension data {}", ext_path);
|
info!("Successfully downloaded remote extension data {}", ext_path);
|
||||||
REMOTE_EXT_REQUESTS_TOTAL
|
REMOTE_EXT_REQUESTS_TOTAL
|
||||||
@@ -302,13 +293,10 @@ async fn download_extension_tar(ext_remote_storage: &str, ext_path: &str) -> Res
|
|||||||
|
|
||||||
// Do a single remote extensions server request.
|
// Do a single remote extensions server request.
|
||||||
// Return result or (error message + stringified status code) in case of any failures.
|
// Return result or (error message + stringified status code) in case of any failures.
|
||||||
async fn do_extension_server_request(uri: &str) -> Result<Bytes, (String, String)> {
|
async fn do_extension_server_request(uri: Url) -> Result<Bytes, (String, String)> {
|
||||||
let resp = reqwest::get(uri).await.map_err(|e| {
|
let resp = reqwest::get(uri).await.map_err(|e| {
|
||||||
(
|
(
|
||||||
format!(
|
format!("could not perform remote extensions server request: {e:?}"),
|
||||||
"could not perform remote extensions server request: {:?}",
|
|
||||||
e
|
|
||||||
),
|
|
||||||
UNKNOWN_HTTP_STATUS.to_string(),
|
UNKNOWN_HTTP_STATUS.to_string(),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
@@ -318,7 +306,7 @@ async fn do_extension_server_request(uri: &str) -> Result<Bytes, (String, String
|
|||||||
StatusCode::OK => match resp.bytes().await {
|
StatusCode::OK => match resp.bytes().await {
|
||||||
Ok(resp) => Ok(resp),
|
Ok(resp) => Ok(resp),
|
||||||
Err(e) => Err((
|
Err(e) => Err((
|
||||||
format!("could not read remote extensions server response: {:?}", e),
|
format!("could not read remote extensions server response: {e:?}"),
|
||||||
// It's fine to return and report error with status as 200 OK,
|
// It's fine to return and report error with status as 200 OK,
|
||||||
// because we still failed to read the response.
|
// because we still failed to read the response.
|
||||||
status.to_string(),
|
status.to_string(),
|
||||||
@@ -329,10 +317,7 @@ async fn do_extension_server_request(uri: &str) -> Result<Bytes, (String, String
|
|||||||
status.to_string(),
|
status.to_string(),
|
||||||
)),
|
)),
|
||||||
_ => Err((
|
_ => Err((
|
||||||
format!(
|
format!("unexpected remote extensions server response status code: {status}"),
|
||||||
"unexpected remote extensions server response status code: {}",
|
|
||||||
status
|
|
||||||
),
|
|
||||||
status.to_string(),
|
status.to_string(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
@@ -344,25 +329,25 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_pg_version() {
|
fn test_parse_pg_version() {
|
||||||
use super::PostgresMajorVersion::*;
|
use postgres_versioninfo::PgMajorVersion::*;
|
||||||
assert_eq!(parse_pg_version("PostgreSQL 15.4"), V15);
|
assert_eq!(parse_pg_version("PostgreSQL 15.4"), PG15);
|
||||||
assert_eq!(parse_pg_version("PostgreSQL 15.14"), V15);
|
assert_eq!(parse_pg_version("PostgreSQL 15.14"), PG15);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_pg_version("PostgreSQL 15.4 (Ubuntu 15.4-0ubuntu0.23.04.1)"),
|
parse_pg_version("PostgreSQL 15.4 (Ubuntu 15.4-0ubuntu0.23.04.1)"),
|
||||||
V15
|
PG15
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(parse_pg_version("PostgreSQL 14.15"), V14);
|
assert_eq!(parse_pg_version("PostgreSQL 14.15"), PG14);
|
||||||
assert_eq!(parse_pg_version("PostgreSQL 14.0"), V14);
|
assert_eq!(parse_pg_version("PostgreSQL 14.0"), PG14);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_pg_version("PostgreSQL 14.9 (Debian 14.9-1.pgdg120+1"),
|
parse_pg_version("PostgreSQL 14.9 (Debian 14.9-1.pgdg120+1"),
|
||||||
V14
|
PG14
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(parse_pg_version("PostgreSQL 16devel"), V16);
|
assert_eq!(parse_pg_version("PostgreSQL 16devel"), PG16);
|
||||||
assert_eq!(parse_pg_version("PostgreSQL 16beta1"), V16);
|
assert_eq!(parse_pg_version("PostgreSQL 16beta1"), PG16);
|
||||||
assert_eq!(parse_pg_version("PostgreSQL 16rc2"), V16);
|
assert_eq!(parse_pg_version("PostgreSQL 16rc2"), PG16);
|
||||||
assert_eq!(parse_pg_version("PostgreSQL 16extra"), V16);
|
assert_eq!(parse_pg_version("PostgreSQL 16extra"), PG16);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use axum::{RequestExt, body::Body};
|
use axum::{RequestExt, body::Body};
|
||||||
use axum_extra::{
|
use axum_extra::{
|
||||||
TypedHeader,
|
TypedHeader,
|
||||||
headers::{Authorization, authorization::Bearer},
|
headers::{Authorization, authorization::Bearer},
|
||||||
};
|
};
|
||||||
use compute_api::requests::ComputeClaims;
|
use compute_api::requests::{COMPUTE_AUDIENCE, ComputeClaims, ComputeClaimsScope};
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use http::{Request, Response, StatusCode};
|
use http::{Request, Response, StatusCode};
|
||||||
use jsonwebtoken::{Algorithm, DecodingKey, TokenData, Validation, jwk::JwkSet};
|
use jsonwebtoken::{Algorithm, DecodingKey, TokenData, Validation, jwk::JwkSet};
|
||||||
@@ -25,13 +23,14 @@ pub(in crate::http) struct Authorize {
|
|||||||
impl Authorize {
|
impl Authorize {
|
||||||
pub fn new(compute_id: String, jwks: JwkSet) -> Self {
|
pub fn new(compute_id: String, jwks: JwkSet) -> Self {
|
||||||
let mut validation = Validation::new(Algorithm::EdDSA);
|
let mut validation = Validation::new(Algorithm::EdDSA);
|
||||||
// Nothing is currently required
|
|
||||||
validation.required_spec_claims = HashSet::new();
|
|
||||||
validation.validate_exp = true;
|
validation.validate_exp = true;
|
||||||
// Unused by the control plane
|
// Unused by the control plane
|
||||||
validation.validate_aud = false;
|
|
||||||
// Unused by the control plane
|
|
||||||
validation.validate_nbf = false;
|
validation.validate_nbf = false;
|
||||||
|
// Unused by the control plane
|
||||||
|
validation.validate_aud = false;
|
||||||
|
validation.set_audience(&[COMPUTE_AUDIENCE]);
|
||||||
|
// Nothing is currently required
|
||||||
|
validation.set_required_spec_claims(&[] as &[&str; 0]);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
compute_id,
|
compute_id,
|
||||||
@@ -64,11 +63,47 @@ impl AsyncAuthorizeRequest<Body> for Authorize {
|
|||||||
Err(e) => return Err(JsonResponse::error(StatusCode::UNAUTHORIZED, e)),
|
Err(e) => return Err(JsonResponse::error(StatusCode::UNAUTHORIZED, e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if data.claims.compute_id != compute_id {
|
match data.claims.scope {
|
||||||
return Err(JsonResponse::error(
|
// TODO: We should validate audience for every token, but
|
||||||
StatusCode::UNAUTHORIZED,
|
// instead of this ad-hoc validation, we should turn
|
||||||
"invalid compute ID in authorization token claims",
|
// [`Validation::validate_aud`] on. This is merely a stopgap
|
||||||
));
|
// while we roll out `aud` deployment. We return a 401
|
||||||
|
// Unauthorized because when we eventually do use
|
||||||
|
// [`Validation`], we will hit the above `Err` match arm which
|
||||||
|
// returns 401 Unauthorized.
|
||||||
|
Some(ComputeClaimsScope::Admin) => {
|
||||||
|
let Some(ref audience) = data.claims.audience else {
|
||||||
|
return Err(JsonResponse::error(
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
"missing audience in authorization token claims",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
if !audience.iter().any(|a| a == COMPUTE_AUDIENCE) {
|
||||||
|
return Err(JsonResponse::error(
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
"invalid audience in authorization token claims",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the scope is not [`ComputeClaimsScope::Admin`], then we
|
||||||
|
// must validate the compute_id
|
||||||
|
_ => {
|
||||||
|
let Some(ref claimed_compute_id) = data.claims.compute_id else {
|
||||||
|
return Err(JsonResponse::error(
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
"missing compute_id in authorization token claims",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
if *claimed_compute_id != compute_id {
|
||||||
|
return Err(JsonResponse::error(
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
"invalid compute ID in authorization token claims",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make claims available to any subsequent middleware or request
|
// Make claims available to any subsequent middleware or request
|
||||||
|
|||||||
@@ -48,11 +48,9 @@ impl JsonResponse {
|
|||||||
|
|
||||||
/// Create an error response related to the compute being in an invalid state
|
/// Create an error response related to the compute being in an invalid state
|
||||||
pub(self) fn invalid_status(status: ComputeStatus) -> Response {
|
pub(self) fn invalid_status(status: ComputeStatus) -> Response {
|
||||||
Self::create_response(
|
Self::error(
|
||||||
StatusCode::PRECONDITION_FAILED,
|
StatusCode::PRECONDITION_FAILED,
|
||||||
&GenericAPIError {
|
format!("invalid compute status: {status}"),
|
||||||
error: format!("invalid compute status: {status}"),
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub(in crate::http) async fn configure(
|
|||||||
State(compute): State<Arc<ComputeNode>>,
|
State(compute): State<Arc<ComputeNode>>,
|
||||||
request: Json<ConfigurationRequest>,
|
request: Json<ConfigurationRequest>,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let pspec = match ParsedSpec::try_from(request.spec.clone()) {
|
let pspec = match ParsedSpec::try_from(request.0.spec) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return JsonResponse::error(StatusCode::BAD_REQUEST, e),
|
Err(e) => return JsonResponse::error(StatusCode::BAD_REQUEST, e),
|
||||||
};
|
};
|
||||||
@@ -65,7 +65,7 @@ pub(in crate::http) async fn configure(
|
|||||||
|
|
||||||
if state.status == ComputeStatus::Failed {
|
if state.status == ComputeStatus::Failed {
|
||||||
let err = state.error.as_ref().map_or("unknown error", |x| x);
|
let err = state.error.as_ref().map_or("unknown error", |x| x);
|
||||||
let msg = format!("compute configuration failed: {:?}", err);
|
let msg = format!("compute configuration failed: {err:?}");
|
||||||
return Err(msg);
|
return Err(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub(in crate::http) async fn download_extension(
|
|||||||
State(compute): State<Arc<ComputeNode>>,
|
State(compute): State<Arc<ComputeNode>>,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
// Don't even try to download extensions if no remote storage is configured
|
// Don't even try to download extensions if no remote storage is configured
|
||||||
if compute.params.ext_remote_storage.is_none() {
|
if compute.params.remote_ext_base_url.is_none() {
|
||||||
return JsonResponse::error(
|
return JsonResponse::error(
|
||||||
StatusCode::PRECONDITION_FAILED,
|
StatusCode::PRECONDITION_FAILED,
|
||||||
"remote storage is not configured",
|
"remote storage is not configured",
|
||||||
|
|||||||
48
compute_tools/src/http/routes/lfc.rs
Normal file
48
compute_tools/src/http/routes/lfc.rs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
use crate::compute_prewarm::LfcPrewarmStateWithProgress;
|
||||||
|
use crate::http::JsonResponse;
|
||||||
|
use axum::response::{IntoResponse, Response};
|
||||||
|
use axum::{Json, http::StatusCode};
|
||||||
|
use axum_extra::extract::OptionalQuery;
|
||||||
|
use compute_api::responses::LfcOffloadState;
|
||||||
|
type Compute = axum::extract::State<std::sync::Arc<crate::compute::ComputeNode>>;
|
||||||
|
|
||||||
|
pub(in crate::http) async fn prewarm_state(compute: Compute) -> Json<LfcPrewarmStateWithProgress> {
|
||||||
|
Json(compute.lfc_prewarm_state().await)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Following functions are marked async for axum, as it's more convenient than wrapping these
|
||||||
|
// in async lambdas at call site
|
||||||
|
|
||||||
|
pub(in crate::http) async fn offload_state(compute: Compute) -> Json<LfcOffloadState> {
|
||||||
|
Json(compute.lfc_offload_state())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
pub struct PrewarmQuery {
|
||||||
|
pub from_endpoint: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::http) async fn prewarm(
|
||||||
|
compute: Compute,
|
||||||
|
OptionalQuery(query): OptionalQuery<PrewarmQuery>,
|
||||||
|
) -> Response {
|
||||||
|
if compute.prewarm_lfc(query.map(|q| q.from_endpoint)) {
|
||||||
|
StatusCode::ACCEPTED.into_response()
|
||||||
|
} else {
|
||||||
|
JsonResponse::error(
|
||||||
|
StatusCode::TOO_MANY_REQUESTS,
|
||||||
|
"Multiple requests for prewarm are not allowed",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::http) async fn offload(compute: Compute) -> Response {
|
||||||
|
if compute.offload_lfc() {
|
||||||
|
StatusCode::ACCEPTED.into_response()
|
||||||
|
} else {
|
||||||
|
JsonResponse::error(
|
||||||
|
StatusCode::TOO_MANY_REQUESTS,
|
||||||
|
"Multiple requests for prewarm offload are not allowed",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ pub(in crate::http) mod extensions;
|
|||||||
pub(in crate::http) mod failpoints;
|
pub(in crate::http) mod failpoints;
|
||||||
pub(in crate::http) mod grants;
|
pub(in crate::http) mod grants;
|
||||||
pub(in crate::http) mod insights;
|
pub(in crate::http) mod insights;
|
||||||
|
pub(in crate::http) mod lfc;
|
||||||
pub(in crate::http) mod metrics;
|
pub(in crate::http) mod metrics;
|
||||||
pub(in crate::http) mod metrics_json;
|
pub(in crate::http) mod metrics_json;
|
||||||
pub(in crate::http) mod status;
|
pub(in crate::http) mod status;
|
||||||
|
|||||||
@@ -1,32 +1,42 @@
|
|||||||
use std::sync::Arc;
|
use crate::compute::{ComputeNode, forward_termination_signal};
|
||||||
|
use crate::http::JsonResponse;
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::Response;
|
||||||
use compute_api::responses::ComputeStatus;
|
use axum_extra::extract::OptionalQuery;
|
||||||
|
use compute_api::responses::{ComputeStatus, TerminateResponse};
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::compute::{ComputeNode, forward_termination_signal};
|
#[derive(Deserialize, Default)]
|
||||||
use crate::http::JsonResponse;
|
pub struct TerminateQuery {
|
||||||
|
mode: compute_api::responses::TerminateMode,
|
||||||
|
}
|
||||||
|
|
||||||
/// Terminate the compute.
|
/// Terminate the compute.
|
||||||
pub(in crate::http) async fn terminate(State(compute): State<Arc<ComputeNode>>) -> Response {
|
pub(in crate::http) async fn terminate(
|
||||||
|
State(compute): State<Arc<ComputeNode>>,
|
||||||
|
OptionalQuery(terminate): OptionalQuery<TerminateQuery>,
|
||||||
|
) -> Response {
|
||||||
|
let mode = terminate.unwrap_or_default().mode;
|
||||||
{
|
{
|
||||||
let mut state = compute.state.lock().unwrap();
|
let mut state = compute.state.lock().unwrap();
|
||||||
if state.status == ComputeStatus::Terminated {
|
if state.status == ComputeStatus::Terminated {
|
||||||
return StatusCode::CREATED.into_response();
|
return JsonResponse::success(StatusCode::CREATED, state.terminate_flush_lsn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches!(state.status, ComputeStatus::Empty | ComputeStatus::Running) {
|
if !matches!(state.status, ComputeStatus::Empty | ComputeStatus::Running) {
|
||||||
return JsonResponse::invalid_status(state.status);
|
return JsonResponse::invalid_status(state.status);
|
||||||
}
|
}
|
||||||
|
state.set_status(
|
||||||
state.set_status(ComputeStatus::TerminationPending, &compute.state_changed);
|
ComputeStatus::TerminationPending { mode },
|
||||||
drop(state);
|
&compute.state_changed,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
forward_termination_signal();
|
forward_termination_signal(false);
|
||||||
info!("sent signal and notified waiters");
|
info!("sent signal and notified waiters");
|
||||||
|
|
||||||
// Spawn a blocking thread to wait for compute to become Terminated.
|
// Spawn a blocking thread to wait for compute to become Terminated.
|
||||||
@@ -34,7 +44,7 @@ pub(in crate::http) async fn terminate(State(compute): State<Arc<ComputeNode>>)
|
|||||||
// be able to serve other requests while some particular request
|
// be able to serve other requests while some particular request
|
||||||
// is waiting for compute to finish configuration.
|
// is waiting for compute to finish configuration.
|
||||||
let c = compute.clone();
|
let c = compute.clone();
|
||||||
task::spawn_blocking(move || {
|
let lsn = task::spawn_blocking(move || {
|
||||||
let mut state = c.state.lock().unwrap();
|
let mut state = c.state.lock().unwrap();
|
||||||
while state.status != ComputeStatus::Terminated {
|
while state.status != ComputeStatus::Terminated {
|
||||||
state = c.state_changed.wait(state).unwrap();
|
state = c.state_changed.wait(state).unwrap();
|
||||||
@@ -44,11 +54,10 @@ pub(in crate::http) async fn terminate(State(compute): State<Arc<ComputeNode>>)
|
|||||||
state.status
|
state.status
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
state.terminate_flush_lsn
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("terminated Postgres");
|
info!("terminated Postgres");
|
||||||
|
JsonResponse::success(StatusCode::OK, TerminateResponse { lsn })
|
||||||
StatusCode::OK.into_response()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use super::{
|
|||||||
middleware::authorize::Authorize,
|
middleware::authorize::Authorize,
|
||||||
routes::{
|
routes::{
|
||||||
check_writability, configure, database_schema, dbs_and_roles, extension_server, extensions,
|
check_writability, configure, database_schema, dbs_and_roles, extension_server, extensions,
|
||||||
grants, insights, metrics, metrics_json, status, terminate,
|
grants, insights, lfc, metrics, metrics_json, status, terminate,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::compute::ComputeNode;
|
use crate::compute::ComputeNode;
|
||||||
@@ -85,6 +85,8 @@ impl From<&Server> for Router<Arc<ComputeNode>> {
|
|||||||
Router::<Arc<ComputeNode>>::new().route("/metrics", get(metrics::get_metrics));
|
Router::<Arc<ComputeNode>>::new().route("/metrics", get(metrics::get_metrics));
|
||||||
|
|
||||||
let authenticated_router = Router::<Arc<ComputeNode>>::new()
|
let authenticated_router = Router::<Arc<ComputeNode>>::new()
|
||||||
|
.route("/lfc/prewarm", get(lfc::prewarm_state).post(lfc::prewarm))
|
||||||
|
.route("/lfc/offload", get(lfc::offload_state).post(lfc::offload))
|
||||||
.route("/check_writability", post(check_writability::is_writable))
|
.route("/check_writability", post(check_writability::is_writable))
|
||||||
.route("/configure", post(configure::configure))
|
.route("/configure", post(configure::configure))
|
||||||
.route("/database_schema", get(database_schema::get_schema_dump))
|
.route("/database_schema", get(database_schema::get_schema_dump))
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ pub async fn get_installed_extensions(mut conf: Config) -> Result<InstalledExten
|
|||||||
let (mut client, connection) = conf.connect(NoTls).await?;
|
let (mut client, connection) = conf.connect(NoTls).await?;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = connection.await {
|
if let Err(e) = connection.await {
|
||||||
eprintln!("connection error: {}", e);
|
eprintln!("connection error: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ pub async fn get_installed_extensions(mut conf: Config) -> Result<InstalledExten
|
|||||||
let (client, connection) = conf.connect(NoTls).await?;
|
let (client, connection) = conf.connect(NoTls).await?;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = connection.await {
|
if let Err(e) = connection.await {
|
||||||
eprintln!("connection error: {}", e);
|
eprintln!("connection error: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub mod http;
|
|||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod catalog;
|
pub mod catalog;
|
||||||
pub mod compute;
|
pub mod compute;
|
||||||
|
pub mod compute_prewarm;
|
||||||
pub mod disk_quota;
|
pub mod disk_quota;
|
||||||
pub mod extension_server;
|
pub mod extension_server;
|
||||||
pub mod installed_extensions;
|
pub mod installed_extensions;
|
||||||
@@ -21,6 +22,7 @@ mod migration;
|
|||||||
pub mod monitor;
|
pub mod monitor;
|
||||||
pub mod params;
|
pub mod params;
|
||||||
pub mod pg_helpers;
|
pub mod pg_helpers;
|
||||||
|
pub mod pgbouncer;
|
||||||
pub mod rsyslog;
|
pub mod rsyslog;
|
||||||
pub mod spec;
|
pub mod spec;
|
||||||
mod spec_apply;
|
mod spec_apply;
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ use std::thread;
|
|||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use compute_api::spec::ComputeMode;
|
use compute_api::spec::{ComputeMode, PageserverConnectionInfo};
|
||||||
|
use pageserver_page_api as page_api;
|
||||||
use postgres::{NoTls, SimpleQueryMessage};
|
use postgres::{NoTls, SimpleQueryMessage};
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
use utils::id::{TenantId, TimelineId};
|
use utils::id::{TenantId, TimelineId};
|
||||||
@@ -76,25 +77,16 @@ fn acquire_lsn_lease_with_retry(
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Note: List of pageservers is dynamic, need to re-read configs before each attempt.
|
// Note: List of pageservers is dynamic, need to re-read configs before each attempt.
|
||||||
let configs = {
|
let (conninfo, auth) = {
|
||||||
let state = compute.state.lock().unwrap();
|
let state = compute.state.lock().unwrap();
|
||||||
|
|
||||||
let spec = state.pspec.as_ref().expect("spec must be set");
|
let spec = state.pspec.as_ref().expect("spec must be set");
|
||||||
|
(
|
||||||
let conn_strings = spec.pageserver_connstr.split(',');
|
spec.pageserver_conninfo.clone(),
|
||||||
|
spec.storage_auth_token.clone(),
|
||||||
conn_strings
|
)
|
||||||
.map(|connstr| {
|
|
||||||
let mut config = postgres::Config::from_str(connstr).expect("Invalid connstr");
|
|
||||||
if let Some(storage_auth_token) = &spec.storage_auth_token {
|
|
||||||
config.password(storage_auth_token.clone());
|
|
||||||
}
|
|
||||||
config
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = try_acquire_lsn_lease(tenant_id, timeline_id, lsn, &configs);
|
let result = try_acquire_lsn_lease(conninfo, auth.as_deref(), tenant_id, timeline_id, lsn);
|
||||||
match result {
|
match result {
|
||||||
Ok(Some(res)) => {
|
Ok(Some(res)) => {
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
@@ -116,68 +108,112 @@ fn acquire_lsn_lease_with_retry(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to acquire an LSN lease through PS page_service API.
|
/// Tries to acquire LSN leases on all Pageserver shards.
|
||||||
fn try_acquire_lsn_lease(
|
fn try_acquire_lsn_lease(
|
||||||
|
conninfo: PageserverConnectionInfo,
|
||||||
|
auth: Option<&str>,
|
||||||
tenant_id: TenantId,
|
tenant_id: TenantId,
|
||||||
timeline_id: TimelineId,
|
timeline_id: TimelineId,
|
||||||
lsn: Lsn,
|
lsn: Lsn,
|
||||||
configs: &[postgres::Config],
|
|
||||||
) -> Result<Option<SystemTime>> {
|
) -> Result<Option<SystemTime>> {
|
||||||
fn get_valid_until(
|
let shard_count = conninfo.shards.len();
|
||||||
config: &postgres::Config,
|
let mut leases = Vec::new();
|
||||||
tenant_shard_id: TenantShardId,
|
|
||||||
timeline_id: TimelineId,
|
for (shard_number, shard) in conninfo.shards.into_iter() {
|
||||||
lsn: Lsn,
|
let tenant_shard_id = match shard_count {
|
||||||
) -> Result<Option<SystemTime>> {
|
0 | 1 => TenantShardId::unsharded(tenant_id),
|
||||||
let mut client = config.connect(NoTls)?;
|
shard_count => TenantShardId {
|
||||||
let cmd = format!("lease lsn {} {} {} ", tenant_shard_id, timeline_id, lsn);
|
tenant_id,
|
||||||
let res = client.simple_query(&cmd)?;
|
shard_number: ShardNumber(shard_number as u8),
|
||||||
let msg = match res.first() {
|
shard_count: ShardCount::new(shard_count as u8),
|
||||||
Some(msg) => msg,
|
},
|
||||||
None => bail!("empty response"),
|
|
||||||
};
|
|
||||||
let row = match msg {
|
|
||||||
SimpleQueryMessage::Row(row) => row,
|
|
||||||
_ => bail!("error parsing lsn lease response"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note: this will be None if a lease is explicitly not granted.
|
let lease = if conninfo.prefer_grpc {
|
||||||
let valid_until_str = row.get("valid_until");
|
acquire_lsn_lease_grpc(
|
||||||
|
&shard.grpc_url.unwrap(),
|
||||||
let valid_until = valid_until_str.map(|s| {
|
auth,
|
||||||
SystemTime::UNIX_EPOCH
|
tenant_shard_id,
|
||||||
.checked_add(Duration::from_millis(u128::from_str(s).unwrap() as u64))
|
timeline_id,
|
||||||
.expect("Time larger than max SystemTime could handle")
|
lsn,
|
||||||
});
|
)?
|
||||||
Ok(valid_until)
|
} else {
|
||||||
|
acquire_lsn_lease_libpq(
|
||||||
|
&shard.libpq_url.unwrap(),
|
||||||
|
auth,
|
||||||
|
tenant_shard_id,
|
||||||
|
timeline_id,
|
||||||
|
lsn,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
leases.push(lease);
|
||||||
}
|
}
|
||||||
|
|
||||||
let shard_count = configs.len();
|
Ok(leases.into_iter().min().flatten())
|
||||||
|
}
|
||||||
|
|
||||||
let valid_until = if shard_count > 1 {
|
/// Acquires an LSN lease on a single shard, using the libpq API. The connstring must use a
|
||||||
configs
|
/// postgresql:// scheme.
|
||||||
.iter()
|
fn acquire_lsn_lease_libpq(
|
||||||
.enumerate()
|
connstring: &str,
|
||||||
.map(|(shard_number, config)| {
|
auth: Option<&str>,
|
||||||
let tenant_shard_id = TenantShardId {
|
tenant_shard_id: TenantShardId,
|
||||||
tenant_id,
|
timeline_id: TimelineId,
|
||||||
shard_count: ShardCount::new(shard_count as u8),
|
lsn: Lsn,
|
||||||
shard_number: ShardNumber(shard_number as u8),
|
) -> Result<Option<SystemTime>> {
|
||||||
};
|
let mut config = postgres::Config::from_str(connstring)?;
|
||||||
get_valid_until(config, tenant_shard_id, timeline_id, lsn)
|
if let Some(auth) = auth {
|
||||||
})
|
config.password(auth);
|
||||||
.collect::<Result<Vec<Option<SystemTime>>>>()?
|
}
|
||||||
.into_iter()
|
let mut client = config.connect(NoTls)?;
|
||||||
.min()
|
let cmd = format!("lease lsn {tenant_shard_id} {timeline_id} {lsn} ");
|
||||||
.unwrap()
|
let res = client.simple_query(&cmd)?;
|
||||||
} else {
|
let msg = match res.first() {
|
||||||
get_valid_until(
|
Some(msg) => msg,
|
||||||
&configs[0],
|
None => bail!("empty response"),
|
||||||
TenantShardId::unsharded(tenant_id),
|
};
|
||||||
timeline_id,
|
let row = match msg {
|
||||||
lsn,
|
SimpleQueryMessage::Row(row) => row,
|
||||||
)?
|
_ => bail!("error parsing lsn lease response"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Note: this will be None if a lease is explicitly not granted.
|
||||||
|
let valid_until_str = row.get("valid_until");
|
||||||
|
|
||||||
|
let valid_until = valid_until_str.map(|s| {
|
||||||
|
SystemTime::UNIX_EPOCH
|
||||||
|
.checked_add(Duration::from_millis(u128::from_str(s).unwrap() as u64))
|
||||||
|
.expect("Time larger than max SystemTime could handle")
|
||||||
|
});
|
||||||
Ok(valid_until)
|
Ok(valid_until)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Acquires an LSN lease on a single shard, using the gRPC API. The connstring must use a
|
||||||
|
/// grpc:// scheme.
|
||||||
|
fn acquire_lsn_lease_grpc(
|
||||||
|
connstring: &str,
|
||||||
|
auth: Option<&str>,
|
||||||
|
tenant_shard_id: TenantShardId,
|
||||||
|
timeline_id: TimelineId,
|
||||||
|
lsn: Lsn,
|
||||||
|
) -> Result<Option<SystemTime>> {
|
||||||
|
tokio::runtime::Handle::current().block_on(async move {
|
||||||
|
let mut client = page_api::Client::connect(
|
||||||
|
connstring.to_string(),
|
||||||
|
tenant_shard_id.tenant_id,
|
||||||
|
timeline_id,
|
||||||
|
tenant_shard_id.to_index(),
|
||||||
|
auth.map(String::from),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let req = page_api::LeaseLsnRequest { lsn };
|
||||||
|
match client.lease_lsn(req).await {
|
||||||
|
Ok(expires) => Ok(Some(expires)),
|
||||||
|
// Lease couldn't be acquired because the LSN has been garbage collected.
|
||||||
|
Err(err) if err.code() == tonic::Code::FailedPrecondition => Ok(None),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use metrics::core::{AtomicF64, AtomicU64, Collector, GenericCounter, GenericGauge};
|
use metrics::core::{AtomicF64, AtomicU64, Collector, GenericCounter, GenericGauge};
|
||||||
use metrics::proto::MetricFamily;
|
use metrics::proto::MetricFamily;
|
||||||
use metrics::{
|
use metrics::{
|
||||||
IntCounterVec, IntGaugeVec, UIntGaugeVec, register_gauge, register_int_counter,
|
IntCounter, IntCounterVec, IntGaugeVec, UIntGaugeVec, register_gauge, register_int_counter,
|
||||||
register_int_counter_vec, register_int_gauge_vec, register_uint_gauge_vec,
|
register_int_counter_vec, register_int_gauge_vec, register_uint_gauge_vec,
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
@@ -97,6 +97,24 @@ pub(crate) static PG_TOTAL_DOWNTIME_MS: Lazy<GenericCounter<AtomicU64>> = Lazy::
|
|||||||
.expect("failed to define a metric")
|
.expect("failed to define a metric")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Needed as neon.file_cache_prewarm_batch == 0 doesn't mean we never tried to prewarm.
|
||||||
|
/// On the other hand, LFC_PREWARMED_PAGES is excessive as we can GET /lfc/prewarm
|
||||||
|
pub(crate) static LFC_PREWARM_REQUESTS: Lazy<IntCounter> = Lazy::new(|| {
|
||||||
|
register_int_counter!(
|
||||||
|
"compute_ctl_lfc_prewarm_requests_total",
|
||||||
|
"Total number of LFC prewarm requests made by compute_ctl",
|
||||||
|
)
|
||||||
|
.expect("failed to define a metric")
|
||||||
|
});
|
||||||
|
|
||||||
|
pub(crate) static LFC_OFFLOAD_REQUESTS: Lazy<IntCounter> = Lazy::new(|| {
|
||||||
|
register_int_counter!(
|
||||||
|
"compute_ctl_lfc_offload_requests_total",
|
||||||
|
"Total number of LFC offload requests made by compute_ctl",
|
||||||
|
)
|
||||||
|
.expect("failed to define a metric")
|
||||||
|
});
|
||||||
|
|
||||||
pub fn collect() -> Vec<MetricFamily> {
|
pub fn collect() -> Vec<MetricFamily> {
|
||||||
let mut metrics = COMPUTE_CTL_UP.collect();
|
let mut metrics = COMPUTE_CTL_UP.collect();
|
||||||
metrics.extend(INSTALLED_EXTENSIONS.collect());
|
metrics.extend(INSTALLED_EXTENSIONS.collect());
|
||||||
@@ -106,5 +124,7 @@ pub fn collect() -> Vec<MetricFamily> {
|
|||||||
metrics.extend(AUDIT_LOG_DIR_SIZE.collect());
|
metrics.extend(AUDIT_LOG_DIR_SIZE.collect());
|
||||||
metrics.extend(PG_CURR_DOWNTIME_MS.collect());
|
metrics.extend(PG_CURR_DOWNTIME_MS.collect());
|
||||||
metrics.extend(PG_TOTAL_DOWNTIME_MS.collect());
|
metrics.extend(PG_TOTAL_DOWNTIME_MS.collect());
|
||||||
|
metrics.extend(LFC_PREWARM_REQUESTS.collect());
|
||||||
|
metrics.extend(LFC_OFFLOAD_REQUESTS.collect());
|
||||||
metrics
|
metrics
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ use crate::metrics::{PG_CURR_DOWNTIME_MS, PG_TOTAL_DOWNTIME_MS};
|
|||||||
|
|
||||||
const MONITOR_CHECK_INTERVAL: Duration = Duration::from_millis(500);
|
const MONITOR_CHECK_INTERVAL: Duration = Duration::from_millis(500);
|
||||||
|
|
||||||
|
/// Struct to store runtime state of the compute monitor thread.
|
||||||
|
/// In theory, this could be a part of `Compute`, but i)
|
||||||
|
/// this state is expected to be accessed only by single thread,
|
||||||
|
/// so we don't need to care about locking; ii) `Compute` is
|
||||||
|
/// already quite big. Thus, it seems to be a good idea to keep
|
||||||
|
/// all the activity/health monitoring parts here.
|
||||||
struct ComputeMonitor {
|
struct ComputeMonitor {
|
||||||
compute: Arc<ComputeNode>,
|
compute: Arc<ComputeNode>,
|
||||||
|
|
||||||
@@ -70,12 +76,38 @@ impl ComputeMonitor {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if compute is in some terminal or soon-to-be-terminal
|
||||||
|
/// state, then return `true`, signalling the caller that it
|
||||||
|
/// should exit gracefully. Otherwise, return `false`.
|
||||||
|
fn check_interrupts(&mut self) -> bool {
|
||||||
|
let compute_status = self.compute.get_status();
|
||||||
|
if matches!(
|
||||||
|
compute_status,
|
||||||
|
ComputeStatus::Terminated
|
||||||
|
| ComputeStatus::TerminationPending { .. }
|
||||||
|
| ComputeStatus::Failed
|
||||||
|
) {
|
||||||
|
info!(
|
||||||
|
"compute is in {} status, stopping compute monitor",
|
||||||
|
compute_status
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Spin in a loop and figure out the last activity time in the Postgres.
|
/// Spin in a loop and figure out the last activity time in the Postgres.
|
||||||
/// Then update it in the shared state. This function never errors out.
|
/// Then update it in the shared state. This function currently never
|
||||||
|
/// errors out explicitly, but there is a graceful termination path.
|
||||||
|
/// Every time we receive an error trying to check Postgres, we use
|
||||||
|
/// [`ComputeMonitor::check_interrupts()`] because it could be that
|
||||||
|
/// compute is being terminated already, then we can exit gracefully
|
||||||
|
/// to not produce errors' noise in the log.
|
||||||
/// NB: the only expected panic is at `Mutex` unwrap(), all other errors
|
/// NB: the only expected panic is at `Mutex` unwrap(), all other errors
|
||||||
/// should be handled gracefully.
|
/// should be handled gracefully.
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) -> anyhow::Result<()> {
|
||||||
// Suppose that `connstr` doesn't change
|
// Suppose that `connstr` doesn't change
|
||||||
let connstr = self.compute.params.connstr.clone();
|
let connstr = self.compute.params.connstr.clone();
|
||||||
let conf = self
|
let conf = self
|
||||||
@@ -93,6 +125,10 @@ impl ComputeMonitor {
|
|||||||
info!("starting compute monitor for {}", connstr);
|
info!("starting compute monitor for {}", connstr);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
if self.check_interrupts() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
match &mut client {
|
match &mut client {
|
||||||
Ok(cli) => {
|
Ok(cli) => {
|
||||||
if cli.is_closed() {
|
if cli.is_closed() {
|
||||||
@@ -100,6 +136,10 @@ impl ComputeMonitor {
|
|||||||
downtime_info = self.downtime_info(),
|
downtime_info = self.downtime_info(),
|
||||||
"connection to Postgres is closed, trying to reconnect"
|
"connection to Postgres is closed, trying to reconnect"
|
||||||
);
|
);
|
||||||
|
if self.check_interrupts() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
self.report_down();
|
self.report_down();
|
||||||
|
|
||||||
// Connection is closed, reconnect and try again.
|
// Connection is closed, reconnect and try again.
|
||||||
@@ -111,15 +151,19 @@ impl ComputeMonitor {
|
|||||||
self.compute.update_last_active(self.last_active);
|
self.compute.update_last_active(self.last_active);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
downtime_info = self.downtime_info(),
|
||||||
|
"could not check Postgres: {}", e
|
||||||
|
);
|
||||||
|
if self.check_interrupts() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Although we have many places where we can return errors in `check()`,
|
// Although we have many places where we can return errors in `check()`,
|
||||||
// normally it shouldn't happen. I.e., we will likely return error if
|
// normally it shouldn't happen. I.e., we will likely return error if
|
||||||
// connection got broken, query timed out, Postgres returned invalid data, etc.
|
// connection got broken, query timed out, Postgres returned invalid data, etc.
|
||||||
// In all such cases it's suspicious, so let's report this as downtime.
|
// In all such cases it's suspicious, so let's report this as downtime.
|
||||||
self.report_down();
|
self.report_down();
|
||||||
error!(
|
|
||||||
downtime_info = self.downtime_info(),
|
|
||||||
"could not check Postgres: {}", e
|
|
||||||
);
|
|
||||||
|
|
||||||
// Reconnect to Postgres just in case. During tests, I noticed
|
// Reconnect to Postgres just in case. During tests, I noticed
|
||||||
// that queries in `check()` can fail with `connection closed`,
|
// that queries in `check()` can fail with `connection closed`,
|
||||||
@@ -136,6 +180,10 @@ impl ComputeMonitor {
|
|||||||
downtime_info = self.downtime_info(),
|
downtime_info = self.downtime_info(),
|
||||||
"could not connect to Postgres: {}, retrying", e
|
"could not connect to Postgres: {}, retrying", e
|
||||||
);
|
);
|
||||||
|
if self.check_interrupts() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
self.report_down();
|
self.report_down();
|
||||||
|
|
||||||
// Establish a new connection and try again.
|
// Establish a new connection and try again.
|
||||||
@@ -147,6 +195,9 @@ impl ComputeMonitor {
|
|||||||
self.last_checked = Utc::now();
|
self.last_checked = Utc::now();
|
||||||
thread::sleep(MONITOR_CHECK_INTERVAL);
|
thread::sleep(MONITOR_CHECK_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Graceful termination path
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
@@ -424,12 +475,15 @@ pub fn launch_monitor(compute: &Arc<ComputeNode>) -> thread::JoinHandle<()> {
|
|||||||
experimental,
|
experimental,
|
||||||
};
|
};
|
||||||
|
|
||||||
let span = span!(Level::INFO, "compute_monitor");
|
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("compute-monitor".into())
|
.name("compute-monitor".into())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
|
let span = span!(Level::INFO, "compute_monitor");
|
||||||
let _enter = span.enter();
|
let _enter = span.enter();
|
||||||
monitor.run();
|
match monitor.run() {
|
||||||
|
Ok(_) => info!("compute monitor thread terminated gracefully"),
|
||||||
|
Err(err) => error!("compute monitor thread terminated abnormally {:?}", err),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.expect("cannot launch compute monitor thread")
|
.expect("cannot launch compute monitor thread")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ pub fn escape_literal(s: &str) -> String {
|
|||||||
let res = s.replace('\'', "''").replace('\\', "\\\\");
|
let res = s.replace('\'', "''").replace('\\', "\\\\");
|
||||||
|
|
||||||
if res.contains('\\') {
|
if res.contains('\\') {
|
||||||
format!("E'{}'", res)
|
format!("E'{res}'")
|
||||||
} else {
|
} else {
|
||||||
format!("'{}'", res)
|
format!("'{res}'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ pub fn escape_literal(s: &str) -> String {
|
|||||||
/// with `'{}'` is not required, as it returns a ready-to-use config string.
|
/// with `'{}'` is not required, as it returns a ready-to-use config string.
|
||||||
pub fn escape_conf_value(s: &str) -> String {
|
pub fn escape_conf_value(s: &str) -> String {
|
||||||
let res = s.replace('\'', "''").replace('\\', "\\\\");
|
let res = s.replace('\'', "''").replace('\\', "\\\\");
|
||||||
format!("'{}'", res)
|
format!("'{res}'")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GenericOptionExt {
|
pub trait GenericOptionExt {
|
||||||
@@ -213,8 +213,10 @@ impl Escaping for PgIdent {
|
|||||||
|
|
||||||
// Find the first suitable tag that is not present in the string.
|
// Find the first suitable tag that is not present in the string.
|
||||||
// Postgres' max role/DB name length is 63 bytes, so even in the
|
// Postgres' max role/DB name length is 63 bytes, so even in the
|
||||||
// worst case it won't take long.
|
// worst case it won't take long. Outer tag is always `tag + "x"`,
|
||||||
while self.contains(&format!("${tag}$")) || self.contains(&format!("${outer_tag}$")) {
|
// so if `tag` is not present in the string, `outer_tag` is not
|
||||||
|
// present in the string either.
|
||||||
|
while self.contains(&tag.to_string()) {
|
||||||
tag += "x";
|
tag += "x";
|
||||||
outer_tag = tag.clone() + "x";
|
outer_tag = tag.clone() + "x";
|
||||||
}
|
}
|
||||||
@@ -444,7 +446,7 @@ pub async fn tune_pgbouncer(
|
|||||||
let mut pgbouncer_connstr =
|
let mut pgbouncer_connstr =
|
||||||
"host=localhost port=6432 dbname=pgbouncer user=postgres sslmode=disable".to_string();
|
"host=localhost port=6432 dbname=pgbouncer user=postgres sslmode=disable".to_string();
|
||||||
if let Ok(pass) = std::env::var("PGBOUNCER_PASSWORD") {
|
if let Ok(pass) = std::env::var("PGBOUNCER_PASSWORD") {
|
||||||
pgbouncer_connstr.push_str(format!(" password={}", pass).as_str());
|
pgbouncer_connstr.push_str(format!(" password={pass}").as_str());
|
||||||
}
|
}
|
||||||
pgbouncer_connstr
|
pgbouncer_connstr
|
||||||
};
|
};
|
||||||
@@ -462,7 +464,7 @@ pub async fn tune_pgbouncer(
|
|||||||
Ok((client, connection)) => {
|
Ok((client, connection)) => {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = connection.await {
|
if let Err(e) = connection.await {
|
||||||
eprintln!("connection error: {}", e);
|
eprintln!("connection error: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break client;
|
break client;
|
||||||
|
|||||||
1
compute_tools/src/pgbouncer.rs
Normal file
1
compute_tools/src/pgbouncer.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub const PGBOUNCER_PIDFILE: &str = "/tmp/pgbouncer.pid";
|
||||||
@@ -27,6 +27,40 @@ fn get_rsyslog_pid() -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wait_for_rsyslog_pid() -> Result<String, anyhow::Error> {
|
||||||
|
const MAX_WAIT: Duration = Duration::from_secs(5);
|
||||||
|
const INITIAL_SLEEP: Duration = Duration::from_millis(2);
|
||||||
|
|
||||||
|
let mut sleep_duration = INITIAL_SLEEP;
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
let mut attempts = 1;
|
||||||
|
|
||||||
|
for attempt in 1.. {
|
||||||
|
attempts = attempt;
|
||||||
|
match get_rsyslog_pid() {
|
||||||
|
Some(pid) => return Ok(pid),
|
||||||
|
None => {
|
||||||
|
if start.elapsed() >= MAX_WAIT {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
"rsyslogd is not running, attempt {}. Sleeping for {} ms",
|
||||||
|
attempt,
|
||||||
|
sleep_duration.as_millis()
|
||||||
|
);
|
||||||
|
std::thread::sleep(sleep_duration);
|
||||||
|
sleep_duration *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"rsyslogd is not running after waiting for {} seconds and {} attempts",
|
||||||
|
attempts,
|
||||||
|
start.elapsed().as_secs()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
// Restart rsyslogd to apply the new configuration.
|
// Restart rsyslogd to apply the new configuration.
|
||||||
// This is necessary, because there is no other way to reload the rsyslog configuration.
|
// This is necessary, because there is no other way to reload the rsyslog configuration.
|
||||||
//
|
//
|
||||||
@@ -36,27 +70,29 @@ fn get_rsyslog_pid() -> Option<String> {
|
|||||||
// TODO: test it properly
|
// TODO: test it properly
|
||||||
//
|
//
|
||||||
fn restart_rsyslog() -> Result<()> {
|
fn restart_rsyslog() -> Result<()> {
|
||||||
let old_pid = get_rsyslog_pid().context("rsyslogd is not running")?;
|
|
||||||
info!("rsyslogd is running with pid: {}, restart it", old_pid);
|
|
||||||
|
|
||||||
// kill it to restart
|
// kill it to restart
|
||||||
let _ = Command::new("pkill")
|
let _ = Command::new("pkill")
|
||||||
.arg("rsyslogd")
|
.arg("rsyslogd")
|
||||||
.output()
|
.output()
|
||||||
.context("Failed to stop rsyslogd")?;
|
.context("Failed to restart rsyslogd")?;
|
||||||
|
|
||||||
|
// ensure rsyslogd is running
|
||||||
|
wait_for_rsyslog_pid()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure_audit_rsyslog(
|
pub fn configure_audit_rsyslog(
|
||||||
log_directory: String,
|
log_directory: String,
|
||||||
tag: Option<String>,
|
endpoint_id: &str,
|
||||||
|
project_id: &str,
|
||||||
remote_endpoint: &str,
|
remote_endpoint: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let config_content: String = format!(
|
let config_content: String = format!(
|
||||||
include_str!("config_template/compute_audit_rsyslog_template.conf"),
|
include_str!("config_template/compute_audit_rsyslog_template.conf"),
|
||||||
log_directory = log_directory,
|
log_directory = log_directory,
|
||||||
tag = tag.unwrap_or("".to_string()),
|
endpoint_id = endpoint_id,
|
||||||
|
project_id = project_id,
|
||||||
remote_endpoint = remote_endpoint
|
remote_endpoint = remote_endpoint
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -131,15 +167,11 @@ pub fn configure_postgres_logs_export(conf: PostgresLogsRsyslogConfig) -> Result
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// When new config is empty we can simply remove the configuration file.
|
// Nothing to configure
|
||||||
if new_config.is_empty() {
|
if new_config.is_empty() {
|
||||||
info!("removing rsyslog config file: {}", POSTGRES_LOGS_CONF_PATH);
|
// When the configuration is removed, PostgreSQL will stop sending data
|
||||||
match std::fs::remove_file(POSTGRES_LOGS_CONF_PATH) {
|
// to the files watched by rsyslog, so restarting rsyslog is more effort
|
||||||
Ok(_) => {}
|
// than just ignoring this change.
|
||||||
Err(err) if err.kind() == ErrorKind::NotFound => {}
|
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
}
|
|
||||||
restart_rsyslog()?;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ fn do_control_plane_request(
|
|||||||
) -> Result<ControlPlaneConfigResponse, (bool, String, String)> {
|
) -> Result<ControlPlaneConfigResponse, (bool, String, String)> {
|
||||||
let resp = reqwest::blocking::Client::new()
|
let resp = reqwest::blocking::Client::new()
|
||||||
.get(uri)
|
.get(uri)
|
||||||
.header("Authorization", format!("Bearer {}", jwt))
|
.header("Authorization", format!("Bearer {jwt}"))
|
||||||
.send()
|
.send()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
(
|
(
|
||||||
true,
|
true,
|
||||||
format!("could not perform request to control plane: {:?}", e),
|
format!("could not perform request to control plane: {e:?}"),
|
||||||
UNKNOWN_HTTP_STATUS.to_string(),
|
UNKNOWN_HTTP_STATUS.to_string(),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
@@ -39,7 +39,7 @@ fn do_control_plane_request(
|
|||||||
Ok(spec_resp) => Ok(spec_resp),
|
Ok(spec_resp) => Ok(spec_resp),
|
||||||
Err(e) => Err((
|
Err(e) => Err((
|
||||||
true,
|
true,
|
||||||
format!("could not deserialize control plane response: {:?}", e),
|
format!("could not deserialize control plane response: {e:?}"),
|
||||||
status.to_string(),
|
status.to_string(),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
@@ -62,7 +62,7 @@ fn do_control_plane_request(
|
|||||||
// or some internal failure happened. Doesn't make much sense to retry in this case.
|
// or some internal failure happened. Doesn't make much sense to retry in this case.
|
||||||
_ => Err((
|
_ => Err((
|
||||||
false,
|
false,
|
||||||
format!("unexpected control plane response status code: {}", status),
|
format!("unexpected control plane response status code: {status}"),
|
||||||
status.to_string(),
|
status.to_string(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -933,56 +933,53 @@ async fn get_operations<'a>(
|
|||||||
PerDatabasePhase::DeleteDBRoleReferences => {
|
PerDatabasePhase::DeleteDBRoleReferences => {
|
||||||
let ctx = ctx.read().await;
|
let ctx = ctx.read().await;
|
||||||
|
|
||||||
let operations =
|
let operations = spec
|
||||||
spec.delta_operations
|
.delta_operations
|
||||||
.iter()
|
.iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter(|op| op.action == "delete_role")
|
.filter(|op| op.action == "delete_role")
|
||||||
.filter_map(move |op| {
|
.filter_map(move |op| {
|
||||||
if db.is_owned_by(&op.name) {
|
if db.is_owned_by(&op.name) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if !ctx.roles.contains_key(&op.name) {
|
if !ctx.roles.contains_key(&op.name) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let quoted = op.name.pg_quote();
|
let quoted = op.name.pg_quote();
|
||||||
let new_owner = match &db {
|
let new_owner = match &db {
|
||||||
DB::SystemDB => PgIdent::from("cloud_admin").pg_quote(),
|
DB::SystemDB => PgIdent::from("cloud_admin").pg_quote(),
|
||||||
DB::UserDB(db) => db.owner.pg_quote(),
|
DB::UserDB(db) => db.owner.pg_quote(),
|
||||||
};
|
};
|
||||||
let (escaped_role, outer_tag) = op.name.pg_quote_dollar();
|
let (escaped_role, outer_tag) = op.name.pg_quote_dollar();
|
||||||
|
|
||||||
Some(vec![
|
Some(vec![
|
||||||
// This will reassign all dependent objects to the db owner
|
// This will reassign all dependent objects to the db owner
|
||||||
Operation {
|
Operation {
|
||||||
query: format!(
|
query: format!("REASSIGN OWNED BY {quoted} TO {new_owner}",),
|
||||||
"REASSIGN OWNED BY {} TO {}",
|
comment: None,
|
||||||
quoted, new_owner,
|
},
|
||||||
),
|
// Revoke some potentially blocking privileges (Neon-specific currently)
|
||||||
comment: None,
|
Operation {
|
||||||
},
|
query: format!(
|
||||||
// Revoke some potentially blocking privileges (Neon-specific currently)
|
include_str!("sql/pre_drop_role_revoke_privileges.sql"),
|
||||||
Operation {
|
// N.B. this has to be properly dollar-escaped with `pg_quote_dollar()`
|
||||||
query: format!(
|
role_name = escaped_role,
|
||||||
include_str!("sql/pre_drop_role_revoke_privileges.sql"),
|
outer_tag = outer_tag,
|
||||||
// N.B. this has to be properly dollar-escaped with `pg_quote_dollar()`
|
),
|
||||||
role_name = escaped_role,
|
comment: None,
|
||||||
outer_tag = outer_tag,
|
},
|
||||||
),
|
// This now will only drop privileges of the role
|
||||||
comment: None,
|
// TODO: this is obviously not 100% true because of the above case,
|
||||||
},
|
// there could be still some privileges that are not revoked. Maybe this
|
||||||
// This now will only drop privileges of the role
|
// only drops privileges that were granted *by this* role, not *to this* role,
|
||||||
// TODO: this is obviously not 100% true because of the above case,
|
// but this has to be checked.
|
||||||
// there could be still some privileges that are not revoked. Maybe this
|
Operation {
|
||||||
// only drops privileges that were granted *by this* role, not *to this* role,
|
query: format!("DROP OWNED BY {quoted}"),
|
||||||
// but this has to be checked.
|
comment: None,
|
||||||
Operation {
|
},
|
||||||
query: format!("DROP OWNED BY {}", quoted),
|
])
|
||||||
comment: None,
|
})
|
||||||
},
|
.flatten();
|
||||||
])
|
|
||||||
})
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
Ok(Box::new(operations))
|
Ok(Box::new(operations))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub async fn ping_safekeeper(
|
|||||||
let (client, conn) = config.connect(tokio_postgres::NoTls).await?;
|
let (client, conn) = config.connect(tokio_postgres::NoTls).await?;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = conn.await {
|
if let Err(e) = conn.await {
|
||||||
eprintln!("connection error: {}", e);
|
eprintln!("connection error: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use std::{io::Write, os::unix::fs::OpenOptionsExt, path::Path, time::Duration};
|
|||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use compute_api::responses::TlsConfig;
|
use compute_api::responses::TlsConfig;
|
||||||
use ring::digest;
|
use ring::digest;
|
||||||
use spki::der::{Decode, PemReader};
|
|
||||||
use x509_cert::Certificate;
|
use x509_cert::Certificate;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -52,7 +51,7 @@ pub fn update_key_path_blocking(pg_data: &Path, tls_config: &TlsConfig) {
|
|||||||
match try_update_key_path_blocking(pg_data, tls_config) {
|
match try_update_key_path_blocking(pg_data, tls_config) {
|
||||||
Ok(()) => break,
|
Ok(()) => break,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("could not create key file {e:?}");
|
tracing::error!(error = ?e, "could not create key file");
|
||||||
std::thread::sleep(Duration::from_secs(1))
|
std::thread::sleep(Duration::from_secs(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,8 +91,14 @@ fn try_update_key_path_blocking(pg_data: &Path, tls_config: &TlsConfig) -> Resul
|
|||||||
fn verify_key_cert(key: &str, cert: &str) -> Result<()> {
|
fn verify_key_cert(key: &str, cert: &str) -> Result<()> {
|
||||||
use x509_cert::der::oid::db::rfc5912::ECDSA_WITH_SHA_256;
|
use x509_cert::der::oid::db::rfc5912::ECDSA_WITH_SHA_256;
|
||||||
|
|
||||||
let cert = Certificate::decode(&mut PemReader::new(cert.as_bytes()).context("pem reader")?)
|
let certs = Certificate::load_pem_chain(cert.as_bytes())
|
||||||
.context("decode cert")?;
|
.context("decoding PEM encoded certificates")?;
|
||||||
|
|
||||||
|
// First certificate is our server-cert,
|
||||||
|
// all the rest of the certs are the CA cert chain.
|
||||||
|
let Some(cert) = certs.first() else {
|
||||||
|
bail!("no certificates found");
|
||||||
|
};
|
||||||
|
|
||||||
match cert.signature_algorithm.oid {
|
match cert.signature_algorithm.oid {
|
||||||
ECDSA_WITH_SHA_256 => {
|
ECDSA_WITH_SHA_256 => {
|
||||||
@@ -115,3 +120,82 @@ fn verify_key_cert(key: &str, cert: &str) -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::verify_key_cert;
|
||||||
|
|
||||||
|
/// Real certificate chain file, generated by cert-manager in dev.
|
||||||
|
/// The server auth certificate has expired since 2025-04-24T15:41:35Z.
|
||||||
|
const CERT: &str = "
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICCDCCAa+gAwIBAgIQKhLomFcNULbZA/bPdGzaSzAKBggqhkjOPQQDAjBEMQsw
|
||||||
|
CQYDVQQGEwJVUzESMBAGA1UEChMJTmVvbiBJbmMuMSEwHwYDVQQDExhOZW9uIEs4
|
||||||
|
cyBJbnRlcm1lZGlhdGUgQ0EwHhcNMjUwNDIzMTU0MTM1WhcNMjUwNDI0MTU0MTM1
|
||||||
|
WjBBMT8wPQYDVQQDEzZjb21wdXRlLXdpc3B5LWdyYXNzLXcwY21laWp3LmRlZmF1
|
||||||
|
bHQuc3ZjLmNsdXN0ZXIubG9jYWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATF
|
||||||
|
QCcG2m/EVHAiZtSsYgVnHgoTjUL/Jtwfdrpvz2t0bVRZmBmSKhlo53uPV9Y5eKFG
|
||||||
|
AmR54p9/gT2eO3xU7vAgo4GFMIGCMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8E
|
||||||
|
AjAAMB8GA1UdIwQYMBaAFFR2JAhXkeiNQNEixTvAYIwxUu3QMEEGA1UdEQQ6MDiC
|
||||||
|
NmNvbXB1dGUtd2lzcHktZ3Jhc3MtdzBjbWVpancuZGVmYXVsdC5zdmMuY2x1c3Rl
|
||||||
|
ci5sb2NhbDAKBggqhkjOPQQDAgNHADBEAiBLG22wKG8XS9e9RxBT+kmUx/kIThcP
|
||||||
|
DIpp7jx0PrFcdQIgEMTdnXpx5Cv/Z0NIEDxtMHUD7G0vuRPfztki36JuakM=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICFzCCAb6gAwIBAgIUbbX98N2Ip6lWAONRk8dU9hSz+YIwCgYIKoZIzj0EAwIw
|
||||||
|
RDELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCU5lb24gSW5jLjEhMB8GA1UEAxMYTmVv
|
||||||
|
biBBV1MgSW50ZXJtZWRpYXRlIENBMB4XDTI1MDQyMjE1MTAxMFoXDTI1MDcyMTE1
|
||||||
|
MTAxMFowRDELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCU5lb24gSW5jLjEhMB8GA1UE
|
||||||
|
AxMYTmVvbiBLOHMgSW50ZXJtZWRpYXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||||
|
AQcDQgAE5++m5owqNI4BPMTVNIUQH0qvU7pYhdpHGVGhdj/Lgars6ROvE6uSNQV4
|
||||||
|
SAmJN5HBzj5/6kLQaTPWpXW7EHXjK6OBjTCBijAOBgNVHQ8BAf8EBAMCAQYwEgYD
|
||||||
|
VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUVHYkCFeR6I1A0SLFO8BgjDFS7dAw
|
||||||
|
HwYDVR0jBBgwFoAUgHfNXfyKtHO0V9qoLOWCjkNiaI8wJAYDVR0eAQH/BBowGKAW
|
||||||
|
MBSCEi5zdmMuY2x1c3Rlci5sb2NhbDAKBggqhkjOPQQDAgNHADBEAiBObVFFdXaL
|
||||||
|
QpOXmN60dYUNnQRwjKreFduEkQgOdOlssgIgVAdJJQFgvlrvEOBhY8j5WyeKRwUN
|
||||||
|
k/ALs6KpgaFBCGY=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB4jCCAYegAwIBAgIUFlxWFn/11yoGdmD+6gf+yQMToS0wCgYIKoZIzj0EAwIw
|
||||||
|
ODELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCU5lb24gSW5jLjEVMBMGA1UEAxMMTmVv
|
||||||
|
biBSb290IENBMB4XDTI1MDQwMzA3MTUyMloXDTI2MDQwMzA3MTUyMlowRDELMAkG
|
||||||
|
A1UEBhMCVVMxEjAQBgNVBAoTCU5lb24gSW5jLjEhMB8GA1UEAxMYTmVvbiBBV1Mg
|
||||||
|
SW50ZXJtZWRpYXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqonG/IQ6
|
||||||
|
ZxtEtOUTkkoNopPieXDO5CBKUkNFTGeJEB7OxRlSpYJgsBpaYIaD6Vc4sVk3thIF
|
||||||
|
p+pLw52idQOIN6NjMGEwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
|
||||||
|
HQYDVR0OBBYEFIB3zV38irRztFfaqCzlgo5DYmiPMB8GA1UdIwQYMBaAFKh7M4/G
|
||||||
|
FHvr/ORDQZt4bMLlJvHCMAoGCCqGSM49BAMCA0kAMEYCIQCbS4x7QPslONzBYbjC
|
||||||
|
UQaQ0QLDW4CJHvQ4u4gbWFG87wIhAJMsHQHjP9qTT27Q65zQCR7O8QeLAfha1jrH
|
||||||
|
Ag/LsxSr
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
";
|
||||||
|
|
||||||
|
/// The key corresponding to [`CERT`]
|
||||||
|
const KEY: &str = "
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIDnAnrqmIJjndCLWP1iIO5X3X63Aia48TGpGuMXwvm6IoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAExUAnBtpvxFRwImbUrGIFZx4KE41C/ybcH3a6b89rdG1UWZgZkioZ
|
||||||
|
aOd7j1fWOXihRgJkeeKff4E9njt8VO7wIA==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
|
";
|
||||||
|
|
||||||
|
/// An incorrect key.
|
||||||
|
const INCORRECT_KEY: &str = "
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIL6WqqBDyvM0HWz7Ir5M5+jhFWB7IzOClGn26OPrzHCXoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAE7XVvdOy5lfwtNKb+gJEUtnG+DrnnXLY5LsHDeGQKV9PTRcEMeCrG
|
||||||
|
YZzHyML4P6Sr4yi2ts+4B9i47uvAG8+XwQ==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
|
";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn certificate_verification() {
|
||||||
|
verify_key_cert(KEY, CERT).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "private key file does not match certificate")]
|
||||||
|
fn certificate_verification_fail() {
|
||||||
|
verify_key_cert(INCORRECT_KEY, CERT).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
6
compute_tools/tests/README.md
Normal file
6
compute_tools/tests/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
### Test files
|
||||||
|
|
||||||
|
The file `cluster_spec.json` has been copied over from libs/compute_api
|
||||||
|
tests, with some edits:
|
||||||
|
|
||||||
|
- the neon.safekeepers setting contains a duplicate value
|
||||||
245
compute_tools/tests/cluster_spec.json
Normal file
245
compute_tools/tests/cluster_spec.json
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
{
|
||||||
|
"format_version": 1.0,
|
||||||
|
|
||||||
|
"timestamp": "2021-05-23T18:25:43.511Z",
|
||||||
|
"operation_uuid": "0f657b36-4b0f-4a2d-9c2e-1dcd615e7d8b",
|
||||||
|
|
||||||
|
"cluster": {
|
||||||
|
"cluster_id": "test-cluster-42",
|
||||||
|
"name": "Zenith Test",
|
||||||
|
"state": "restarted",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"name": "postgres",
|
||||||
|
"encrypted_password": "6b1d16b78004bbd51fa06af9eda75972",
|
||||||
|
"options": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alexk",
|
||||||
|
"encrypted_password": null,
|
||||||
|
"options": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zenith \"new\"",
|
||||||
|
"encrypted_password": "5b1d16b78004bbd51fa06af9eda75972",
|
||||||
|
"options": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zen",
|
||||||
|
"encrypted_password": "9b1d16b78004bbd51fa06af9eda75972"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "\"name\";\\n select 1;",
|
||||||
|
"encrypted_password": "5b1d16b78004bbd51fa06af9eda75972"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MyRole",
|
||||||
|
"encrypted_password": "5b1d16b78004bbd51fa06af9eda75972"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"databases": [
|
||||||
|
{
|
||||||
|
"name": "DB2",
|
||||||
|
"owner": "alexk",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "LC_COLLATE",
|
||||||
|
"value": "C",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LC_CTYPE",
|
||||||
|
"value": "C",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TEMPLATE",
|
||||||
|
"value": "template0",
|
||||||
|
"vartype": "enum"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zenith",
|
||||||
|
"owner": "MyRole"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zen",
|
||||||
|
"owner": "zen"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"name": "fsync",
|
||||||
|
"value": "off",
|
||||||
|
"vartype": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wal_level",
|
||||||
|
"value": "logical",
|
||||||
|
"vartype": "enum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hot_standby",
|
||||||
|
"value": "on",
|
||||||
|
"vartype": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "prewarm_lfc_on_startup",
|
||||||
|
"value": "off",
|
||||||
|
"vartype": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "neon.safekeepers",
|
||||||
|
"value": "127.0.0.1:6502,127.0.0.1:6503,127.0.0.1:6501,127.0.0.1:6502",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wal_log_hints",
|
||||||
|
"value": "on",
|
||||||
|
"vartype": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "log_connections",
|
||||||
|
"value": "on",
|
||||||
|
"vartype": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "shared_buffers",
|
||||||
|
"value": "32768",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "port",
|
||||||
|
"value": "55432",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_connections",
|
||||||
|
"value": "100",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_wal_senders",
|
||||||
|
"value": "10",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "listen_addresses",
|
||||||
|
"value": "0.0.0.0",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wal_sender_timeout",
|
||||||
|
"value": "0",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "password_encryption",
|
||||||
|
"value": "md5",
|
||||||
|
"vartype": "enum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintenance_work_mem",
|
||||||
|
"value": "65536",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_parallel_workers",
|
||||||
|
"value": "8",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_worker_processes",
|
||||||
|
"value": "8",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "neon.tenant_id",
|
||||||
|
"value": "b0554b632bd4d547a63b86c3630317e8",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_replication_slots",
|
||||||
|
"value": "10",
|
||||||
|
"vartype": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "neon.timeline_id",
|
||||||
|
"value": "2414a61ffc94e428f14b5758fe308e13",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "shared_preload_libraries",
|
||||||
|
"value": "neon",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "synchronous_standby_names",
|
||||||
|
"value": "walproposer",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "neon.pageserver_connstring",
|
||||||
|
"value": "host=127.0.0.1 port=6400",
|
||||||
|
"vartype": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test.escaping",
|
||||||
|
"value": "here's a backslash \\ and a quote ' and a double-quote \" hooray",
|
||||||
|
"vartype": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"delta_operations": [
|
||||||
|
{
|
||||||
|
"action": "delete_db",
|
||||||
|
"name": "zenith_test"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "rename_db",
|
||||||
|
"name": "DB",
|
||||||
|
"new_name": "DB2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "delete_role",
|
||||||
|
"name": "zenith2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "rename_role",
|
||||||
|
"name": "zenith new",
|
||||||
|
"new_name": "zenith \"new\""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"remote_extensions": {
|
||||||
|
"library_index": {
|
||||||
|
"postgis-3": "postgis",
|
||||||
|
"libpgrouting-3.4": "postgis",
|
||||||
|
"postgis_raster-3": "postgis",
|
||||||
|
"postgis_sfcgal-3": "postgis",
|
||||||
|
"postgis_topology-3": "postgis",
|
||||||
|
"address_standardizer-3": "postgis"
|
||||||
|
},
|
||||||
|
"extension_data": {
|
||||||
|
"postgis": {
|
||||||
|
"archive_path": "5834329303/v15/extensions/postgis.tar.zst",
|
||||||
|
"control_data": {
|
||||||
|
"postgis.control": "# postgis extension\ncomment = ''PostGIS geometry and geography spatial types and functions''\ndefault_version = ''3.3.2''\nmodule_pathname = ''$libdir/postgis-3''\nrelocatable = false\ntrusted = true\n",
|
||||||
|
"pgrouting.control": "# pgRouting Extension\ncomment = ''pgRouting Extension''\ndefault_version = ''3.4.2''\nmodule_pathname = ''$libdir/libpgrouting-3.4''\nrelocatable = true\nrequires = ''plpgsql''\nrequires = ''postgis''\ntrusted = true\n",
|
||||||
|
"postgis_raster.control": "# postgis_raster extension\ncomment = ''PostGIS raster types and functions''\ndefault_version = ''3.3.2''\nmodule_pathname = ''$libdir/postgis_raster-3''\nrelocatable = false\nrequires = postgis\ntrusted = true\n",
|
||||||
|
"postgis_sfcgal.control": "# postgis topology extension\ncomment = ''PostGIS SFCGAL functions''\ndefault_version = ''3.3.2''\nrelocatable = true\nrequires = postgis\ntrusted = true\n",
|
||||||
|
"postgis_topology.control": "# postgis topology extension\ncomment = ''PostGIS topology spatial types and functions''\ndefault_version = ''3.3.2''\nrelocatable = false\nschema = topology\nrequires = postgis\ntrusted = true\n",
|
||||||
|
"address_standardizer.control": "# address_standardizer extension\ncomment = ''Used to parse an address into constituent elements. Generally used to support geocoding address normalization step.''\ndefault_version = ''3.3.2''\nrelocatable = true\ntrusted = true\n",
|
||||||
|
"postgis_tiger_geocoder.control": "# postgis tiger geocoder extension\ncomment = ''PostGIS tiger geocoder and reverse geocoder''\ndefault_version = ''3.3.2''\nrelocatable = false\nschema = tiger\nrequires = ''postgis,fuzzystrmatch''\nsuperuser= false\ntrusted = true\n",
|
||||||
|
"address_standardizer_data_us.control": "# address standardizer us dataset\ncomment = ''Address Standardizer US dataset example''\ndefault_version = ''3.3.2''\nrelocatable = true\ntrusted = true\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"custom_extensions": [],
|
||||||
|
"public_extensions": ["postgis"]
|
||||||
|
},
|
||||||
|
"pgbouncer_settings": {
|
||||||
|
"default_pool_size": "42",
|
||||||
|
"pool_mode": "session"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ mod pg_helpers_tests {
|
|||||||
r#"fsync = off
|
r#"fsync = off
|
||||||
wal_level = logical
|
wal_level = logical
|
||||||
hot_standby = on
|
hot_standby = on
|
||||||
|
autoprewarm = off
|
||||||
neon.safekeepers = '127.0.0.1:6502,127.0.0.1:6503,127.0.0.1:6501'
|
neon.safekeepers = '127.0.0.1:6502,127.0.0.1:6503,127.0.0.1:6501'
|
||||||
wal_log_hints = on
|
wal_log_hints = on
|
||||||
log_connections = on
|
log_connections = on
|
||||||
@@ -70,6 +71,14 @@ test.escaping = 'here''s a backslash \\ and a quote '' and a double-quote " hoor
|
|||||||
("name$$$", ("$x$name$$$$x$", "xx")),
|
("name$$$", ("$x$name$$$$x$", "xx")),
|
||||||
("name$$$$", ("$x$name$$$$$x$", "xx")),
|
("name$$$$", ("$x$name$$$$$x$", "xx")),
|
||||||
("name$x$", ("$xx$name$x$$xx$", "xxx")),
|
("name$x$", ("$xx$name$x$$xx$", "xxx")),
|
||||||
|
("x", ("$xx$x$xx$", "xxx")),
|
||||||
|
("xx", ("$xxx$xx$xxx$", "xxxx")),
|
||||||
|
("$x", ("$xx$$x$xx$", "xxx")),
|
||||||
|
("x$", ("$xx$x$$xx$", "xxx")),
|
||||||
|
("$x$", ("$xx$$x$$xx$", "xxx")),
|
||||||
|
("xx$", ("$xxx$xx$$xxx$", "xxxx")),
|
||||||
|
("$xx", ("$xxx$$xx$xxx$", "xxxx")),
|
||||||
|
("$xx$", ("$xxx$$xx$$xxx$", "xxxx")),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (input, expected) in test_cases {
|
for (input, expected) in test_cases {
|
||||||
|
|||||||
@@ -36,12 +36,13 @@ pageserver_api.workspace = true
|
|||||||
pageserver_client.workspace = true
|
pageserver_client.workspace = true
|
||||||
postgres_backend.workspace = true
|
postgres_backend.workspace = true
|
||||||
safekeeper_api.workspace = true
|
safekeeper_api.workspace = true
|
||||||
|
safekeeper_client.workspace = true
|
||||||
postgres_connection.workspace = true
|
postgres_connection.workspace = true
|
||||||
storage_broker.workspace = true
|
storage_broker.workspace = true
|
||||||
http-utils.workspace = true
|
http-utils.workspace = true
|
||||||
utils.workspace = true
|
utils.workspace = true
|
||||||
whoami.workspace = true
|
whoami.workspace = true
|
||||||
|
endpoint_storage.workspace = true
|
||||||
compute_api.workspace = true
|
compute_api.workspace = true
|
||||||
workspace_hack.workspace = true
|
workspace_hack.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
[pageserver]
|
[pageserver]
|
||||||
listen_pg_addr = '127.0.0.1:64000'
|
listen_pg_addr = '127.0.0.1:64000'
|
||||||
listen_http_addr = '127.0.0.1:9898'
|
listen_http_addr = '127.0.0.1:9898'
|
||||||
|
listen_grpc_addr = '127.0.0.1:51051'
|
||||||
pg_auth_type = 'Trust'
|
pg_auth_type = 'Trust'
|
||||||
http_auth_type = 'Trust'
|
http_auth_type = 'Trust'
|
||||||
|
grpc_auth_type = 'Trust'
|
||||||
|
|
||||||
[[safekeepers]]
|
[[safekeepers]]
|
||||||
id = 1
|
id = 1
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
id=1
|
id=1
|
||||||
listen_pg_addr = '127.0.0.1:64000'
|
listen_pg_addr = '127.0.0.1:64000'
|
||||||
listen_http_addr = '127.0.0.1:9898'
|
listen_http_addr = '127.0.0.1:9898'
|
||||||
|
listen_grpc_addr = '127.0.0.1:51051'
|
||||||
pg_auth_type = 'Trust'
|
pg_auth_type = 'Trust'
|
||||||
http_auth_type = 'Trust'
|
http_auth_type = 'Trust'
|
||||||
|
grpc_auth_type = 'Trust'
|
||||||
|
|
||||||
[[safekeepers]]
|
[[safekeepers]]
|
||||||
id = 1
|
id = 1
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user