Compare commits
6 Commits
fix_finali
...
add-gc-for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c77d84ef6d | ||
|
|
186be4c213 | ||
|
|
4e06e769f1 | ||
|
|
311c129bfc | ||
|
|
fe577aab18 | ||
|
|
9a3ce1ef01 |
@@ -6,7 +6,6 @@ Checks: '*,
|
|||||||
-altera-unroll-loops,
|
-altera-unroll-loops,
|
||||||
-android-*,
|
-android-*,
|
||||||
-cert-err58-cpp,
|
-cert-err58-cpp,
|
||||||
-cppcoreguidelines-avoid-do-while,
|
|
||||||
-cppcoreguidelines-avoid-c-arrays,
|
-cppcoreguidelines-avoid-c-arrays,
|
||||||
-cppcoreguidelines-avoid-goto,
|
-cppcoreguidelines-avoid-goto,
|
||||||
-cppcoreguidelines-avoid-magic-numbers,
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
@@ -61,7 +60,6 @@ Checks: '*,
|
|||||||
-readability-implicit-bool-conversion,
|
-readability-implicit-bool-conversion,
|
||||||
-readability-magic-numbers,
|
-readability-magic-numbers,
|
||||||
-readability-named-parameter,
|
-readability-named-parameter,
|
||||||
-readability-identifier-length,
|
|
||||||
-misc-no-recursion,
|
-misc-no-recursion,
|
||||||
-concurrency-mt-unsafe,
|
-concurrency-mt-unsafe,
|
||||||
-bugprone-easily-swappable-parameters'
|
-bugprone-easily-swappable-parameters'
|
||||||
|
|||||||
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -3,6 +3,7 @@ name: Bug report
|
|||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
title: ""
|
title: ""
|
||||||
labels: bug
|
labels: bug
|
||||||
|
assignees: gitbuda
|
||||||
---
|
---
|
||||||
|
|
||||||
**Memgraph version**
|
**Memgraph version**
|
||||||
|
|||||||
2
.github/workflows/daily_benchmark.yaml
vendored
2
.github/workflows/daily_benchmark.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
|
|||||||
55
.github/workflows/diff.yaml
vendored
55
.github/workflows/diff.yaml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -65,7 +65,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -96,7 +96,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Python code analysis
|
- name: Python code analysis
|
||||||
run: |
|
run: |
|
||||||
CHANGED_FILES=$(git diff -U0 ${{ env.BASE_BRANCH }}... --name-only --diff-filter=d)
|
CHANGED_FILES=$(git diff -U0 ${{ env.BASE_BRANCH }}... --name-only)
|
||||||
for file in ${CHANGED_FILES}; do
|
for file in ${CHANGED_FILES}; do
|
||||||
echo ${file}
|
echo ${file}
|
||||||
if [[ ${file} == *.py ]]; then
|
if [[ ${file} == *.py ]]; then
|
||||||
@@ -137,9 +137,9 @@ jobs:
|
|||||||
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||||
|
|
||||||
- name: Save code coverage
|
- name: Save code coverage
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Code coverage(Code analysis)"
|
name: "Code coverage"
|
||||||
path: tools/github/generated/code_coverage.tar.gz
|
path: tools/github/generated/code_coverage.tar.gz
|
||||||
|
|
||||||
- name: Run clang-tidy
|
- name: Run clang-tidy
|
||||||
@@ -162,7 +162,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -208,9 +208,9 @@ jobs:
|
|||||||
./cppcheck_and_clang_format diff
|
./cppcheck_and_clang_format diff
|
||||||
|
|
||||||
- name: Save cppcheck and clang-format errors
|
- name: Save cppcheck and clang-format errors
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Code coverage(Debug build)"
|
name: "Code coverage"
|
||||||
path: tools/github/cppcheck_and_clang_format.txt
|
path: tools/github/cppcheck_and_clang_format.txt
|
||||||
|
|
||||||
release_build:
|
release_build:
|
||||||
@@ -223,12 +223,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check e2e service dependencies
|
||||||
|
run: |
|
||||||
|
cd tests/e2e
|
||||||
|
./dependency_check.sh
|
||||||
|
|
||||||
- name: Build release binaries
|
- name: Build release binaries
|
||||||
run: |
|
run: |
|
||||||
@@ -251,7 +255,7 @@ jobs:
|
|||||||
./continuous_integration
|
./continuous_integration
|
||||||
|
|
||||||
- name: Save quality assurance status
|
- name: Save quality assurance status
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "GQL Behave Status"
|
name: "GQL Behave Status"
|
||||||
path: |
|
path: |
|
||||||
@@ -267,13 +271,6 @@ jobs:
|
|||||||
cd build
|
cd build
|
||||||
ctest -R memgraph__unit --output-on-failure -j$THREADS
|
ctest -R memgraph__unit --output-on-failure -j$THREADS
|
||||||
|
|
||||||
- name: Ensure Kafka and Pulsar are up
|
|
||||||
run: |
|
|
||||||
cd tests/e2e/streams/kafka
|
|
||||||
docker-compose up -d
|
|
||||||
cd ../pulsar
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
run: |
|
run: |
|
||||||
cd tests
|
cd tests
|
||||||
@@ -282,13 +279,6 @@ jobs:
|
|||||||
cd e2e
|
cd e2e
|
||||||
./run.sh
|
./run.sh
|
||||||
|
|
||||||
- name: Ensure Kafka and Pulsar are down
|
|
||||||
run: |
|
|
||||||
cd tests/e2e/streams/kafka
|
|
||||||
docker-compose down
|
|
||||||
cd ../pulsar
|
|
||||||
docker-compose down
|
|
||||||
|
|
||||||
- name: Run stress test (plain)
|
- name: Run stress test (plain)
|
||||||
run: |
|
run: |
|
||||||
cd tests/stress
|
cd tests/stress
|
||||||
@@ -322,16 +312,16 @@ jobs:
|
|||||||
cpack -G DEB --config ../CPackConfig.cmake
|
cpack -G DEB --config ../CPackConfig.cmake
|
||||||
|
|
||||||
- name: Save enterprise DEB package
|
- name: Save enterprise DEB package
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Enterprise DEB package"
|
name: "Enterprise DEB package"
|
||||||
path: build/output/memgraph*.deb
|
path: build/output/memgraph*.deb
|
||||||
|
|
||||||
- name: Save test data
|
- name: Save test data
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: "Test data(Release build)"
|
name: "Test data"
|
||||||
path: |
|
path: |
|
||||||
# multiple paths could be defined
|
# multiple paths could be defined
|
||||||
build/logs
|
build/logs
|
||||||
@@ -347,7 +337,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -364,18 +354,13 @@ jobs:
|
|||||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||||
make -j$THREADS memgraph
|
make -j$THREADS memgraph
|
||||||
|
|
||||||
- name: Refresh Jepsen Cluster
|
|
||||||
run: |
|
|
||||||
cd tests/jepsen
|
|
||||||
./run.sh cluster-refresh
|
|
||||||
|
|
||||||
- name: Run Jepsen tests
|
- name: Run Jepsen tests
|
||||||
run: |
|
run: |
|
||||||
cd tests/jepsen
|
cd tests/jepsen
|
||||||
./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs
|
./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs
|
||||||
|
|
||||||
- name: Save Jepsen report
|
- name: Save Jepsen report
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
name: "Jepsen Report"
|
name: "Jepsen Report"
|
||||||
@@ -391,7 +376,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
|
|||||||
2
.github/workflows/full_clang_tidy.yaml
vendored
2
.github/workflows/full_clang_tidy.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
|
|||||||
263
.github/workflows/package_all.yaml
vendored
Normal file
263
.github/workflows/package_all.yaml
vendored
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
name: Package All
|
||||||
|
|
||||||
|
# TODO(gitbuda): Cleanup docker container if GHA job was canceled.
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
memgraph_version:
|
||||||
|
description: "Memgraph version to upload as. If empty upload is skipped. Format: 'X.Y.Z'"
|
||||||
|
required: false
|
||||||
|
build_type:
|
||||||
|
type: choice
|
||||||
|
description: "Memgraph Build type. Default value is Release."
|
||||||
|
default: 'Release'
|
||||||
|
options:
|
||||||
|
- Release
|
||||||
|
- RelWithDebInfo
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
centos-7:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package centos-7 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: centos-7
|
||||||
|
path: build/output/centos-7/memgraph*.rpm
|
||||||
|
|
||||||
|
centos-9:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package centos-9 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: centos-9
|
||||||
|
path: build/output/centos-9/memgraph*.rpm
|
||||||
|
|
||||||
|
debian-10:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package debian-10 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: debian-10
|
||||||
|
path: build/output/debian-10/memgraph*.deb
|
||||||
|
|
||||||
|
debian-11:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package debian-11 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: debian-11
|
||||||
|
path: build/output/debian-11/memgraph*.deb
|
||||||
|
|
||||||
|
docker:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
cd release/package
|
||||||
|
./run.sh package debian-11 ${{ github.event.inputs.build_type }} --for-docker
|
||||||
|
./run.sh docker
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: docker
|
||||||
|
path: build/output/docker/memgraph*.tar.gz
|
||||||
|
|
||||||
|
ubuntu-1804:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package ubuntu-18.04 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ubuntu-18.04
|
||||||
|
path: build/output/ubuntu-18.04/memgraph*.deb
|
||||||
|
|
||||||
|
ubuntu-2004:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package ubuntu-20.04 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ubuntu-20.04
|
||||||
|
path: build/output/ubuntu-20.04/memgraph*.deb
|
||||||
|
|
||||||
|
ubuntu-2204:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package ubuntu-22.04 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ubuntu-22.04
|
||||||
|
path: build/output/ubuntu-22.04/memgraph*.deb
|
||||||
|
|
||||||
|
debian-11-platform:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package debian-11 ${{ github.event.inputs.build_type }} --for-platform
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: debian-11-platform
|
||||||
|
path: build/output/debian-11/memgraph*.deb
|
||||||
|
|
||||||
|
fedora-36:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package fedora-36 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: fedora-36
|
||||||
|
path: build/output/fedora-36/memgraph*.rpm
|
||||||
|
|
||||||
|
amzn-2:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package amzn-2 ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: amzn-2
|
||||||
|
path: build/output/amzn-2/memgraph*.rpm
|
||||||
|
|
||||||
|
debian-11-arm:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||||
|
timeout-minutes: 120
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package debian-11-arm ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: debian-11-aarch64
|
||||||
|
path: build/output/debian-11-arm/memgraph*.deb
|
||||||
|
|
||||||
|
ubuntu-2204-arm:
|
||||||
|
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||||
|
timeout-minutes: 120
|
||||||
|
steps:
|
||||||
|
- name: "Set up repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
|
- name: "Build package"
|
||||||
|
run: |
|
||||||
|
./release/package/run.sh package ubuntu-22.04-arm ${{ github.event.inputs.build_type }}
|
||||||
|
- name: "Upload package"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ubuntu-22.04-aarch64
|
||||||
|
path: build/output/ubuntu-22.04-arm/memgraph*.deb
|
||||||
|
|
||||||
|
upload-to-s3:
|
||||||
|
# only run upload if we specified version. Allows for runs without upload
|
||||||
|
if: "${{ github.event.inputs.memgraph_version != '' }}"
|
||||||
|
needs: [centos-7, centos-9, debian-10, debian-11, docker, ubuntu-1804, ubuntu-2004, ubuntu-2204, debian-11-platform, fedora-36, amzn-2, debian-11-arm, ubuntu-2204-arm]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
# name: # if name input parameter is not provided, all artifacts are downloaded
|
||||||
|
# and put in directories named after each one.
|
||||||
|
path: build/output/release
|
||||||
|
- name: Upload to S3
|
||||||
|
uses: jakejarvis/s3-sync-action@v0.5.1
|
||||||
|
env:
|
||||||
|
AWS_S3_BUCKET: "download.memgraph.com"
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.S3_AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_AWS_SECRET_ACCESS_KEY }}
|
||||||
|
AWS_REGION: "eu-west-1"
|
||||||
|
SOURCE_DIR: "build/output/release"
|
||||||
|
DEST_DIR: "memgraph/v${{ github.event.inputs.memgraph_version }}/"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Package memgraph
|
name: Package Specific
|
||||||
|
|
||||||
# TODO(gitbuda): Cleanup docker container if GHA job was canceled.
|
# TODO(gitbuda): Cleanup docker container if GHA job was canceled.
|
||||||
|
|
||||||
@@ -10,17 +10,16 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
build_type:
|
build_type:
|
||||||
type: choice
|
type: choice
|
||||||
description: "Memgraph Build type. Default value is Release"
|
description: "Memgraph Build type. Default value is Release."
|
||||||
default: 'Release'
|
default: 'Release'
|
||||||
options:
|
options:
|
||||||
- Release
|
- Release
|
||||||
- RelWithDebInfo
|
- RelWithDebInfo
|
||||||
target_os:
|
target_os:
|
||||||
type: choice
|
type: choice
|
||||||
description: "Target OS for which memgraph will be packaged. Select 'all' if you want to package for every listed OS. Default is Ubuntu 22.04"
|
description: "Target OS for which memgraph will be packaged. Default is Ubuntu 22.04"
|
||||||
default: 'ubuntu-22_04'
|
default: 'ubuntu-22_04'
|
||||||
options:
|
options:
|
||||||
- all
|
|
||||||
- amzn-2
|
- amzn-2
|
||||||
- centos-7
|
- centos-7
|
||||||
- centos-9
|
- centos-9
|
||||||
@@ -37,138 +36,138 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
amzn-2:
|
amzn-2:
|
||||||
if: ${{ github.event.inputs.target_os == 'amzn-2' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'amzn-2' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package amzn-2 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package amzn-2 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: amzn-2
|
name: amzn-2
|
||||||
path: build/output/amzn-2/memgraph*.rpm
|
path: build/output/amzn-2/memgraph*.rpm
|
||||||
|
|
||||||
centos-7:
|
centos-7:
|
||||||
if: ${{ github.event.inputs.target_os == 'centos-7' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'centos-7' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package centos-7 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package centos-7 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: centos-7
|
name: centos-7
|
||||||
path: build/output/centos-7/memgraph*.rpm
|
path: build/output/centos-7/memgraph*.rpm
|
||||||
|
|
||||||
centos-9:
|
centos-9:
|
||||||
if: ${{ github.event.inputs.target_os == 'centos-9' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'centos-9' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package centos-9 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package centos-9 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: centos-9
|
name: centos-9
|
||||||
path: build/output/centos-9/memgraph*.rpm
|
path: build/output/centos-9/memgraph*.rpm
|
||||||
|
|
||||||
debian-10:
|
debian-10:
|
||||||
if: ${{ github.event.inputs.target_os == 'debian-10' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'debian-10' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package debian-10 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package debian-10 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: debian-10
|
name: debian-10
|
||||||
path: build/output/debian-10/memgraph*.deb
|
path: build/output/debian-10/memgraph*.deb
|
||||||
|
|
||||||
debian-11:
|
debian-11:
|
||||||
if: ${{ github.event.inputs.target_os == 'debian-11' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'debian-11' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package debian-11 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package debian-11 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: debian-11
|
name: debian-11
|
||||||
path: build/output/debian-11/memgraph*.deb
|
path: build/output/debian-11/memgraph*.deb
|
||||||
|
|
||||||
debian-11-arm:
|
debian-11-arm:
|
||||||
if: ${{ github.event.inputs.target_os == 'debian-11-arm' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'debian-11-arm' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package debian-11-arm ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package debian-11-arm ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: debian-11-aarch64
|
name: debian-11-aarch64
|
||||||
path: build/output/debian-11-arm/memgraph*.deb
|
path: build/output/debian-11-arm/memgraph*.deb
|
||||||
|
|
||||||
debian-11-platform:
|
debian-11-platform:
|
||||||
if: ${{ github.event.inputs.target_os == 'debian-11-platform' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'debian-11-platform' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package debian-11 ${{ github.event.inputs.build_type }} --for-platform
|
./release/package/run.sh package debian-11 ${{ github.event.inputs.build_type }} --for-platform
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: debian-11-platform
|
name: debian-11-platform
|
||||||
path: build/output/debian-11/memgraph*.deb
|
path: build/output/debian-11/memgraph*.deb
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
if: ${{ github.event.inputs.target_os == 'docker' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'docker' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
@@ -177,97 +176,97 @@ jobs:
|
|||||||
./run.sh package debian-11 ${{ github.event.inputs.build_type }} --for-docker
|
./run.sh package debian-11 ${{ github.event.inputs.build_type }} --for-docker
|
||||||
./run.sh docker
|
./run.sh docker
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: docker
|
name: docker
|
||||||
path: build/output/docker/memgraph*.tar.gz
|
path: build/output/docker/memgraph*.tar.gz
|
||||||
|
|
||||||
fedora-36:
|
fedora-36:
|
||||||
if: ${{ github.event.inputs.target_os == 'fedora-36' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'fedora-36' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package fedora-36 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package fedora-36 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: fedora-36
|
name: fedora-36
|
||||||
path: build/output/fedora-36/memgraph*.rpm
|
path: build/output/fedora-36/memgraph*.rpm
|
||||||
|
|
||||||
ubuntu-18_04:
|
ubuntu-18_04:
|
||||||
if: ${{ github.event.inputs.target_os == 'ubuntu-18_04' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'ubuntu-18_04' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package ubuntu-18.04 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package ubuntu-18.04 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ubuntu-18.04
|
name: ubuntu-18.04
|
||||||
path: build/output/ubuntu-18.04/memgraph*.deb
|
path: build/output/ubuntu-18.04/memgraph*.deb
|
||||||
|
|
||||||
ubuntu-20_04:
|
ubuntu-20_04:
|
||||||
if: ${{ github.event.inputs.target_os == 'ubuntu-20_04' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'ubuntu-20_04' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package ubuntu-20.04 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package ubuntu-20.04 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ubuntu-20.04
|
name: ubuntu-20.04
|
||||||
path: build/output/ubuntu-20.04/memgraph*.deb
|
path: build/output/ubuntu-20.04/memgraph*.deb
|
||||||
|
|
||||||
ubuntu-22_04:
|
ubuntu-22_04:
|
||||||
if: ${{ github.event.inputs.target_os == 'ubuntu-22_04' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'ubuntu-22_04' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
runs-on: [self-hosted, DockerMgBuild, X64]
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package ubuntu-22.04 ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package ubuntu-22.04 ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ubuntu-22.04
|
name: ubuntu-22.04
|
||||||
path: build/output/ubuntu-22.04/memgraph*.deb
|
path: build/output/ubuntu-22.04/memgraph*.deb
|
||||||
|
|
||||||
ubuntu-22_04-arm:
|
ubuntu-22_04-arm:
|
||||||
if: ${{ github.event.inputs.target_os == 'ubuntu-22_04-arm' || github.event.inputs.target_os == 'all' }}
|
if: ${{ github.event.inputs.target_os == 'ubuntu-22_04-arm' }}
|
||||||
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
runs-on: [self-hosted, DockerMgBuild, ARM64, strange]
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
steps:
|
steps:
|
||||||
- name: "Set up repository"
|
- name: "Set up repository"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
fetch-depth: 0 # Required because of release/get_version.py
|
||||||
- name: "Build package"
|
- name: "Build package"
|
||||||
run: |
|
run: |
|
||||||
./release/package/run.sh package ubuntu-22.04-arm ${{ github.event.inputs.build_type }}
|
./release/package/run.sh package ubuntu-22.04-arm ${{ github.event.inputs.build_type }}
|
||||||
- name: "Upload package"
|
- name: "Upload package"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ubuntu-22.04-aarch64
|
name: ubuntu-22.04-aarch64
|
||||||
path: build/output/ubuntu-22.04-arm/memgraph*.deb
|
path: build/output/ubuntu-22.04-arm/memgraph*.deb
|
||||||
@@ -279,7 +278,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
# name: # if name input parameter is not provided, all artifacts are downloaded
|
# name: # if name input parameter is not provided, all artifacts are downloaded
|
||||||
# and put in directories named after each one.
|
# and put in directories named after each one.
|
||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
|
|||||||
162
.github/workflows/release_build_test.yaml
vendored
162
.github/workflows/release_build_test.yaml
vendored
@@ -1,162 +0,0 @@
|
|||||||
name: Release build test
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
build_type:
|
|
||||||
type: choice
|
|
||||||
description: "Memgraph Build type. Default value is Release."
|
|
||||||
default: 'Release'
|
|
||||||
options:
|
|
||||||
- Release
|
|
||||||
- RelWithDebInfo
|
|
||||||
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "release/**"
|
|
||||||
tags:
|
|
||||||
- "v*.*.*-rc*"
|
|
||||||
- "v*.*-rc*"
|
|
||||||
schedule:
|
|
||||||
# UTC
|
|
||||||
- cron: "0 22 * * *"
|
|
||||||
|
|
||||||
env:
|
|
||||||
THREADS: 24
|
|
||||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
|
||||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
|
||||||
BUILD_TYPE: ${{ github.event.inputs.build_type || 'Release' }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Debian10:
|
|
||||||
uses: ./.github/workflows/release_debian10.yaml
|
|
||||||
with:
|
|
||||||
build_type: ${{ github.event.inputs.build_type || 'Release' }}
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
Ubuntu20_04:
|
|
||||||
uses: ./.github/workflows/release_ubuntu2004.yaml
|
|
||||||
with:
|
|
||||||
build_type: ${{ github.event.inputs.build_type || 'Release' }}
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
PackageDebian10:
|
|
||||||
if: github.ref_type == 'tag'
|
|
||||||
needs: [Debian10]
|
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
|
||||||
timeout-minutes: 60
|
|
||||||
steps:
|
|
||||||
- name: "Set up repository"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
|
||||||
- name: "Build package"
|
|
||||||
run: |
|
|
||||||
./release/package/run.sh package debian-10 $BUILD_TYPE
|
|
||||||
- name: "Upload package"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: debian-10
|
|
||||||
path: build/output/debian-10/memgraph*.deb
|
|
||||||
|
|
||||||
PackageUbuntu20_04:
|
|
||||||
if: github.ref_type == 'tag'
|
|
||||||
needs: [Ubuntu20_04]
|
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
|
||||||
timeout-minutes: 60
|
|
||||||
steps:
|
|
||||||
- name: "Set up repository"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
|
||||||
- name: "Build package"
|
|
||||||
run: |
|
|
||||||
./release/package/run.sh package ubuntu-22.04 $BUILD_TYPE
|
|
||||||
- name: "Upload package"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ubuntu-22.04
|
|
||||||
path: build/output/ubuntu-22.04/memgraph*.deb
|
|
||||||
|
|
||||||
PackageUbuntu20_04_ARM:
|
|
||||||
if: github.ref_type == 'tag'
|
|
||||||
needs: [Ubuntu20_04]
|
|
||||||
runs-on: [self-hosted, DockerMgBuild, ARM64]
|
|
||||||
# M1 Mac mini is sometimes slower
|
|
||||||
timeout-minutes: 90
|
|
||||||
steps:
|
|
||||||
- name: "Set up repository"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
|
||||||
- name: "Build package"
|
|
||||||
run: |
|
|
||||||
./release/package/run.sh package ubuntu-22.04-arm $BUILD_TYPE
|
|
||||||
- name: "Upload package"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ubuntu-22.04-aarch64
|
|
||||||
path: build/output/ubuntu-22.04-arm/memgraph*.deb
|
|
||||||
|
|
||||||
PackageDebian11:
|
|
||||||
if: github.ref_type == 'tag'
|
|
||||||
needs: [Debian10, Ubuntu20_04]
|
|
||||||
runs-on: [self-hosted, DockerMgBuild, X64]
|
|
||||||
timeout-minutes: 60
|
|
||||||
steps:
|
|
||||||
- name: "Set up repository"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
|
||||||
- name: "Build package"
|
|
||||||
run: |
|
|
||||||
./release/package/run.sh package debian-11 $BUILD_TYPE
|
|
||||||
- name: "Upload package"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: debian-11
|
|
||||||
path: build/output/debian-11/memgraph*.deb
|
|
||||||
|
|
||||||
PackageDebian11_ARM:
|
|
||||||
if: github.ref_type == 'tag'
|
|
||||||
needs: [Debian10, Ubuntu20_04]
|
|
||||||
runs-on: [self-hosted, DockerMgBuild, ARM64]
|
|
||||||
# M1 Mac mini is sometimes slower
|
|
||||||
timeout-minutes: 90
|
|
||||||
steps:
|
|
||||||
- name: "Set up repository"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Required because of release/get_version.py
|
|
||||||
- name: "Build package"
|
|
||||||
run: |
|
|
||||||
./release/package/run.sh package debian-11-arm $BUILD_TYPE
|
|
||||||
- name: "Upload package"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: debian-11-aarch64
|
|
||||||
path: build/output/debian-11-arm/memgraph*.deb
|
|
||||||
|
|
||||||
PushToS3:
|
|
||||||
if: github.ref_type == 'tag'
|
|
||||||
needs: [PackageDebian10, PackageDebian11, PackageDebian11_ARM, PackageUbuntu20_04, PackageUbuntu20_04_ARM]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Download artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
# name: # if name input parameter is not provided, all artifacts are downloaded
|
|
||||||
# and put in directories named after each one.
|
|
||||||
path: build/output/release
|
|
||||||
- name: Upload to S3
|
|
||||||
uses: jakejarvis/s3-sync-action@v0.5.1
|
|
||||||
env:
|
|
||||||
AWS_S3_BUCKET: "deps.memgraph.io"
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.S3_AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_REGION: "eu-west-1"
|
|
||||||
SOURCE_DIR: "build/output/release"
|
|
||||||
DEST_DIR: "memgraph-unofficial/${{ github.ref_name }}/"
|
|
||||||
318
.github/workflows/release_centos8.yaml
vendored
Normal file
318
.github/workflows/release_centos8.yaml
vendored
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
name: Release CentOS 8
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
build_type:
|
||||||
|
type: choice
|
||||||
|
description: "Memgraph Build type. Default value is Release."
|
||||||
|
default: 'Release'
|
||||||
|
options:
|
||||||
|
- Release
|
||||||
|
- RelWithDebInfo
|
||||||
|
|
||||||
|
schedule:
|
||||||
|
- cron: "0 22 * * *"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
community_build:
|
||||||
|
name: "Community build"
|
||||||
|
runs-on: [self-hosted, Linux, X64, CentOS8]
|
||||||
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
timeout-minutes: 960
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
|
# branches and tags. (default: 1)
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Build community binaries
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Initialize dependencies.
|
||||||
|
./init
|
||||||
|
|
||||||
|
# Set default build_type to Release
|
||||||
|
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||||
|
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||||
|
|
||||||
|
# Build community binaries.
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
|
||||||
|
make -j$THREADS
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Run unit tests.
|
||||||
|
cd build
|
||||||
|
ctest -R memgraph__unit --output-on-failure
|
||||||
|
|
||||||
|
coverage_build:
|
||||||
|
name: "Coverage build"
|
||||||
|
runs-on: [self-hosted, Linux, X64, CentOS8]
|
||||||
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
|
# branches and tags. (default: 1)
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Build coverage binaries
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Initialize dependencies.
|
||||||
|
./init
|
||||||
|
|
||||||
|
# Build coverage binaries.
|
||||||
|
cd build
|
||||||
|
cmake -DTEST_COVERAGE=ON ..
|
||||||
|
make -j$THREADS memgraph__unit
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Run unit tests.
|
||||||
|
cd build
|
||||||
|
ctest -R memgraph__unit --output-on-failure
|
||||||
|
|
||||||
|
- name: Compute code coverage
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Compute code coverage.
|
||||||
|
cd tools/github
|
||||||
|
./coverage_convert
|
||||||
|
|
||||||
|
# Package code coverage.
|
||||||
|
cd generated
|
||||||
|
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||||
|
|
||||||
|
- name: Save code coverage
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: "Code coverage"
|
||||||
|
path: tools/github/generated/code_coverage.tar.gz
|
||||||
|
|
||||||
|
debug_build:
|
||||||
|
name: "Debug build"
|
||||||
|
runs-on: [self-hosted, Linux, X64, CentOS8]
|
||||||
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
|
# branches and tags. (default: 1)
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Build debug binaries
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Initialize dependencies.
|
||||||
|
./init
|
||||||
|
|
||||||
|
# Build debug binaries.
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j$THREADS
|
||||||
|
|
||||||
|
- name: Run leftover CTest tests
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Run leftover CTest tests (all except unit and benchmark tests).
|
||||||
|
cd build
|
||||||
|
ctest -E "(memgraph__unit|memgraph__benchmark)" --output-on-failure
|
||||||
|
|
||||||
|
- name: Run drivers tests
|
||||||
|
run: |
|
||||||
|
./tests/drivers/run.sh
|
||||||
|
|
||||||
|
- name: Run integration tests
|
||||||
|
run: |
|
||||||
|
tests/integration/run.sh
|
||||||
|
|
||||||
|
- name: Run cppcheck and clang-format
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Run cppcheck and clang-format.
|
||||||
|
cd tools/github
|
||||||
|
./cppcheck_and_clang_format diff
|
||||||
|
|
||||||
|
- name: Save cppcheck and clang-format errors
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: "Code coverage"
|
||||||
|
path: tools/github/cppcheck_and_clang_format.txt
|
||||||
|
|
||||||
|
release_build:
|
||||||
|
name: "Release build"
|
||||||
|
runs-on: [self-hosted, Linux, X64, CentOS8]
|
||||||
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
timeout-minutes: 960
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
|
# branches and tags. (default: 1)
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Build release binaries
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Initialize dependencies.
|
||||||
|
./init
|
||||||
|
|
||||||
|
# Set default build_type to Release
|
||||||
|
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||||
|
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||||
|
|
||||||
|
# Build release binaries.
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
||||||
|
make -j$THREADS
|
||||||
|
|
||||||
|
- name: Create enterprise RPM package
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
cd build
|
||||||
|
|
||||||
|
# create mgconsole
|
||||||
|
# we use the -B to force the build
|
||||||
|
make -j$THREADS -B mgconsole
|
||||||
|
|
||||||
|
# Create enterprise RPM package.
|
||||||
|
mkdir output && cd output
|
||||||
|
cpack -G RPM --config ../CPackConfig.cmake
|
||||||
|
rpmlint memgraph*.rpm
|
||||||
|
|
||||||
|
- name: Save enterprise RPM package
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: "Enterprise RPM package"
|
||||||
|
path: build/output/memgraph*.rpm
|
||||||
|
|
||||||
|
- name: Run micro benchmark tests
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Run micro benchmark tests.
|
||||||
|
cd build
|
||||||
|
# The `eval` benchmark needs a large stack limit.
|
||||||
|
ulimit -s 262144
|
||||||
|
ctest -R memgraph__benchmark -V
|
||||||
|
|
||||||
|
- name: Run macro benchmark tests
|
||||||
|
run: |
|
||||||
|
cd tests/macro_benchmark
|
||||||
|
./harness QuerySuite MemgraphRunner \
|
||||||
|
--groups aggregation 1000_create unwind_create dense_expand match \
|
||||||
|
--no-strict
|
||||||
|
|
||||||
|
- name: Run parallel macro benchmark tests
|
||||||
|
run: |
|
||||||
|
cd tests/macro_benchmark
|
||||||
|
./harness QueryParallelSuite MemgraphRunner \
|
||||||
|
--groups aggregation_parallel create_parallel bfs_parallel \
|
||||||
|
--num-database-workers 9 --num-clients-workers 30 \
|
||||||
|
--no-strict
|
||||||
|
|
||||||
|
- name: Run GQL Behave tests
|
||||||
|
run: |
|
||||||
|
cd tests
|
||||||
|
./setup.sh /opt/toolchain-v4/activate
|
||||||
|
cd gql_behave
|
||||||
|
./continuous_integration
|
||||||
|
|
||||||
|
- name: Save quality assurance status
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: "GQL Behave Status"
|
||||||
|
path: |
|
||||||
|
tests/gql_behave/gql_behave_status.csv
|
||||||
|
tests/gql_behave/gql_behave_status.html
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
run: |
|
||||||
|
# Activate toolchain.
|
||||||
|
source /opt/toolchain-v4/activate
|
||||||
|
|
||||||
|
# Run unit tests.
|
||||||
|
cd build
|
||||||
|
ctest -R memgraph__unit --output-on-failure
|
||||||
|
|
||||||
|
- name: Run e2e tests
|
||||||
|
run: |
|
||||||
|
cd tests
|
||||||
|
./setup.sh /opt/toolchain-v4/activate
|
||||||
|
source ve3/bin/activate_e2e
|
||||||
|
cd e2e
|
||||||
|
./run.sh
|
||||||
|
|
||||||
|
- name: Run stress test (plain)
|
||||||
|
run: |
|
||||||
|
cd tests/stress
|
||||||
|
./continuous_integration
|
||||||
|
|
||||||
|
- name: Run stress test (SSL)
|
||||||
|
run: |
|
||||||
|
cd tests/stress
|
||||||
|
./continuous_integration --use-ssl
|
||||||
|
|
||||||
|
- name: Run stress test (large)
|
||||||
|
run: |
|
||||||
|
cd tests/stress
|
||||||
|
./continuous_integration --large-dataset
|
||||||
|
|
||||||
|
- name: Run durability test (plain)
|
||||||
|
run: |
|
||||||
|
cd tests/stress
|
||||||
|
source ve3/bin/activate
|
||||||
|
python3 durability --num-steps 5
|
||||||
|
|
||||||
|
- name: Run durability test (large)
|
||||||
|
run: |
|
||||||
|
cd tests/stress
|
||||||
|
source ve3/bin/activate
|
||||||
|
python3 durability --num-steps 20
|
||||||
239
.github/workflows/release_debian10.yaml
vendored
239
.github/workflows/release_debian10.yaml
vendored
@@ -1,12 +1,6 @@
|
|||||||
name: Release Debian 10
|
name: Release Debian 10
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
build_type:
|
|
||||||
type: string
|
|
||||||
description: "Memgraph Build type. Default value is Release."
|
|
||||||
default: 'Release'
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
build_type:
|
build_type:
|
||||||
@@ -17,22 +11,22 @@ on:
|
|||||||
- Release
|
- Release
|
||||||
- RelWithDebInfo
|
- RelWithDebInfo
|
||||||
|
|
||||||
env:
|
schedule:
|
||||||
OS: "Debian10"
|
- cron: "0 22 * * *"
|
||||||
THREADS: 24
|
|
||||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
|
||||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
|
||||||
BUILD_TYPE: ${{ github.event.inputs.build_type || 'Release' }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
community_build:
|
community_build:
|
||||||
name: "Community build"
|
name: "Community build"
|
||||||
runs-on: [self-hosted, Linux, X64, Debian10]
|
runs-on: [self-hosted, Linux, X64, Debian10]
|
||||||
timeout-minutes: 60
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
timeout-minutes: 960
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -46,6 +40,10 @@ jobs:
|
|||||||
# Initialize dependencies.
|
# Initialize dependencies.
|
||||||
./init
|
./init
|
||||||
|
|
||||||
|
# Set default build_type to Release
|
||||||
|
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||||
|
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||||
|
|
||||||
# Build community binaries.
|
# Build community binaries.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
|
||||||
@@ -67,11 +65,10 @@ jobs:
|
|||||||
THREADS: 24
|
THREADS: 24
|
||||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
timeout-minutes: 60
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -113,19 +110,22 @@ jobs:
|
|||||||
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||||
|
|
||||||
- name: Save code coverage
|
- name: Save code coverage
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Code coverage(Coverage build)-${{ env.OS }}"
|
name: "Code coverage"
|
||||||
path: tools/github/generated/code_coverage.tar.gz
|
path: tools/github/generated/code_coverage.tar.gz
|
||||||
|
|
||||||
debug_build:
|
debug_build:
|
||||||
name: "Debug build"
|
name: "Debug build"
|
||||||
runs-on: [self-hosted, Linux, X64, Debian10]
|
runs-on: [self-hosted, Linux, X64, Debian10]
|
||||||
timeout-minutes: 60
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -157,6 +157,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./tests/drivers/run.sh
|
./tests/drivers/run.sh
|
||||||
|
|
||||||
|
- name: Run integration tests
|
||||||
|
run: |
|
||||||
|
tests/integration/run.sh
|
||||||
|
|
||||||
- name: Run cppcheck and clang-format
|
- name: Run cppcheck and clang-format
|
||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
@@ -167,49 +171,23 @@ jobs:
|
|||||||
./cppcheck_and_clang_format diff
|
./cppcheck_and_clang_format diff
|
||||||
|
|
||||||
- name: Save cppcheck and clang-format errors
|
- name: Save cppcheck and clang-format errors
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Code coverage(Debug build)-${{ env.OS }}"
|
name: "Code coverage"
|
||||||
path: tools/github/cppcheck_and_clang_format.txt
|
path: tools/github/cppcheck_and_clang_format.txt
|
||||||
|
|
||||||
debug_integration_test:
|
|
||||||
name: "Debug integration tests"
|
|
||||||
runs-on: [self-hosted, Linux, X64, Debian10]
|
|
||||||
timeout-minutes: 60
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
|
||||||
# branches and tags. (default: 1)
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Build debug binaries
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
|
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build debug binaries.
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Run integration tests
|
|
||||||
run: |
|
|
||||||
tests/integration/run.sh
|
|
||||||
|
|
||||||
release_build:
|
release_build:
|
||||||
name: "Release build"
|
name: "Release build"
|
||||||
runs-on: [self-hosted, Linux, X64, Debian10]
|
runs-on: [self-hosted, Linux, X64, Debian10]
|
||||||
timeout-minutes: 60
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
timeout-minutes: 960
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -223,6 +201,10 @@ jobs:
|
|||||||
# Initialize dependencies.
|
# Initialize dependencies.
|
||||||
./init
|
./init
|
||||||
|
|
||||||
|
# Set default build_type to Release
|
||||||
|
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||||
|
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||||
|
|
||||||
# Build release binaries.
|
# Build release binaries.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
||||||
@@ -244,60 +226,11 @@ jobs:
|
|||||||
cpack -G DEB --config ../CPackConfig.cmake
|
cpack -G DEB --config ../CPackConfig.cmake
|
||||||
|
|
||||||
- name: Save enterprise DEB package
|
- name: Save enterprise DEB package
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Enterprise DEB package-${{ env.OS}}"
|
name: "Enterprise DEB package"
|
||||||
path: build/output/memgraph*.deb
|
path: build/output/memgraph*.deb
|
||||||
|
|
||||||
- name: Run GQL Behave tests
|
|
||||||
run: |
|
|
||||||
cd tests
|
|
||||||
./setup.sh /opt/toolchain-v4/activate
|
|
||||||
cd gql_behave
|
|
||||||
./continuous_integration
|
|
||||||
|
|
||||||
- name: Save quality assurance status
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: "GQL Behave Status-${{ env.OS }}"
|
|
||||||
path: |
|
|
||||||
tests/gql_behave/gql_behave_status.csv
|
|
||||||
tests/gql_behave/gql_behave_status.html
|
|
||||||
|
|
||||||
- name: Run unit tests
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
|
|
||||||
# Run unit tests.
|
|
||||||
cd build
|
|
||||||
ctest -R memgraph__unit --output-on-failure
|
|
||||||
|
|
||||||
release_benchmark_tests:
|
|
||||||
name: "Release Benchmark Tests"
|
|
||||||
runs-on: [self-hosted, Linux, X64, Debian10]
|
|
||||||
timeout-minutes: 60
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
|
||||||
# branches and tags. (default: 1)
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Build release binaries
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build release binaries
|
|
||||||
cd build
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Run micro benchmark tests
|
- name: Run micro benchmark tests
|
||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
@@ -324,37 +257,29 @@ jobs:
|
|||||||
--num-database-workers 9 --num-clients-workers 30 \
|
--num-database-workers 9 --num-clients-workers 30 \
|
||||||
--no-strict
|
--no-strict
|
||||||
|
|
||||||
release_e2e_test:
|
- name: Run GQL Behave tests
|
||||||
name: "Release End-to-end Test"
|
run: |
|
||||||
runs-on: [self-hosted, Linux, X64, Debian10]
|
cd tests
|
||||||
timeout-minutes: 60
|
./setup.sh /opt/toolchain-v4/activate
|
||||||
|
cd gql_behave
|
||||||
|
./continuous_integration
|
||||||
|
|
||||||
steps:
|
- name: Save quality assurance status
|
||||||
- name: Set up repository
|
uses: actions/upload-artifact@v3
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
name: "GQL Behave Status"
|
||||||
# branches and tags. (default: 1)
|
path: |
|
||||||
fetch-depth: 0
|
tests/gql_behave/gql_behave_status.csv
|
||||||
|
tests/gql_behave/gql_behave_status.html
|
||||||
|
|
||||||
- name: Build release binaries
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
source /opt/toolchain-v4/activate
|
source /opt/toolchain-v4/activate
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build release binaries
|
# Run unit tests.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
ctest -R memgraph__unit --output-on-failure
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Ensure Kafka and Pulsar are up
|
|
||||||
run: |
|
|
||||||
cd tests/e2e/streams/kafka
|
|
||||||
docker-compose up -d
|
|
||||||
cd ../pulsar
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
run: |
|
run: |
|
||||||
@@ -364,40 +289,6 @@ jobs:
|
|||||||
cd e2e
|
cd e2e
|
||||||
./run.sh
|
./run.sh
|
||||||
|
|
||||||
- name: Ensure Kafka and Pulsar are down
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
cd tests/e2e/streams/kafka
|
|
||||||
docker-compose down
|
|
||||||
cd ../pulsar
|
|
||||||
docker-compose down
|
|
||||||
|
|
||||||
release_durability_stress_tests:
|
|
||||||
name: "Release durability and stress tests"
|
|
||||||
runs-on: [self-hosted, Linux, X64, Debian10]
|
|
||||||
timeout-minutes: 60
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
|
||||||
# branches and tags. (default: 1)
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Build release binaries
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
|
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build release binaries.
|
|
||||||
cd build
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Run stress test (plain)
|
- name: Run stress test (plain)
|
||||||
run: |
|
run: |
|
||||||
cd tests/stress
|
cd tests/stress
|
||||||
@@ -408,6 +299,11 @@ jobs:
|
|||||||
cd tests/stress
|
cd tests/stress
|
||||||
./continuous_integration --use-ssl
|
./continuous_integration --use-ssl
|
||||||
|
|
||||||
|
- name: Run stress test (large)
|
||||||
|
run: |
|
||||||
|
cd tests/stress
|
||||||
|
./continuous_integration --large-dataset
|
||||||
|
|
||||||
- name: Run durability test (plain)
|
- name: Run durability test (plain)
|
||||||
run: |
|
run: |
|
||||||
cd tests/stress
|
cd tests/stress
|
||||||
@@ -423,11 +319,15 @@ jobs:
|
|||||||
release_jepsen_test:
|
release_jepsen_test:
|
||||||
name: "Release Jepsen Test"
|
name: "Release Jepsen Test"
|
||||||
runs-on: [self-hosted, Linux, X64, Debian10, JepsenControl]
|
runs-on: [self-hosted, Linux, X64, Debian10, JepsenControl]
|
||||||
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -440,24 +340,23 @@ jobs:
|
|||||||
# Initialize dependencies.
|
# Initialize dependencies.
|
||||||
./init
|
./init
|
||||||
|
|
||||||
|
# Set default build_type to Release
|
||||||
|
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||||
|
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||||
|
|
||||||
# Build only memgraph release binary.
|
# Build only memgraph release binary.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
||||||
make -j$THREADS memgraph
|
make -j$THREADS memgraph
|
||||||
|
|
||||||
- name: Refresh Jepsen Cluster
|
|
||||||
run: |
|
|
||||||
cd tests/jepsen
|
|
||||||
./run.sh cluster-refresh
|
|
||||||
|
|
||||||
- name: Run Jepsen tests
|
- name: Run Jepsen tests
|
||||||
run: |
|
run: |
|
||||||
cd tests/jepsen
|
cd tests/jepsen
|
||||||
./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs
|
./run.sh test-all-individually --binary ../../build/memgraph --ignore-run-stdout-logs --ignore-run-stderr-logs
|
||||||
|
|
||||||
- name: Save Jepsen report
|
- name: Save Jepsen report
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
name: "Jepsen Report-${{ env.OS }}"
|
name: "Jepsen Report"
|
||||||
path: tests/jepsen/Jepsen.tar.gz
|
path: tests/jepsen/Jepsen.tar.gz
|
||||||
|
|||||||
2
.github/workflows/release_docker.yaml
vendored
2
.github/workflows/release_docker.yaml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
DOCKER_REPOSITORY_NAME: memgraph
|
DOCKER_REPOSITORY_NAME: memgraph
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|||||||
224
.github/workflows/release_ubuntu2004.yaml
vendored
224
.github/workflows/release_ubuntu2004.yaml
vendored
@@ -1,12 +1,6 @@
|
|||||||
name: Release Ubuntu 20.04
|
name: Release Ubuntu 20.04
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
build_type:
|
|
||||||
type: string
|
|
||||||
description: "Memgraph Build type. Default value is Release."
|
|
||||||
default: 'Release'
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
build_type:
|
build_type:
|
||||||
@@ -17,22 +11,22 @@ on:
|
|||||||
- Release
|
- Release
|
||||||
- RelWithDebInfo
|
- RelWithDebInfo
|
||||||
|
|
||||||
env:
|
schedule:
|
||||||
OS: "Ubuntu 20.04"
|
- cron: "0 22 * * *"
|
||||||
THREADS: 24
|
|
||||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
|
||||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
|
||||||
BUILD_TYPE: ${{ github.event.inputs.build_type || 'Release' }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
community_build:
|
community_build:
|
||||||
name: "Community build"
|
name: "Community build"
|
||||||
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
||||||
timeout-minutes: 60
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
timeout-minutes: 960
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -46,6 +40,10 @@ jobs:
|
|||||||
# Initialize dependencies.
|
# Initialize dependencies.
|
||||||
./init
|
./init
|
||||||
|
|
||||||
|
# Set default build_type to Release
|
||||||
|
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||||
|
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||||
|
|
||||||
# Build community binaries.
|
# Build community binaries.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DMG_ENTERPRISE=OFF ..
|
||||||
@@ -63,11 +61,14 @@ jobs:
|
|||||||
coverage_build:
|
coverage_build:
|
||||||
name: "Coverage build"
|
name: "Coverage build"
|
||||||
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
||||||
timeout-minutes: 60
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -109,19 +110,22 @@ jobs:
|
|||||||
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
tar -czf code_coverage.tar.gz coverage.json html report.json summary.rmu
|
||||||
|
|
||||||
- name: Save code coverage
|
- name: Save code coverage
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Code coverage(Coverage build)-${{ env.OS }}"
|
name: "Code coverage"
|
||||||
path: tools/github/generated/code_coverage.tar.gz
|
path: tools/github/generated/code_coverage.tar.gz
|
||||||
|
|
||||||
debug_build:
|
debug_build:
|
||||||
name: "Debug build"
|
name: "Debug build"
|
||||||
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
||||||
timeout-minutes: 60
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -153,6 +157,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./tests/drivers/run.sh
|
./tests/drivers/run.sh
|
||||||
|
|
||||||
|
- name: Run integration tests
|
||||||
|
run: |
|
||||||
|
tests/integration/run.sh
|
||||||
|
|
||||||
- name: Run cppcheck and clang-format
|
- name: Run cppcheck and clang-format
|
||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
@@ -163,49 +171,23 @@ jobs:
|
|||||||
./cppcheck_and_clang_format diff
|
./cppcheck_and_clang_format diff
|
||||||
|
|
||||||
- name: Save cppcheck and clang-format errors
|
- name: Save cppcheck and clang-format errors
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Code coverage(Debug build)-${{ env.OS }}"
|
name: "Code coverage"
|
||||||
path: tools/github/cppcheck_and_clang_format.txt
|
path: tools/github/cppcheck_and_clang_format.txt
|
||||||
|
|
||||||
debug_integration_test:
|
|
||||||
name: "Debug integration tests"
|
|
||||||
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
|
||||||
timeout-minutes: 60
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
|
||||||
# branches and tags. (default: 1)
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Build debug binaries
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
|
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build debug binaries.
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Run integration tests
|
|
||||||
run: |
|
|
||||||
tests/integration/run.sh
|
|
||||||
|
|
||||||
release_build:
|
release_build:
|
||||||
name: "Release build"
|
name: "Release build"
|
||||||
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
||||||
timeout-minutes: 60
|
env:
|
||||||
|
THREADS: 24
|
||||||
|
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
||||||
|
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
||||||
|
timeout-minutes: 960
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up repository
|
- name: Set up repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
# Number of commits to fetch. `0` indicates all history for all
|
||||||
# branches and tags. (default: 1)
|
# branches and tags. (default: 1)
|
||||||
@@ -219,6 +201,10 @@ jobs:
|
|||||||
# Initialize dependencies.
|
# Initialize dependencies.
|
||||||
./init
|
./init
|
||||||
|
|
||||||
|
# Set default build_type to Release
|
||||||
|
INPUT_BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||||
|
BUILD_TYPE=${INPUT_BUILD_TYPE:-"Release"}
|
||||||
|
|
||||||
# Build release binaries.
|
# Build release binaries.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
||||||
@@ -240,60 +226,11 @@ jobs:
|
|||||||
cpack -G DEB --config ../CPackConfig.cmake
|
cpack -G DEB --config ../CPackConfig.cmake
|
||||||
|
|
||||||
- name: Save enterprise DEB package
|
- name: Save enterprise DEB package
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "Enterprise DEB package-${{ env.OS }}"
|
name: "Enterprise DEB package"
|
||||||
path: build/output/memgraph*.deb
|
path: build/output/memgraph*.deb
|
||||||
|
|
||||||
- name: Run GQL Behave tests
|
|
||||||
run: |
|
|
||||||
cd tests
|
|
||||||
./setup.sh /opt/toolchain-v4/activate
|
|
||||||
cd gql_behave
|
|
||||||
./continuous_integration
|
|
||||||
|
|
||||||
- name: Save quality assurance status
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: "GQL Behave Status-${{ env.OS }}"
|
|
||||||
path: |
|
|
||||||
tests/gql_behave/gql_behave_status.csv
|
|
||||||
tests/gql_behave/gql_behave_status.html
|
|
||||||
|
|
||||||
- name: Run unit tests
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
|
|
||||||
# Run unit tests.
|
|
||||||
cd build
|
|
||||||
ctest -R memgraph__unit --output-on-failure
|
|
||||||
|
|
||||||
release_benchmark_tests:
|
|
||||||
name: "Release Benchmark Tests"
|
|
||||||
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
|
||||||
timeout-minutes: 60
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
|
||||||
# branches and tags. (default: 1)
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Build release binaries
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build release binaries
|
|
||||||
cd build
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Run micro benchmark tests
|
- name: Run micro benchmark tests
|
||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
@@ -320,37 +257,29 @@ jobs:
|
|||||||
--num-database-workers 9 --num-clients-workers 30 \
|
--num-database-workers 9 --num-clients-workers 30 \
|
||||||
--no-strict
|
--no-strict
|
||||||
|
|
||||||
release_e2e_test:
|
- name: Run GQL Behave tests
|
||||||
name: "Release End-to-end Test"
|
run: |
|
||||||
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
cd tests
|
||||||
timeout-minutes: 60
|
./setup.sh /opt/toolchain-v4/activate
|
||||||
|
cd gql_behave
|
||||||
|
./continuous_integration
|
||||||
|
|
||||||
steps:
|
- name: Save quality assurance status
|
||||||
- name: Set up repository
|
uses: actions/upload-artifact@v3
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
with:
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
name: "GQL Behave Status"
|
||||||
# branches and tags. (default: 1)
|
path: |
|
||||||
fetch-depth: 0
|
tests/gql_behave/gql_behave_status.csv
|
||||||
|
tests/gql_behave/gql_behave_status.html
|
||||||
|
|
||||||
- name: Build release binaries
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
# Activate toolchain.
|
# Activate toolchain.
|
||||||
source /opt/toolchain-v4/activate
|
source /opt/toolchain-v4/activate
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build release binaries
|
# Run unit tests.
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
ctest -R memgraph__unit --output-on-failure
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Ensure Kafka and Pulsar are up
|
|
||||||
run: |
|
|
||||||
cd tests/e2e/streams/kafka
|
|
||||||
docker-compose up -d
|
|
||||||
cd ../pulsar
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
run: |
|
run: |
|
||||||
@@ -360,40 +289,6 @@ jobs:
|
|||||||
cd e2e
|
cd e2e
|
||||||
./run.sh
|
./run.sh
|
||||||
|
|
||||||
- name: Ensure Kafka and Pulsar are down
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
cd tests/e2e/streams/kafka
|
|
||||||
docker-compose down
|
|
||||||
cd ../pulsar
|
|
||||||
docker-compose down
|
|
||||||
|
|
||||||
release_durability_stress_tests:
|
|
||||||
name: "Release durability and stress tests"
|
|
||||||
runs-on: [self-hosted, Linux, X64, Ubuntu20.04]
|
|
||||||
timeout-minutes: 60
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
|
||||||
# branches and tags. (default: 1)
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Build release binaries
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
|
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build release binaries.
|
|
||||||
cd build
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Run stress test (plain)
|
- name: Run stress test (plain)
|
||||||
run: |
|
run: |
|
||||||
cd tests/stress
|
cd tests/stress
|
||||||
@@ -404,6 +299,11 @@ jobs:
|
|||||||
cd tests/stress
|
cd tests/stress
|
||||||
./continuous_integration --use-ssl
|
./continuous_integration --use-ssl
|
||||||
|
|
||||||
|
- name: Run stress test (large)
|
||||||
|
run: |
|
||||||
|
cd tests/stress
|
||||||
|
./continuous_integration --large-dataset
|
||||||
|
|
||||||
- name: Run durability test (plain)
|
- name: Run durability test (plain)
|
||||||
run: |
|
run: |
|
||||||
cd tests/stress
|
cd tests/stress
|
||||||
|
|||||||
68
.github/workflows/stress_test_large.yaml
vendored
68
.github/workflows/stress_test_large.yaml
vendored
@@ -1,68 +0,0 @@
|
|||||||
name: Stress test large
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
build_type:
|
|
||||||
type: choice
|
|
||||||
description: "Memgraph Build type. Default value is Release."
|
|
||||||
default: 'Release'
|
|
||||||
options:
|
|
||||||
- Release
|
|
||||||
- RelWithDebInfo
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*.*.*-rc*"
|
|
||||||
- "v*.*-rc*"
|
|
||||||
schedule:
|
|
||||||
- cron: "0 22 * * *"
|
|
||||||
|
|
||||||
env:
|
|
||||||
THREADS: 24
|
|
||||||
MEMGRAPH_ENTERPRISE_LICENSE: ${{ secrets.MEMGRAPH_ENTERPRISE_LICENSE }}
|
|
||||||
MEMGRAPH_ORGANIZATION_NAME: ${{ secrets.MEMGRAPH_ORGANIZATION_NAME }}
|
|
||||||
BUILD_TYPE: ${{ github.event.inputs.build_type || 'Release' }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stress_test_large:
|
|
||||||
name: "Stress test large"
|
|
||||||
timeout-minutes: 720
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [Debian10, Ubuntu20.04]
|
|
||||||
extra: [BigMemory, Gen8]
|
|
||||||
exclude:
|
|
||||||
- os: Debian10
|
|
||||||
extra: Gen8
|
|
||||||
- os: Ubuntu20.04
|
|
||||||
extra: BigMemory
|
|
||||||
runs-on: [self-hosted, Linux, X64, "${{ matrix.os }}", "${{ matrix.extra }}"]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Number of commits to fetch. `0` indicates all history for all
|
|
||||||
# branches and tags. (default: 1)
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Build release binaries
|
|
||||||
run: |
|
|
||||||
# Activate toolchain.
|
|
||||||
source /opt/toolchain-v4/activate
|
|
||||||
|
|
||||||
# Initialize dependencies.
|
|
||||||
./init
|
|
||||||
|
|
||||||
# Build release binaries.
|
|
||||||
cd build
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
|
|
||||||
make -j$THREADS
|
|
||||||
|
|
||||||
- name: Run stress test (large)
|
|
||||||
run: |
|
|
||||||
cd tests/stress
|
|
||||||
./continuous_integration --large-dataset
|
|
||||||
2
.github/workflows/upload_to_s3.yaml
vendored
2
.github/workflows/upload_to_s3.yaml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: dawidd6/action-download-artifact@v4
|
uses: dawidd6/action-download-artifact@v2
|
||||||
with:
|
with:
|
||||||
workflow: package_all.yaml
|
workflow: package_all.yaml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
# Path to sources
|
|
||||||
sonar.sources = .
|
|
||||||
# sonar.exclusions=
|
|
||||||
sonar.inclusions=src,include,query_modules
|
|
||||||
|
|
||||||
# Path to tests
|
|
||||||
sonar.tests = tests/
|
|
||||||
# sonar.test.exclusions=
|
|
||||||
# sonar.test.inclusions=
|
|
||||||
|
|
||||||
# Source encoding
|
|
||||||
# sonar.sourceEncoding=
|
|
||||||
|
|
||||||
# Exclusions for copy-paste detection
|
|
||||||
# sonar.cpd.exclusions=
|
|
||||||
|
|
||||||
# Python version (for python projects only)
|
|
||||||
# sonar.python.version=
|
|
||||||
|
|
||||||
# C++ standard version (for C++ projects only)
|
|
||||||
# If not specified, it defaults to the latest supported standard
|
|
||||||
# sonar.cfamily.reportingCppStandardOverride=c++98|c++11|c++14|c++17|c++20
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Tantivy ADR
|
|
||||||
|
|
||||||
**Author**
|
|
||||||
Marko Budiselic (github.com/gitbuda)
|
|
||||||
|
|
||||||
**Status**
|
|
||||||
APPROVED
|
|
||||||
|
|
||||||
**Date**
|
|
||||||
January 5, 2024
|
|
||||||
|
|
||||||
**Problem**
|
|
||||||
|
|
||||||
For some of Memgraph workloads, text search is a required feature. We don't
|
|
||||||
want to build a new text search engine because that's not Memgraph's core
|
|
||||||
value.
|
|
||||||
|
|
||||||
**Criteria**
|
|
||||||
|
|
||||||
- easy integration with our C++ codebase
|
|
||||||
- ability to operate in-memory and on-disk
|
|
||||||
- sufficient features (regex, full-text search, fuzzy search, aggregations over
|
|
||||||
text data)
|
|
||||||
- production-ready
|
|
||||||
|
|
||||||
**Decision**
|
|
||||||
|
|
||||||
All known C++ libraries are not production-ready. Recent Rust libraries, in
|
|
||||||
particular [Tantivy](https://github.com/quickwit-oss/tantivy), seem to provide
|
|
||||||
much more features, it is production ready. The way how we'll integrate Tantivy
|
|
||||||
into the current Memgraph codebase is via
|
|
||||||
[cxx](https://github.com/dtolnay/cxx). **We select Tantivy.**
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# NuRaft ADR
|
|
||||||
|
|
||||||
**Author**
|
|
||||||
Marko Budiselic (github.com/gitbuda)
|
|
||||||
|
|
||||||
**Status**
|
|
||||||
PROPOSED
|
|
||||||
|
|
||||||
**Date**
|
|
||||||
January 10, 2024
|
|
||||||
|
|
||||||
**Problem**
|
|
||||||
|
|
||||||
In order to enhance Memgraph to have High Availability features as requested by
|
|
||||||
customers, we want to have reliable coordinators backed by RAFT consensus algorithm. Implementing
|
|
||||||
RAFT to be correct and performant is a very challenging task. Skillful Memgraph
|
|
||||||
engineers already tried 3 times and failed to deliver in a reasonable timeframe
|
|
||||||
all three times (approximately 4 person-weeks of engineering work each time).
|
|
||||||
|
|
||||||
**Criteria**
|
|
||||||
|
|
||||||
- easy integration with our C++ codebase
|
|
||||||
- heavily tested in production environments
|
|
||||||
- implementation of performance optimizations on top of the canonical Raft
|
|
||||||
implementation
|
|
||||||
|
|
||||||
**Decision**
|
|
||||||
|
|
||||||
There are a few, robust C++ implementations of Raft but as a part of other
|
|
||||||
projects or bigger libraries. **We select
|
|
||||||
[NuRaft](https://github.com/eBay/NuRaft)** because it focuses on delivering
|
|
||||||
Raft without bloatware, and it's used by
|
|
||||||
[Clickhouse](https://github.com/ClickHouse/ClickHouse) (an comparable peer to
|
|
||||||
Memgraph, a very well-established product).
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# RocksDB ADR
|
|
||||||
|
|
||||||
**Author**
|
|
||||||
Marko Budiselic (github.com/gitbuda)
|
|
||||||
|
|
||||||
**Status**
|
|
||||||
ACCEPTED
|
|
||||||
|
|
||||||
**Date**
|
|
||||||
January 23, 2024
|
|
||||||
|
|
||||||
**Problem**
|
|
||||||
|
|
||||||
Interacting with data (reads and writes) on disk in a concurrent, safe, and
|
|
||||||
fast way is a challenging task. Implementing all low-level primitives to
|
|
||||||
interact with various disk hardware efficiently consumes significant
|
|
||||||
engineering people. Whenever Memgraph has to store data on disk (or any
|
|
||||||
other colder than RAM storage system), the problem is how to do that in the
|
|
||||||
least amount of development time while satisfying all functional requirements
|
|
||||||
(often performance).
|
|
||||||
|
|
||||||
**Criteria**
|
|
||||||
|
|
||||||
- working efficiently in a highly concurrent environment
|
|
||||||
- easy integration with Memgraph's C++ codebase
|
|
||||||
- providing low-level key-value API
|
|
||||||
- heavily tested in production environments
|
|
||||||
- providing abstractions for the storage hardware (even for cloud-based
|
|
||||||
storages like S3)
|
|
||||||
|
|
||||||
**Decision**
|
|
||||||
|
|
||||||
There are a few robust key-value stores, but finding one that is
|
|
||||||
production-ready and compatible with Memgraph's C++ codebase is challenging.
|
|
||||||
**We select [RocksDB](https://github.com/facebook/rocksdb)** because it
|
|
||||||
delivers robust API to manage data on disk; it's battle-tested in many
|
|
||||||
production environments (many databases systems are embedding RocksDB), and
|
|
||||||
it's the most compatible one.
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
# Architecture Decision Records
|
|
||||||
|
|
||||||
Also known as ADRs. This practice has become widespread in many
|
|
||||||
high performing engineering teams. It is a technique for communicating
|
|
||||||
between software engineers. ADRs provide a clear and documented
|
|
||||||
history of architectural choices, ensuring that everyone on the
|
|
||||||
team is on the same page. This improves communication and reduces
|
|
||||||
misunderstandings. The act of recording decisions encourages
|
|
||||||
thoughtful consideration before making choices. This can lead to
|
|
||||||
more robust and better-informed architectural decisions.
|
|
||||||
|
|
||||||
Links must be created, pointing both to and from the Github Issues
|
|
||||||
and/or the Notion Program Management "Initiative" database.
|
|
||||||
|
|
||||||
ADRs are complimentary to any tech specs that get written while
|
|
||||||
designing a solution. ADRs are very short and to the point, while
|
|
||||||
tech specs will include diagrams and can be quite verbose.
|
|
||||||
|
|
||||||
## HOWTO
|
|
||||||
|
|
||||||
Each ADR will be assigned a monotonically increasing unique numeric
|
|
||||||
identifier, which will be zero-padded to 3 digits. Each ADR will
|
|
||||||
be in a single markdown file containing no more than one page of
|
|
||||||
text, and the filename will start with that unique identifier,
|
|
||||||
followed by a camel case phrase summarizing the problem. For
|
|
||||||
example: `001_architecture_decision_records.md` or
|
|
||||||
`002_big_integration_cap_theorem.md`.
|
|
||||||
|
|
||||||
We want to use an ADR when:
|
|
||||||
1. Significant Impact: This includes choices that affect scalability, performance, or fundamental design principles.
|
|
||||||
1. Long-Term Ramifications: When a decision is expected to have long-term ramifications or is difficult to reverse.
|
|
||||||
1. Architectural Principles: ADRs are suitable for documenting decisions related to architectural principles, frameworks, or patterns that shape the system's structure.
|
|
||||||
1. Controversial Choices: When a decision is likely to be controversial or may require justification in the future.
|
|
||||||
|
|
||||||
The most senior engineer on a project will evaluate and decide
|
|
||||||
whether or not an ADR is needed.
|
|
||||||
|
|
||||||
## Do
|
|
||||||
|
|
||||||
1. Keep them brief and concise.
|
|
||||||
1. Explain the trade-offs.
|
|
||||||
1. Each ADR should be about one AD, not multiple ADs
|
|
||||||
1. Don't alter existing information in an ADR. Instead, amend the ADR by adding new information, or supersede the ADR by creating a new ADR.
|
|
||||||
1. Explain your organization's situation and business priorities.
|
|
||||||
1. Include rationale and considerations based on social and skills makeups of your teams.
|
|
||||||
1. Include pros and cons that are relevant, and describe them in terms that align with your needs and goals.
|
|
||||||
1. Explain what follows from making the decision. This can include the effects, outcomes, outputs, follow ups, and more.
|
|
||||||
|
|
||||||
## Don't
|
|
||||||
|
|
||||||
1. Try to guess what the executive leader wants, and then attempt to please them. Be objective.
|
|
||||||
1. Try to solve everything all at once. A pretty good solution now is MUCH BETTER than a perfect solution later. Carpe diem!
|
|
||||||
1. Hide any doubts or unanswered questions.
|
|
||||||
1. Make it a sales pitch. Everything has upsides and downsides - be authentic and honest about them.
|
|
||||||
1. Perform merely a superficial investigation. If an ADR doesn't call for some deep thinking, then it probably shouldn't exist.
|
|
||||||
1. Ignore the long-term costs such as performance, tech debt or hardware and maintenance.
|
|
||||||
1. Get tunnel vision where creative or surprising approaches are not explored.
|
|
||||||
|
|
||||||
# Template - use the format below for each new ADR
|
|
||||||
|
|
||||||
1. **Author** - who has written the ADR
|
|
||||||
1. **Status** - one of: PROPOSED, ACCEPTED, REJECTED, SUPERSEDED-BY or DEPRECATED
|
|
||||||
1. **Date** - when the status was most recently updated
|
|
||||||
1. **Problem** - a concise paragraph explaining the context
|
|
||||||
1. **Criteria** - a list of the two or three metrics by which the solution was evaluated, and their relative weights (importance)
|
|
||||||
1. **Decision** - what was chosen as the way forward, and what the consequences are of the decision
|
|
||||||
|
|
||||||
@@ -211,13 +211,8 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
|||||||
# ** Static linking is allowed only for executables! **
|
# ** Static linking is allowed only for executables! **
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
||||||
|
|
||||||
# Use lld linker to speedup build and use less memory.
|
# Use lld linker to speedup build
|
||||||
add_link_options(-fuse-ld=lld)
|
add_link_options(-fuse-ld=lld) # TODO: use mold linker
|
||||||
# NOTE: Moving to latest Clang (probably starting from 15), lld stopped to work
|
|
||||||
# without explicit link_directories call.
|
|
||||||
string(REPLACE ":" " " LD_LIBS $ENV{LD_LIBRARY_PATH})
|
|
||||||
separate_arguments(LD_LIBS)
|
|
||||||
link_directories(${LD_LIBS})
|
|
||||||
|
|
||||||
# release flags
|
# release flags
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
|
||||||
@@ -276,6 +271,7 @@ endif()
|
|||||||
set(libs_dir ${CMAKE_SOURCE_DIR}/libs)
|
set(libs_dir ${CMAKE_SOURCE_DIR}/libs)
|
||||||
add_subdirectory(libs EXCLUDE_FROM_ALL)
|
add_subdirectory(libs EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
# Optional subproject configuration -------------------------------------------
|
||||||
option(TEST_COVERAGE "Generate coverage reports from running memgraph" OFF)
|
option(TEST_COVERAGE "Generate coverage reports from running memgraph" OFF)
|
||||||
option(TOOLS "Build tools binaries" ON)
|
option(TOOLS "Build tools binaries" ON)
|
||||||
option(QUERY_MODULES "Build query modules containing custom procedures" ON)
|
option(QUERY_MODULES "Build query modules containing custom procedures" ON)
|
||||||
@@ -283,8 +279,6 @@ option(ASAN "Build with Address Sanitizer. To get a reasonable performance optio
|
|||||||
option(TSAN "Build with Thread Sanitizer. To get a reasonable performance option should be used only in Release or RelWithDebInfo build " OFF)
|
option(TSAN "Build with Thread Sanitizer. To get a reasonable performance option should be used only in Release or RelWithDebInfo build " OFF)
|
||||||
option(UBSAN "Build with Undefined Behaviour Sanitizer" OFF)
|
option(UBSAN "Build with Undefined Behaviour Sanitizer" OFF)
|
||||||
|
|
||||||
# Build feature flags
|
|
||||||
|
|
||||||
if (TEST_COVERAGE)
|
if (TEST_COVERAGE)
|
||||||
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
||||||
if (NOT lower_build_type STREQUAL "debug")
|
if (NOT lower_build_type STREQUAL "debug")
|
||||||
|
|||||||
@@ -111,14 +111,6 @@ modifications:
|
|||||||
value: "false"
|
value: "false"
|
||||||
override: true
|
override: true
|
||||||
|
|
||||||
- name: "storage_parallel_schema_recovery"
|
|
||||||
value: "false"
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: "storage_enable_schema_metadata"
|
|
||||||
value: "false"
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: "query_callable_mappings_path"
|
- name: "query_callable_mappings_path"
|
||||||
value: "/etc/memgraph/apoc_compatibility_mappings.json"
|
value: "/etc/memgraph/apoc_compatibility_mappings.json"
|
||||||
override: true
|
override: true
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -7,7 +9,7 @@ check_operating_system "amzn-2"
|
|||||||
check_architecture "x86_64"
|
check_architecture "x86_64"
|
||||||
|
|
||||||
TOOLCHAIN_BUILD_DEPS=(
|
TOOLCHAIN_BUILD_DEPS=(
|
||||||
git gcc gcc-c++ make # generic build tools
|
gcc gcc-c++ make # generic build tools
|
||||||
wget # used for archive download
|
wget # used for archive download
|
||||||
gnupg2 # used for archive signature verification
|
gnupg2 # used for archive signature verification
|
||||||
tar gzip bzip2 xz unzip # used for archive unpacking
|
tar gzip bzip2 xz unzip # used for archive unpacking
|
||||||
@@ -61,8 +63,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
cyrus-sasl-devel
|
cyrus-sasl-devel
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
MEMGRAPH_RUN_DEPS=(
|
||||||
logrotate openssl python3 libseccomp
|
logrotate openssl python3 libseccomp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -61,8 +63,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
cyrus-sasl-devel
|
cyrus-sasl-devel
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
MEMGRAPH_RUN_DEPS=(
|
||||||
logrotate openssl python3 libseccomp
|
logrotate openssl python3 libseccomp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -7,10 +9,8 @@ check_operating_system "centos-9"
|
|||||||
check_architecture "x86_64"
|
check_architecture "x86_64"
|
||||||
|
|
||||||
TOOLCHAIN_BUILD_DEPS=(
|
TOOLCHAIN_BUILD_DEPS=(
|
||||||
wget # used for archive download
|
|
||||||
coreutils-common gcc gcc-c++ make # generic build tools
|
coreutils-common gcc gcc-c++ make # generic build tools
|
||||||
# NOTE: Pure libcurl conflicts with libcurl-minimal
|
wget # used for archive download
|
||||||
libcurl-devel # cmake build requires it
|
|
||||||
gnupg2 # used for archive signature verification
|
gnupg2 # used for archive signature verification
|
||||||
tar gzip bzip2 xz unzip # used for archive unpacking
|
tar gzip bzip2 xz unzip # used for archive unpacking
|
||||||
zlib-devel # zlib library used for all builds
|
zlib-devel # zlib library used for all builds
|
||||||
@@ -64,8 +64,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
cyrus-sasl-devel
|
cyrus-sasl-devel
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
MEMGRAPH_RUN_DEPS=(
|
||||||
logrotate openssl python3 libseccomp
|
logrotate openssl python3 libseccomp
|
||||||
)
|
)
|
||||||
@@ -125,9 +123,7 @@ install() {
|
|||||||
else
|
else
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
echo "NOTE: export LANG=en_US.utf8"
|
||||||
fi
|
fi
|
||||||
# --nobest is used because of libipt because we install custom versions
|
yum update -y
|
||||||
# because libipt-devel is not available on CentOS 9 Stream
|
|
||||||
yum update -y --nobest
|
|
||||||
yum install -y wget git python3 python3-pip
|
yum install -y wget git python3 python3-pip
|
||||||
|
|
||||||
for pkg in $1; do
|
for pkg in $1; do
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
# IMPORTANT: Deprecated since memgraph v2.12.0.
|
|
||||||
|
|
||||||
check_operating_system "debian-10"
|
check_operating_system "debian-10"
|
||||||
check_architecture "x86_64"
|
check_architecture "x86_64"
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
# IMPORTANT: Deprecated since memgraph v2.12.0.
|
|
||||||
|
|
||||||
check_operating_system "debian-11"
|
check_operating_system "debian-11"
|
||||||
check_architecture "arm64" "aarch64"
|
check_architecture "arm64" "aarch64"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -59,8 +61,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libsasl2-dev
|
libsasl2-dev
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
MEMGRAPH_RUN_DEPS=(
|
||||||
logrotate openssl python3 libseccomp
|
logrotate openssl python3 libseccomp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,134 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -Eeuo pipefail
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|
||||||
source "$DIR/../util.sh"
|
|
||||||
|
|
||||||
check_operating_system "debian-12"
|
|
||||||
check_architecture "arm64" "aarch64"
|
|
||||||
|
|
||||||
TOOLCHAIN_BUILD_DEPS=(
|
|
||||||
coreutils gcc g++ build-essential make # generic build tools
|
|
||||||
wget # used for archive download
|
|
||||||
gnupg # used for archive signature verification
|
|
||||||
tar gzip bzip2 xz-utils unzip # used for archive unpacking
|
|
||||||
zlib1g-dev # zlib library used for all builds
|
|
||||||
libexpat1-dev liblzma-dev python3-dev texinfo # for gdb
|
|
||||||
libcurl4-openssl-dev # for cmake
|
|
||||||
libreadline-dev # for cmake and llvm
|
|
||||||
libffi-dev libxml2-dev # for llvm
|
|
||||||
libedit-dev libpcre2-dev libpcre3-dev automake bison # for swig
|
|
||||||
curl # snappy
|
|
||||||
file # for libunwind
|
|
||||||
libssl-dev # for libevent
|
|
||||||
libgmp-dev
|
|
||||||
gperf # for proxygen
|
|
||||||
git # for fbthrift
|
|
||||||
)
|
|
||||||
|
|
||||||
TOOLCHAIN_RUN_DEPS=(
|
|
||||||
make # generic build tools
|
|
||||||
tar gzip bzip2 xz-utils # used for archive unpacking
|
|
||||||
zlib1g # zlib library used for all builds
|
|
||||||
libexpat1 liblzma5 python3 # for gdb
|
|
||||||
libcurl4 # for cmake
|
|
||||||
file # for CPack
|
|
||||||
libreadline8 # for cmake and llvm
|
|
||||||
libffi8 libxml2 # for llvm
|
|
||||||
libssl-dev # for libevent
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
|
||||||
git # source code control
|
|
||||||
make pkg-config # build system
|
|
||||||
curl wget # for downloading libs
|
|
||||||
uuid-dev default-jre-headless # required by antlr
|
|
||||||
libreadline-dev # for memgraph console
|
|
||||||
libpython3-dev python3-dev # for query modules
|
|
||||||
libssl-dev
|
|
||||||
libseccomp-dev
|
|
||||||
netcat # tests are using nc to wait for memgraph
|
|
||||||
python3 virtualenv python3-virtualenv python3-pip # for qa, macro_benchmark and stress tests
|
|
||||||
python3-yaml # for the configuration generator
|
|
||||||
libcurl4-openssl-dev # mg-requests
|
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
|
||||||
doxygen graphviz # source documentation generators
|
|
||||||
mono-runtime mono-mcs zip unzip default-jdk-headless custom-maven3.9.3 # for driver tests
|
|
||||||
dotnet-sdk-7.0 golang custom-golang1.18.9 nodejs npm
|
|
||||||
autoconf # for jemalloc code generation
|
|
||||||
libtool # for protobuf code generation
|
|
||||||
libsasl2-dev
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
|
||||||
logrotate openssl python3 libseccomp
|
|
||||||
)
|
|
||||||
|
|
||||||
NEW_DEPS=(
|
|
||||||
wget curl tar gzip
|
|
||||||
)
|
|
||||||
|
|
||||||
list() {
|
|
||||||
echo "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
check() {
|
|
||||||
local missing=""
|
|
||||||
for pkg in $1; do
|
|
||||||
if [ "$pkg" == custom-maven3.9.3 ]; then
|
|
||||||
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == custom-golang1.18.9 ]; then
|
|
||||||
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$missing" != "" ]; then
|
|
||||||
echo "MISSING PACKAGES: $missing"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install() {
|
|
||||||
cd "$DIR"
|
|
||||||
apt update
|
|
||||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
|
||||||
# Python related tests doesn't work the LANG export.
|
|
||||||
if [ -d "/home/gh/actions-runner" ]; then
|
|
||||||
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
|
|
||||||
else
|
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
|
||||||
fi
|
|
||||||
apt install -y wget
|
|
||||||
|
|
||||||
for pkg in $1; do
|
|
||||||
if [ "$pkg" == custom-maven3.9.3 ]; then
|
|
||||||
install_custom_maven "3.9.3"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == custom-golang1.18.9 ]; then
|
|
||||||
install_custom_golang "1.18.9"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == dotnet-sdk-7.0 ]; then
|
|
||||||
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
|
||||||
wget -nv https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
|
||||||
dpkg -i packages-microsoft-prod.deb
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y apt-transport-https dotnet-sdk-7.0
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
apt install -y "$pkg"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
deps=$2"[*]"
|
|
||||||
"$1" "${!deps}"
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -Eeuo pipefail
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|
||||||
source "$DIR/../util.sh"
|
|
||||||
|
|
||||||
check_operating_system "debian-12"
|
|
||||||
check_architecture "x86_64"
|
|
||||||
|
|
||||||
TOOLCHAIN_BUILD_DEPS=(
|
|
||||||
coreutils gcc g++ build-essential make # generic build tools
|
|
||||||
wget # used for archive download
|
|
||||||
gnupg # used for archive signature verification
|
|
||||||
tar gzip bzip2 xz-utils unzip # used for archive unpacking
|
|
||||||
zlib1g-dev # zlib library used for all builds
|
|
||||||
libexpat1-dev libipt-dev libbabeltrace-dev liblzma-dev python3-dev texinfo # for gdb
|
|
||||||
libcurl4-openssl-dev # for cmake
|
|
||||||
libreadline-dev # for cmake and llvm
|
|
||||||
libffi-dev libxml2-dev # for llvm
|
|
||||||
libedit-dev libpcre2-dev libpcre3-dev automake bison # for swig
|
|
||||||
curl # snappy
|
|
||||||
file # for libunwind
|
|
||||||
libssl-dev # for libevent
|
|
||||||
libgmp-dev
|
|
||||||
gperf # for proxygen
|
|
||||||
git # for fbthrift
|
|
||||||
)
|
|
||||||
|
|
||||||
TOOLCHAIN_RUN_DEPS=(
|
|
||||||
make # generic build tools
|
|
||||||
tar gzip bzip2 xz-utils # used for archive unpacking
|
|
||||||
zlib1g # zlib library used for all builds
|
|
||||||
libexpat1 libipt2 libbabeltrace1 liblzma5 python3 # for gdb
|
|
||||||
libcurl4 # for cmake
|
|
||||||
file # for CPack
|
|
||||||
libreadline8 # for cmake and llvm
|
|
||||||
libffi8 libxml2 # for llvm
|
|
||||||
libssl-dev # for libevent
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
|
||||||
git # source code control
|
|
||||||
make cmake pkg-config # build system
|
|
||||||
curl wget # for downloading libs
|
|
||||||
uuid-dev default-jre-headless # required by antlr
|
|
||||||
libreadline-dev # for memgraph console
|
|
||||||
libpython3-dev python3-dev # for query modules
|
|
||||||
libssl-dev
|
|
||||||
libseccomp-dev
|
|
||||||
netcat-traditional # tests are using nc to wait for memgraph
|
|
||||||
python3 virtualenv python3-virtualenv python3-pip # for qa, macro_benchmark and stress tests
|
|
||||||
python3-yaml # for the configuration generator
|
|
||||||
libcurl4-openssl-dev # mg-requests
|
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
|
||||||
doxygen graphviz # source documentation generators
|
|
||||||
mono-runtime mono-mcs zip unzip default-jdk-headless custom-maven3.9.3 # for driver tests
|
|
||||||
dotnet-sdk-7.0 golang custom-golang1.18.9 nodejs npm
|
|
||||||
autoconf # for jemalloc code generation
|
|
||||||
libtool # for protobuf code generation
|
|
||||||
libsasl2-dev
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
|
||||||
logrotate openssl python3 libseccomp
|
|
||||||
)
|
|
||||||
|
|
||||||
NEW_DEPS=(
|
|
||||||
wget curl tar gzip
|
|
||||||
)
|
|
||||||
|
|
||||||
list() {
|
|
||||||
echo "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
check() {
|
|
||||||
local missing=""
|
|
||||||
for pkg in $1; do
|
|
||||||
if [ "$pkg" == custom-maven3.9.3 ]; then
|
|
||||||
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == custom-golang1.18.9 ]; then
|
|
||||||
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$missing" != "" ]; then
|
|
||||||
echo "MISSING PACKAGES: $missing"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install() {
|
|
||||||
cd "$DIR"
|
|
||||||
apt update
|
|
||||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
|
||||||
# Python related tests doesn't work the LANG export.
|
|
||||||
if [ -d "/home/gh/actions-runner" ]; then
|
|
||||||
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
|
|
||||||
else
|
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
|
||||||
fi
|
|
||||||
apt install -y wget
|
|
||||||
|
|
||||||
for pkg in $1; do
|
|
||||||
if [ "$pkg" == custom-maven3.9.3 ]; then
|
|
||||||
install_custom_maven "3.9.3"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == custom-golang1.18.9 ]; then
|
|
||||||
install_custom_golang "1.18.9"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == dotnet-sdk-7.0 ]; then
|
|
||||||
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
|
|
||||||
wget -nv https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
|
||||||
dpkg -i packages-microsoft-prod.deb
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y apt-transport-https dotnet-sdk-7.0
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
apt install -y "$pkg"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
deps=$2"[*]"
|
|
||||||
"$1" "${!deps}"
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
# IMPORTANT: Deprecated since memgraph v2.12.0.
|
|
||||||
|
|
||||||
check_operating_system "fedora-36"
|
check_operating_system "fedora-36"
|
||||||
check_architecture "x86_64"
|
check_architecture "x86_64"
|
||||||
|
|
||||||
@@ -27,7 +27,6 @@ TOOLCHAIN_BUILD_DEPS=(
|
|||||||
libipt libipt-devel # intel
|
libipt libipt-devel # intel
|
||||||
patch
|
patch
|
||||||
perl # for openssl
|
perl # for openssl
|
||||||
git
|
|
||||||
)
|
)
|
||||||
|
|
||||||
TOOLCHAIN_RUN_DEPS=(
|
TOOLCHAIN_RUN_DEPS=(
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -25,7 +27,6 @@ TOOLCHAIN_BUILD_DEPS=(
|
|||||||
libipt libipt-devel # intel
|
libipt libipt-devel # intel
|
||||||
patch
|
patch
|
||||||
perl # for openssl
|
perl # for openssl
|
||||||
git
|
|
||||||
)
|
)
|
||||||
|
|
||||||
TOOLCHAIN_RUN_DEPS=(
|
TOOLCHAIN_RUN_DEPS=(
|
||||||
@@ -57,16 +58,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libtool # for protobuf code generation
|
libtool # for protobuf code generation
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
|
||||||
logrotate openssl python3 libseccomp
|
|
||||||
)
|
|
||||||
|
|
||||||
NEW_DEPS=(
|
|
||||||
wget curl tar gzip
|
|
||||||
)
|
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
echo "$1"
|
echo "$1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -Eeuo pipefail
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|
||||||
source "$DIR/../util.sh"
|
|
||||||
|
|
||||||
check_operating_system "fedora-39"
|
|
||||||
check_architecture "x86_64"
|
|
||||||
|
|
||||||
TOOLCHAIN_BUILD_DEPS=(
|
|
||||||
coreutils-common gcc gcc-c++ make # generic build tools
|
|
||||||
wget # used for archive download
|
|
||||||
gnupg2 # used for archive signature verification
|
|
||||||
tar gzip bzip2 xz unzip # used for archive unpacking
|
|
||||||
zlib-devel # zlib library used for all builds
|
|
||||||
expat-devel xz-devel python3-devel texinfo libbabeltrace-devel # for gdb
|
|
||||||
curl libcurl-devel # for cmake
|
|
||||||
readline-devel # for cmake and llvm
|
|
||||||
libffi-devel libxml2-devel # for llvm
|
|
||||||
libedit-devel pcre-devel pcre2-devel automake bison # for swig
|
|
||||||
file
|
|
||||||
openssl-devel
|
|
||||||
gmp-devel
|
|
||||||
gperf
|
|
||||||
diffutils
|
|
||||||
libipt libipt-devel # intel
|
|
||||||
patch
|
|
||||||
perl # for openssl
|
|
||||||
git
|
|
||||||
)
|
|
||||||
|
|
||||||
TOOLCHAIN_RUN_DEPS=(
|
|
||||||
make # generic build tools
|
|
||||||
tar gzip bzip2 xz # used for archive unpacking
|
|
||||||
zlib # zlib library used for all builds
|
|
||||||
expat xz-libs python3 # for gdb
|
|
||||||
readline # for cmake and llvm
|
|
||||||
libffi libxml2 # for llvm
|
|
||||||
openssl-devel
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
|
||||||
git # source code control
|
|
||||||
make pkgconf-pkg-config # build system
|
|
||||||
wget # for downloading libs
|
|
||||||
libuuid-devel java-11-openjdk # required by antlr
|
|
||||||
readline-devel # for memgraph console
|
|
||||||
python3-devel # for query modules
|
|
||||||
openssl-devel
|
|
||||||
libseccomp-devel
|
|
||||||
python3 python3-pip python3-virtualenv python3-virtualenvwrapper python3-pyyaml nmap-ncat # for tests
|
|
||||||
libcurl-devel # mg-requests
|
|
||||||
rpm-build rpmlint # for RPM package building
|
|
||||||
doxygen graphviz # source documentation generators
|
|
||||||
which nodejs golang zip unzip java-11-openjdk-devel # for driver tests
|
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
|
||||||
autoconf # for jemalloc code generation
|
|
||||||
libtool # for protobuf code generation
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
|
||||||
logrotate openssl python3 libseccomp
|
|
||||||
)
|
|
||||||
|
|
||||||
NEW_DEPS=(
|
|
||||||
wget curl tar gzip
|
|
||||||
)
|
|
||||||
|
|
||||||
list() {
|
|
||||||
echo "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
check() {
|
|
||||||
if [ -v LD_LIBRARY_PATH ]; then
|
|
||||||
# On Fedora 38 yum/dnf and python11 use newer glibc which is not compatible
|
|
||||||
# with ours, so we need to momentarely disable env
|
|
||||||
local OLD_LD_LIBRARY_PATH=${LD_LIBRARY_PATH}
|
|
||||||
LD_LIBRARY_PATH=""
|
|
||||||
fi
|
|
||||||
local missing=""
|
|
||||||
for pkg in $1; do
|
|
||||||
if ! dnf list installed "$pkg" >/dev/null 2>/dev/null; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$missing" != "" ]; then
|
|
||||||
echo "MISSING PACKAGES: $missing"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -v OLD_LD_LIBRARY_PATH ]; then
|
|
||||||
echo "Restoring LD_LIBRARY_PATH..."
|
|
||||||
LD_LIBRARY_PATH=${OLD_LD_LIBRARY_PATH}
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install() {
|
|
||||||
cd "$DIR"
|
|
||||||
if [ "$EUID" -ne 0 ]; then
|
|
||||||
echo "Please run as root."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
|
||||||
# Python related tests don't work without the LANG export.
|
|
||||||
if [ -d "/home/gh/actions-runner" ]; then
|
|
||||||
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
|
|
||||||
else
|
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
|
||||||
fi
|
|
||||||
dnf update -y
|
|
||||||
for pkg in $1; do
|
|
||||||
dnf install -y "$pkg"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
deps=$2"[*]"
|
|
||||||
"$1" "${!deps}"
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -Eeuo pipefail
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|
||||||
source "$DIR/../util.sh"
|
|
||||||
|
|
||||||
# TODO(gitbuda): Rocky gets automatically updates -> figure out how to handle it.
|
|
||||||
check_operating_system "rocky-9.3"
|
|
||||||
check_architecture "x86_64"
|
|
||||||
|
|
||||||
TOOLCHAIN_BUILD_DEPS=(
|
|
||||||
wget # used for archive download
|
|
||||||
coreutils-common gcc gcc-c++ make # generic build tools
|
|
||||||
# NOTE: Pure libcurl conflicts with libcurl-minimal
|
|
||||||
libcurl-devel # cmake build requires it
|
|
||||||
gnupg2 # used for archive signature verification
|
|
||||||
tar gzip bzip2 xz unzip # used for archive unpacking
|
|
||||||
zlib-devel # zlib library used for all builds
|
|
||||||
expat-devel xz-devel python3-devel perl-Unicode-EastAsianWidth texinfo libbabeltrace-devel # for gdb
|
|
||||||
readline-devel # for cmake and llvm
|
|
||||||
libffi-devel libxml2-devel # for llvm
|
|
||||||
libedit-devel pcre-devel pcre2-devel automake bison # for swig
|
|
||||||
file
|
|
||||||
openssl-devel
|
|
||||||
gmp-devel
|
|
||||||
gperf
|
|
||||||
diffutils
|
|
||||||
libipt libipt-devel # intel
|
|
||||||
patch
|
|
||||||
)
|
|
||||||
|
|
||||||
TOOLCHAIN_RUN_DEPS=(
|
|
||||||
make # generic build tools
|
|
||||||
tar gzip bzip2 xz # used for archive unpacking
|
|
||||||
zlib # zlib library used for all builds
|
|
||||||
expat xz-libs python3 # for gdb
|
|
||||||
readline # for cmake and llvm
|
|
||||||
libffi libxml2 # for llvm
|
|
||||||
openssl-devel
|
|
||||||
perl # for openssl
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_BUILD_DEPS=(
|
|
||||||
git # source code control
|
|
||||||
make cmake pkgconf-pkg-config # build system
|
|
||||||
wget # for downloading libs
|
|
||||||
libuuid-devel java-11-openjdk # required by antlr
|
|
||||||
readline-devel # for memgraph console
|
|
||||||
python3-devel # for query modules
|
|
||||||
openssl-devel
|
|
||||||
libseccomp-devel
|
|
||||||
python3 python3-pip python3-virtualenv nmap-ncat # for qa, macro_benchmark and stress tests
|
|
||||||
#
|
|
||||||
# IMPORTANT: python3-yaml does NOT exist on CentOS
|
|
||||||
# Install it manually using `pip3 install PyYAML`
|
|
||||||
#
|
|
||||||
PyYAML # Package name here does not correspond to the yum package!
|
|
||||||
libcurl-devel # mg-requests
|
|
||||||
rpm-build rpmlint # for RPM package building
|
|
||||||
doxygen graphviz # source documentation generators
|
|
||||||
which nodejs golang custom-golang1.18.9 # for driver tests
|
|
||||||
zip unzip java-11-openjdk-devel java-17-openjdk java-17-openjdk-devel custom-maven3.9.3 # for driver tests
|
|
||||||
sbcl # for custom Lisp C++ preprocessing
|
|
||||||
autoconf # for jemalloc code generation
|
|
||||||
libtool # for protobuf code generation
|
|
||||||
cyrus-sasl-devel
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
|
||||||
logrotate openssl python3 libseccomp
|
|
||||||
)
|
|
||||||
|
|
||||||
NEW_DEPS=(
|
|
||||||
wget curl tar gzip
|
|
||||||
)
|
|
||||||
|
|
||||||
list() {
|
|
||||||
echo "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
check() {
|
|
||||||
local missing=""
|
|
||||||
for pkg in $1; do
|
|
||||||
if [ "$pkg" == custom-maven3.9.3 ]; then
|
|
||||||
if [ ! -f "/opt/apache-maven-3.9.3/bin/mvn" ]; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == custom-golang1.18.9 ]; then
|
|
||||||
if [ ! -f "/opt/go1.18.9/go/bin/go" ]; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == "PyYAML" ]; then
|
|
||||||
if ! python3 -c "import yaml" >/dev/null 2>/dev/null; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == "python3-virtualenv" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if ! yum list installed "$pkg" >/dev/null 2>/dev/null; then
|
|
||||||
missing="$pkg $missing"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$missing" != "" ]; then
|
|
||||||
echo "MISSING PACKAGES: $missing"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install() {
|
|
||||||
cd "$DIR"
|
|
||||||
if [ "$EUID" -ne 0 ]; then
|
|
||||||
echo "Please run as root."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
|
||||||
# Python related tests doesn't work the LANG export.
|
|
||||||
if [ -d "/home/gh/actions-runner" ]; then
|
|
||||||
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
|
|
||||||
else
|
|
||||||
echo "NOTE: export LANG=en_US.utf8"
|
|
||||||
fi
|
|
||||||
yum update -y
|
|
||||||
yum install -y wget git python3 python3-pip
|
|
||||||
|
|
||||||
for pkg in $1; do
|
|
||||||
if [ "$pkg" == custom-maven3.9.3 ]; then
|
|
||||||
install_custom_maven "3.9.3"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == custom-golang1.18.9 ]; then
|
|
||||||
install_custom_golang "1.18.9"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == perl-Unicode-EastAsianWidth ]; then
|
|
||||||
if ! dnf list installed perl-Unicode-EastAsianWidth >/dev/null 2>/dev/null; then
|
|
||||||
dnf install -y https://dl.rockylinux.org/pub/rocky/9/CRB/x86_64/os/Packages/p/perl-Unicode-EastAsianWidth-12.0-7.el9.noarch.rpm
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == texinfo ]; then
|
|
||||||
if ! dnf list installed texinfo >/dev/null 2>/dev/null; then
|
|
||||||
dnf install -y https://dl.rockylinux.org/pub/rocky/9/CRB/x86_64/os/Packages/t/texinfo-6.7-15.el9.x86_64.rpm
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == libbabeltrace-devel ]; then
|
|
||||||
if ! dnf list installed libbabeltrace-devel >/dev/null 2>/dev/null; then
|
|
||||||
dnf install -y https://dl.rockylinux.org/pub/rocky/9/devel/x86_64/os/Packages/l/libbabeltrace-devel-1.5.8-10.el9.x86_64.rpm
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == libipt-devel ]; then
|
|
||||||
if ! dnf list installed libipt-devel >/dev/null 2>/dev/null; then
|
|
||||||
dnf install -y https://dl.rockylinux.org/pub/rocky/9/devel/x86_64/os/Packages/l/libipt-devel-2.0.4-5.el9.x86_64.rpm
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == PyYAML ]; then
|
|
||||||
if [ -z ${SUDO_USER+x} ]; then # Running as root (e.g. Docker).
|
|
||||||
pip3 install --user PyYAML
|
|
||||||
else # Running using sudo.
|
|
||||||
sudo -H -u "$SUDO_USER" bash -c "pip3 install --user PyYAML"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$pkg" == python3-virtualenv ]; then
|
|
||||||
if [ -z ${SUDO_USER+x} ]; then # Running as root (e.g. Docker).
|
|
||||||
pip3 install virtualenv
|
|
||||||
pip3 install virtualenvwrapper
|
|
||||||
else # Running using sudo.
|
|
||||||
sudo -H -u "$SUDO_USER" bash -c "pip3 install virtualenv"
|
|
||||||
sudo -H -u "$SUDO_USER" bash -c "pip3 install virtualenvwrapper"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
yum install -y "$pkg"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
deps=$2"[*]"
|
|
||||||
"$1" "${!deps}"
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -18,10 +20,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
pkg
|
pkg
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS=(
|
|
||||||
pkg
|
|
||||||
)
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
MEMGRAPH_RUN_DEPS=(
|
||||||
pkg
|
pkg
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
# IMPORTANT: Deprecated since memgraph v2.12.0.
|
|
||||||
|
|
||||||
check_operating_system "ubuntu-18.04"
|
check_operating_system "ubuntu-18.04"
|
||||||
check_architecture "x86_64"
|
check_architecture "x86_64"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -58,8 +60,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libsasl2-dev
|
libsasl2-dev
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
MEMGRAPH_RUN_DEPS=(
|
||||||
logrotate openssl python3 libseccomp2
|
logrotate openssl python3 libseccomp2
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -58,8 +60,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libsasl2-dev
|
libsasl2-dev
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
MEMGRAPH_RUN_DEPS=(
|
||||||
logrotate openssl python3 libseccomp2
|
logrotate openssl python3 libseccomp2
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
source "$DIR/../util.sh"
|
source "$DIR/../util.sh"
|
||||||
|
|
||||||
@@ -58,8 +60,6 @@ MEMGRAPH_BUILD_DEPS=(
|
|||||||
libsasl2-dev
|
libsasl2-dev
|
||||||
)
|
)
|
||||||
|
|
||||||
MEMGRAPH_TEST_DEPS="${MEMGRAPH_BUILD_DEPS[*]}"
|
|
||||||
|
|
||||||
MEMGRAPH_RUN_DEPS=(
|
MEMGRAPH_RUN_DEPS=(
|
||||||
logrotate openssl python3 libseccomp2
|
logrotate openssl python3 libseccomp2
|
||||||
)
|
)
|
||||||
|
|||||||
1
environment/toolchain/.gitignore
vendored
1
environment/toolchain/.gitignore
vendored
@@ -2,4 +2,3 @@ archives
|
|||||||
build
|
build
|
||||||
output
|
output
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
tmp_build.sh
|
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
#!/bin/bash -e
|
|
||||||
|
|
||||||
# NOTE: Copy this under memgraph/environment/toolchain/vN/tmp_build.sh, edit and test.
|
|
||||||
|
|
||||||
pushd () { command pushd "$@" > /dev/null; }
|
|
||||||
popd () { command popd "$@" > /dev/null; }
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|
||||||
CPUS=$( grep -c processor < /proc/cpuinfo )
|
|
||||||
cd "$DIR"
|
|
||||||
source "$DIR/../../util.sh"
|
|
||||||
DISTRO="$(operating_system)"
|
|
||||||
TOOLCHAIN_VERSION=5
|
|
||||||
NAME=toolchain-v$TOOLCHAIN_VERSION
|
|
||||||
PREFIX=/opt/$NAME
|
|
||||||
function log_tool_name () {
|
|
||||||
echo ""
|
|
||||||
echo ""
|
|
||||||
echo "#### $1 ####"
|
|
||||||
echo ""
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# HERE: Remove/clear dependencies from a given toolchain.
|
|
||||||
|
|
||||||
mkdir -p archives && pushd archives
|
|
||||||
# HERE: Download dependencies here.
|
|
||||||
popd
|
|
||||||
|
|
||||||
mkdir -p build
|
|
||||||
pushd build
|
|
||||||
source $PREFIX/activate
|
|
||||||
export CC=$PREFIX/bin/clang
|
|
||||||
export CXX=$PREFIX/bin/clang++
|
|
||||||
export CFLAGS="$CFLAGS -fPIC"
|
|
||||||
export PATH=$PREFIX/bin:$PATH
|
|
||||||
export LD_LIBRARY_PATH=$PREFIX/lib64
|
|
||||||
COMMON_CMAKE_FLAGS="-DCMAKE_INSTALL_PREFIX=$PREFIX
|
|
||||||
-DCMAKE_PREFIX_PATH=$PREFIX
|
|
||||||
-DCMAKE_BUILD_TYPE=Release
|
|
||||||
-DCMAKE_C_COMPILER=$CC
|
|
||||||
-DCMAKE_CXX_COMPILER=$CXX
|
|
||||||
-DBUILD_SHARED_LIBS=OFF
|
|
||||||
-DCMAKE_CXX_STANDARD=20
|
|
||||||
-DBUILD_TESTING=OFF
|
|
||||||
-DCMAKE_REQUIRED_INCLUDES=$PREFIX/include
|
|
||||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON"
|
|
||||||
|
|
||||||
# HERE: Add dependencies to test below.
|
|
||||||
@@ -307,7 +307,7 @@ if [ ! -f $PREFIX/bin/ld.gold ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
log_tool_name "GDB $GDB_VERSION"
|
log_tool_name "GDB $GDB_VERSION"
|
||||||
if [[ ! -f "$PREFIX/bin/gdb" && "$DISTRO" -ne "amzn-2" ]]; then
|
if [ ! -f $PREFIX/bin/gdb ]; then
|
||||||
if [ -d gdb-$GDB_VERSION ]; then
|
if [ -d gdb-$GDB_VERSION ]; then
|
||||||
rm -rf gdb-$GDB_VERSION
|
rm -rf gdb-$GDB_VERSION
|
||||||
fi
|
fi
|
||||||
@@ -671,6 +671,7 @@ PROXYGEN_SHA256=5360a8ccdfb2f5a6c7b3eed331ec7ab0e2c792d579c6fff499c85c516c11fe14
|
|||||||
WANGLE_SHA256=1002e9c32b6f4837f6a760016e3b3e22f3509880ef3eaad191c80dc92655f23f
|
WANGLE_SHA256=1002e9c32b6f4837f6a760016e3b3e22f3509880ef3eaad191c80dc92655f23f
|
||||||
# WANGLE_SHA256=0e493c03572bb27fe9ca03a9da5023e52fde99c95abdcaa919bb6190e7e69532
|
# WANGLE_SHA256=0e493c03572bb27fe9ca03a9da5023e52fde99c95abdcaa919bb6190e7e69532
|
||||||
|
|
||||||
|
FLEX_VERSION=2.6.4
|
||||||
FMT_SHA256=78b8c0a72b1c35e4443a7e308df52498252d1cefc2b08c9a97bc9ee6cfe61f8b
|
FMT_SHA256=78b8c0a72b1c35e4443a7e308df52498252d1cefc2b08c9a97bc9ee6cfe61f8b
|
||||||
FMT_VERSION=10.1.1
|
FMT_VERSION=10.1.1
|
||||||
# NOTE: spdlog depends on exact fmt versions -> UPGRADE fmt and spdlog TOGETHER.
|
# NOTE: spdlog depends on exact fmt versions -> UPGRADE fmt and spdlog TOGETHER.
|
||||||
@@ -689,8 +690,8 @@ LZ4_VERSION=1.9.4
|
|||||||
SNAPPY_SHA256=75c1fbb3d618dd3a0483bff0e26d0a92b495bbe5059c8b4f1c962b478b6e06e7
|
SNAPPY_SHA256=75c1fbb3d618dd3a0483bff0e26d0a92b495bbe5059c8b4f1c962b478b6e06e7
|
||||||
SNAPPY_VERSION=1.1.9
|
SNAPPY_VERSION=1.1.9
|
||||||
XZ_VERSION=5.2.5 # for LZMA
|
XZ_VERSION=5.2.5 # for LZMA
|
||||||
ZLIB_VERSION=1.3.1
|
ZLIB_VERSION=1.3
|
||||||
ZSTD_VERSION=1.5.5
|
ZSTD_VERSION=1.5.0
|
||||||
|
|
||||||
pushd archives
|
pushd archives
|
||||||
if [ ! -f boost_$BOOST_VERSION_UNDERSCORES.tar.gz ]; then
|
if [ ! -f boost_$BOOST_VERSION_UNDERSCORES.tar.gz ]; then
|
||||||
@@ -699,7 +700,7 @@ if [ ! -f boost_$BOOST_VERSION_UNDERSCORES.tar.gz ]; then
|
|||||||
wget https://boostorg.jfrog.io/artifactory/main/release/$BOOST_VERSION/source/boost_$BOOST_VERSION_UNDERSCORES.tar.gz -O boost_$BOOST_VERSION_UNDERSCORES.tar.gz
|
wget https://boostorg.jfrog.io/artifactory/main/release/$BOOST_VERSION/source/boost_$BOOST_VERSION_UNDERSCORES.tar.gz -O boost_$BOOST_VERSION_UNDERSCORES.tar.gz
|
||||||
fi
|
fi
|
||||||
if [ ! -f bzip2-$BZIP2_VERSION.tar.gz ]; then
|
if [ ! -f bzip2-$BZIP2_VERSION.tar.gz ]; then
|
||||||
wget https://sourceware.org/pub/bzip2/bzip2-$BZIP2_VERSION.tar.gz -O bzip2-$BZIP2_VERSION.tar.gz
|
wget https://sourceforge.net/projects/bzip2/files/bzip2-$BZIP2_VERSION.tar.gz -O bzip2-$BZIP2_VERSION.tar.gz
|
||||||
fi
|
fi
|
||||||
if [ ! -f double-conversion-$DOUBLE_CONVERSION_VERSION.tar.gz ]; then
|
if [ ! -f double-conversion-$DOUBLE_CONVERSION_VERSION.tar.gz ]; then
|
||||||
wget https://github.com/google/double-conversion/archive/refs/tags/v$DOUBLE_CONVERSION_VERSION.tar.gz -O double-conversion-$DOUBLE_CONVERSION_VERSION.tar.gz
|
wget https://github.com/google/double-conversion/archive/refs/tags/v$DOUBLE_CONVERSION_VERSION.tar.gz -O double-conversion-$DOUBLE_CONVERSION_VERSION.tar.gz
|
||||||
@@ -707,7 +708,9 @@ fi
|
|||||||
if [ ! -f fizz-$FBLIBS_VERSION.tar.gz ]; then
|
if [ ! -f fizz-$FBLIBS_VERSION.tar.gz ]; then
|
||||||
wget https://github.com/facebookincubator/fizz/releases/download/v$FBLIBS_VERSION/fizz-v$FBLIBS_VERSION.tar.gz -O fizz-$FBLIBS_VERSION.tar.gz
|
wget https://github.com/facebookincubator/fizz/releases/download/v$FBLIBS_VERSION/fizz-v$FBLIBS_VERSION.tar.gz -O fizz-$FBLIBS_VERSION.tar.gz
|
||||||
fi
|
fi
|
||||||
|
if [ ! -f flex-$FLEX_VERSION.tar.gz ]; then
|
||||||
|
wget https://github.com/westes/flex/releases/download/v$FLEX_VERSION/flex-$FLEX_VERSION.tar.gz -O flex-$FLEX_VERSION.tar.gz
|
||||||
|
fi
|
||||||
if [ ! -f fmt-$FMT_VERSION.tar.gz ]; then
|
if [ ! -f fmt-$FMT_VERSION.tar.gz ]; then
|
||||||
wget https://github.com/fmtlib/fmt/archive/refs/tags/$FMT_VERSION.tar.gz -O fmt-$FMT_VERSION.tar.gz
|
wget https://github.com/fmtlib/fmt/archive/refs/tags/$FMT_VERSION.tar.gz -O fmt-$FMT_VERSION.tar.gz
|
||||||
fi
|
fi
|
||||||
@@ -762,6 +765,14 @@ echo "$BZIP2_SHA256 bzip2-$BZIP2_VERSION.tar.gz" | sha256sum -c
|
|||||||
echo "$DOUBLE_CONVERSION_SHA256 double-conversion-$DOUBLE_CONVERSION_VERSION.tar.gz" | sha256sum -c
|
echo "$DOUBLE_CONVERSION_SHA256 double-conversion-$DOUBLE_CONVERSION_VERSION.tar.gz" | sha256sum -c
|
||||||
# verify fizz
|
# verify fizz
|
||||||
echo "$FIZZ_SHA256 fizz-$FBLIBS_VERSION.tar.gz" | sha256sum -c
|
echo "$FIZZ_SHA256 fizz-$FBLIBS_VERSION.tar.gz" | sha256sum -c
|
||||||
|
# verify flex
|
||||||
|
if [ ! -f flex-$FLEX_VERSION.tar.gz.sig ]; then
|
||||||
|
wget https://github.com/westes/flex/releases/download/v$FLEX_VERSION/flex-$FLEX_VERSION.tar.gz.sig
|
||||||
|
fi
|
||||||
|
if false; then
|
||||||
|
$GPG --keyserver $KEYSERVER --recv-keys 0xE4B29C8D64885307
|
||||||
|
$GPG --verify flex-$FLEX_VERSION.tar.gz.sig flex-$FLEX_VERSION.tar.gz
|
||||||
|
fi
|
||||||
# verify fmt
|
# verify fmt
|
||||||
echo "$FMT_SHA256 fmt-$FMT_VERSION.tar.gz" | sha256sum -c
|
echo "$FMT_SHA256 fmt-$FMT_VERSION.tar.gz" | sha256sum -c
|
||||||
# verify spdlog
|
# verify spdlog
|
||||||
@@ -1014,6 +1025,7 @@ if [ ! -d $PREFIX/include/gflags ]; then
|
|||||||
if [ -d gflags ]; then
|
if [ -d gflags ]; then
|
||||||
rm -rf gflags
|
rm -rf gflags
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git clone https://github.com/memgraph/gflags.git gflags
|
git clone https://github.com/memgraph/gflags.git gflags
|
||||||
pushd gflags
|
pushd gflags
|
||||||
git checkout $GFLAGS_COMMIT_HASH
|
git checkout $GFLAGS_COMMIT_HASH
|
||||||
@@ -1022,7 +1034,7 @@ if [ ! -d $PREFIX/include/gflags ]; then
|
|||||||
cmake .. $COMMON_CMAKE_FLAGS \
|
cmake .. $COMMON_CMAKE_FLAGS \
|
||||||
-DREGISTER_INSTALL_PREFIX=OFF \
|
-DREGISTER_INSTALL_PREFIX=OFF \
|
||||||
-DBUILD_gflags_nothreads_LIB=OFF \
|
-DBUILD_gflags_nothreads_LIB=OFF \
|
||||||
-DGFLAGS_NO_FILENAMES=1
|
-DGFLAGS_NO_FILENAMES=0
|
||||||
make -j$CPUS install
|
make -j$CPUS install
|
||||||
popd && popd
|
popd && popd
|
||||||
fi
|
fi
|
||||||
@@ -1220,6 +1232,18 @@ if false; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log_tool_name "flex $FLEX_VERSION"
|
||||||
|
if [ ! -f $PREFIX/include/FlexLexer.h ]; then
|
||||||
|
if [ -d flex-$FLEX_VERSION ]; then
|
||||||
|
rm -rf flex-$FLEX_VERSION
|
||||||
|
fi
|
||||||
|
tar -xzf ../archives/flex-$FLEX_VERSION.tar.gz
|
||||||
|
pushd flex-$FLEX_VERSION
|
||||||
|
./configure $COMMON_CONFIGURE_FLAGS
|
||||||
|
make -j$CPUS install
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
popd
|
popd
|
||||||
# NOTE: It's important/clean (e.g., easier upload to S3) to have a separated
|
# NOTE: It's important/clean (e.g., easier upload to S3) to have a separated
|
||||||
# folder to the output archive.
|
# folder to the output archive.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -234,6 +234,8 @@ inline mgp_type *type_duration() { return MgInvoke<mgp_type *>(mgp_type_duration
|
|||||||
|
|
||||||
inline mgp_type *type_nullable(mgp_type *type) { return MgInvoke<mgp_type *>(mgp_type_nullable, type); }
|
inline mgp_type *type_nullable(mgp_type *type) { return MgInvoke<mgp_type *>(mgp_type_nullable, type); }
|
||||||
|
|
||||||
|
// mgp_graph
|
||||||
|
|
||||||
inline bool create_label_index(mgp_graph *graph, const char *label) {
|
inline bool create_label_index(mgp_graph *graph, const char *label) {
|
||||||
return MgInvoke<int>(mgp_create_label_index, graph, label);
|
return MgInvoke<int>(mgp_create_label_index, graph, label);
|
||||||
}
|
}
|
||||||
@@ -282,10 +284,6 @@ inline mgp_list *list_all_unique_constraints(mgp_graph *graph, mgp_memory *memor
|
|||||||
return MgInvoke<mgp_list *>(mgp_list_all_unique_constraints, graph, memory);
|
return MgInvoke<mgp_list *>(mgp_list_all_unique_constraints, graph, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mgp_graph
|
|
||||||
|
|
||||||
inline bool graph_is_transactional(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_transactional, graph); }
|
|
||||||
|
|
||||||
inline bool graph_is_mutable(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_mutable, graph); }
|
inline bool graph_is_mutable(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_mutable, graph); }
|
||||||
|
|
||||||
inline mgp_vertex *graph_create_vertex(mgp_graph *graph, mgp_memory *memory) {
|
inline mgp_vertex *graph_create_vertex(mgp_graph *graph, mgp_memory *memory) {
|
||||||
@@ -378,8 +376,6 @@ inline mgp_list *list_copy(mgp_list *list, mgp_memory *memory) {
|
|||||||
|
|
||||||
inline void list_destroy(mgp_list *list) { mgp_list_destroy(list); }
|
inline void list_destroy(mgp_list *list) { mgp_list_destroy(list); }
|
||||||
|
|
||||||
inline bool list_contains_deleted(mgp_list *list) { return MgInvoke<int>(mgp_list_contains_deleted, list); }
|
|
||||||
|
|
||||||
inline void list_append(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append, list, val); }
|
inline void list_append(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append, list, val); }
|
||||||
|
|
||||||
inline void list_append_extend(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append_extend, list, val); }
|
inline void list_append_extend(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append_extend, list, val); }
|
||||||
@@ -398,8 +394,6 @@ inline mgp_map *map_copy(mgp_map *map, mgp_memory *memory) { return MgInvoke<mgp
|
|||||||
|
|
||||||
inline void map_destroy(mgp_map *map) { mgp_map_destroy(map); }
|
inline void map_destroy(mgp_map *map) { mgp_map_destroy(map); }
|
||||||
|
|
||||||
inline bool map_contains_deleted(mgp_map *map) { return MgInvoke<int>(mgp_map_contains_deleted, map); }
|
|
||||||
|
|
||||||
inline void map_insert(mgp_map *map, const char *key, mgp_value *value) {
|
inline void map_insert(mgp_map *map, const char *key, mgp_value *value) {
|
||||||
MgInvokeVoid(mgp_map_insert, map, key, value);
|
MgInvokeVoid(mgp_map_insert, map, key, value);
|
||||||
}
|
}
|
||||||
@@ -448,8 +442,6 @@ inline mgp_vertex *vertex_copy(mgp_vertex *v, mgp_memory *memory) {
|
|||||||
|
|
||||||
inline void vertex_destroy(mgp_vertex *v) { mgp_vertex_destroy(v); }
|
inline void vertex_destroy(mgp_vertex *v) { mgp_vertex_destroy(v); }
|
||||||
|
|
||||||
inline bool vertex_is_deleted(mgp_vertex *v) { return MgInvoke<int>(mgp_vertex_is_deleted, v); }
|
|
||||||
|
|
||||||
inline bool vertex_equal(mgp_vertex *v1, mgp_vertex *v2) { return MgInvoke<int>(mgp_vertex_equal, v1, v2); }
|
inline bool vertex_equal(mgp_vertex *v1, mgp_vertex *v2) { return MgInvoke<int>(mgp_vertex_equal, v1, v2); }
|
||||||
|
|
||||||
inline size_t vertex_labels_count(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_labels_count, v); }
|
inline size_t vertex_labels_count(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_labels_count, v); }
|
||||||
@@ -502,8 +494,6 @@ inline mgp_edge *edge_copy(mgp_edge *e, mgp_memory *memory) { return MgInvoke<mg
|
|||||||
|
|
||||||
inline void edge_destroy(mgp_edge *e) { mgp_edge_destroy(e); }
|
inline void edge_destroy(mgp_edge *e) { mgp_edge_destroy(e); }
|
||||||
|
|
||||||
inline bool edge_is_deleted(mgp_edge *e) { return MgInvoke<int>(mgp_edge_is_deleted, e); }
|
|
||||||
|
|
||||||
inline bool edge_equal(mgp_edge *e1, mgp_edge *e2) { return MgInvoke<int>(mgp_edge_equal, e1, e2); }
|
inline bool edge_equal(mgp_edge *e1, mgp_edge *e2) { return MgInvoke<int>(mgp_edge_equal, e1, e2); }
|
||||||
|
|
||||||
inline mgp_edge_type edge_get_type(mgp_edge *e) { return MgInvoke<mgp_edge_type>(mgp_edge_get_type, e); }
|
inline mgp_edge_type edge_get_type(mgp_edge *e) { return MgInvoke<mgp_edge_type>(mgp_edge_get_type, e); }
|
||||||
@@ -540,8 +530,6 @@ inline mgp_path *path_copy(mgp_path *path, mgp_memory *memory) {
|
|||||||
|
|
||||||
inline void path_destroy(mgp_path *path) { mgp_path_destroy(path); }
|
inline void path_destroy(mgp_path *path) { mgp_path_destroy(path); }
|
||||||
|
|
||||||
inline bool path_contains_deleted(mgp_path *path) { return MgInvoke<int>(mgp_path_contains_deleted, path); }
|
|
||||||
|
|
||||||
inline void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
|
inline void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
|
||||||
|
|
||||||
inline void path_pop(mgp_path *path) { MgInvokeVoid(mgp_path_pop, path); }
|
inline void path_pop(mgp_path *path) { MgInvokeVoid(mgp_path_pop, path); }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -25,7 +25,7 @@ namespace mg_exception {
|
|||||||
template <typename FirstArg, typename... Args>
|
template <typename FirstArg, typename... Args>
|
||||||
std::string StringSerialize(FirstArg &&firstArg, Args &&...args) {
|
std::string StringSerialize(FirstArg &&firstArg, Args &&...args) {
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << std::forward<FirstArg>(firstArg);
|
stream << firstArg;
|
||||||
((stream << " " << args), ...);
|
((stream << " " << args), ...);
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -429,9 +429,6 @@ enum mgp_error mgp_list_copy(struct mgp_list *list, struct mgp_memory *memory, s
|
|||||||
/// Free the memory used by the given mgp_list and contained elements.
|
/// Free the memory used by the given mgp_list and contained elements.
|
||||||
void mgp_list_destroy(struct mgp_list *list);
|
void mgp_list_destroy(struct mgp_list *list);
|
||||||
|
|
||||||
/// Return whether the given mgp_list contains any deleted values.
|
|
||||||
enum mgp_error mgp_list_contains_deleted(struct mgp_list *list, int *result);
|
|
||||||
|
|
||||||
/// Append a copy of mgp_value to mgp_list if capacity allows.
|
/// Append a copy of mgp_value to mgp_list if capacity allows.
|
||||||
/// The list copies the given value and therefore does not take ownership of the
|
/// The list copies the given value and therefore does not take ownership of the
|
||||||
/// original value. You still need to call mgp_value_destroy to free the
|
/// original value. You still need to call mgp_value_destroy to free the
|
||||||
@@ -472,9 +469,6 @@ enum mgp_error mgp_map_copy(struct mgp_map *map, struct mgp_memory *memory, stru
|
|||||||
/// Free the memory used by the given mgp_map and contained items.
|
/// Free the memory used by the given mgp_map and contained items.
|
||||||
void mgp_map_destroy(struct mgp_map *map);
|
void mgp_map_destroy(struct mgp_map *map);
|
||||||
|
|
||||||
/// Return whether the given mgp_map contains any deleted values.
|
|
||||||
enum mgp_error mgp_map_contains_deleted(struct mgp_map *map, int *result);
|
|
||||||
|
|
||||||
/// Insert a new mapping from a NULL terminated character string to a value.
|
/// Insert a new mapping from a NULL terminated character string to a value.
|
||||||
/// If a mapping with the same key already exists, it is *not* replaced.
|
/// If a mapping with the same key already exists, it is *not* replaced.
|
||||||
/// In case of insertion, both the string and the value are copied into the map.
|
/// In case of insertion, both the string and the value are copied into the map.
|
||||||
@@ -558,9 +552,6 @@ enum mgp_error mgp_path_copy(struct mgp_path *path, struct mgp_memory *memory, s
|
|||||||
/// Free the memory used by the given mgp_path and contained vertices and edges.
|
/// Free the memory used by the given mgp_path and contained vertices and edges.
|
||||||
void mgp_path_destroy(struct mgp_path *path);
|
void mgp_path_destroy(struct mgp_path *path);
|
||||||
|
|
||||||
/// Return whether the given mgp_path contains any deleted values.
|
|
||||||
enum mgp_error mgp_path_contains_deleted(struct mgp_path *path, int *result);
|
|
||||||
|
|
||||||
/// Append an edge continuing from the last vertex on the path.
|
/// Append an edge continuing from the last vertex on the path.
|
||||||
/// The edge is copied into the path. Therefore, the path does not take
|
/// The edge is copied into the path. Therefore, the path does not take
|
||||||
/// ownership of the original edge, so you still need to free the edge memory
|
/// ownership of the original edge, so you still need to free the edge memory
|
||||||
@@ -734,9 +725,6 @@ enum mgp_error mgp_vertex_copy(struct mgp_vertex *v, struct mgp_memory *memory,
|
|||||||
/// Free the memory used by a mgp_vertex.
|
/// Free the memory used by a mgp_vertex.
|
||||||
void mgp_vertex_destroy(struct mgp_vertex *v);
|
void mgp_vertex_destroy(struct mgp_vertex *v);
|
||||||
|
|
||||||
/// Return whether the given mgp_vertex is deleted.
|
|
||||||
enum mgp_error mgp_vertex_is_deleted(struct mgp_vertex *v, int *result);
|
|
||||||
|
|
||||||
/// Result is non-zero if given vertices are equal, otherwise 0.
|
/// Result is non-zero if given vertices are equal, otherwise 0.
|
||||||
enum mgp_error mgp_vertex_equal(struct mgp_vertex *v1, struct mgp_vertex *v2, int *result);
|
enum mgp_error mgp_vertex_equal(struct mgp_vertex *v1, struct mgp_vertex *v2, int *result);
|
||||||
|
|
||||||
@@ -831,9 +819,6 @@ enum mgp_error mgp_edge_copy(struct mgp_edge *e, struct mgp_memory *memory, stru
|
|||||||
/// Free the memory used by a mgp_edge.
|
/// Free the memory used by a mgp_edge.
|
||||||
void mgp_edge_destroy(struct mgp_edge *e);
|
void mgp_edge_destroy(struct mgp_edge *e);
|
||||||
|
|
||||||
/// Return whether the given mgp_edge is deleted.
|
|
||||||
enum mgp_error mgp_edge_is_deleted(struct mgp_edge *e, int *result);
|
|
||||||
|
|
||||||
/// Result is non-zero if given edges are equal, otherwise 0.
|
/// Result is non-zero if given edges are equal, otherwise 0.
|
||||||
enum mgp_error mgp_edge_equal(struct mgp_edge *e1, struct mgp_edge *e2, int *result);
|
enum mgp_error mgp_edge_equal(struct mgp_edge *e1, struct mgp_edge *e2, int *result);
|
||||||
|
|
||||||
@@ -956,12 +941,6 @@ enum mgp_error mgp_list_all_unique_constraints(struct mgp_graph *graph, struct m
|
|||||||
/// Current implementation always returns without errors.
|
/// Current implementation always returns without errors.
|
||||||
enum mgp_error mgp_graph_is_mutable(struct mgp_graph *graph, int *result);
|
enum mgp_error mgp_graph_is_mutable(struct mgp_graph *graph, int *result);
|
||||||
|
|
||||||
/// Result is non-zero if the graph is in transactional storage mode.
|
|
||||||
/// If a graph is not in transactional mode (i.e. analytical mode), then vertices and edges can be missing
|
|
||||||
/// because changes from other transactions are visible.
|
|
||||||
/// Current implementation always returns without errors.
|
|
||||||
enum mgp_error mgp_graph_is_transactional(struct mgp_graph *graph, int *result);
|
|
||||||
|
|
||||||
/// Add a new vertex to the graph.
|
/// Add a new vertex to the graph.
|
||||||
/// Resulting vertex must be freed using mgp_vertex_destroy.
|
/// Resulting vertex must be freed using mgp_vertex_destroy.
|
||||||
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
/// Return mgp_error::MGP_ERROR_IMMUTABLE_OBJECT if `graph` is immutable.
|
||||||
|
|||||||
321
include/mgp.hpp
321
include/mgp.hpp
File diff suppressed because it is too large
Load Diff
1
libs/.gitignore
vendored
1
libs/.gitignore
vendored
@@ -7,4 +7,3 @@
|
|||||||
!pulsar.patch
|
!pulsar.patch
|
||||||
!antlr4.10.1.patch
|
!antlr4.10.1.patch
|
||||||
!rocksdb8.1.1.patch
|
!rocksdb8.1.1.patch
|
||||||
!nuraft2.1.0.patch
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ set(GFLAGS_NOTHREADS OFF)
|
|||||||
|
|
||||||
# NOTE: config/generate.py depends on the gflags help XML format.
|
# NOTE: config/generate.py depends on the gflags help XML format.
|
||||||
find_package(gflags REQUIRED)
|
find_package(gflags REQUIRED)
|
||||||
find_package(fmt 8.0.1 REQUIRED)
|
find_package(fmt 8.0.1)
|
||||||
find_package(ZLIB 1.2.11 REQUIRED)
|
find_package(ZLIB 1.2.11 REQUIRED)
|
||||||
|
|
||||||
set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
@@ -294,10 +294,3 @@ set_path_external_library(jemalloc STATIC
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/jemalloc/include/)
|
${CMAKE_CURRENT_SOURCE_DIR}/jemalloc/include/)
|
||||||
|
|
||||||
import_header_library(rangev3 ${CMAKE_CURRENT_SOURCE_DIR}/rangev3/include)
|
import_header_library(rangev3 ${CMAKE_CURRENT_SOURCE_DIR}/rangev3/include)
|
||||||
|
|
||||||
# Setup NuRaft
|
|
||||||
import_external_library(nuraft STATIC
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/nuraft/lib/libnuraft.a
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/nuraft/include/)
|
|
||||||
find_package(OpenSSL REQUIRED)
|
|
||||||
target_link_libraries(nuraft INTERFACE ${OPENSSL_LIBRARIES})
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ index ee9b58c..31359a9 100644
|
|||||||
@@ -48,7 +48,7 @@ option(LIBRDTSC_USE_PMU "Enables PMU usage on ARM platforms" OFF)
|
@@ -48,7 +48,7 @@ option(LIBRDTSC_USE_PMU "Enables PMU usage on ARM platforms" OFF)
|
||||||
# | Library Build and Install Properties |
|
# | Library Build and Install Properties |
|
||||||
# +--------------------------------------------------------+
|
# +--------------------------------------------------------+
|
||||||
|
|
||||||
-add_library(rdtsc SHARED
|
-add_library(rdtsc SHARED
|
||||||
+add_library(rdtsc
|
+add_library(rdtsc
|
||||||
src/cycles.c
|
src/cycles.c
|
||||||
@@ -14,7 +14,7 @@ index ee9b58c..31359a9 100644
|
|||||||
@@ -72,15 +72,6 @@ target_include_directories(rdtsc
|
@@ -72,15 +72,6 @@ target_include_directories(rdtsc
|
||||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
)
|
)
|
||||||
|
|
||||||
-# Install directory changes depending on build mode
|
-# Install directory changes depending on build mode
|
||||||
-if (CMAKE_BUILD_TYPE MATCHES "^[Dd]ebug")
|
-if (CMAKE_BUILD_TYPE MATCHES "^[Dd]ebug")
|
||||||
- # During debug, the library will be installed into a local directory
|
- # During debug, the library will be installed into a local directory
|
||||||
@@ -27,15 +27,3 @@ index ee9b58c..31359a9 100644
|
|||||||
# Specifying what to export when installing (GNUInstallDirs required)
|
# Specifying what to export when installing (GNUInstallDirs required)
|
||||||
install(TARGETS rdtsc
|
install(TARGETS rdtsc
|
||||||
EXPORT librstsc-config
|
EXPORT librstsc-config
|
||||||
diff --git a/include/librdtsc/common_timer.h b/include/librdtsc/common_timer.h
|
|
||||||
index a6922d8..080dc77 100644
|
|
||||||
--- a/include/librdtsc/common_timer.h
|
|
||||||
+++ b/include/librdtsc/common_timer.h
|
|
||||||
@@ -2,6 +2,7 @@
|
|
||||||
#define LIBRDTSC_COMMON_TIMER_H
|
|
||||||
|
|
||||||
#include <librdtsc/common.h>
|
|
||||||
+#include <librdtsc/cycles.h>
|
|
||||||
|
|
||||||
extern uint64_t rdtsc_get_tsc_freq_arch();
|
|
||||||
extern uint64_t rdtsc_get_tsc_freq();
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
diff --git a/include/libnuraft/asio_service_options.hxx b/include/libnuraft/asio_service_options.hxx
|
|
||||||
index 8fe1ec9..9497355 100644
|
|
||||||
--- a/include/libnuraft/asio_service_options.hxx
|
|
||||||
+++ b/include/libnuraft/asio_service_options.hxx
|
|
||||||
@@ -17,6 +17,7 @@ limitations under the License.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
+#include <cstdint>
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
|
||||||
#include <system_error>
|
|
||||||
diff --git a/include/libnuraft/callback.hxx b/include/libnuraft/callback.hxx
|
|
||||||
index 7b71624..d48c1e2 100644
|
|
||||||
--- a/include/libnuraft/callback.hxx
|
|
||||||
+++ b/include/libnuraft/callback.hxx
|
|
||||||
@@ -18,6 +18,7 @@ limitations under the License.
|
|
||||||
#ifndef _CALLBACK_H_
|
|
||||||
#define _CALLBACK_H_
|
|
||||||
|
|
||||||
+#include <cstdint>
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
21
libs/rocksdb.patch
Normal file
21
libs/rocksdb.patch
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index 6761929..6a369af 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -220,6 +220,7 @@ else()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -momit-leaf-frame-pointer")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-copy -Wno-unused-but-set-variable")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CheckCCompilerFlag)
|
||||||
|
@@ -997,7 +998,7 @@ if(NOT WIN32 OR ROCKSDB_INSTALL_ON_WINDOWS)
|
||||||
|
|
||||||
|
if(ROCKSDB_BUILD_SHARED)
|
||||||
|
install(
|
||||||
|
- TARGETS ${ROCKSDB_SHARED_LIB}
|
||||||
|
+ TARGETS ${ROCKSDB_SHARED_LIB} OPTIONAL
|
||||||
|
EXPORT RocksDBTargets
|
||||||
|
COMPONENT runtime
|
||||||
|
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||||
@@ -123,10 +123,9 @@ declare -A primary_urls=(
|
|||||||
["pulsar"]="http://$local_cache_host/git/pulsar.git"
|
["pulsar"]="http://$local_cache_host/git/pulsar.git"
|
||||||
["librdtsc"]="http://$local_cache_host/git/librdtsc.git"
|
["librdtsc"]="http://$local_cache_host/git/librdtsc.git"
|
||||||
["ctre"]="http://$local_cache_host/file/hanickadot/compile-time-regular-expressions/v3.7.2/single-header/ctre.hpp"
|
["ctre"]="http://$local_cache_host/file/hanickadot/compile-time-regular-expressions/v3.7.2/single-header/ctre.hpp"
|
||||||
["absl"]="http://$local_cache_host/git/abseil-cpp.git"
|
["absl"]="https://$local_cache_host/git/abseil-cpp.git"
|
||||||
["jemalloc"]="http://$local_cache_host/git/jemalloc.git"
|
["jemalloc"]="https://$local_cache_host/git/jemalloc.git"
|
||||||
["range-v3"]="http://$local_cache_host/git/range-v3.git"
|
["range-v3"]="https://$local_cache_host/git/ericniebler/range-v3.git"
|
||||||
["nuraft"]="http://$local_cache_host/git/NuRaft.git"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# The goal of secondary urls is to have links to the "source of truth" of
|
# The goal of secondary urls is to have links to the "source of truth" of
|
||||||
@@ -156,7 +155,6 @@ declare -A secondary_urls=(
|
|||||||
["absl"]="https://github.com/abseil/abseil-cpp.git"
|
["absl"]="https://github.com/abseil/abseil-cpp.git"
|
||||||
["jemalloc"]="https://github.com/jemalloc/jemalloc.git"
|
["jemalloc"]="https://github.com/jemalloc/jemalloc.git"
|
||||||
["range-v3"]="https://github.com/ericniebler/range-v3.git"
|
["range-v3"]="https://github.com/ericniebler/range-v3.git"
|
||||||
["nuraft"]="https://github.com/eBay/NuRaft.git"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# antlr
|
# antlr
|
||||||
@@ -168,11 +166,12 @@ pushd antlr4
|
|||||||
git apply ../antlr4.10.1.patch
|
git apply ../antlr4.10.1.patch
|
||||||
popd
|
popd
|
||||||
|
|
||||||
cppitertools_ref="v2.1" # 2021-01-15
|
# cppitertools v2.0 2019-12-23
|
||||||
|
cppitertools_ref="cb3635456bdb531121b82b4d2e3afc7ae1f56d47"
|
||||||
repo_clone_try_double "${primary_urls[cppitertools]}" "${secondary_urls[cppitertools]}" "cppitertools" "$cppitertools_ref"
|
repo_clone_try_double "${primary_urls[cppitertools]}" "${secondary_urls[cppitertools]}" "cppitertools" "$cppitertools_ref"
|
||||||
|
|
||||||
# rapidcheck
|
# rapidcheck
|
||||||
rapidcheck_tag="1c91f40e64d87869250cfb610376c629307bf77d" # (2023-08-15)
|
rapidcheck_tag="7bc7d302191a4f3d0bf005692677126136e02f60" # (2020-05-04)
|
||||||
repo_clone_try_double "${primary_urls[rapidcheck]}" "${secondary_urls[rapidcheck]}" "rapidcheck" "$rapidcheck_tag"
|
repo_clone_try_double "${primary_urls[rapidcheck]}" "${secondary_urls[rapidcheck]}" "rapidcheck" "$rapidcheck_tag"
|
||||||
|
|
||||||
# google benchmark
|
# google benchmark
|
||||||
@@ -220,7 +219,7 @@ repo_clone_try_double "${primary_urls[pymgclient]}" "${secondary_urls[pymgclient
|
|||||||
mgconsole_tag="v1.4.0" # (2023-05-21)
|
mgconsole_tag="v1.4.0" # (2023-05-21)
|
||||||
repo_clone_try_double "${primary_urls[mgconsole]}" "${secondary_urls[mgconsole]}" "mgconsole" "$mgconsole_tag" true
|
repo_clone_try_double "${primary_urls[mgconsole]}" "${secondary_urls[mgconsole]}" "mgconsole" "$mgconsole_tag" true
|
||||||
|
|
||||||
spdlog_tag="v1.12.0" # (2022-11-02)
|
spdlog_tag="v1.9.2" # (2021-08-12)
|
||||||
repo_clone_try_double "${primary_urls[spdlog]}" "${secondary_urls[spdlog]}" "spdlog" "$spdlog_tag" true
|
repo_clone_try_double "${primary_urls[spdlog]}" "${secondary_urls[spdlog]}" "spdlog" "$spdlog_tag" true
|
||||||
|
|
||||||
# librdkafka
|
# librdkafka
|
||||||
@@ -260,7 +259,7 @@ repo_clone_try_double "${primary_urls[absl]}" "${secondary_urls[absl]}" "absl" "
|
|||||||
|
|
||||||
# jemalloc ea6b3e973b477b8061e0076bb257dbd7f3faa756
|
# jemalloc ea6b3e973b477b8061e0076bb257dbd7f3faa756
|
||||||
JEMALLOC_COMMIT_VERSION="5.2.1"
|
JEMALLOC_COMMIT_VERSION="5.2.1"
|
||||||
repo_clone_try_double "${primary_urls[jemalloc]}" "${secondary_urls[jemalloc]}" "jemalloc" "$JEMALLOC_COMMIT_VERSION"
|
repo_clone_try_double "${secondary_urls[jemalloc]}" "${secondary_urls[jemalloc]}" "jemalloc" "$JEMALLOC_COMMIT_VERSION"
|
||||||
|
|
||||||
# this is hack for cmake in libs to set path, and for FindJemalloc to use Jemalloc_INCLUDE_DIR
|
# this is hack for cmake in libs to set path, and for FindJemalloc to use Jemalloc_INCLUDE_DIR
|
||||||
pushd jemalloc
|
pushd jemalloc
|
||||||
@@ -269,8 +268,6 @@ pushd jemalloc
|
|||||||
MALLOC_CONF="retain:false,percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000" \
|
MALLOC_CONF="retain:false,percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000" \
|
||||||
./configure \
|
./configure \
|
||||||
--disable-cxx \
|
--disable-cxx \
|
||||||
--with-lg-page=12 \
|
|
||||||
--with-lg-hugepage=21 \
|
|
||||||
--enable-shared=no --prefix=$working_dir \
|
--enable-shared=no --prefix=$working_dir \
|
||||||
--with-malloc-conf="retain:false,percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000"
|
--with-malloc-conf="retain:false,percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000"
|
||||||
|
|
||||||
@@ -280,11 +277,3 @@ popd
|
|||||||
#range-v3 release-0.12.0
|
#range-v3 release-0.12.0
|
||||||
range_v3_ref="release-0.12.0"
|
range_v3_ref="release-0.12.0"
|
||||||
repo_clone_try_double "${primary_urls[range-v3]}" "${secondary_urls[range-v3]}" "rangev3" "$range_v3_ref"
|
repo_clone_try_double "${primary_urls[range-v3]}" "${secondary_urls[range-v3]}" "rangev3" "$range_v3_ref"
|
||||||
|
|
||||||
# NuRaft
|
|
||||||
nuraft_tag="v2.1.0"
|
|
||||||
repo_clone_try_double "${primary_urls[nuraft]}" "${secondary_urls[nuraft]}" "nuraft" "$nuraft_tag" true
|
|
||||||
pushd nuraft
|
|
||||||
git apply ../nuraft2.1.0.patch
|
|
||||||
./prepare.sh
|
|
||||||
popd
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ ADDITIONAL USE GRANT: You may use the Licensed Work in accordance with the
|
|||||||
3. using the Licensed Work to create a work or solution
|
3. using the Licensed Work to create a work or solution
|
||||||
which competes (or might reasonably be expected to
|
which competes (or might reasonably be expected to
|
||||||
compete) with the Licensed Work.
|
compete) with the Licensed Work.
|
||||||
CHANGE DATE: 2028-21-01
|
CHANGE DATE: 2027-30-10
|
||||||
CHANGE LICENSE: Apache License, Version 2.0
|
CHANGE LICENSE: Apache License, Version 2.0
|
||||||
|
|
||||||
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.
|
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.
|
||||||
|
|||||||
@@ -108,83 +108,32 @@ void Schema::ProcessPropertiesRel(mgp::Record &record, const std::string_view &t
|
|||||||
record.Insert(std::string(kReturnMandatory).c_str(), mandatory);
|
record.Insert(std::string(kReturnMandatory).c_str(), mandatory);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Property {
|
|
||||||
std::string name;
|
|
||||||
mgp::Value value;
|
|
||||||
|
|
||||||
Property(const std::string &name, mgp::Value &&value) : name(name), value(std::move(value)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LabelsHash {
|
|
||||||
std::size_t operator()(const std::set<std::string> &set) const {
|
|
||||||
std::size_t seed = set.size();
|
|
||||||
for (const auto &i : set) {
|
|
||||||
seed ^= std::hash<std::string>{}(i) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
||||||
}
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LabelsComparator {
|
|
||||||
bool operator()(const std::set<std::string> &lhs, const std::set<std::string> &rhs) const { return lhs == rhs; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PropertyComparator {
|
|
||||||
bool operator()(const Property &lhs, const Property &rhs) const { return lhs.name < rhs.name; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PropertyInfo {
|
|
||||||
std::set<Property, PropertyComparator> properties;
|
|
||||||
bool mandatory;
|
|
||||||
};
|
|
||||||
|
|
||||||
void Schema::NodeTypeProperties(mgp_list * /*args*/, mgp_graph *memgraph_graph, mgp_result *result,
|
void Schema::NodeTypeProperties(mgp_list * /*args*/, mgp_graph *memgraph_graph, mgp_result *result,
|
||||||
mgp_memory *memory) {
|
mgp_memory *memory) {
|
||||||
mgp::MemoryDispatcherGuard guard{memory};
|
mgp::MemoryDispatcherGuard guard{memory};
|
||||||
|
;
|
||||||
const auto record_factory = mgp::RecordFactory(result);
|
const auto record_factory = mgp::RecordFactory(result);
|
||||||
try {
|
try {
|
||||||
std::unordered_map<std::set<std::string>, PropertyInfo, LabelsHash, LabelsComparator> node_types_properties;
|
const mgp::Graph graph = mgp::Graph(memgraph_graph);
|
||||||
|
for (auto node : graph.Nodes()) {
|
||||||
for (auto node : mgp::Graph(memgraph_graph).Nodes()) {
|
std::string type;
|
||||||
std::set<std::string> labels_set = {};
|
mgp::List labels = mgp::List();
|
||||||
for (auto label : node.Labels()) {
|
for (auto label : node.Labels()) {
|
||||||
labels_set.emplace(label);
|
labels.AppendExtend(mgp::Value(label));
|
||||||
}
|
type += ":`" + std::string(label) + "`";
|
||||||
|
|
||||||
if (node_types_properties.find(labels_set) == node_types_properties.end()) {
|
|
||||||
node_types_properties[labels_set] = PropertyInfo{std::set<Property, PropertyComparator>(), true};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.Properties().empty()) {
|
if (node.Properties().empty()) {
|
||||||
node_types_properties[labels_set].mandatory = false; // if there is node with no property, it is not mandatory
|
auto record = record_factory.NewRecord();
|
||||||
|
ProcessPropertiesNode<std::string>(record, type, labels, "", "", false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &property_info = node_types_properties.at(labels_set);
|
|
||||||
for (auto &[key, prop] : node.Properties()) {
|
for (auto &[key, prop] : node.Properties()) {
|
||||||
property_info.properties.emplace(key, std::move(prop));
|
auto property_type = mgp::List();
|
||||||
if (property_info.mandatory) {
|
|
||||||
property_info.mandatory =
|
|
||||||
property_info.properties.size() == 1; // if there is only one property, it is mandatory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &[labels, property_info] : node_types_properties) {
|
|
||||||
std::string label_type;
|
|
||||||
mgp::List labels_list = mgp::List();
|
|
||||||
for (auto const &label : labels) {
|
|
||||||
label_type += ":`" + std::string(label) + "`";
|
|
||||||
labels_list.AppendExtend(mgp::Value(label));
|
|
||||||
}
|
|
||||||
for (auto const &prop : property_info.properties) {
|
|
||||||
auto record = record_factory.NewRecord();
|
auto record = record_factory.NewRecord();
|
||||||
ProcessPropertiesNode(record, label_type, labels_list, prop.name, TypeOf(prop.value.Type()),
|
property_type.AppendExtend(mgp::Value(TypeOf(prop.Type())));
|
||||||
property_info.mandatory);
|
ProcessPropertiesNode<mgp::List>(record, type, labels, key, property_type, true);
|
||||||
}
|
|
||||||
if (property_info.properties.empty()) {
|
|
||||||
auto record = record_factory.NewRecord();
|
|
||||||
ProcessPropertiesNode<std::string>(record, label_type, labels_list, "", "", false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,41 +145,23 @@ void Schema::NodeTypeProperties(mgp_list * /*args*/, mgp_graph *memgraph_graph,
|
|||||||
|
|
||||||
void Schema::RelTypeProperties(mgp_list * /*args*/, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
|
void Schema::RelTypeProperties(mgp_list * /*args*/, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
|
||||||
mgp::MemoryDispatcherGuard guard{memory};
|
mgp::MemoryDispatcherGuard guard{memory};
|
||||||
|
|
||||||
std::unordered_map<std::string, PropertyInfo> rel_types_properties;
|
|
||||||
const auto record_factory = mgp::RecordFactory(result);
|
const auto record_factory = mgp::RecordFactory(result);
|
||||||
try {
|
try {
|
||||||
const mgp::Graph graph = mgp::Graph(memgraph_graph);
|
const mgp::Graph graph = mgp::Graph(memgraph_graph);
|
||||||
for (auto rel : graph.Relationships()) {
|
|
||||||
std::string rel_type = std::string(rel.Type());
|
|
||||||
if (rel_types_properties.find(rel_type) == rel_types_properties.end()) {
|
|
||||||
rel_types_properties[rel_type] = PropertyInfo{std::set<Property, PropertyComparator>(), true};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (auto rel : graph.Relationships()) {
|
||||||
|
std::string type = ":`" + std::string(rel.Type()) + "`";
|
||||||
if (rel.Properties().empty()) {
|
if (rel.Properties().empty()) {
|
||||||
rel_types_properties[rel_type].mandatory = false; // if there is rel with no property, it is not mandatory
|
auto record = record_factory.NewRecord();
|
||||||
|
ProcessPropertiesRel<std::string>(record, type, "", "", false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &property_info = rel_types_properties.at(rel_type);
|
|
||||||
for (auto &[key, prop] : rel.Properties()) {
|
for (auto &[key, prop] : rel.Properties()) {
|
||||||
property_info.properties.emplace(key, std::move(prop));
|
auto property_type = mgp::List();
|
||||||
if (property_info.mandatory) {
|
|
||||||
property_info.mandatory =
|
|
||||||
property_info.properties.size() == 1; // if there is only one property, it is mandatory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &[type, property_info] : rel_types_properties) {
|
|
||||||
std::string type_str = ":`" + std::string(type) + "`";
|
|
||||||
for (auto const &prop : property_info.properties) {
|
|
||||||
auto record = record_factory.NewRecord();
|
auto record = record_factory.NewRecord();
|
||||||
ProcessPropertiesRel(record, type_str, prop.name, TypeOf(prop.value.Type()), property_info.mandatory);
|
property_type.AppendExtend(mgp::Value(TypeOf(prop.Type())));
|
||||||
}
|
ProcessPropertiesRel<mgp::List>(record, type, key, property_type, true);
|
||||||
if (property_info.properties.empty()) {
|
|
||||||
auto record = record_factory.NewRecord();
|
|
||||||
ProcessPropertiesRel<std::string>(record, type_str, "", "", false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,6 +570,7 @@ void Schema::Assert(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *resul
|
|||||||
extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) {
|
extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) {
|
||||||
try {
|
try {
|
||||||
mgp::MemoryDispatcherGuard guard{memory};
|
mgp::MemoryDispatcherGuard guard{memory};
|
||||||
|
;
|
||||||
|
|
||||||
AddProcedure(Schema::NodeTypeProperties, Schema::kProcedureNodeType, mgp::ProcedureType::Read, {},
|
AddProcedure(Schema::NodeTypeProperties, Schema::kProcedureNodeType, mgp::ProcedureType::Read, {},
|
||||||
{mgp::Return(Schema::kReturnNodeType, mgp::Type::String),
|
{mgp::Return(Schema::kReturnNodeType, mgp::Type::String),
|
||||||
|
|||||||
@@ -104,9 +104,7 @@ def retry(retry_limit, timeout=100):
|
|||||||
except Exception:
|
except Exception:
|
||||||
time.sleep(timeout)
|
time.sleep(timeout)
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
return inner_func
|
return inner_func
|
||||||
|
|
||||||
|
|
||||||
@@ -202,19 +200,19 @@ if args.version:
|
|||||||
try:
|
try:
|
||||||
current_branch = get_output("git", "rev-parse", "--abbrev-ref", "HEAD")
|
current_branch = get_output("git", "rev-parse", "--abbrev-ref", "HEAD")
|
||||||
if current_branch != "master":
|
if current_branch != "master":
|
||||||
branches = get_output("git", "branch", "-r", "--list", "origin/master")
|
branches = get_output("git", "branch")
|
||||||
if "origin/master" in branches:
|
if "master" in branches:
|
||||||
# If master is present locally, the fetch is allowed to fail
|
# If master is present locally, the fetch is allowed to fail
|
||||||
# because this script will still be able to compare against the
|
# because this script will still be able to compare against the
|
||||||
# master branch.
|
# master branch.
|
||||||
try:
|
try:
|
||||||
get_output("git", "fetch", "origin", "master")
|
get_output("git", "fetch", "origin", "master:master")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# If master is not present locally, the fetch command has to
|
# If master is not present locally, the fetch command has to
|
||||||
# succeed because something else will fail otherwise.
|
# succeed because something else will fail otherwise.
|
||||||
get_output("git", "fetch", "origin", "master")
|
get_output("git", "fetch", "origin", "master:master")
|
||||||
except Exception:
|
except Exception:
|
||||||
print("Fatal error while ensuring local master branch.")
|
print("Fatal error while ensuring local master branch.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -234,7 +232,7 @@ for branch in branches:
|
|||||||
match = branch_regex.match(branch)
|
match = branch_regex.match(branch)
|
||||||
if match is not None:
|
if match is not None:
|
||||||
version = tuple(map(int, match.group(1).split(".")))
|
version = tuple(map(int, match.group(1).split(".")))
|
||||||
master_branch_merge = get_output("git", "merge-base", "origin/master", branch)
|
master_branch_merge = get_output("git", "merge-base", "master", branch)
|
||||||
versions.append((version, branch, master_branch_merge))
|
versions.append((version, branch, master_branch_merge))
|
||||||
versions.sort(reverse=True)
|
versions.sort(reverse=True)
|
||||||
|
|
||||||
@@ -245,7 +243,7 @@ current_version = None
|
|||||||
for version in versions:
|
for version in versions:
|
||||||
version_tuple, branch, master_branch_merge = version
|
version_tuple, branch, master_branch_merge = version
|
||||||
current_branch_merge = get_output("git", "merge-base", current_hash, branch)
|
current_branch_merge = get_output("git", "merge-base", current_hash, branch)
|
||||||
master_current_merge = get_output("git", "merge-base", current_hash, "origin/master")
|
master_current_merge = get_output("git", "merge-base", current_hash, "master")
|
||||||
# The first check checks whether this commit is a child of `master` and
|
# The first check checks whether this commit is a child of `master` and
|
||||||
# the version branch was created before us.
|
# the version branch was created before us.
|
||||||
# The second check checks whether this commit is a child of the version
|
# The second check checks whether this commit is a child of the version
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ add_subdirectory(dbms)
|
|||||||
add_subdirectory(flags)
|
add_subdirectory(flags)
|
||||||
add_subdirectory(distributed)
|
add_subdirectory(distributed)
|
||||||
add_subdirectory(replication)
|
add_subdirectory(replication)
|
||||||
add_subdirectory(replication_handler)
|
|
||||||
add_subdirectory(coordination)
|
|
||||||
add_subdirectory(replication_coordination_glue)
|
|
||||||
add_subdirectory(system)
|
|
||||||
|
|
||||||
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
||||||
|
|
||||||
@@ -45,10 +41,10 @@ set(mg_single_node_v2_sources
|
|||||||
add_executable(memgraph ${mg_single_node_v2_sources})
|
add_executable(memgraph ${mg_single_node_v2_sources})
|
||||||
target_include_directories(memgraph PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
target_include_directories(memgraph PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||||
target_link_libraries(memgraph stdc++fs Threads::Threads
|
target_link_libraries(memgraph stdc++fs Threads::Threads
|
||||||
mg-telemetry mg-communication mg-communication-metrics mg-memory mg-utils mg-license mg-settings mg-glue mg-flags mg::system mg::replication_handler)
|
mg-telemetry mg-communication mg-communication-metrics mg-memory mg-utils mg-license mg-settings mg-glue mg-flags)
|
||||||
|
|
||||||
# NOTE: `include/mg_procedure.syms` describes a pattern match for symbols which
|
# NOTE: `include/mg_procedure.syms` describes a pattern match for symbols which
|
||||||
# should be dynamically exported, so that `dlopen` can correctly link th
|
# should be dynamically exported, so that `dlopen` can correctly link the
|
||||||
# symbols in custom procedure module libraries.
|
# symbols in custom procedure module libraries.
|
||||||
target_link_libraries(memgraph "-Wl,--dynamic-list=${CMAKE_SOURCE_DIR}/include/mg_procedure.syms")
|
target_link_libraries(memgraph "-Wl,--dynamic-list=${CMAKE_SOURCE_DIR}/include/mg_procedure.syms")
|
||||||
set_target_properties(memgraph PROPERTIES
|
set_target_properties(memgraph PROPERTIES
|
||||||
@@ -57,10 +53,7 @@ set_target_properties(memgraph PROPERTIES
|
|||||||
OUTPUT_NAME "memgraph-${MEMGRAPH_VERSION}_${CMAKE_BUILD_TYPE}"
|
OUTPUT_NAME "memgraph-${MEMGRAPH_VERSION}_${CMAKE_BUILD_TYPE}"
|
||||||
|
|
||||||
# Output the executable in main binary dir.
|
# Output the executable in main binary dir.
|
||||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
|
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
POSITION_INDEPENDENT_CODE ON
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create symlink to the built executable.
|
# Create symlink to the built executable.
|
||||||
add_custom_command(TARGET memgraph POST_BUILD
|
add_custom_command(TARGET memgraph POST_BUILD
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <json/json.hpp>
|
#include <json/json.hpp>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "storage/v2/temporal.hpp"
|
#include "storage/v2/temporal.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
@@ -88,8 +87,8 @@ inline nlohmann::json PropertyValueToJson(const storage::PropertyValue &pv) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::Log(std::filesystem::path storage_directory, int32_t buffer_size, int32_t buffer_flush_interval_millis)
|
Log::Log(const std::filesystem::path &storage_directory, int32_t buffer_size, int32_t buffer_flush_interval_millis)
|
||||||
: storage_directory_(std::move(storage_directory)),
|
: storage_directory_(storage_directory),
|
||||||
buffer_size_(buffer_size),
|
buffer_size_(buffer_size),
|
||||||
buffer_flush_interval_millis_(buffer_flush_interval_millis),
|
buffer_flush_interval_millis_(buffer_flush_interval_millis),
|
||||||
started_(false) {}
|
started_(false) {}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class Log {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Log(std::filesystem::path storage_directory, int32_t buffer_size, int32_t buffer_flush_interval_millis);
|
Log(const std::filesystem::path &storage_directory, int32_t buffer_size, int32_t buffer_flush_interval_millis);
|
||||||
|
|
||||||
~Log();
|
~Log();
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ set(auth_src_files
|
|||||||
auth.cpp
|
auth.cpp
|
||||||
crypto.cpp
|
crypto.cpp
|
||||||
models.cpp
|
models.cpp
|
||||||
module.cpp
|
module.cpp)
|
||||||
rpc.cpp
|
|
||||||
replication_handlers.cpp)
|
|
||||||
|
|
||||||
find_package(Seccomp REQUIRED)
|
find_package(Seccomp REQUIRED)
|
||||||
find_package(fmt REQUIRED)
|
find_package(fmt REQUIRED)
|
||||||
@@ -13,7 +11,7 @@ find_package(gflags REQUIRED)
|
|||||||
|
|
||||||
add_library(mg-auth STATIC ${auth_src_files})
|
add_library(mg-auth STATIC ${auth_src_files})
|
||||||
target_link_libraries(mg-auth json libbcrypt gflags fmt::fmt)
|
target_link_libraries(mg-auth json libbcrypt gflags fmt::fmt)
|
||||||
target_link_libraries(mg-auth mg-utils mg-kvstore mg-license mg::system mg-replication)
|
target_link_libraries(mg-auth mg-utils mg-kvstore mg-license )
|
||||||
|
|
||||||
target_link_libraries(mg-auth ${Seccomp_LIBRARIES})
|
target_link_libraries(mg-auth ${Seccomp_LIBRARIES})
|
||||||
target_include_directories(mg-auth SYSTEM PRIVATE ${Seccomp_INCLUDE_DIRS})
|
target_include_directories(mg-auth SYSTEM PRIVATE ${Seccomp_INCLUDE_DIRS})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -8,18 +8,17 @@
|
|||||||
|
|
||||||
#include "auth/auth.hpp"
|
#include "auth/auth.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <optional>
|
#include <limits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "auth/crypto.hpp"
|
|
||||||
#include "auth/exceptions.hpp"
|
#include "auth/exceptions.hpp"
|
||||||
#include "auth/rpc.hpp"
|
|
||||||
#include "license/license.hpp"
|
#include "license/license.hpp"
|
||||||
#include "system/transaction.hpp"
|
|
||||||
#include "utils/flag_validation.hpp"
|
#include "utils/flag_validation.hpp"
|
||||||
|
#include "utils/logging.hpp"
|
||||||
#include "utils/message.hpp"
|
#include "utils/message.hpp"
|
||||||
#include "utils/settings.hpp"
|
#include "utils/settings.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
@@ -35,124 +34,18 @@ DEFINE_VALIDATED_string(auth_module_executable, "", "Absolute path to the auth m
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
DEFINE_bool(auth_module_create_missing_user, true, "Set to false to disable creation of missing users.");
|
||||||
|
DEFINE_bool(auth_module_create_missing_role, true, "Set to false to disable creation of missing roles.");
|
||||||
|
DEFINE_bool(auth_module_manage_roles, true, "Set to false to disable management of roles through the auth module.");
|
||||||
DEFINE_VALIDATED_int32(auth_module_timeout_ms, 10000,
|
DEFINE_VALIDATED_int32(auth_module_timeout_ms, 10000,
|
||||||
"Timeout (in milliseconds) used when waiting for a "
|
"Timeout (in milliseconds) used when waiting for a "
|
||||||
"response from the auth module.",
|
"response from the auth module.",
|
||||||
FLAG_IN_RANGE(100, 1800000));
|
FLAG_IN_RANGE(100, 1800000));
|
||||||
|
|
||||||
// DEPRECATED FLAGS
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables, misc-unused-parameters)
|
|
||||||
DEFINE_VALIDATED_HIDDEN_bool(auth_module_create_missing_user, true,
|
|
||||||
"Set to false to disable creation of missing users.", {
|
|
||||||
spdlog::warn(
|
|
||||||
"auth_module_create_missing_user flag is deprecated. It not possible to create "
|
|
||||||
"users through the module anymore.");
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables, misc-unused-parameters)
|
|
||||||
DEFINE_VALIDATED_HIDDEN_bool(auth_module_create_missing_role, true,
|
|
||||||
"Set to false to disable creation of missing roles.", {
|
|
||||||
spdlog::warn(
|
|
||||||
"auth_module_create_missing_role flag is deprecated. It not possible to create "
|
|
||||||
"roles through the module anymore.");
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables, misc-unused-parameters)
|
|
||||||
DEFINE_VALIDATED_HIDDEN_bool(
|
|
||||||
auth_module_manage_roles, true, "Set to false to disable management of roles through the auth module.", {
|
|
||||||
spdlog::warn(
|
|
||||||
"auth_module_manage_roles flag is deprecated. It not possible to create roles through the module anymore.");
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
namespace memgraph::auth {
|
namespace memgraph::auth {
|
||||||
|
|
||||||
const Auth::Epoch Auth::kStartEpoch = 1;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
/**
|
|
||||||
* REPLICATION SYSTEM ACTION IMPLEMENTATIONS
|
|
||||||
*/
|
|
||||||
struct UpdateAuthData : memgraph::system::ISystemAction {
|
|
||||||
explicit UpdateAuthData(User user) : user_{std::move(user)}, role_{std::nullopt} {}
|
|
||||||
explicit UpdateAuthData(Role role) : user_{std::nullopt}, role_{std::move(role)} {}
|
|
||||||
|
|
||||||
void DoDurability() override { /* Done during Auth execution */
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DoReplication(replication::ReplicationClient &client, const utils::UUID &main_uuid,
|
|
||||||
replication::ReplicationEpoch const &epoch,
|
|
||||||
memgraph::system::Transaction const &txn) const override {
|
|
||||||
auto check_response = [](const replication::UpdateAuthDataRes &response) { return response.success; };
|
|
||||||
if (user_) {
|
|
||||||
return client.SteamAndFinalizeDelta<replication::UpdateAuthDataRpc>(
|
|
||||||
check_response, main_uuid, std::string{epoch.id()}, txn.last_committed_system_timestamp(), txn.timestamp(),
|
|
||||||
*user_);
|
|
||||||
}
|
|
||||||
if (role_) {
|
|
||||||
return client.SteamAndFinalizeDelta<replication::UpdateAuthDataRpc>(
|
|
||||||
check_response, main_uuid, std::string{epoch.id()}, txn.last_committed_system_timestamp(), txn.timestamp(),
|
|
||||||
*role_);
|
|
||||||
}
|
|
||||||
// Should never get here
|
|
||||||
MG_ASSERT(false, "Trying to update auth data that is not a user nor a role");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void PostReplication(replication::RoleMainData &mainData) const override {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::optional<User> user_;
|
|
||||||
std::optional<Role> role_;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DropAuthData : memgraph::system::ISystemAction {
|
|
||||||
enum class AuthDataType { USER, ROLE };
|
|
||||||
|
|
||||||
explicit DropAuthData(AuthDataType type, std::string_view name) : type_{type}, name_{name} {}
|
|
||||||
|
|
||||||
void DoDurability() override { /* Done during Auth execution */
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DoReplication(replication::ReplicationClient &client, const utils::UUID &main_uuid,
|
|
||||||
replication::ReplicationEpoch const &epoch,
|
|
||||||
memgraph::system::Transaction const &txn) const override {
|
|
||||||
auto check_response = [](const replication::DropAuthDataRes &response) { return response.success; };
|
|
||||||
|
|
||||||
memgraph::replication::DropAuthDataReq::DataType type{};
|
|
||||||
switch (type_) {
|
|
||||||
case AuthDataType::USER:
|
|
||||||
type = memgraph::replication::DropAuthDataReq::DataType::USER;
|
|
||||||
break;
|
|
||||||
case AuthDataType::ROLE:
|
|
||||||
type = memgraph::replication::DropAuthDataReq::DataType::ROLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return client.SteamAndFinalizeDelta<replication::DropAuthDataRpc>(
|
|
||||||
check_response, main_uuid, std::string{epoch.id()}, txn.last_committed_system_timestamp(), txn.timestamp(),
|
|
||||||
type, name_);
|
|
||||||
}
|
|
||||||
void PostReplication(replication::RoleMainData &mainData) const override {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
AuthDataType type_;
|
|
||||||
std::string name_;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CONSTANTS
|
|
||||||
*/
|
|
||||||
const std::string kUserPrefix = "user:";
|
const std::string kUserPrefix = "user:";
|
||||||
const std::string kRolePrefix = "role:";
|
const std::string kRolePrefix = "role:";
|
||||||
const std::string kLinkPrefix = "link:";
|
const std::string kLinkPrefix = "link:";
|
||||||
const std::string kVersion = "version";
|
|
||||||
|
|
||||||
static constexpr auto kVersionV1 = "V1";
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All data stored in the `Auth` storage is stored in an underlying
|
* All data stored in the `Auth` storage is stored in an underlying
|
||||||
@@ -171,76 +64,10 @@ static constexpr auto kVersionV1 = "V1";
|
|||||||
* key="link:<username>", value="<rolename>"
|
* key="link:<username>", value="<rolename>"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace {
|
Auth::Auth(const std::string &storage_directory) : storage_(storage_directory), module_(FLAGS_auth_module_executable) {}
|
||||||
void MigrateVersions(kvstore::KVStore &store) {
|
|
||||||
static constexpr auto kPasswordHashV0V1 = "password_hash";
|
|
||||||
auto version_str = store.Get(kVersion);
|
|
||||||
|
|
||||||
if (!version_str) {
|
std::optional<User> Auth::Authenticate(const std::string &username, const std::string &password) {
|
||||||
using namespace std::string_literals;
|
|
||||||
|
|
||||||
// pre versioning, add version to the store
|
|
||||||
auto puts = std::map<std::string, std::string>{{kVersion, kVersionV1}};
|
|
||||||
|
|
||||||
// also add hash kind into durability
|
|
||||||
|
|
||||||
auto it = store.begin(kUserPrefix);
|
|
||||||
auto const e = store.end(kUserPrefix);
|
|
||||||
|
|
||||||
if (it != e) {
|
|
||||||
const auto hash_algo = CurrentHashAlgorithm();
|
|
||||||
spdlog::info("Updating auth durability, assuming previously stored as {}", AsString(hash_algo));
|
|
||||||
|
|
||||||
for (; it != e; ++it) {
|
|
||||||
auto const &[key, value] = *it;
|
|
||||||
try {
|
|
||||||
auto user_data = nlohmann::json::parse(value);
|
|
||||||
|
|
||||||
auto password_hash = user_data[kPasswordHashV0V1];
|
|
||||||
if (!password_hash.is_string()) {
|
|
||||||
throw AuthException("Couldn't load user data!");
|
|
||||||
}
|
|
||||||
// upgrade the password_hash to include the hash algortihm
|
|
||||||
if (password_hash.empty()) {
|
|
||||||
user_data[kPasswordHashV0V1] = nullptr;
|
|
||||||
} else {
|
|
||||||
user_data[kPasswordHashV0V1] = HashedPassword{hash_algo, password_hash};
|
|
||||||
}
|
|
||||||
puts.emplace(key, user_data.dump());
|
|
||||||
} catch (const nlohmann::json::parse_error &e) {
|
|
||||||
throw AuthException("Couldn't load user data!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform migration to V1
|
|
||||||
store.PutMultiple(puts);
|
|
||||||
version_str = kVersionV1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ParseJson(std::string_view str) {
|
|
||||||
nlohmann::json data;
|
|
||||||
try {
|
|
||||||
data = nlohmann::json::parse(str);
|
|
||||||
} catch (const nlohmann::json::parse_error &e) {
|
|
||||||
throw AuthException("Couldn't load auth data!");
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace
|
|
||||||
|
|
||||||
Auth::Auth(std::string storage_directory, Config config)
|
|
||||||
: storage_(std::move(storage_directory)), module_(FLAGS_auth_module_executable), config_{std::move(config)} {
|
|
||||||
MigrateVersions(storage_);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<UserOrRole> Auth::Authenticate(const std::string &username, const std::string &password) {
|
|
||||||
if (module_.IsUsed()) {
|
if (module_.IsUsed()) {
|
||||||
/*
|
|
||||||
* MODULE AUTH STORAGE
|
|
||||||
*/
|
|
||||||
const auto license_check_result = license::global_license_checker.IsEnterpriseValid(utils::global_settings);
|
const auto license_check_result = license::global_license_checker.IsEnterpriseValid(utils::global_settings);
|
||||||
if (license_check_result.HasError()) {
|
if (license_check_result.HasError()) {
|
||||||
spdlog::warn(license::LicenseCheckErrorToString(license_check_result.GetError(), "authentication modules"));
|
spdlog::warn(license::LicenseCheckErrorToString(license_check_result.GetError(), "authentication modules"));
|
||||||
@@ -265,64 +92,98 @@ std::optional<UserOrRole> Auth::Authenticate(const std::string &username, const
|
|||||||
auto is_authenticated = ret_authenticated.get<bool>();
|
auto is_authenticated = ret_authenticated.get<bool>();
|
||||||
const auto &rolename = ret_role.get<std::string>();
|
const auto &rolename = ret_role.get<std::string>();
|
||||||
|
|
||||||
// Check if role is present
|
|
||||||
auto role = GetRole(rolename);
|
|
||||||
if (!role) {
|
|
||||||
spdlog::warn(utils::MessageWithLink("Couldn't authenticate user '{}' because the role '{}' doesn't exist.",
|
|
||||||
username, rolename, "https://memgr.ph/auth"));
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authenticate the user.
|
// Authenticate the user.
|
||||||
if (!is_authenticated) return std::nullopt;
|
if (!is_authenticated) return std::nullopt;
|
||||||
|
|
||||||
return RoleWUsername{username, std::move(*role)};
|
// Find or create the user and return it.
|
||||||
}
|
auto user = GetUser(username);
|
||||||
|
if (!user) {
|
||||||
/*
|
if (FLAGS_auth_module_create_missing_user) {
|
||||||
* LOCAL AUTH STORAGE
|
user = AddUser(username, password);
|
||||||
*/
|
if (!user) {
|
||||||
auto user = GetUser(username);
|
spdlog::warn(utils::MessageWithLink(
|
||||||
if (!user) {
|
"Couldn't create the missing user '{}' using the auth module because the user already exists as a role.",
|
||||||
spdlog::warn(utils::MessageWithLink("Couldn't authenticate user '{}' because the user doesn't exist.", username,
|
username, "https://memgr.ph/auth"));
|
||||||
"https://memgr.ph/auth"));
|
return std::nullopt;
|
||||||
return std::nullopt;
|
}
|
||||||
}
|
} else {
|
||||||
if (!user->CheckPassword(password)) {
|
spdlog::warn(utils::MessageWithLink(
|
||||||
spdlog::warn(utils::MessageWithLink("Couldn't authenticate user '{}' because the password is not correct.",
|
"Couldn't authenticate user '{}' using the auth module because the user doesn't exist.", username,
|
||||||
username, "https://memgr.ph/auth"));
|
"https://memgr.ph/auth"));
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
if (user->UpgradeHash(password)) {
|
} else {
|
||||||
|
user->UpdatePassword(password);
|
||||||
|
}
|
||||||
|
if (FLAGS_auth_module_manage_roles) {
|
||||||
|
if (!rolename.empty()) {
|
||||||
|
auto role = GetRole(rolename);
|
||||||
|
if (!role) {
|
||||||
|
if (FLAGS_auth_module_create_missing_role) {
|
||||||
|
role = AddRole(rolename);
|
||||||
|
if (!role) {
|
||||||
|
spdlog::warn(
|
||||||
|
utils::MessageWithLink("Couldn't authenticate user '{}' using the auth module because the user's "
|
||||||
|
"role '{}' already exists as a user.",
|
||||||
|
username, rolename, "https://memgr.ph/auth"));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
SaveRole(*role);
|
||||||
|
} else {
|
||||||
|
spdlog::warn(utils::MessageWithLink(
|
||||||
|
"Couldn't authenticate user '{}' using the auth module because the user's role '{}' doesn't exist.",
|
||||||
|
username, rolename, "https://memgr.ph/auth"));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user->SetRole(*role);
|
||||||
|
} else {
|
||||||
|
user->ClearRole();
|
||||||
|
}
|
||||||
|
}
|
||||||
SaveUser(*user);
|
SaveUser(*user);
|
||||||
|
return user;
|
||||||
|
} else {
|
||||||
|
auto user = GetUser(username);
|
||||||
|
if (!user) {
|
||||||
|
spdlog::warn(utils::MessageWithLink("Couldn't authenticate user '{}' because the user doesn't exist.", username,
|
||||||
|
"https://memgr.ph/auth"));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
if (!user->CheckPassword(password)) {
|
||||||
|
spdlog::warn(utils::MessageWithLink("Couldn't authenticate user '{}' because the password is not correct.",
|
||||||
|
username, "https://memgr.ph/auth"));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::LinkUser(User &user) const {
|
std::optional<User> Auth::GetUser(const std::string &username_orig) const {
|
||||||
auto link = storage_.Get(kLinkPrefix + user.username());
|
auto username = utils::ToLowerCase(username_orig);
|
||||||
|
auto existing_user = storage_.Get(kUserPrefix + username);
|
||||||
|
if (!existing_user) return std::nullopt;
|
||||||
|
|
||||||
|
nlohmann::json data;
|
||||||
|
try {
|
||||||
|
data = nlohmann::json::parse(*existing_user);
|
||||||
|
} catch (const nlohmann::json::parse_error &e) {
|
||||||
|
throw AuthException("Couldn't load user data!");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto user = User::Deserialize(data);
|
||||||
|
auto link = storage_.Get(kLinkPrefix + username);
|
||||||
|
|
||||||
if (link) {
|
if (link) {
|
||||||
auto role = GetRole(*link);
|
auto role = GetRole(*link);
|
||||||
if (role) {
|
if (role) {
|
||||||
user.SetRole(*role);
|
user.SetRole(*role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<User> Auth::GetUser(const std::string &username_orig) const {
|
|
||||||
if (module_.IsUsed()) return std::nullopt; // User's are not supported when using module
|
|
||||||
auto username = utils::ToLowerCase(username_orig);
|
|
||||||
auto existing_user = storage_.Get(kUserPrefix + username);
|
|
||||||
if (!existing_user) return std::nullopt;
|
|
||||||
|
|
||||||
auto user = User::Deserialize(ParseJson(*existing_user));
|
|
||||||
LinkUser(user);
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::SaveUser(const User &user, system::Transaction *system_tx) {
|
void Auth::SaveUser(const User &user) {
|
||||||
DisableIfModuleUsed();
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (const auto *role = user.role(); role != nullptr) {
|
if (const auto *role = user.role(); role != nullptr) {
|
||||||
success = storage_.PutMultiple(
|
success = storage_.PutMultiple(
|
||||||
@@ -334,83 +195,26 @@ void Auth::SaveUser(const User &user, system::Transaction *system_tx) {
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
throw AuthException("Couldn't save user '{}'!", user.username());
|
throw AuthException("Couldn't save user '{}'!", user.username());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Durability updated -> new epoch
|
|
||||||
UpdateEpoch();
|
|
||||||
|
|
||||||
// All changes to the user end up calling this function, so no need to add a delta anywhere else
|
|
||||||
if (system_tx) {
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
system_tx->AddAction<UpdateAuthData>(user);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::UpdatePassword(auth::User &user, const std::optional<std::string> &password) {
|
std::optional<User> Auth::AddUser(const std::string &username, const std::optional<std::string> &password) {
|
||||||
DisableIfModuleUsed();
|
|
||||||
// Check if null
|
|
||||||
if (!password) {
|
|
||||||
if (!config_.password_permit_null) {
|
|
||||||
throw AuthException("Null passwords aren't permitted!");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Check if compliant with our filter
|
|
||||||
if (config_.custom_password_regex) {
|
|
||||||
if (const auto license_check_result = license::global_license_checker.IsEnterpriseValid(utils::global_settings);
|
|
||||||
license_check_result.HasError()) {
|
|
||||||
throw AuthException(
|
|
||||||
"Custom password regex is a Memgraph Enterprise feature. Please set the config "
|
|
||||||
"(\"--auth-password-strength-regex\") to its default value (\"{}\") or remove the flag.\n{}",
|
|
||||||
glue::kDefaultPasswordRegex,
|
|
||||||
license::LicenseCheckErrorToString(license_check_result.GetError(), "password regex"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!std::regex_match(*password, config_.password_regex)) {
|
|
||||||
throw AuthException(
|
|
||||||
"The user password doesn't conform to the required strength! Regex: "
|
|
||||||
"\"{}\"",
|
|
||||||
config_.password_regex_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All checks passed; update
|
|
||||||
user.UpdatePassword(password);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<User> Auth::AddUser(const std::string &username, const std::optional<std::string> &password,
|
|
||||||
system::Transaction *system_tx) {
|
|
||||||
DisableIfModuleUsed();
|
|
||||||
if (!NameRegexMatch(username)) {
|
|
||||||
throw AuthException("Invalid user name.");
|
|
||||||
}
|
|
||||||
auto existing_user = GetUser(username);
|
auto existing_user = GetUser(username);
|
||||||
if (existing_user) return std::nullopt;
|
if (existing_user) return std::nullopt;
|
||||||
auto existing_role = GetRole(username);
|
auto existing_role = GetRole(username);
|
||||||
if (existing_role) return std::nullopt;
|
if (existing_role) return std::nullopt;
|
||||||
auto new_user = User(username);
|
auto new_user = User(username);
|
||||||
UpdatePassword(new_user, password);
|
new_user.UpdatePassword(password);
|
||||||
SaveUser(new_user, system_tx);
|
SaveUser(new_user);
|
||||||
return new_user;
|
return new_user;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Auth::RemoveUser(const std::string &username_orig, system::Transaction *system_tx) {
|
bool Auth::RemoveUser(const std::string &username_orig) {
|
||||||
DisableIfModuleUsed();
|
|
||||||
auto username = utils::ToLowerCase(username_orig);
|
auto username = utils::ToLowerCase(username_orig);
|
||||||
if (!storage_.Get(kUserPrefix + username)) return false;
|
if (!storage_.Get(kUserPrefix + username)) return false;
|
||||||
std::vector<std::string> keys({kLinkPrefix + username, kUserPrefix + username});
|
std::vector<std::string> keys({kLinkPrefix + username, kUserPrefix + username});
|
||||||
if (!storage_.DeleteMultiple(keys)) {
|
if (!storage_.DeleteMultiple(keys)) {
|
||||||
throw AuthException("Couldn't remove user '{}'!", username);
|
throw AuthException("Couldn't remove user '{}'!", username);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Durability updated -> new epoch
|
|
||||||
UpdateEpoch();
|
|
||||||
|
|
||||||
// Handling drop user delta
|
|
||||||
if (system_tx) {
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
system_tx->AddAction<DropAuthData>(DropAuthData::AuthDataType::USER, username);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,28 +223,9 @@ std::vector<auth::User> Auth::AllUsers() const {
|
|||||||
for (auto it = storage_.begin(kUserPrefix); it != storage_.end(kUserPrefix); ++it) {
|
for (auto it = storage_.begin(kUserPrefix); it != storage_.end(kUserPrefix); ++it) {
|
||||||
auto username = it->first.substr(kUserPrefix.size());
|
auto username = it->first.substr(kUserPrefix.size());
|
||||||
if (username != utils::ToLowerCase(username)) continue;
|
if (username != utils::ToLowerCase(username)) continue;
|
||||||
try {
|
auto user = GetUser(username);
|
||||||
User user = auth::User::Deserialize(ParseJson(it->second)); // Will throw on failure
|
if (user) {
|
||||||
LinkUser(user);
|
ret.push_back(std::move(*user));
|
||||||
ret.emplace_back(std::move(user));
|
|
||||||
} catch (AuthException &) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> Auth::AllUsernames() const {
|
|
||||||
std::vector<std::string> ret;
|
|
||||||
for (auto it = storage_.begin(kUserPrefix); it != storage_.end(kUserPrefix); ++it) {
|
|
||||||
auto username = it->first.substr(kUserPrefix.size());
|
|
||||||
if (username != utils::ToLowerCase(username)) continue;
|
|
||||||
try {
|
|
||||||
// Check if serialized correctly
|
|
||||||
memgraph::auth::User::Deserialize(ParseJson(it->second)); // Will throw on failure
|
|
||||||
ret.emplace_back(std::move(username));
|
|
||||||
} catch (AuthException &) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -448,44 +233,38 @@ std::vector<std::string> Auth::AllUsernames() const {
|
|||||||
|
|
||||||
bool Auth::HasUsers() const { return storage_.begin(kUserPrefix) != storage_.end(kUserPrefix); }
|
bool Auth::HasUsers() const { return storage_.begin(kUserPrefix) != storage_.end(kUserPrefix); }
|
||||||
|
|
||||||
bool Auth::AccessControlled() const { return HasUsers() || module_.IsUsed(); }
|
|
||||||
|
|
||||||
std::optional<Role> Auth::GetRole(const std::string &rolename_orig) const {
|
std::optional<Role> Auth::GetRole(const std::string &rolename_orig) const {
|
||||||
auto rolename = utils::ToLowerCase(rolename_orig);
|
auto rolename = utils::ToLowerCase(rolename_orig);
|
||||||
auto existing_role = storage_.Get(kRolePrefix + rolename);
|
auto existing_role = storage_.Get(kRolePrefix + rolename);
|
||||||
if (!existing_role) return std::nullopt;
|
if (!existing_role) return std::nullopt;
|
||||||
|
|
||||||
return Role::Deserialize(ParseJson(*existing_role));
|
nlohmann::json data;
|
||||||
|
try {
|
||||||
|
data = nlohmann::json::parse(*existing_role);
|
||||||
|
} catch (const nlohmann::json::parse_error &e) {
|
||||||
|
throw AuthException("Couldn't load role data!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Role::Deserialize(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::SaveRole(const Role &role, system::Transaction *system_tx) {
|
void Auth::SaveRole(const Role &role) {
|
||||||
if (!storage_.Put(kRolePrefix + role.rolename(), role.Serialize().dump())) {
|
if (!storage_.Put(kRolePrefix + role.rolename(), role.Serialize().dump())) {
|
||||||
throw AuthException("Couldn't save role '{}'!", role.rolename());
|
throw AuthException("Couldn't save role '{}'!", role.rolename());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Durability updated -> new epoch
|
|
||||||
UpdateEpoch();
|
|
||||||
|
|
||||||
// All changes to the role end up calling this function, so no need to add a delta anywhere else
|
|
||||||
if (system_tx) {
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
system_tx->AddAction<UpdateAuthData>(role);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Role> Auth::AddRole(const std::string &rolename, system::Transaction *system_tx) {
|
std::optional<Role> Auth::AddRole(const std::string &rolename) {
|
||||||
if (!NameRegexMatch(rolename)) {
|
auto existing_role = GetRole(rolename);
|
||||||
throw AuthException("Invalid role name.");
|
if (existing_role) return std::nullopt;
|
||||||
}
|
auto existing_user = GetUser(rolename);
|
||||||
if (auto existing_role = GetRole(rolename)) return std::nullopt;
|
if (existing_user) return std::nullopt;
|
||||||
if (auto existing_user = GetUser(rolename)) return std::nullopt;
|
|
||||||
auto new_role = Role(rolename);
|
auto new_role = Role(rolename);
|
||||||
SaveRole(new_role, system_tx);
|
SaveRole(new_role);
|
||||||
return new_role;
|
return new_role;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Auth::RemoveRole(const std::string &rolename_orig, system::Transaction *system_tx) {
|
bool Auth::RemoveRole(const std::string &rolename_orig) {
|
||||||
auto rolename = utils::ToLowerCase(rolename_orig);
|
auto rolename = utils::ToLowerCase(rolename_orig);
|
||||||
if (!storage_.Get(kRolePrefix + rolename)) return false;
|
if (!storage_.Get(kRolePrefix + rolename)) return false;
|
||||||
std::vector<std::string> keys;
|
std::vector<std::string> keys;
|
||||||
@@ -498,16 +277,6 @@ bool Auth::RemoveRole(const std::string &rolename_orig, system::Transaction *sys
|
|||||||
if (!storage_.DeleteMultiple(keys)) {
|
if (!storage_.DeleteMultiple(keys)) {
|
||||||
throw AuthException("Couldn't remove role '{}'!", rolename);
|
throw AuthException("Couldn't remove role '{}'!", rolename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Durability updated -> new epoch
|
|
||||||
UpdateEpoch();
|
|
||||||
|
|
||||||
// Handling drop role delta
|
|
||||||
if (system_tx) {
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
system_tx->AddAction<DropAuthData>(DropAuthData::AuthDataType::ROLE, rolename);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,38 +285,26 @@ std::vector<auth::Role> Auth::AllRoles() const {
|
|||||||
for (auto it = storage_.begin(kRolePrefix); it != storage_.end(kRolePrefix); ++it) {
|
for (auto it = storage_.begin(kRolePrefix); it != storage_.end(kRolePrefix); ++it) {
|
||||||
auto rolename = it->first.substr(kRolePrefix.size());
|
auto rolename = it->first.substr(kRolePrefix.size());
|
||||||
if (rolename != utils::ToLowerCase(rolename)) continue;
|
if (rolename != utils::ToLowerCase(rolename)) continue;
|
||||||
Role role = memgraph::auth::Role::Deserialize(ParseJson(it->second)); // Will throw on failure
|
auto role = GetRole(rolename);
|
||||||
ret.emplace_back(std::move(role));
|
if (role) {
|
||||||
}
|
ret.push_back(*role);
|
||||||
return ret;
|
} else {
|
||||||
}
|
throw AuthException("Couldn't load role '{}'!", rolename);
|
||||||
|
|
||||||
std::vector<std::string> Auth::AllRolenames() const {
|
|
||||||
std::vector<std::string> ret;
|
|
||||||
for (auto it = storage_.begin(kRolePrefix); it != storage_.end(kRolePrefix); ++it) {
|
|
||||||
auto rolename = it->first.substr(kRolePrefix.size());
|
|
||||||
if (rolename != utils::ToLowerCase(rolename)) continue;
|
|
||||||
try {
|
|
||||||
// Check that the data is serialized correctly
|
|
||||||
memgraph::auth::Role::Deserialize(ParseJson(it->second));
|
|
||||||
ret.emplace_back(std::move(rolename));
|
|
||||||
} catch (AuthException &) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<auth::User> Auth::AllUsersForRole(const std::string &rolename_orig) const {
|
std::vector<auth::User> Auth::AllUsersForRole(const std::string &rolename_orig) const {
|
||||||
DisableIfModuleUsed();
|
auto rolename = utils::ToLowerCase(rolename_orig);
|
||||||
const auto rolename = utils::ToLowerCase(rolename_orig);
|
|
||||||
std::vector<auth::User> ret;
|
std::vector<auth::User> ret;
|
||||||
for (auto it = storage_.begin(kLinkPrefix); it != storage_.end(kLinkPrefix); ++it) {
|
for (auto it = storage_.begin(kLinkPrefix); it != storage_.end(kLinkPrefix); ++it) {
|
||||||
auto username = it->first.substr(kLinkPrefix.size());
|
auto username = it->first.substr(kLinkPrefix.size());
|
||||||
if (username != utils::ToLowerCase(username)) continue;
|
if (username != utils::ToLowerCase(username)) continue;
|
||||||
if (it->second != utils::ToLowerCase(it->second)) continue;
|
if (it->second != utils::ToLowerCase(it->second)) continue;
|
||||||
if (it->second == rolename) {
|
if (it->second == rolename) {
|
||||||
if (auto user = GetUser(username)) {
|
auto user = GetUser(username);
|
||||||
|
if (user) {
|
||||||
ret.push_back(std::move(*user));
|
ret.push_back(std::move(*user));
|
||||||
} else {
|
} else {
|
||||||
throw AuthException("Couldn't load user '{}'!", username);
|
throw AuthException("Couldn't load user '{}'!", username);
|
||||||
@@ -558,192 +315,56 @@ std::vector<auth::User> Auth::AllUsersForRole(const std::string &rolename_orig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
Auth::Result Auth::GrantDatabase(const std::string &db, const std::string &name, system::Transaction *system_tx) {
|
bool Auth::GrantDatabaseToUser(const std::string &db, const std::string &name) {
|
||||||
using enum Auth::Result;
|
auto user = GetUser(name);
|
||||||
if (module_.IsUsed()) {
|
if (user) {
|
||||||
if (auto role = GetRole(name)) {
|
if (db == kAllDatabases) {
|
||||||
GrantDatabase(db, *role, system_tx);
|
user->db_access().GrantAll();
|
||||||
return SUCCESS;
|
} else {
|
||||||
|
user->db_access().Add(db);
|
||||||
}
|
}
|
||||||
return NO_ROLE;
|
SaveUser(*user);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (auto user = GetUser(name)) {
|
return false;
|
||||||
GrantDatabase(db, *user, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
if (auto role = GetRole(name)) {
|
|
||||||
GrantDatabase(db, *role, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
return NO_USER_ROLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::GrantDatabase(const std::string &db, User &user, system::Transaction *system_tx) {
|
bool Auth::RevokeDatabaseFromUser(const std::string &db, const std::string &name) {
|
||||||
if (db == kAllDatabases) {
|
auto user = GetUser(name);
|
||||||
user.db_access().GrantAll();
|
if (user) {
|
||||||
} else {
|
if (db == kAllDatabases) {
|
||||||
user.db_access().Grant(db);
|
user->db_access().DenyAll();
|
||||||
}
|
} else {
|
||||||
SaveUser(user, system_tx);
|
user->db_access().Remove(db);
|
||||||
}
|
|
||||||
|
|
||||||
void Auth::GrantDatabase(const std::string &db, Role &role, system::Transaction *system_tx) {
|
|
||||||
if (db == kAllDatabases) {
|
|
||||||
role.db_access().GrantAll();
|
|
||||||
} else {
|
|
||||||
role.db_access().Grant(db);
|
|
||||||
}
|
|
||||||
SaveRole(role, system_tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
Auth::Result Auth::DenyDatabase(const std::string &db, const std::string &name, system::Transaction *system_tx) {
|
|
||||||
using enum Auth::Result;
|
|
||||||
if (module_.IsUsed()) {
|
|
||||||
if (auto role = GetRole(name)) {
|
|
||||||
DenyDatabase(db, *role, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
}
|
||||||
return NO_ROLE;
|
SaveUser(*user);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (auto user = GetUser(name)) {
|
return false;
|
||||||
DenyDatabase(db, *user, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
if (auto role = GetRole(name)) {
|
|
||||||
DenyDatabase(db, *role, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
return NO_USER_ROLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Auth::DenyDatabase(const std::string &db, User &user, system::Transaction *system_tx) {
|
void Auth::DeleteDatabase(const std::string &db) {
|
||||||
if (db == kAllDatabases) {
|
|
||||||
user.db_access().DenyAll();
|
|
||||||
} else {
|
|
||||||
user.db_access().Deny(db);
|
|
||||||
}
|
|
||||||
SaveUser(user, system_tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Auth::DenyDatabase(const std::string &db, Role &role, system::Transaction *system_tx) {
|
|
||||||
if (db == kAllDatabases) {
|
|
||||||
role.db_access().DenyAll();
|
|
||||||
} else {
|
|
||||||
role.db_access().Deny(db);
|
|
||||||
}
|
|
||||||
SaveRole(role, system_tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
Auth::Result Auth::RevokeDatabase(const std::string &db, const std::string &name, system::Transaction *system_tx) {
|
|
||||||
using enum Auth::Result;
|
|
||||||
if (module_.IsUsed()) {
|
|
||||||
if (auto role = GetRole(name)) {
|
|
||||||
RevokeDatabase(db, *role, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
return NO_ROLE;
|
|
||||||
}
|
|
||||||
if (auto user = GetUser(name)) {
|
|
||||||
RevokeDatabase(db, *user, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
if (auto role = GetRole(name)) {
|
|
||||||
RevokeDatabase(db, *role, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
return NO_USER_ROLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Auth::RevokeDatabase(const std::string &db, User &user, system::Transaction *system_tx) {
|
|
||||||
if (db == kAllDatabases) {
|
|
||||||
user.db_access().RevokeAll();
|
|
||||||
} else {
|
|
||||||
user.db_access().Revoke(db);
|
|
||||||
}
|
|
||||||
SaveUser(user, system_tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Auth::RevokeDatabase(const std::string &db, Role &role, system::Transaction *system_tx) {
|
|
||||||
if (db == kAllDatabases) {
|
|
||||||
role.db_access().RevokeAll();
|
|
||||||
} else {
|
|
||||||
role.db_access().Revoke(db);
|
|
||||||
}
|
|
||||||
SaveRole(role, system_tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Auth::DeleteDatabase(const std::string &db, system::Transaction *system_tx) {
|
|
||||||
for (auto it = storage_.begin(kUserPrefix); it != storage_.end(kUserPrefix); ++it) {
|
for (auto it = storage_.begin(kUserPrefix); it != storage_.end(kUserPrefix); ++it) {
|
||||||
auto username = it->first.substr(kUserPrefix.size());
|
auto username = it->first.substr(kUserPrefix.size());
|
||||||
try {
|
auto user = GetUser(username);
|
||||||
User user = auth::User::Deserialize(ParseJson(it->second));
|
if (user) {
|
||||||
LinkUser(user);
|
user->db_access().Delete(db);
|
||||||
user.db_access().Revoke(db);
|
SaveUser(*user);
|
||||||
SaveUser(user, system_tx);
|
|
||||||
} catch (AuthException &) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto it = storage_.begin(kRolePrefix); it != storage_.end(kRolePrefix); ++it) {
|
|
||||||
auto rolename = it->first.substr(kRolePrefix.size());
|
|
||||||
try {
|
|
||||||
auto role = memgraph::auth::Role::Deserialize(ParseJson(it->second));
|
|
||||||
role.db_access().Revoke(db);
|
|
||||||
SaveRole(role, system_tx);
|
|
||||||
} catch (AuthException &) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth::Result Auth::SetMainDatabase(std::string_view db, const std::string &name, system::Transaction *system_tx) {
|
bool Auth::SetMainDatabase(const std::string &db, const std::string &name) {
|
||||||
using enum Auth::Result;
|
auto user = GetUser(name);
|
||||||
if (module_.IsUsed()) {
|
if (user) {
|
||||||
if (auto role = GetRole(name)) {
|
if (!user->db_access().SetDefault(db)) {
|
||||||
SetMainDatabase(db, *role, system_tx);
|
throw AuthException("Couldn't set default database '{}' for user '{}'!", db, name);
|
||||||
return SUCCESS;
|
|
||||||
}
|
}
|
||||||
return NO_ROLE;
|
SaveUser(*user);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (auto user = GetUser(name)) {
|
return false;
|
||||||
SetMainDatabase(db, *user, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
if (auto role = GetRole(name)) {
|
|
||||||
SetMainDatabase(db, *role, system_tx);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
return NO_USER_ROLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Auth::SetMainDatabase(std::string_view db, User &user, system::Transaction *system_tx) {
|
|
||||||
if (!user.db_access().SetMain(db)) {
|
|
||||||
throw AuthException("Couldn't set default database '{}' for '{}'!", db, user.username());
|
|
||||||
}
|
|
||||||
SaveUser(user, system_tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Auth::SetMainDatabase(std::string_view db, Role &role, system::Transaction *system_tx) {
|
|
||||||
if (!role.db_access().SetMain(db)) {
|
|
||||||
throw AuthException("Couldn't set default database '{}' for '{}'!", db, role.rolename());
|
|
||||||
}
|
|
||||||
SaveRole(role, system_tx);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool Auth::NameRegexMatch(const std::string &user_or_role) const {
|
|
||||||
if (config_.custom_name_regex) {
|
|
||||||
if (const auto license_check_result =
|
|
||||||
memgraph::license::global_license_checker.IsEnterpriseValid(memgraph::utils::global_settings);
|
|
||||||
license_check_result.HasError()) {
|
|
||||||
throw memgraph::auth::AuthException(
|
|
||||||
"Custom user/role regex is a Memgraph Enterprise feature. Please set the config "
|
|
||||||
"(\"--auth-user-or-role-name-regex\") to its default value (\"{}\") or remove the flag.\n{}",
|
|
||||||
glue::kDefaultUserRoleRegex,
|
|
||||||
memgraph::license::LicenseCheckErrorToString(license_check_result.GetError(), "user/role regex"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::regex_match(user_or_role, config_.name_regex);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace memgraph::auth
|
} // namespace memgraph::auth
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -10,37 +10,18 @@
|
|||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <regex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "auth/exceptions.hpp"
|
#include "auth/exceptions.hpp"
|
||||||
#include "auth/models.hpp"
|
#include "auth/models.hpp"
|
||||||
#include "auth/module.hpp"
|
#include "auth/module.hpp"
|
||||||
#include "glue/auth_global.hpp"
|
|
||||||
#include "kvstore/kvstore.hpp"
|
#include "kvstore/kvstore.hpp"
|
||||||
#include "system/action.hpp"
|
|
||||||
#include "utils/settings.hpp"
|
#include "utils/settings.hpp"
|
||||||
#include "utils/synchronized.hpp"
|
|
||||||
|
|
||||||
namespace memgraph::auth {
|
namespace memgraph::auth {
|
||||||
|
|
||||||
class Auth;
|
|
||||||
using SynchedAuth = memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock>;
|
|
||||||
|
|
||||||
static const constexpr char *const kAllDatabases = "*";
|
static const constexpr char *const kAllDatabases = "*";
|
||||||
|
|
||||||
struct RoleWUsername : Role {
|
|
||||||
template <typename... Args>
|
|
||||||
RoleWUsername(std::string_view username, Args &&...args) : Role{std::forward<Args>(args)...}, username_{username} {}
|
|
||||||
|
|
||||||
std::string username() { return username_; }
|
|
||||||
const std::string &username() const { return username_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string username_;
|
|
||||||
};
|
|
||||||
using UserOrRole = std::variant<User, RoleWUsername>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class serves as the main Authentication/Authorization storage.
|
* This class serves as the main Authentication/Authorization storage.
|
||||||
* It provides functions for managing Users, Roles, Permissions and FineGrainedAccessPermissions.
|
* It provides functions for managing Users, Roles, Permissions and FineGrainedAccessPermissions.
|
||||||
@@ -50,66 +31,7 @@ using UserOrRole = std::variant<User, RoleWUsername>;
|
|||||||
*/
|
*/
|
||||||
class Auth final {
|
class Auth final {
|
||||||
public:
|
public:
|
||||||
struct Config {
|
explicit Auth(const std::string &storage_directory);
|
||||||
Config() {}
|
|
||||||
Config(std::string name_regex, std::string password_regex, bool password_permit_null)
|
|
||||||
: name_regex_str{std::move(name_regex)},
|
|
||||||
password_regex_str{std::move(password_regex)},
|
|
||||||
password_permit_null{password_permit_null},
|
|
||||||
custom_name_regex{name_regex_str != glue::kDefaultUserRoleRegex},
|
|
||||||
name_regex{name_regex_str},
|
|
||||||
custom_password_regex{password_regex_str != glue::kDefaultPasswordRegex},
|
|
||||||
password_regex{password_regex_str} {}
|
|
||||||
|
|
||||||
std::string name_regex_str{glue::kDefaultUserRoleRegex};
|
|
||||||
std::string password_regex_str{glue::kDefaultPasswordRegex};
|
|
||||||
bool password_permit_null{true};
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class Auth;
|
|
||||||
bool custom_name_regex{false};
|
|
||||||
std::regex name_regex{name_regex_str};
|
|
||||||
bool custom_password_regex{false};
|
|
||||||
std::regex password_regex{password_regex_str};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Epoch {
|
|
||||||
Epoch() : epoch_{0} {}
|
|
||||||
Epoch(unsigned e) : epoch_{e} {}
|
|
||||||
|
|
||||||
Epoch operator++() { return ++epoch_; }
|
|
||||||
bool operator==(const Epoch &rhs) const = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned epoch_;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Epoch kStartEpoch;
|
|
||||||
|
|
||||||
enum class Result {
|
|
||||||
SUCCESS,
|
|
||||||
NO_USER_ROLE,
|
|
||||||
NO_ROLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit Auth(std::string storage_directory, Config config);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the Config object
|
|
||||||
*
|
|
||||||
* @param config
|
|
||||||
*/
|
|
||||||
void SetConfig(Config config) {
|
|
||||||
// NOTE: The Auth class itself is not thread-safe, higher-level code needs to synchronize it when using it.
|
|
||||||
config_ = std::move(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @return Config
|
|
||||||
*/
|
|
||||||
Config GetConfig() const { return config_; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates a user using his username and password.
|
* Authenticates a user using his username and password.
|
||||||
@@ -120,7 +42,7 @@ class Auth final {
|
|||||||
* @return a user when the username and password match, nullopt otherwise
|
* @return a user when the username and password match, nullopt otherwise
|
||||||
* @throw AuthException if unable to authenticate for whatever reason.
|
* @throw AuthException if unable to authenticate for whatever reason.
|
||||||
*/
|
*/
|
||||||
std::optional<UserOrRole> Authenticate(const std::string &username, const std::string &password);
|
std::optional<User> Authenticate(const std::string &username, const std::string &password);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a user from the storage.
|
* Gets a user from the storage.
|
||||||
@@ -132,8 +54,6 @@ class Auth final {
|
|||||||
*/
|
*/
|
||||||
std::optional<User> GetUser(const std::string &username) const;
|
std::optional<User> GetUser(const std::string &username) const;
|
||||||
|
|
||||||
void LinkUser(User &user) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a user object to the storage.
|
* Saves a user object to the storage.
|
||||||
*
|
*
|
||||||
@@ -141,7 +61,7 @@ class Auth final {
|
|||||||
*
|
*
|
||||||
* @throw AuthException if unable to save the user.
|
* @throw AuthException if unable to save the user.
|
||||||
*/
|
*/
|
||||||
void SaveUser(const User &user, system::Transaction *system_tx = nullptr);
|
void SaveUser(const User &user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a user if the user doesn't exist.
|
* Creates a user if the user doesn't exist.
|
||||||
@@ -152,8 +72,7 @@ class Auth final {
|
|||||||
* @return a user when the user is created, nullopt if the user exists
|
* @return a user when the user is created, nullopt if the user exists
|
||||||
* @throw AuthException if unable to save the user.
|
* @throw AuthException if unable to save the user.
|
||||||
*/
|
*/
|
||||||
std::optional<User> AddUser(const std::string &username, const std::optional<std::string> &password = std::nullopt,
|
std::optional<User> AddUser(const std::string &username, const std::optional<std::string> &password = std::nullopt);
|
||||||
system::Transaction *system_tx = nullptr);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a user from the storage.
|
* Removes a user from the storage.
|
||||||
@@ -164,15 +83,7 @@ class Auth final {
|
|||||||
* doesn't exist
|
* doesn't exist
|
||||||
* @throw AuthException if unable to remove the user.
|
* @throw AuthException if unable to remove the user.
|
||||||
*/
|
*/
|
||||||
bool RemoveUser(const std::string &username, system::Transaction *system_tx = nullptr);
|
bool RemoveUser(const std::string &username);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param password
|
|
||||||
*/
|
|
||||||
void UpdatePassword(auth::User &user, const std::optional<std::string> &password);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all users from the storage.
|
* Gets all users from the storage.
|
||||||
@@ -182,13 +93,6 @@ class Auth final {
|
|||||||
*/
|
*/
|
||||||
std::vector<User> AllUsers() const;
|
std::vector<User> AllUsers() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @return std::vector<std::string>
|
|
||||||
*/
|
|
||||||
std::vector<std::string> AllUsernames() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether there are users in the storage.
|
* Returns whether there are users in the storage.
|
||||||
*
|
*
|
||||||
@@ -196,13 +100,6 @@ class Auth final {
|
|||||||
*/
|
*/
|
||||||
bool HasUsers() const;
|
bool HasUsers() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the access is controlled by authentication/authorization.
|
|
||||||
*
|
|
||||||
* @return `true` if auth needs to run
|
|
||||||
*/
|
|
||||||
bool AccessControlled() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a role from the storage.
|
* Gets a role from the storage.
|
||||||
*
|
*
|
||||||
@@ -213,37 +110,6 @@ class Auth final {
|
|||||||
*/
|
*/
|
||||||
std::optional<Role> GetRole(const std::string &rolename) const;
|
std::optional<Role> GetRole(const std::string &rolename) const;
|
||||||
|
|
||||||
std::optional<UserOrRole> GetUserOrRole(const std::optional<std::string> &username,
|
|
||||||
const std::optional<std::string> &rolename) const {
|
|
||||||
auto expect = [](bool condition, std::string &&msg) {
|
|
||||||
if (!condition) throw AuthException(std::move(msg));
|
|
||||||
};
|
|
||||||
// Special case if we are using a module; we must find the specified role
|
|
||||||
if (module_.IsUsed()) {
|
|
||||||
expect(username && rolename, "When using a module, a role needs to be connected to a username.");
|
|
||||||
const auto role = GetRole(*rolename);
|
|
||||||
expect(role != std::nullopt, "No role named " + *rolename);
|
|
||||||
return UserOrRole(auth::RoleWUsername{*username, *role});
|
|
||||||
}
|
|
||||||
|
|
||||||
// First check if we need to find a role
|
|
||||||
if (username && rolename) {
|
|
||||||
const auto role = GetRole(*rolename);
|
|
||||||
expect(role != std::nullopt, "No role named " + *rolename);
|
|
||||||
return UserOrRole(auth::RoleWUsername{*username, *role});
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are only looking for a user
|
|
||||||
if (username) {
|
|
||||||
const auto user = GetUser(*username);
|
|
||||||
expect(user != std::nullopt, "No user named " + *username);
|
|
||||||
return *user;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No user or role
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a role object to the storage.
|
* Saves a role object to the storage.
|
||||||
*
|
*
|
||||||
@@ -251,7 +117,7 @@ class Auth final {
|
|||||||
*
|
*
|
||||||
* @throw AuthException if unable to save the role.
|
* @throw AuthException if unable to save the role.
|
||||||
*/
|
*/
|
||||||
void SaveRole(const Role &role, system::Transaction *system_tx = nullptr);
|
void SaveRole(const Role &role);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a role if the role doesn't exist.
|
* Creates a role if the role doesn't exist.
|
||||||
@@ -261,7 +127,7 @@ class Auth final {
|
|||||||
* @return a role when the role is created, nullopt if the role exists
|
* @return a role when the role is created, nullopt if the role exists
|
||||||
* @throw AuthException if unable to save the role.
|
* @throw AuthException if unable to save the role.
|
||||||
*/
|
*/
|
||||||
std::optional<Role> AddRole(const std::string &rolename, system::Transaction *system_tx = nullptr);
|
std::optional<Role> AddRole(const std::string &rolename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a role from the storage.
|
* Removes a role from the storage.
|
||||||
@@ -272,7 +138,7 @@ class Auth final {
|
|||||||
* doesn't exist
|
* doesn't exist
|
||||||
* @throw AuthException if unable to remove the role.
|
* @throw AuthException if unable to remove the role.
|
||||||
*/
|
*/
|
||||||
bool RemoveRole(const std::string &rolename, system::Transaction *system_tx = nullptr);
|
bool RemoveRole(const std::string &rolename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all roles from the storage.
|
* Gets all roles from the storage.
|
||||||
@@ -282,13 +148,6 @@ class Auth final {
|
|||||||
*/
|
*/
|
||||||
std::vector<Role> AllRoles() const;
|
std::vector<Role> AllRoles() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @return std::vector<std::string>
|
|
||||||
*/
|
|
||||||
std::vector<std::string> AllRolenames() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all users for a role from the storage.
|
* Gets all users for a role from the storage.
|
||||||
*
|
*
|
||||||
@@ -300,6 +159,16 @@ class Auth final {
|
|||||||
std::vector<User> AllUsersForRole(const std::string &rolename) const;
|
std::vector<User> AllUsersForRole(const std::string &rolename) const;
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
|
/**
|
||||||
|
* @brief Revoke access to individual database for a user.
|
||||||
|
*
|
||||||
|
* @param db name of the database to revoke
|
||||||
|
* @param name user's username
|
||||||
|
* @return true on success
|
||||||
|
* @throw AuthException if unable to find or update the user
|
||||||
|
*/
|
||||||
|
bool RevokeDatabaseFromUser(const std::string &db, const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Grant access to individual database for a user.
|
* @brief Grant access to individual database for a user.
|
||||||
*
|
*
|
||||||
@@ -308,33 +177,7 @@ class Auth final {
|
|||||||
* @return true on success
|
* @return true on success
|
||||||
* @throw AuthException if unable to find or update the user
|
* @throw AuthException if unable to find or update the user
|
||||||
*/
|
*/
|
||||||
Result GrantDatabase(const std::string &db, const std::string &name, system::Transaction *system_tx = nullptr);
|
bool GrantDatabaseToUser(const std::string &db, const std::string &name);
|
||||||
void GrantDatabase(const std::string &db, User &user, system::Transaction *system_tx = nullptr);
|
|
||||||
void GrantDatabase(const std::string &db, Role &role, system::Transaction *system_tx = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Revoke access to individual database for a user.
|
|
||||||
*
|
|
||||||
* @param db name of the database to revoke
|
|
||||||
* @param name user's username
|
|
||||||
* @return true on success
|
|
||||||
* @throw AuthException if unable to find or update the user
|
|
||||||
*/
|
|
||||||
Result DenyDatabase(const std::string &db, const std::string &name, system::Transaction *system_tx = nullptr);
|
|
||||||
void DenyDatabase(const std::string &db, User &user, system::Transaction *system_tx = nullptr);
|
|
||||||
void DenyDatabase(const std::string &db, Role &role, system::Transaction *system_tx = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Revoke access to individual database for a user.
|
|
||||||
*
|
|
||||||
* @param db name of the database to revoke
|
|
||||||
* @param name user's username
|
|
||||||
* @return true on success
|
|
||||||
* @throw AuthException if unable to find or update the user
|
|
||||||
*/
|
|
||||||
Result RevokeDatabase(const std::string &db, const std::string &name, system::Transaction *system_tx = nullptr);
|
|
||||||
void RevokeDatabase(const std::string &db, User &user, system::Transaction *system_tx = nullptr);
|
|
||||||
void RevokeDatabase(const std::string &db, Role &role, system::Transaction *system_tx = nullptr);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Delete a database from all users.
|
* @brief Delete a database from all users.
|
||||||
@@ -342,7 +185,7 @@ class Auth final {
|
|||||||
* @param db name of the database to delete
|
* @param db name of the database to delete
|
||||||
* @throw AuthException if unable to read data
|
* @throw AuthException if unable to read data
|
||||||
*/
|
*/
|
||||||
void DeleteDatabase(const std::string &db, system::Transaction *system_tx = nullptr);
|
void DeleteDatabase(const std::string &db);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set main database for an individual user.
|
* @brief Set main database for an individual user.
|
||||||
@@ -352,39 +195,14 @@ class Auth final {
|
|||||||
* @return true on success
|
* @return true on success
|
||||||
* @throw AuthException if unable to find or update the user
|
* @throw AuthException if unable to find or update the user
|
||||||
*/
|
*/
|
||||||
Result SetMainDatabase(std::string_view db, const std::string &name, system::Transaction *system_tx = nullptr);
|
bool SetMainDatabase(const std::string &db, const std::string &name);
|
||||||
void SetMainDatabase(std::string_view db, User &user, system::Transaction *system_tx = nullptr);
|
|
||||||
void SetMainDatabase(std::string_view db, Role &role, system::Transaction *system_tx = nullptr);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool UpToDate(Epoch &e) const {
|
|
||||||
bool res = e == epoch_;
|
|
||||||
e = epoch_;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @param user_or_role
|
|
||||||
* @return true
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
bool NameRegexMatch(const std::string &user_or_role) const;
|
|
||||||
|
|
||||||
void UpdateEpoch() { ++epoch_; }
|
|
||||||
|
|
||||||
void DisableIfModuleUsed() const {
|
|
||||||
if (module_.IsUsed()) throw AuthException("Operation not permited when using an authentication module.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Even though the `kvstore::KVStore` class is guaranteed to be thread-safe,
|
// Even though the `kvstore::KVStore` class is guaranteed to be thread-safe,
|
||||||
// Auth is not thread-safe because modifying users and roles might require
|
// Auth is not thread-safe because modifying users and roles might require
|
||||||
// more than one operation on the storage.
|
// more than one operation on the storage.
|
||||||
kvstore::KVStore storage_;
|
kvstore::KVStore storage_;
|
||||||
auth::Module module_;
|
auth::Module module_;
|
||||||
Config config_;
|
|
||||||
Epoch epoch_{kStartEpoch};
|
|
||||||
};
|
};
|
||||||
} // namespace memgraph::auth
|
} // namespace memgraph::auth
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -22,14 +22,10 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
inline constexpr std::array password_encryption_mappings{
|
||||||
constexpr auto kHashAlgo = "hash_algo";
|
std::pair{"bcrypt"sv, memgraph::auth::PasswordEncryptionAlgorithm::BCRYPT},
|
||||||
constexpr auto kPasswordHash = "password_hash";
|
std::pair{"sha256"sv, memgraph::auth::PasswordEncryptionAlgorithm::SHA256},
|
||||||
|
std::pair{"sha256-multiple"sv, memgraph::auth::PasswordEncryptionAlgorithm::SHA256_MULTIPLE}};
|
||||||
inline constexpr std::array password_hash_mappings{
|
|
||||||
std::pair{"bcrypt"sv, memgraph::auth::PasswordHashAlgorithm::BCRYPT},
|
|
||||||
std::pair{"sha256"sv, memgraph::auth::PasswordHashAlgorithm::SHA256},
|
|
||||||
std::pair{"sha256-multiple"sv, memgraph::auth::PasswordHashAlgorithm::SHA256_MULTIPLE}};
|
|
||||||
|
|
||||||
inline constexpr uint64_t ONE_SHA_ITERATION = 1;
|
inline constexpr uint64_t ONE_SHA_ITERATION = 1;
|
||||||
inline constexpr uint64_t MULTIPLE_SHA_ITERATIONS = 1024;
|
inline constexpr uint64_t MULTIPLE_SHA_ITERATIONS = 1024;
|
||||||
@@ -39,7 +35,7 @@ inline constexpr uint64_t MULTIPLE_SHA_ITERATIONS = 1024;
|
|||||||
DEFINE_VALIDATED_string(password_encryption_algorithm, "bcrypt",
|
DEFINE_VALIDATED_string(password_encryption_algorithm, "bcrypt",
|
||||||
"The password encryption algorithm used for authentication.", {
|
"The password encryption algorithm used for authentication.", {
|
||||||
if (const auto result =
|
if (const auto result =
|
||||||
memgraph::utils::IsValidEnumValueString(value, password_hash_mappings);
|
memgraph::utils::IsValidEnumValueString(value, password_encryption_mappings);
|
||||||
result.HasError()) {
|
result.HasError()) {
|
||||||
const auto error = result.GetError();
|
const auto error = result.GetError();
|
||||||
switch (error) {
|
switch (error) {
|
||||||
@@ -49,7 +45,7 @@ DEFINE_VALIDATED_string(password_encryption_algorithm, "bcrypt",
|
|||||||
}
|
}
|
||||||
case memgraph::utils::ValidationError::InvalidValue: {
|
case memgraph::utils::ValidationError::InvalidValue: {
|
||||||
std::cout << "Invalid value for password encryption algorithm. Allowed values: "
|
std::cout << "Invalid value for password encryption algorithm. Allowed values: "
|
||||||
<< memgraph::utils::GetAllowedEnumValuesString(password_hash_mappings)
|
<< memgraph::utils::GetAllowedEnumValuesString(password_encryption_mappings)
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -62,7 +58,7 @@ DEFINE_VALIDATED_string(password_encryption_algorithm, "bcrypt",
|
|||||||
|
|
||||||
namespace memgraph::auth {
|
namespace memgraph::auth {
|
||||||
namespace BCrypt {
|
namespace BCrypt {
|
||||||
std::string HashPassword(const std::string &password) {
|
std::string EncryptPassword(const std::string &password) {
|
||||||
char salt[BCRYPT_HASHSIZE];
|
char salt[BCRYPT_HASHSIZE];
|
||||||
char hash[BCRYPT_HASHSIZE];
|
char hash[BCRYPT_HASHSIZE];
|
||||||
|
|
||||||
@@ -90,30 +86,16 @@ bool VerifyPassword(const std::string &password, const std::string &hash) {
|
|||||||
} // namespace BCrypt
|
} // namespace BCrypt
|
||||||
|
|
||||||
namespace SHA {
|
namespace SHA {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr auto SHA_LENGTH = 64U;
|
|
||||||
constexpr auto SALT_SIZE = 16U;
|
|
||||||
constexpr auto SALT_SIZE_DURABLE = SALT_SIZE * 2;
|
|
||||||
|
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
std::string HashPasswordOpenSSL3(std::string_view password, const uint64_t number_of_iterations,
|
std::string EncryptPasswordOpenSSL3(const std::string &password, const uint64_t number_of_iterations) {
|
||||||
std::string_view salt) {
|
|
||||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
|
|
||||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||||
EVP_MD *md = EVP_MD_fetch(nullptr, "SHA2-256", nullptr);
|
EVP_MD *md = EVP_MD_fetch(nullptr, "SHA2-256", nullptr);
|
||||||
|
|
||||||
EVP_DigestInit_ex(ctx, md, nullptr);
|
EVP_DigestInit_ex(ctx, md, nullptr);
|
||||||
|
|
||||||
if (!salt.empty()) {
|
|
||||||
DMG_ASSERT(salt.size() == SALT_SIZE);
|
|
||||||
EVP_DigestUpdate(ctx, salt.data(), salt.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto i = 0; i < number_of_iterations; i++) {
|
for (auto i = 0; i < number_of_iterations; i++) {
|
||||||
EVP_DigestUpdate(ctx, password.data(), password.size());
|
EVP_DigestUpdate(ctx, password.c_str(), password.size());
|
||||||
}
|
}
|
||||||
EVP_DigestFinal_ex(ctx, hash, nullptr);
|
EVP_DigestFinal_ex(ctx, hash, nullptr);
|
||||||
|
|
||||||
@@ -121,11 +103,6 @@ std::string HashPasswordOpenSSL3(std::string_view password, const uint64_t numbe
|
|||||||
EVP_MD_CTX_free(ctx);
|
EVP_MD_CTX_free(ctx);
|
||||||
|
|
||||||
std::stringstream result_stream;
|
std::stringstream result_stream;
|
||||||
|
|
||||||
for (unsigned char salt_char : salt) {
|
|
||||||
result_stream << std::hex << std::setw(2) << std::setfill('0') << (((unsigned int)salt_char) & 0xFFU);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto hash_char : hash) {
|
for (auto hash_char : hash) {
|
||||||
result_stream << std::hex << std::setw(2) << std::setfill('0') << (int)hash_char;
|
result_stream << std::hex << std::setw(2) << std::setfill('0') << (int)hash_char;
|
||||||
}
|
}
|
||||||
@@ -133,27 +110,17 @@ std::string HashPasswordOpenSSL3(std::string_view password, const uint64_t numbe
|
|||||||
return result_stream.str();
|
return result_stream.str();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
std::string HashPasswordOpenSSL1_1(std::string_view password, const uint64_t number_of_iterations,
|
std::string EncryptPasswordOpenSSL1_1(const std::string &password, const uint64_t number_of_iterations) {
|
||||||
std::string_view salt) {
|
|
||||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
|
|
||||||
SHA256_CTX sha256;
|
SHA256_CTX sha256;
|
||||||
SHA256_Init(&sha256);
|
SHA256_Init(&sha256);
|
||||||
|
|
||||||
if (!salt.empty()) {
|
|
||||||
DMG_ASSERT(salt.size() == SALT_SIZE);
|
|
||||||
SHA256_Update(&sha256, salt.data(), salt.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto i = 0; i < number_of_iterations; i++) {
|
for (auto i = 0; i < number_of_iterations; i++) {
|
||||||
SHA256_Update(&sha256, password.data(), password.size());
|
SHA256_Update(&sha256, password.c_str(), password.size());
|
||||||
}
|
}
|
||||||
SHA256_Final(hash, &sha256);
|
SHA256_Final(hash, &sha256);
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
for (unsigned char salt_char : salt) {
|
|
||||||
ss << std::hex << std::setw(2) << std::setfill('0') << (((unsigned int)salt_char) & 0xFFU);
|
|
||||||
}
|
|
||||||
for (auto hash_char : hash) {
|
for (auto hash_char : hash) {
|
||||||
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash_char;
|
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash_char;
|
||||||
}
|
}
|
||||||
@@ -162,144 +129,55 @@ std::string HashPasswordOpenSSL1_1(std::string_view password, const uint64_t num
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string HashPassword(std::string_view password, const uint64_t number_of_iterations, std::string_view salt) {
|
std::string EncryptPassword(const std::string &password, const uint64_t number_of_iterations) {
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
return HashPasswordOpenSSL3(password, number_of_iterations, salt);
|
return EncryptPasswordOpenSSL3(password, number_of_iterations);
|
||||||
#else
|
#else
|
||||||
return HashPasswordOpenSSL1_1(password, number_of_iterations, salt);
|
return EncryptPasswordOpenSSL1_1(password, number_of_iterations);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ExtractSalt(std::string_view salt_durable) -> std::array<char, SALT_SIZE> {
|
bool VerifyPassword(const std::string &password, const std::string &hash, const uint64_t number_of_iterations) {
|
||||||
static_assert(SALT_SIZE_DURABLE % 2 == 0);
|
auto password_hash = EncryptPassword(password, number_of_iterations);
|
||||||
static_assert(SALT_SIZE_DURABLE / 2 == SALT_SIZE);
|
|
||||||
|
|
||||||
MG_ASSERT(salt_durable.size() == SALT_SIZE_DURABLE);
|
|
||||||
auto const *b = salt_durable.cbegin();
|
|
||||||
auto const *const e = salt_durable.cend();
|
|
||||||
|
|
||||||
auto salt = std::array<char, SALT_SIZE>{};
|
|
||||||
auto *inserter = salt.begin();
|
|
||||||
|
|
||||||
auto const toval = [](char a) -> uint8_t {
|
|
||||||
if ('0' <= a && a <= '9') {
|
|
||||||
return a - '0';
|
|
||||||
}
|
|
||||||
if ('a' <= a && a <= 'f') {
|
|
||||||
return 10 + (a - 'a');
|
|
||||||
}
|
|
||||||
MG_ASSERT(false, "Currupt hash, can't extract salt");
|
|
||||||
__builtin_unreachable();
|
|
||||||
};
|
|
||||||
|
|
||||||
for (; b != e; b += 2, ++inserter) {
|
|
||||||
*inserter = static_cast<char>(static_cast<uint8_t>(toval(b[0]) << 4U) | toval(b[1]));
|
|
||||||
}
|
|
||||||
return salt;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsSalted(std::string_view hash) { return hash.size() == SHA_LENGTH + SALT_SIZE_DURABLE; }
|
|
||||||
|
|
||||||
bool VerifyPassword(std::string_view password, std::string_view hash, const uint64_t number_of_iterations) {
|
|
||||||
auto password_hash = std::invoke([&] {
|
|
||||||
if (hash.size() == SHA_LENGTH) [[unlikely]] {
|
|
||||||
// Just SHA256
|
|
||||||
return HashPassword(password, number_of_iterations, {});
|
|
||||||
} else {
|
|
||||||
// SHA256 + SALT
|
|
||||||
MG_ASSERT(IsSalted(hash));
|
|
||||||
auto const salt_durable = std::string_view{hash.data(), SALT_SIZE_DURABLE};
|
|
||||||
std::array<char, SALT_SIZE> salt = ExtractSalt(salt_durable);
|
|
||||||
return HashPassword(password, number_of_iterations, {salt.data(), salt.size()});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return password_hash == hash;
|
return password_hash == hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
} // namespace SHA
|
} // namespace SHA
|
||||||
|
|
||||||
HashedPassword HashPassword(const std::string &password, std::optional<PasswordHashAlgorithm> override_algo) {
|
bool VerifyPassword(const std::string &password, const std::string &hash) {
|
||||||
auto const hash_algo = override_algo.value_or(CurrentHashAlgorithm());
|
const auto password_encryption_algorithm = utils::StringToEnum<PasswordEncryptionAlgorithm>(
|
||||||
auto password_hash = std::invoke([&] {
|
FLAGS_password_encryption_algorithm, password_encryption_mappings);
|
||||||
switch (hash_algo) {
|
|
||||||
case PasswordHashAlgorithm::BCRYPT: {
|
|
||||||
return BCrypt::HashPassword(password);
|
|
||||||
}
|
|
||||||
case PasswordHashAlgorithm::SHA256:
|
|
||||||
case PasswordHashAlgorithm::SHA256_MULTIPLE: {
|
|
||||||
auto gen = std::mt19937(std::random_device{}());
|
|
||||||
auto salt = std::array<char, SHA::SALT_SIZE>{};
|
|
||||||
auto dis = std::uniform_int_distribution<unsigned char>(0, 255);
|
|
||||||
std::generate(salt.begin(), salt.end(), [&]() { return dis(gen); });
|
|
||||||
auto iterations = (hash_algo == PasswordHashAlgorithm::SHA256) ? ONE_SHA_ITERATION : MULTIPLE_SHA_ITERATIONS;
|
|
||||||
return SHA::HashPassword(password, iterations, {salt.data(), salt.size()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return HashedPassword{hash_algo, std::move(password_hash)};
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
if (!password_encryption_algorithm.has_value()) {
|
||||||
|
throw AuthException("Invalid password encryption flag '{}'!", FLAGS_password_encryption_algorithm);
|
||||||
auto InternalParseHashAlgorithm(std::string_view algo) -> PasswordHashAlgorithm {
|
|
||||||
auto maybe_parsed = utils::StringToEnum<PasswordHashAlgorithm>(algo, password_hash_mappings);
|
|
||||||
if (!maybe_parsed) {
|
|
||||||
throw AuthException("Invalid password encryption '{}'!", algo);
|
|
||||||
}
|
}
|
||||||
return *maybe_parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
PasswordHashAlgorithm &InternalCurrentHashAlgorithm() {
|
switch (password_encryption_algorithm.value()) {
|
||||||
static auto current = PasswordHashAlgorithm::BCRYPT;
|
case PasswordEncryptionAlgorithm::BCRYPT:
|
||||||
static std::once_flag flag;
|
return BCrypt::VerifyPassword(password, hash);
|
||||||
std::call_once(flag, [] { current = InternalParseHashAlgorithm(FLAGS_password_encryption_algorithm); });
|
case PasswordEncryptionAlgorithm::SHA256:
|
||||||
return current;
|
return SHA::VerifyPassword(password, hash, ONE_SHA_ITERATION);
|
||||||
}
|
case PasswordEncryptionAlgorithm::SHA256_MULTIPLE:
|
||||||
} // namespace
|
return SHA::VerifyPassword(password, hash, MULTIPLE_SHA_ITERATIONS);
|
||||||
|
|
||||||
auto CurrentHashAlgorithm() -> PasswordHashAlgorithm { return InternalCurrentHashAlgorithm(); }
|
|
||||||
|
|
||||||
void SetHashAlgorithm(std::string_view algo) {
|
|
||||||
auto ¤t = InternalCurrentHashAlgorithm();
|
|
||||||
current = InternalParseHashAlgorithm(algo);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto AsString(PasswordHashAlgorithm hash_algo) -> std::string_view {
|
|
||||||
return *utils::EnumToString<PasswordHashAlgorithm>(hash_algo, password_hash_mappings);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HashedPassword::VerifyPassword(const std::string &password) {
|
|
||||||
switch (hash_algo) {
|
|
||||||
case PasswordHashAlgorithm::BCRYPT:
|
|
||||||
return BCrypt::VerifyPassword(password, password_hash);
|
|
||||||
case PasswordHashAlgorithm::SHA256:
|
|
||||||
return SHA::VerifyPassword(password, password_hash, ONE_SHA_ITERATION);
|
|
||||||
case PasswordHashAlgorithm::SHA256_MULTIPLE:
|
|
||||||
return SHA::VerifyPassword(password, password_hash, MULTIPLE_SHA_ITERATIONS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw AuthException("Invalid password encryption flag '{}'!", FLAGS_password_encryption_algorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void to_json(nlohmann::json &j, const HashedPassword &p) {
|
std::string EncryptPassword(const std::string &password) {
|
||||||
j = nlohmann::json{{kHashAlgo, p.hash_algo}, {kPasswordHash, p.password_hash}};
|
const auto password_encryption_algorithm = utils::StringToEnum<PasswordEncryptionAlgorithm>(
|
||||||
}
|
FLAGS_password_encryption_algorithm, password_encryption_mappings);
|
||||||
|
|
||||||
void from_json(const nlohmann::json &j, HashedPassword &p) {
|
if (!password_encryption_algorithm.has_value()) {
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
throw AuthException("Invalid password encryption flag '{}'!", FLAGS_password_encryption_algorithm);
|
||||||
PasswordHashAlgorithm hash_algo;
|
}
|
||||||
j.at(kHashAlgo).get_to(hash_algo);
|
|
||||||
auto password_hash = j.value(kPasswordHash, std::string());
|
|
||||||
p = HashedPassword{hash_algo, std::move(password_hash)};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HashedPassword::IsSalted() const {
|
switch (password_encryption_algorithm.value()) {
|
||||||
switch (hash_algo) {
|
case PasswordEncryptionAlgorithm::BCRYPT:
|
||||||
case PasswordHashAlgorithm::BCRYPT:
|
return BCrypt::EncryptPassword(password);
|
||||||
return true;
|
case PasswordEncryptionAlgorithm::SHA256:
|
||||||
case PasswordHashAlgorithm::SHA256:
|
return SHA::EncryptPassword(password, ONE_SHA_ITERATION);
|
||||||
case PasswordHashAlgorithm::SHA256_MULTIPLE:
|
case PasswordEncryptionAlgorithm::SHA256_MULTIPLE:
|
||||||
return SHA::IsSalted(password_hash);
|
return SHA::EncryptPassword(password, MULTIPLE_SHA_ITERATIONS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -8,47 +8,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <json/json.hpp>
|
|
||||||
|
|
||||||
namespace memgraph::auth {
|
namespace memgraph::auth {
|
||||||
/// Need to be stable, auth durability depends on this
|
enum class PasswordEncryptionAlgorithm : uint8_t { BCRYPT, SHA256, SHA256_MULTIPLE };
|
||||||
enum class PasswordHashAlgorithm : uint8_t { BCRYPT = 0, SHA256 = 1, SHA256_MULTIPLE = 2 };
|
|
||||||
|
|
||||||
void SetHashAlgorithm(std::string_view algo);
|
/// @throw AuthException if unable to encrypt the password.
|
||||||
|
std::string EncryptPassword(const std::string &password);
|
||||||
|
|
||||||
auto CurrentHashAlgorithm() -> PasswordHashAlgorithm;
|
/// @throw AuthException if unable to verify the password.
|
||||||
|
bool VerifyPassword(const std::string &password, const std::string &hash);
|
||||||
auto AsString(PasswordHashAlgorithm hash_algo) -> std::string_view;
|
|
||||||
|
|
||||||
struct HashedPassword {
|
|
||||||
HashedPassword() = default;
|
|
||||||
HashedPassword(PasswordHashAlgorithm hash_algo, std::string password_hash)
|
|
||||||
: hash_algo{hash_algo}, password_hash{std::move(password_hash)} {}
|
|
||||||
HashedPassword(HashedPassword const &) = default;
|
|
||||||
HashedPassword(HashedPassword &&) = default;
|
|
||||||
HashedPassword &operator=(HashedPassword const &) = default;
|
|
||||||
HashedPassword &operator=(HashedPassword &&) = default;
|
|
||||||
|
|
||||||
friend bool operator==(HashedPassword const &, HashedPassword const &) = default;
|
|
||||||
|
|
||||||
bool VerifyPassword(const std::string &password);
|
|
||||||
|
|
||||||
bool IsSalted() const;
|
|
||||||
|
|
||||||
auto HashAlgo() const -> PasswordHashAlgorithm { return hash_algo; }
|
|
||||||
|
|
||||||
friend void to_json(nlohmann::json &j, const HashedPassword &p);
|
|
||||||
friend void from_json(const nlohmann::json &j, HashedPassword &p);
|
|
||||||
|
|
||||||
private:
|
|
||||||
PasswordHashAlgorithm hash_algo{PasswordHashAlgorithm::BCRYPT};
|
|
||||||
std::string password_hash{};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @throw AuthException if unable to hash the password.
|
|
||||||
HashedPassword HashPassword(const std::string &password, std::optional<PasswordHashAlgorithm> override_algo = {});
|
|
||||||
} // namespace memgraph::auth
|
} // namespace memgraph::auth
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "auth/models.hpp"
|
#include "auth/models.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <utility>
|
#include <regex>
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
@@ -20,26 +20,22 @@
|
|||||||
#include "query/constants.hpp"
|
#include "query/constants.hpp"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "utils/cast.hpp"
|
#include "utils/cast.hpp"
|
||||||
|
#include "utils/logging.hpp"
|
||||||
|
#include "utils/settings.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
DEFINE_bool(auth_password_permit_null, true, "Set to false to disable null passwords.");
|
||||||
|
|
||||||
|
inline constexpr std::string_view default_password_regex = ".+";
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
DEFINE_string(auth_password_strength_regex, default_password_regex.data(),
|
||||||
|
"The regular expression that should be used to match the entire "
|
||||||
|
"entered password to ensure its strength.");
|
||||||
|
|
||||||
namespace memgraph::auth {
|
namespace memgraph::auth {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kRoleName = "rolename";
|
|
||||||
constexpr auto kPermissions = "permissions";
|
|
||||||
constexpr auto kGrants = "grants";
|
|
||||||
constexpr auto kDenies = "denies";
|
|
||||||
constexpr auto kUsername = "username";
|
|
||||||
constexpr auto kPasswordHash = "password_hash";
|
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
constexpr auto kGlobalPermission = "global_permission";
|
|
||||||
constexpr auto kFineGrainedAccessHandler = "fine_grained_access_handler";
|
|
||||||
constexpr auto kAllowAll = "allow_all";
|
|
||||||
constexpr auto kDefault = "default";
|
|
||||||
constexpr auto kDatabases = "databases";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Constant list of all available permissions.
|
// Constant list of all available permissions.
|
||||||
const std::vector<Permission> kPermissionsAll = {Permission::MATCH,
|
const std::vector<Permission> kPermissionsAll = {Permission::MATCH,
|
||||||
Permission::CREATE,
|
Permission::CREATE,
|
||||||
@@ -65,8 +61,7 @@ const std::vector<Permission> kPermissionsAll = {Permission::MATCH,
|
|||||||
Permission::TRANSACTION_MANAGEMENT,
|
Permission::TRANSACTION_MANAGEMENT,
|
||||||
Permission::STORAGE_MODE,
|
Permission::STORAGE_MODE,
|
||||||
Permission::MULTI_DATABASE_EDIT,
|
Permission::MULTI_DATABASE_EDIT,
|
||||||
Permission::MULTI_DATABASE_USE,
|
Permission::MULTI_DATABASE_USE};
|
||||||
Permission::COORDINATOR};
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -122,8 +117,6 @@ std::string PermissionToString(Permission permission) {
|
|||||||
return "MULTI_DATABASE_EDIT";
|
return "MULTI_DATABASE_EDIT";
|
||||||
case Permission::MULTI_DATABASE_USE:
|
case Permission::MULTI_DATABASE_USE:
|
||||||
return "MULTI_DATABASE_USE";
|
return "MULTI_DATABASE_USE";
|
||||||
case Permission::COORDINATOR:
|
|
||||||
return "COORDINATOR";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,9 +241,8 @@ std::vector<Permission> Permissions::GetDenies() const {
|
|||||||
|
|
||||||
nlohmann::json Permissions::Serialize() const {
|
nlohmann::json Permissions::Serialize() const {
|
||||||
nlohmann::json data = nlohmann::json::object();
|
nlohmann::json data = nlohmann::json::object();
|
||||||
|
data["grants"] = grants_;
|
||||||
data[kGrants] = grants_;
|
data["denies"] = denies_;
|
||||||
data[kDenies] = denies_;
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,10 +250,10 @@ Permissions Permissions::Deserialize(const nlohmann::json &data) {
|
|||||||
if (!data.is_object()) {
|
if (!data.is_object()) {
|
||||||
throw AuthException("Couldn't load permissions data!");
|
throw AuthException("Couldn't load permissions data!");
|
||||||
}
|
}
|
||||||
if (!data[kGrants].is_number_unsigned() || !data[kDenies].is_number_unsigned()) {
|
if (!data["grants"].is_number_unsigned() || !data["denies"].is_number_unsigned()) {
|
||||||
throw AuthException("Couldn't load permissions data!");
|
throw AuthException("Couldn't load permissions data!");
|
||||||
}
|
}
|
||||||
return Permissions{data[kGrants], data[kDenies]};
|
return Permissions{data["grants"], data["denies"]};
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Permissions::grants() const { return grants_; }
|
uint64_t Permissions::grants() const { return grants_; }
|
||||||
@@ -323,8 +315,8 @@ nlohmann::json FineGrainedAccessPermissions::Serialize() const {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
nlohmann::json data = nlohmann::json::object();
|
nlohmann::json data = nlohmann::json::object();
|
||||||
data[kPermissions] = permissions_;
|
data["permissions"] = permissions_;
|
||||||
data[kGlobalPermission] = global_permission_.has_value() ? global_permission_.value() : -1;
|
data["global_permission"] = global_permission_.has_value() ? global_permission_.value() : -1;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,13 +329,13 @@ FineGrainedAccessPermissions FineGrainedAccessPermissions::Deserialize(const nlo
|
|||||||
}
|
}
|
||||||
std::optional<uint64_t> global_permission;
|
std::optional<uint64_t> global_permission;
|
||||||
|
|
||||||
if (data[kGlobalPermission].empty() || data[kGlobalPermission] == -1) {
|
if (data["global_permission"].empty() || data["global_permission"] == -1) {
|
||||||
global_permission = std::nullopt;
|
global_permission = std::nullopt;
|
||||||
} else {
|
} else {
|
||||||
global_permission = data[kGlobalPermission];
|
global_permission = data["global_permission"];
|
||||||
}
|
}
|
||||||
|
|
||||||
return FineGrainedAccessPermissions(data[kPermissions], global_permission);
|
return FineGrainedAccessPermissions(data["permissions"], global_permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, uint64_t> &FineGrainedAccessPermissions::GetPermissions() const {
|
const std::unordered_map<std::string, uint64_t> &FineGrainedAccessPermissions::GetPermissions() const {
|
||||||
@@ -425,11 +417,10 @@ Role::Role(const std::string &rolename, const Permissions &permissions)
|
|||||||
: rolename_(utils::ToLowerCase(rolename)), permissions_(permissions) {}
|
: rolename_(utils::ToLowerCase(rolename)), permissions_(permissions) {}
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
Role::Role(const std::string &rolename, const Permissions &permissions,
|
Role::Role(const std::string &rolename, const Permissions &permissions,
|
||||||
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access)
|
FineGrainedAccessHandler fine_grained_access_handler)
|
||||||
: rolename_(utils::ToLowerCase(rolename)),
|
: rolename_(utils::ToLowerCase(rolename)),
|
||||||
permissions_(permissions),
|
permissions_(permissions),
|
||||||
fine_grained_access_handler_(std::move(fine_grained_access_handler)),
|
fine_grained_access_handler_(std::move(fine_grained_access_handler)) {}
|
||||||
db_access_(std::move(db_access)) {}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const std::string &Role::rolename() const { return rolename_; }
|
const std::string &Role::rolename() const { return rolename_; }
|
||||||
@@ -450,15 +441,13 @@ const FineGrainedAccessPermissions &Role::GetFineGrainedAccessEdgeTypePermission
|
|||||||
|
|
||||||
nlohmann::json Role::Serialize() const {
|
nlohmann::json Role::Serialize() const {
|
||||||
nlohmann::json data = nlohmann::json::object();
|
nlohmann::json data = nlohmann::json::object();
|
||||||
data[kRoleName] = rolename_;
|
data["rolename"] = rolename_;
|
||||||
data[kPermissions] = permissions_.Serialize();
|
data["permissions"] = permissions_.Serialize();
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
data[kFineGrainedAccessHandler] = fine_grained_access_handler_.Serialize();
|
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
|
||||||
data[kDatabases] = db_access_.Serialize();
|
|
||||||
} else {
|
} else {
|
||||||
data[kFineGrainedAccessHandler] = {};
|
data["fine_grained_access_handler"] = {};
|
||||||
data[kDatabases] = {};
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return data;
|
return data;
|
||||||
@@ -468,30 +457,21 @@ Role Role::Deserialize(const nlohmann::json &data) {
|
|||||||
if (!data.is_object()) {
|
if (!data.is_object()) {
|
||||||
throw AuthException("Couldn't load role data!");
|
throw AuthException("Couldn't load role data!");
|
||||||
}
|
}
|
||||||
if (!data[kRoleName].is_string() || !data[kPermissions].is_object()) {
|
if (!data["rolename"].is_string() || !data["permissions"].is_object()) {
|
||||||
throw AuthException("Couldn't load role data!");
|
throw AuthException("Couldn't load role data!");
|
||||||
}
|
}
|
||||||
auto permissions = Permissions::Deserialize(data[kPermissions]);
|
auto permissions = Permissions::Deserialize(data["permissions"]);
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
Databases db_access;
|
|
||||||
if (data[kDatabases].is_structured()) {
|
|
||||||
db_access = Databases::Deserialize(data[kDatabases]);
|
|
||||||
} else {
|
|
||||||
// Back-compatibility
|
|
||||||
spdlog::warn("Role without specified database access. Given access to the default database.");
|
|
||||||
db_access.Grant(dbms::kDefaultDB);
|
|
||||||
db_access.SetMain(dbms::kDefaultDB);
|
|
||||||
}
|
|
||||||
FineGrainedAccessHandler fine_grained_access_handler;
|
FineGrainedAccessHandler fine_grained_access_handler;
|
||||||
// We can have an empty fine_grained if the user was created without a valid license
|
// We can have an empty fine_grained if the user was created without a valid license
|
||||||
if (data[kFineGrainedAccessHandler].is_object()) {
|
if (data["fine_grained_access_handler"].is_object()) {
|
||||||
fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data[kFineGrainedAccessHandler]);
|
fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
|
||||||
}
|
}
|
||||||
return {data[kRoleName], permissions, std::move(fine_grained_access_handler), std::move(db_access)};
|
return {data["rolename"], permissions, std::move(fine_grained_access_handler)};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return {data[kRoleName], permissions};
|
return {data["rolename"], permissions};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Role &first, const Role &second) {
|
bool operator==(const Role &first, const Role &second) {
|
||||||
@@ -505,28 +485,28 @@ bool operator==(const Role &first, const Role &second) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
void Databases::Grant(std::string_view db) {
|
void Databases::Add(const std::string &db) {
|
||||||
if (allow_all_) {
|
if (allow_all_) {
|
||||||
grants_dbs_.clear();
|
grants_dbs_.clear();
|
||||||
allow_all_ = false;
|
allow_all_ = false;
|
||||||
}
|
}
|
||||||
grants_dbs_.emplace(db);
|
grants_dbs_.emplace(db);
|
||||||
denies_dbs_.erase(std::string{db}); // TODO: C++23 use transparent key compare
|
denies_dbs_.erase(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Databases::Deny(const std::string &db) {
|
void Databases::Remove(const std::string &db) {
|
||||||
denies_dbs_.emplace(db);
|
denies_dbs_.emplace(db);
|
||||||
grants_dbs_.erase(db);
|
grants_dbs_.erase(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Databases::Revoke(const std::string &db) {
|
void Databases::Delete(const std::string &db) {
|
||||||
denies_dbs_.erase(db);
|
denies_dbs_.erase(db);
|
||||||
if (!allow_all_) {
|
if (!allow_all_) {
|
||||||
grants_dbs_.erase(db);
|
grants_dbs_.erase(db);
|
||||||
}
|
}
|
||||||
// Reset if default deleted
|
// Reset if default deleted
|
||||||
if (main_db_ == db) {
|
if (default_db_ == db) {
|
||||||
main_db_ = "";
|
default_db_ = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,36 +522,29 @@ void Databases::DenyAll() {
|
|||||||
denies_dbs_.clear();
|
denies_dbs_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Databases::RevokeAll() {
|
bool Databases::SetDefault(const std::string &db) {
|
||||||
allow_all_ = false;
|
|
||||||
grants_dbs_.clear();
|
|
||||||
denies_dbs_.clear();
|
|
||||||
main_db_ = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Databases::SetMain(std::string_view db) {
|
|
||||||
if (!Contains(db)) return false;
|
if (!Contains(db)) return false;
|
||||||
main_db_ = db;
|
default_db_ = db;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool Databases::Contains(std::string_view db) const {
|
[[nodiscard]] bool Databases::Contains(const std::string &db) const {
|
||||||
return !denies_dbs_.contains(db) && (allow_all_ || grants_dbs_.contains(db));
|
return !denies_dbs_.contains(db) && (allow_all_ || grants_dbs_.contains(db));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &Databases::GetMain() const {
|
const std::string &Databases::GetDefault() const {
|
||||||
if (!Contains(main_db_)) {
|
if (!Contains(default_db_)) {
|
||||||
throw AuthException("No access to the set default database \"{}\".", main_db_);
|
throw AuthException("No access to the set default database \"{}\".", default_db_);
|
||||||
}
|
}
|
||||||
return main_db_;
|
return default_db_;
|
||||||
}
|
}
|
||||||
|
|
||||||
nlohmann::json Databases::Serialize() const {
|
nlohmann::json Databases::Serialize() const {
|
||||||
nlohmann::json data = nlohmann::json::object();
|
nlohmann::json data = nlohmann::json::object();
|
||||||
data[kGrants] = grants_dbs_;
|
data["grants"] = grants_dbs_;
|
||||||
data[kDenies] = denies_dbs_;
|
data["denies"] = denies_dbs_;
|
||||||
data[kAllowAll] = allow_all_;
|
data["allow_all"] = allow_all_;
|
||||||
data[kDefault] = main_db_;
|
data["default"] = default_db_;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,41 +552,63 @@ Databases Databases::Deserialize(const nlohmann::json &data) {
|
|||||||
if (!data.is_object()) {
|
if (!data.is_object()) {
|
||||||
throw AuthException("Couldn't load database data!");
|
throw AuthException("Couldn't load database data!");
|
||||||
}
|
}
|
||||||
if (!data[kGrants].is_structured() || !data[kDenies].is_structured() || !data[kAllowAll].is_boolean() ||
|
if (!data["grants"].is_structured() || !data["denies"].is_structured() || !data["allow_all"].is_boolean() ||
|
||||||
!data[kDefault].is_string()) {
|
!data["default"].is_string()) {
|
||||||
throw AuthException("Couldn't load database data!");
|
throw AuthException("Couldn't load database data!");
|
||||||
}
|
}
|
||||||
return {data[kAllowAll], data[kGrants], data[kDenies], data[kDefault]};
|
return {data["allow_all"], data["grants"], data["denies"], data["default"]};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
User::User() = default;
|
User::User() {}
|
||||||
|
|
||||||
User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {}
|
User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {}
|
||||||
User::User(const std::string &username, std::optional<HashedPassword> password_hash, const Permissions &permissions)
|
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions)
|
||||||
: username_(utils::ToLowerCase(username)), password_hash_(std::move(password_hash)), permissions_(permissions) {}
|
: username_(utils::ToLowerCase(username)), password_hash_(password_hash), permissions_(permissions) {}
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
User::User(const std::string &username, std::optional<HashedPassword> password_hash, const Permissions &permissions,
|
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
|
||||||
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access)
|
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access)
|
||||||
: username_(utils::ToLowerCase(username)),
|
: username_(utils::ToLowerCase(username)),
|
||||||
password_hash_(std::move(password_hash)),
|
password_hash_(password_hash),
|
||||||
permissions_(permissions),
|
permissions_(permissions),
|
||||||
fine_grained_access_handler_(std::move(fine_grained_access_handler)),
|
fine_grained_access_handler_(std::move(fine_grained_access_handler)),
|
||||||
database_access_(std::move(db_access)) {}
|
database_access_(db_access) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool User::CheckPassword(const std::string &password) {
|
bool User::CheckPassword(const std::string &password) {
|
||||||
return password_hash_ ? password_hash_->VerifyPassword(password) : true;
|
if (password_hash_.empty()) return true;
|
||||||
|
return VerifyPassword(password, password_hash_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::UpdatePassword(const std::optional<std::string> &password,
|
void User::UpdatePassword(const std::optional<std::string> &password) {
|
||||||
std::optional<PasswordHashAlgorithm> algo_override) {
|
|
||||||
if (!password) {
|
if (!password) {
|
||||||
password_hash_.reset();
|
if (!FLAGS_auth_password_permit_null) {
|
||||||
|
throw AuthException("Null passwords aren't permitted!");
|
||||||
|
}
|
||||||
|
password_hash_ = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
password_hash_ = HashPassword(*password, algo_override);
|
|
||||||
|
if (FLAGS_auth_password_strength_regex != default_password_regex) {
|
||||||
|
if (const auto license_check_result = license::global_license_checker.IsEnterpriseValid(utils::global_settings);
|
||||||
|
license_check_result.HasError()) {
|
||||||
|
throw AuthException(
|
||||||
|
"Custom password regex is a Memgraph Enterprise feature. Please set the config "
|
||||||
|
"(\"--auth-password-strength-regex\") to its default value (\"{}\") or remove the flag.\n{}",
|
||||||
|
default_password_regex,
|
||||||
|
license::LicenseCheckErrorToString(license_check_result.GetError(), "password regex"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::regex re(FLAGS_auth_password_strength_regex);
|
||||||
|
if (!std::regex_match(*password, re)) {
|
||||||
|
throw AuthException(
|
||||||
|
"The user password doesn't conform to the required strength! Regex: "
|
||||||
|
"\"{}\"",
|
||||||
|
FLAGS_auth_password_strength_regex);
|
||||||
|
}
|
||||||
|
|
||||||
|
password_hash_ = EncryptPassword(*password);
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::SetRole(const Role &role) { role_.emplace(role); }
|
void User::SetRole(const Role &role) { role_.emplace(role); }
|
||||||
@@ -630,49 +625,27 @@ Permissions User::GetPermissions() const {
|
|||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
FineGrainedAccessPermissions User::GetFineGrainedAccessLabelPermissions() const {
|
FineGrainedAccessPermissions User::GetFineGrainedAccessLabelPermissions() const {
|
||||||
return Merge(GetUserFineGrainedAccessLabelPermissions(), GetRoleFineGrainedAccessLabelPermissions());
|
|
||||||
}
|
|
||||||
|
|
||||||
FineGrainedAccessPermissions User::GetFineGrainedAccessEdgeTypePermissions() const {
|
|
||||||
return Merge(GetUserFineGrainedAccessEdgeTypePermissions(), GetRoleFineGrainedAccessEdgeTypePermissions());
|
|
||||||
}
|
|
||||||
|
|
||||||
FineGrainedAccessPermissions User::GetUserFineGrainedAccessEdgeTypePermissions() const {
|
|
||||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
return FineGrainedAccessPermissions{};
|
return FineGrainedAccessPermissions{};
|
||||||
}
|
}
|
||||||
|
|
||||||
return fine_grained_access_handler_.edge_type_permissions();
|
if (role_) {
|
||||||
}
|
return Merge(role()->fine_grained_access_handler().label_permissions(),
|
||||||
|
fine_grained_access_handler_.label_permissions());
|
||||||
FineGrainedAccessPermissions User::GetUserFineGrainedAccessLabelPermissions() const {
|
|
||||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
|
||||||
return FineGrainedAccessPermissions{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fine_grained_access_handler_.label_permissions();
|
return fine_grained_access_handler_.label_permissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
FineGrainedAccessPermissions User::GetRoleFineGrainedAccessEdgeTypePermissions() const {
|
FineGrainedAccessPermissions User::GetFineGrainedAccessEdgeTypePermissions() const {
|
||||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
return FineGrainedAccessPermissions{};
|
return FineGrainedAccessPermissions{};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role_) {
|
if (role_) {
|
||||||
return role()->fine_grained_access_handler().edge_type_permissions();
|
return Merge(role()->fine_grained_access_handler().edge_type_permissions(),
|
||||||
|
fine_grained_access_handler_.edge_type_permissions());
|
||||||
}
|
}
|
||||||
return FineGrainedAccessPermissions{};
|
return fine_grained_access_handler_.edge_type_permissions();
|
||||||
}
|
|
||||||
|
|
||||||
FineGrainedAccessPermissions User::GetRoleFineGrainedAccessLabelPermissions() const {
|
|
||||||
if (!memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
|
||||||
return FineGrainedAccessPermissions{};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role_) {
|
|
||||||
return role()->fine_grained_access_handler().label_permissions();
|
|
||||||
}
|
|
||||||
return FineGrainedAccessPermissions{};
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -694,20 +667,16 @@ const Role *User::role() const {
|
|||||||
|
|
||||||
nlohmann::json User::Serialize() const {
|
nlohmann::json User::Serialize() const {
|
||||||
nlohmann::json data = nlohmann::json::object();
|
nlohmann::json data = nlohmann::json::object();
|
||||||
data[kUsername] = username_;
|
data["username"] = username_;
|
||||||
if (password_hash_.has_value()) {
|
data["password_hash"] = password_hash_;
|
||||||
data[kPasswordHash] = *password_hash_;
|
data["permissions"] = permissions_.Serialize();
|
||||||
} else {
|
|
||||||
data[kPasswordHash] = nullptr;
|
|
||||||
}
|
|
||||||
data[kPermissions] = permissions_.Serialize();
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
data[kFineGrainedAccessHandler] = fine_grained_access_handler_.Serialize();
|
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
|
||||||
data[kDatabases] = database_access_.Serialize();
|
data["databases"] = database_access_.Serialize();
|
||||||
} else {
|
} else {
|
||||||
data[kFineGrainedAccessHandler] = {};
|
data["fine_grained_access_handler"] = {};
|
||||||
data[kDatabases] = {};
|
data["databases"] = {};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// The role shouldn't be serialized here, it is stored as a foreign key.
|
// The role shouldn't be serialized here, it is stored as a foreign key.
|
||||||
@@ -718,39 +687,30 @@ User User::Deserialize(const nlohmann::json &data) {
|
|||||||
if (!data.is_object()) {
|
if (!data.is_object()) {
|
||||||
throw AuthException("Couldn't load user data!");
|
throw AuthException("Couldn't load user data!");
|
||||||
}
|
}
|
||||||
auto password_hash_json = data[kPasswordHash];
|
if (!data["username"].is_string() || !data["password_hash"].is_string() || !data["permissions"].is_object()) {
|
||||||
if (!data[kUsername].is_string() || !(password_hash_json.is_object() || password_hash_json.is_null()) ||
|
|
||||||
!data[kPermissions].is_object()) {
|
|
||||||
throw AuthException("Couldn't load user data!");
|
throw AuthException("Couldn't load user data!");
|
||||||
}
|
}
|
||||||
|
auto permissions = Permissions::Deserialize(data["permissions"]);
|
||||||
std::optional<HashedPassword> password_hash{};
|
|
||||||
if (password_hash_json.is_object()) {
|
|
||||||
password_hash = password_hash_json.get<HashedPassword>();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto permissions = Permissions::Deserialize(data[kPermissions]);
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
if (memgraph::license::global_license_checker.IsEnterpriseValidFast()) {
|
||||||
Databases db_access;
|
Databases db_access;
|
||||||
if (data[kDatabases].is_structured()) {
|
if (data["databases"].is_structured()) {
|
||||||
db_access = Databases::Deserialize(data[kDatabases]);
|
db_access = Databases::Deserialize(data["databases"]);
|
||||||
} else {
|
} else {
|
||||||
// Back-compatibility
|
// Back-compatibility
|
||||||
spdlog::warn("User without specified database access. Given access to the default database.");
|
spdlog::warn("User without specified database access. Given access to the default database.");
|
||||||
db_access.Grant(dbms::kDefaultDB);
|
db_access.Add(dbms::kDefaultDB);
|
||||||
db_access.SetMain(dbms::kDefaultDB);
|
db_access.SetDefault(dbms::kDefaultDB);
|
||||||
}
|
}
|
||||||
FineGrainedAccessHandler fine_grained_access_handler;
|
FineGrainedAccessHandler fine_grained_access_handler;
|
||||||
// We can have an empty fine_grained if the user was created without a valid license
|
// We can have an empty fine_grained if the user was created without a valid license
|
||||||
if (data[kFineGrainedAccessHandler].is_object()) {
|
if (data["fine_grained_access_handler"].is_object()) {
|
||||||
fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data[kFineGrainedAccessHandler]);
|
fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
|
||||||
}
|
}
|
||||||
return {data[kUsername], std::move(password_hash), permissions, std::move(fine_grained_access_handler),
|
return {data["username"], data["password_hash"], permissions, std::move(fine_grained_access_handler), db_access};
|
||||||
std::move(db_access)};
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return {data[kUsername], std::move(password_hash), permissions};
|
return {data["username"], data["password_hash"], permissions};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const User &first, const User &second) {
|
bool operator==(const User &first, const User &second) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -14,8 +14,6 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <json/json.hpp>
|
#include <json/json.hpp>
|
||||||
#include <utility>
|
|
||||||
#include "crypto.hpp"
|
|
||||||
#include "dbms/constants.hpp"
|
#include "dbms/constants.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
@@ -49,7 +47,6 @@ enum class Permission : uint64_t {
|
|||||||
STORAGE_MODE = 1U << 22U,
|
STORAGE_MODE = 1U << 22U,
|
||||||
MULTI_DATABASE_EDIT = 1U << 23U,
|
MULTI_DATABASE_EDIT = 1U << 23U,
|
||||||
MULTI_DATABASE_USE = 1U << 24U,
|
MULTI_DATABASE_USE = 1U << 24U,
|
||||||
COORDINATOR = 1U << 25U,
|
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -205,104 +202,13 @@ class FineGrainedAccessHandler final {
|
|||||||
bool operator==(const FineGrainedAccessHandler &first, const FineGrainedAccessHandler &second);
|
bool operator==(const FineGrainedAccessHandler &first, const FineGrainedAccessHandler &second);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
class Role final {
|
||||||
class Databases final {
|
|
||||||
public:
|
public:
|
||||||
Databases() : grants_dbs_{std::string{dbms::kDefaultDB}}, allow_all_(false), main_db_(dbms::kDefaultDB) {}
|
|
||||||
|
|
||||||
Databases(const Databases &) = default;
|
|
||||||
Databases &operator=(const Databases &) = default;
|
|
||||||
Databases(Databases &&) noexcept = default;
|
|
||||||
Databases &operator=(Databases &&) noexcept = default;
|
|
||||||
~Databases() = default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add database to the list of granted access. @note allow_all_ will be false after execution
|
|
||||||
*
|
|
||||||
* @param db name of the database to grant access to
|
|
||||||
*/
|
|
||||||
void Grant(std::string_view db);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Remove database to the list of granted access.
|
|
||||||
* @note if allow_all_ is set, the flag will remain set and the
|
|
||||||
* database will be added to the set of denied databases.
|
|
||||||
*
|
|
||||||
* @param db name of the database to grant access to
|
|
||||||
*/
|
|
||||||
void Deny(const std::string &db);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Called when database is dropped. Removes it from granted (if allow_all is false) and denied set.
|
|
||||||
* @note allow_all_ is not changed
|
|
||||||
*
|
|
||||||
* @param db name of the database to grant access to
|
|
||||||
*/
|
|
||||||
void Revoke(const std::string &db);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set allow_all_ to true and clears grants and denied sets.
|
|
||||||
*/
|
|
||||||
void GrantAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set allow_all_ to false and clears grants and denied sets.
|
|
||||||
*/
|
|
||||||
void DenyAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set allow_all_ to false and clears grants and denied sets.
|
|
||||||
*/
|
|
||||||
void RevokeAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the default database.
|
|
||||||
*/
|
|
||||||
bool SetMain(std::string_view db);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if access is grated to the database.
|
|
||||||
*
|
|
||||||
* @param db name of the database
|
|
||||||
* @return true if allow_all and not denied or granted
|
|
||||||
*/
|
|
||||||
bool Contains(std::string_view db) const;
|
|
||||||
bool Denies(std::string_view db_name) const { return denies_dbs_.contains(db_name); }
|
|
||||||
bool Grants(std::string_view db_name) const { return allow_all_ || grants_dbs_.contains(db_name); }
|
|
||||||
|
|
||||||
bool GetAllowAll() const { return allow_all_; }
|
|
||||||
const std::set<std::string, std::less<>> &GetGrants() const { return grants_dbs_; }
|
|
||||||
const std::set<std::string, std::less<>> &GetDenies() const { return denies_dbs_; }
|
|
||||||
const std::string &GetMain() const;
|
|
||||||
|
|
||||||
nlohmann::json Serialize() const;
|
|
||||||
/// @throw AuthException if unable to deserialize.
|
|
||||||
static Databases Deserialize(const nlohmann::json &data);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Databases(bool allow_all, std::set<std::string, std::less<>> grant, std::set<std::string, std::less<>> deny,
|
|
||||||
std::string default_db = std::string{dbms::kDefaultDB})
|
|
||||||
: grants_dbs_(std::move(grant)),
|
|
||||||
denies_dbs_(std::move(deny)),
|
|
||||||
allow_all_(allow_all),
|
|
||||||
main_db_(std::move(default_db)) {}
|
|
||||||
|
|
||||||
std::set<std::string, std::less<>> grants_dbs_; //!< set of databases with granted access
|
|
||||||
std::set<std::string, std::less<>> denies_dbs_; //!< set of databases with denied access
|
|
||||||
bool allow_all_; //!< flag to allow access to everything (denied overrides this)
|
|
||||||
std::string main_db_; //!< user's default database
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class Role {
|
|
||||||
public:
|
|
||||||
Role() = default;
|
|
||||||
|
|
||||||
explicit Role(const std::string &rolename);
|
explicit Role(const std::string &rolename);
|
||||||
Role(const std::string &rolename, const Permissions &permissions);
|
Role(const std::string &rolename, const Permissions &permissions);
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
Role(const std::string &rolename, const Permissions &permissions,
|
Role(const std::string &rolename, const Permissions &permissions,
|
||||||
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access = {});
|
FineGrainedAccessHandler fine_grained_access_handler);
|
||||||
#endif
|
#endif
|
||||||
Role(const Role &) = default;
|
Role(const Role &) = default;
|
||||||
Role &operator=(const Role &) = default;
|
Role &operator=(const Role &) = default;
|
||||||
@@ -313,23 +219,12 @@ class Role {
|
|||||||
const std::string &rolename() const;
|
const std::string &rolename() const;
|
||||||
const Permissions &permissions() const;
|
const Permissions &permissions() const;
|
||||||
Permissions &permissions();
|
Permissions &permissions();
|
||||||
Permissions GetPermissions() const { return permissions_; }
|
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
const FineGrainedAccessHandler &fine_grained_access_handler() const;
|
const FineGrainedAccessHandler &fine_grained_access_handler() const;
|
||||||
FineGrainedAccessHandler &fine_grained_access_handler();
|
FineGrainedAccessHandler &fine_grained_access_handler();
|
||||||
const FineGrainedAccessPermissions &GetFineGrainedAccessLabelPermissions() const;
|
const FineGrainedAccessPermissions &GetFineGrainedAccessLabelPermissions() const;
|
||||||
const FineGrainedAccessPermissions &GetFineGrainedAccessEdgeTypePermissions() const;
|
const FineGrainedAccessPermissions &GetFineGrainedAccessEdgeTypePermissions() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
Databases &db_access() { return db_access_; }
|
|
||||||
const Databases &db_access() const { return db_access_; }
|
|
||||||
|
|
||||||
bool DeniesDB(std::string_view db_name) const { return db_access_.Denies(db_name); }
|
|
||||||
bool GrantsDB(std::string_view db_name) const { return db_access_.Grants(db_name); }
|
|
||||||
bool HasAccess(std::string_view db_name) const { return !DeniesDB(db_name) && GrantsDB(db_name); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nlohmann::json Serialize() const;
|
nlohmann::json Serialize() const;
|
||||||
|
|
||||||
/// @throw AuthException if unable to deserialize.
|
/// @throw AuthException if unable to deserialize.
|
||||||
@@ -342,21 +237,99 @@ class Role {
|
|||||||
Permissions permissions_;
|
Permissions permissions_;
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
FineGrainedAccessHandler fine_grained_access_handler_;
|
FineGrainedAccessHandler fine_grained_access_handler_;
|
||||||
Databases db_access_;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const Role &first, const Role &second);
|
bool operator==(const Role &first, const Role &second);
|
||||||
|
|
||||||
|
#ifdef MG_ENTERPRISE
|
||||||
|
class Databases final {
|
||||||
|
public:
|
||||||
|
Databases() : grants_dbs_({dbms::kDefaultDB}), allow_all_(false), default_db_(dbms::kDefaultDB) {}
|
||||||
|
|
||||||
|
Databases(const Databases &) = default;
|
||||||
|
Databases &operator=(const Databases &) = default;
|
||||||
|
Databases(Databases &&) noexcept = default;
|
||||||
|
Databases &operator=(Databases &&) noexcept = default;
|
||||||
|
~Databases() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add database to the list of granted access. @note allow_all_ will be false after execution
|
||||||
|
*
|
||||||
|
* @param db name of the database to grant access to
|
||||||
|
*/
|
||||||
|
void Add(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove database to the list of granted access.
|
||||||
|
* @note if allow_all_ is set, the flag will remain set and the
|
||||||
|
* database will be added to the set of denied databases.
|
||||||
|
*
|
||||||
|
* @param db name of the database to grant access to
|
||||||
|
*/
|
||||||
|
void Remove(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when database is dropped. Removes it from granted (if allow_all is false) and denied set.
|
||||||
|
* @note allow_all_ is not changed
|
||||||
|
*
|
||||||
|
* @param db name of the database to grant access to
|
||||||
|
*/
|
||||||
|
void Delete(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set allow_all_ to true and clears grants and denied sets.
|
||||||
|
*/
|
||||||
|
void GrantAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set allow_all_ to false and clears grants and denied sets.
|
||||||
|
*/
|
||||||
|
void DenyAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the default database.
|
||||||
|
*/
|
||||||
|
bool SetDefault(const std::string &db);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if access is grated to the database.
|
||||||
|
*
|
||||||
|
* @param db name of the database
|
||||||
|
* @return true if allow_all and not denied or granted
|
||||||
|
*/
|
||||||
|
bool Contains(const std::string &db) const;
|
||||||
|
|
||||||
|
bool GetAllowAll() const { return allow_all_; }
|
||||||
|
const std::set<std::string> &GetGrants() const { return grants_dbs_; }
|
||||||
|
const std::set<std::string> &GetDenies() const { return denies_dbs_; }
|
||||||
|
const std::string &GetDefault() const;
|
||||||
|
|
||||||
|
nlohmann::json Serialize() const;
|
||||||
|
/// @throw AuthException if unable to deserialize.
|
||||||
|
static Databases Deserialize(const nlohmann::json &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Databases(bool allow_all, std::set<std::string> grant, std::set<std::string> deny,
|
||||||
|
const std::string &default_db = dbms::kDefaultDB)
|
||||||
|
: grants_dbs_(grant), denies_dbs_(deny), allow_all_(allow_all), default_db_(default_db) {}
|
||||||
|
|
||||||
|
std::set<std::string> grants_dbs_; //!< set of databases with granted access
|
||||||
|
std::set<std::string> denies_dbs_; //!< set of databases with denied access
|
||||||
|
bool allow_all_; //!< flag to allow access to everything (denied overrides this)
|
||||||
|
std::string default_db_; //!< user's default database
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO (mferencevic): Implement password expiry.
|
// TODO (mferencevic): Implement password expiry.
|
||||||
class User final {
|
class User final {
|
||||||
public:
|
public:
|
||||||
User();
|
User();
|
||||||
|
|
||||||
explicit User(const std::string &username);
|
explicit User(const std::string &username);
|
||||||
User(const std::string &username, std::optional<HashedPassword> password_hash, const Permissions &permissions);
|
User(const std::string &username, const std::string &password_hash, const Permissions &permissions);
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
User(const std::string &username, std::optional<HashedPassword> password_hash, const Permissions &permissions,
|
User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
|
||||||
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access = {});
|
FineGrainedAccessHandler fine_grained_access_handler, Databases db_access = {});
|
||||||
#endif
|
#endif
|
||||||
User(const User &) = default;
|
User(const User &) = default;
|
||||||
@@ -368,18 +341,8 @@ class User final {
|
|||||||
/// @throw AuthException if unable to verify the password.
|
/// @throw AuthException if unable to verify the password.
|
||||||
bool CheckPassword(const std::string &password);
|
bool CheckPassword(const std::string &password);
|
||||||
|
|
||||||
bool UpgradeHash(const std::string password) {
|
|
||||||
if (!password_hash_) return false;
|
|
||||||
if (password_hash_->IsSalted()) return false;
|
|
||||||
|
|
||||||
auto const algo = password_hash_->HashAlgo();
|
|
||||||
UpdatePassword(password, algo);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @throw AuthException if unable to set the password.
|
/// @throw AuthException if unable to set the password.
|
||||||
void UpdatePassword(const std::optional<std::string> &password = {},
|
void UpdatePassword(const std::optional<std::string> &password = std::nullopt);
|
||||||
std::optional<PasswordHashAlgorithm> algo_override = std::nullopt);
|
|
||||||
|
|
||||||
void SetRole(const Role &role);
|
void SetRole(const Role &role);
|
||||||
|
|
||||||
@@ -390,10 +353,6 @@ class User final {
|
|||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
FineGrainedAccessPermissions GetFineGrainedAccessLabelPermissions() const;
|
FineGrainedAccessPermissions GetFineGrainedAccessLabelPermissions() const;
|
||||||
FineGrainedAccessPermissions GetFineGrainedAccessEdgeTypePermissions() const;
|
FineGrainedAccessPermissions GetFineGrainedAccessEdgeTypePermissions() const;
|
||||||
FineGrainedAccessPermissions GetUserFineGrainedAccessLabelPermissions() const;
|
|
||||||
FineGrainedAccessPermissions GetUserFineGrainedAccessEdgeTypePermissions() const;
|
|
||||||
FineGrainedAccessPermissions GetRoleFineGrainedAccessLabelPermissions() const;
|
|
||||||
FineGrainedAccessPermissions GetRoleFineGrainedAccessEdgeTypePermissions() const;
|
|
||||||
const FineGrainedAccessHandler &fine_grained_access_handler() const;
|
const FineGrainedAccessHandler &fine_grained_access_handler() const;
|
||||||
FineGrainedAccessHandler &fine_grained_access_handler();
|
FineGrainedAccessHandler &fine_grained_access_handler();
|
||||||
#endif
|
#endif
|
||||||
@@ -407,18 +366,6 @@ class User final {
|
|||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
Databases &db_access() { return database_access_; }
|
Databases &db_access() { return database_access_; }
|
||||||
const Databases &db_access() const { return database_access_; }
|
const Databases &db_access() const { return database_access_; }
|
||||||
|
|
||||||
bool DeniesDB(std::string_view db_name) const {
|
|
||||||
bool denies = database_access_.Denies(db_name);
|
|
||||||
if (role_) denies |= role_->DeniesDB(db_name);
|
|
||||||
return denies;
|
|
||||||
}
|
|
||||||
bool GrantsDB(std::string_view db_name) const {
|
|
||||||
bool grants = database_access_.Grants(db_name);
|
|
||||||
if (role_) grants |= role_->GrantsDB(db_name);
|
|
||||||
return grants;
|
|
||||||
}
|
|
||||||
bool HasAccess(std::string_view db_name) const { return !DeniesDB(db_name) && GrantsDB(db_name); }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nlohmann::json Serialize() const;
|
nlohmann::json Serialize() const;
|
||||||
@@ -430,11 +377,11 @@ class User final {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::string username_;
|
std::string username_;
|
||||||
std::optional<HashedPassword> password_hash_;
|
std::string password_hash_;
|
||||||
Permissions permissions_;
|
Permissions permissions_;
|
||||||
#ifdef MG_ENTERPRISE
|
#ifdef MG_ENTERPRISE
|
||||||
FineGrainedAccessHandler fine_grained_access_handler_;
|
FineGrainedAccessHandler fine_grained_access_handler_;
|
||||||
Databases database_access_{};
|
Databases database_access_;
|
||||||
#endif
|
#endif
|
||||||
std::optional<Role> role_;
|
std::optional<Role> role_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -403,7 +403,7 @@ nlohmann::json Module::Call(const nlohmann::json ¶ms, int timeout_millisec)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Module::IsUsed() const { return !module_executable_path_.empty(); }
|
bool Module::IsUsed() { return !module_executable_path_.empty(); }
|
||||||
|
|
||||||
void Module::Shutdown() {
|
void Module::Shutdown() {
|
||||||
if (pid_ == -1) return;
|
if (pid_ == -1) return;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
|
||||||
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
|
||||||
@@ -49,7 +49,7 @@ class Module final {
|
|||||||
/// specified executable path and can thus be used.
|
/// specified executable path and can thus be used.
|
||||||
///
|
///
|
||||||
/// @return boolean indicating whether the module can be used
|
/// @return boolean indicating whether the module can be used
|
||||||
bool IsUsed() const;
|
bool IsUsed();
|
||||||
|
|
||||||
~Module();
|
~Module();
|
||||||
|
|
||||||
|
|||||||
@@ -1,190 +0,0 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
|
||||||
//
|
|
||||||
// Use of this software is governed by the Business Source License
|
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
|
||||||
// License, and you may not use this file except in compliance with the Business Source License.
|
|
||||||
//
|
|
||||||
// As of the Change Date specified in that file, in accordance with
|
|
||||||
// the Business Source License, use of this software will be governed
|
|
||||||
// by the Apache License, Version 2.0, included in the file
|
|
||||||
// licenses/APL.txt.
|
|
||||||
|
|
||||||
#include "auth/replication_handlers.hpp"
|
|
||||||
|
|
||||||
#include "auth/auth.hpp"
|
|
||||||
#include "auth/rpc.hpp"
|
|
||||||
#include "license/license.hpp"
|
|
||||||
|
|
||||||
namespace memgraph::auth {
|
|
||||||
|
|
||||||
void LogWrongMain(const std::optional<utils::UUID> ¤t_main_uuid, const utils::UUID &main_req_id,
|
|
||||||
std::string_view rpc_req) {
|
|
||||||
spdlog::error(fmt::format("Received {} with main_id: {} != current_main_uuid: {}", rpc_req, std::string(main_req_id),
|
|
||||||
current_main_uuid.has_value() ? std::string(current_main_uuid.value()) : ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
void UpdateAuthDataHandler(memgraph::system::ReplicaHandlerAccessToState &system_state_access,
|
|
||||||
const std::optional<utils::UUID> ¤t_main_uuid, auth::SynchedAuth &auth,
|
|
||||||
slk::Reader *req_reader, slk::Builder *res_builder) {
|
|
||||||
replication::UpdateAuthDataReq req;
|
|
||||||
memgraph::slk::Load(&req, req_reader);
|
|
||||||
|
|
||||||
using memgraph::replication::UpdateAuthDataRes;
|
|
||||||
UpdateAuthDataRes res(false);
|
|
||||||
|
|
||||||
if (!current_main_uuid.has_value() || req.main_uuid != current_main_uuid) [[unlikely]] {
|
|
||||||
LogWrongMain(current_main_uuid, req.main_uuid, replication::UpdateAuthDataReq::kType.name);
|
|
||||||
memgraph::slk::Save(res, res_builder);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: No need to check epoch, recovery mechanism is done by a full uptodate snapshot
|
|
||||||
// of the set of databases. Hence no history exists to maintain regarding epoch change.
|
|
||||||
// If MAIN has changed we need to check this new group_timestamp is consistent with
|
|
||||||
// what we have so far.
|
|
||||||
|
|
||||||
if (req.expected_group_timestamp != system_state_access.LastCommitedTS()) {
|
|
||||||
spdlog::debug("UpdateAuthDataHandler: bad expected timestamp {},{}", req.expected_group_timestamp,
|
|
||||||
system_state_access.LastCommitedTS());
|
|
||||||
memgraph::slk::Save(res, res_builder);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Update
|
|
||||||
if (req.user) auth->SaveUser(*req.user);
|
|
||||||
if (req.role) auth->SaveRole(*req.role);
|
|
||||||
// Success
|
|
||||||
system_state_access.SetLastCommitedTS(req.new_group_timestamp);
|
|
||||||
res = UpdateAuthDataRes(true);
|
|
||||||
spdlog::debug("UpdateAuthDataHandler: SUCCESS updated LCTS to {}", req.new_group_timestamp);
|
|
||||||
} catch (const auth::AuthException & /* not used */) {
|
|
||||||
// Failure
|
|
||||||
}
|
|
||||||
|
|
||||||
memgraph::slk::Save(res, res_builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DropAuthDataHandler(memgraph::system::ReplicaHandlerAccessToState &system_state_access,
|
|
||||||
const std::optional<utils::UUID> ¤t_main_uuid, auth::SynchedAuth &auth,
|
|
||||||
slk::Reader *req_reader, slk::Builder *res_builder) {
|
|
||||||
replication::DropAuthDataReq req;
|
|
||||||
memgraph::slk::Load(&req, req_reader);
|
|
||||||
|
|
||||||
using memgraph::replication::DropAuthDataRes;
|
|
||||||
DropAuthDataRes res(false);
|
|
||||||
|
|
||||||
if (!current_main_uuid.has_value() || req.main_uuid != current_main_uuid) [[unlikely]] {
|
|
||||||
LogWrongMain(current_main_uuid, req.main_uuid, replication::DropAuthDataRes::kType.name);
|
|
||||||
memgraph::slk::Save(res, res_builder);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: No need to check epoch, recovery mechanism is done by a full uptodate snapshot
|
|
||||||
// of the set of databases. Hence no history exists to maintain regarding epoch change.
|
|
||||||
// If MAIN has changed we need to check this new group_timestamp is consistent with
|
|
||||||
// what we have so far.
|
|
||||||
|
|
||||||
if (req.expected_group_timestamp != system_state_access.LastCommitedTS()) {
|
|
||||||
spdlog::debug("DropAuthDataHandler: bad expected timestamp {},{}", req.expected_group_timestamp,
|
|
||||||
system_state_access.LastCommitedTS());
|
|
||||||
memgraph::slk::Save(res, res_builder);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Remove
|
|
||||||
switch (req.type) {
|
|
||||||
case replication::DropAuthDataReq::DataType::USER:
|
|
||||||
auth->RemoveUser(req.name);
|
|
||||||
break;
|
|
||||||
case replication::DropAuthDataReq::DataType::ROLE:
|
|
||||||
auth->RemoveRole(req.name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Success
|
|
||||||
system_state_access.SetLastCommitedTS(req.new_group_timestamp);
|
|
||||||
res = DropAuthDataRes(true);
|
|
||||||
spdlog::debug("DropAuthDataHandler: SUCCESS updated LCTS to {}", req.new_group_timestamp);
|
|
||||||
} catch (const auth::AuthException & /* not used */) {
|
|
||||||
// Failure
|
|
||||||
}
|
|
||||||
|
|
||||||
memgraph::slk::Save(res, res_builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SystemRecoveryHandler(auth::SynchedAuth &auth, auth::Auth::Config auth_config,
|
|
||||||
const std::vector<auth::User> &users, const std::vector<auth::Role> &roles) {
|
|
||||||
return auth.WithLock([&](auto &locked_auth) {
|
|
||||||
// Update config
|
|
||||||
locked_auth.SetConfig(std::move(auth_config));
|
|
||||||
// Get all current users
|
|
||||||
auto old_users = locked_auth.AllUsernames();
|
|
||||||
// Save incoming users
|
|
||||||
for (const auto &user : users) {
|
|
||||||
// Missing users
|
|
||||||
try {
|
|
||||||
locked_auth.SaveUser(user);
|
|
||||||
} catch (const auth::AuthException &) {
|
|
||||||
spdlog::debug("SystemRecoveryHandler: Failed to save user");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto it = std::find(old_users.begin(), old_users.end(), user.username());
|
|
||||||
if (it != old_users.end()) old_users.erase(it);
|
|
||||||
}
|
|
||||||
// Delete all the leftover users
|
|
||||||
for (const auto &user : old_users) {
|
|
||||||
if (!locked_auth.RemoveUser(user)) {
|
|
||||||
spdlog::debug("SystemRecoveryHandler: Failed to remove user \"{}\".", user);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roles are only supported with a license
|
|
||||||
if (license::global_license_checker.IsEnterpriseValidFast()) {
|
|
||||||
// Get all current roles
|
|
||||||
auto old_roles = locked_auth.AllRolenames();
|
|
||||||
// Save incoming users
|
|
||||||
for (const auto &role : roles) {
|
|
||||||
// Missing users
|
|
||||||
try {
|
|
||||||
locked_auth.SaveRole(role);
|
|
||||||
} catch (const auth::AuthException &) {
|
|
||||||
spdlog::debug("SystemRecoveryHandler: Failed to save user");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto it = std::find(old_roles.begin(), old_roles.end(), role.rolename());
|
|
||||||
if (it != old_roles.end()) old_roles.erase(it);
|
|
||||||
}
|
|
||||||
// Delete all the leftover users
|
|
||||||
for (const auto &role : old_roles) {
|
|
||||||
if (!locked_auth.RemoveRole(role)) {
|
|
||||||
spdlog::debug("SystemRecoveryHandler: Failed to remove user \"{}\".", role);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Register(replication::RoleReplicaData const &data, system::ReplicaHandlerAccessToState &system_state_access,
|
|
||||||
auth::SynchedAuth &auth) {
|
|
||||||
// NOTE: Register even without license as the user could add a license at run-time
|
|
||||||
data.server->rpc_server_.Register<replication::UpdateAuthDataRpc>(
|
|
||||||
[&data, system_state_access, &auth](auto *req_reader, auto *res_builder) mutable {
|
|
||||||
spdlog::debug("Received UpdateAuthDataRpc");
|
|
||||||
UpdateAuthDataHandler(system_state_access, data.uuid_, auth, req_reader, res_builder);
|
|
||||||
});
|
|
||||||
data.server->rpc_server_.Register<replication::DropAuthDataRpc>(
|
|
||||||
[&data, system_state_access, &auth](auto *req_reader, auto *res_builder) mutable {
|
|
||||||
spdlog::debug("Received DropAuthDataRpc");
|
|
||||||
DropAuthDataHandler(system_state_access, data.uuid_, auth, req_reader, res_builder);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace memgraph::auth
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
|
||||||
//
|
|
||||||
// Use of this software is governed by the Business Source License
|
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
|
||||||
// License, and you may not use this file except in compliance with the Business Source License.
|
|
||||||
//
|
|
||||||
// As of the Change Date specified in that file, in accordance with
|
|
||||||
// the Business Source License, use of this software will be governed
|
|
||||||
// by the Apache License, Version 2.0, included in the file
|
|
||||||
// licenses/APL.txt.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "auth/auth.hpp"
|
|
||||||
#include "replication/state.hpp"
|
|
||||||
#include "slk/streams.hpp"
|
|
||||||
#include "system/state.hpp"
|
|
||||||
|
|
||||||
namespace memgraph::auth {
|
|
||||||
|
|
||||||
void LogWrongMain(const std::optional<utils::UUID> ¤t_main_uuid, const utils::UUID &main_req_id,
|
|
||||||
std::string_view rpc_req);
|
|
||||||
|
|
||||||
#ifdef MG_ENTERPRISE
|
|
||||||
void UpdateAuthDataHandler(system::ReplicaHandlerAccessToState &system_state_access,
|
|
||||||
const std::optional<utils::UUID> ¤t_main_uuid, auth::SynchedAuth &auth,
|
|
||||||
slk::Reader *req_reader, slk::Builder *res_builder);
|
|
||||||
void DropAuthDataHandler(system::ReplicaHandlerAccessToState &system_state_access,
|
|
||||||
const std::optional<utils::UUID> ¤t_main_uuid, auth::SynchedAuth &auth,
|
|
||||||
slk::Reader *req_reader, slk::Builder *res_builder);
|
|
||||||
|
|
||||||
bool SystemRecoveryHandler(auth::SynchedAuth &auth, auth::Auth::Config auth_config,
|
|
||||||
const std::vector<auth::User> &users, const std::vector<auth::Role> &roles);
|
|
||||||
void Register(replication::RoleReplicaData const &data, system::ReplicaHandlerAccessToState &system_state_access,
|
|
||||||
auth::SynchedAuth &auth);
|
|
||||||
#endif
|
|
||||||
} // namespace memgraph::auth
|
|
||||||
180
src/auth/rpc.cpp
180
src/auth/rpc.cpp
@@ -1,180 +0,0 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
|
||||||
//
|
|
||||||
// Use of this software is governed by the Business Source License
|
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
|
||||||
// License, and you may not use this file except in compliance with the Business Source License.
|
|
||||||
//
|
|
||||||
// As of the Change Date specified in that file, in accordance with
|
|
||||||
// the Business Source License, use of this software will be governed
|
|
||||||
// by the Apache License, Version 2.0, included in the file
|
|
||||||
// licenses/APL.txt.
|
|
||||||
|
|
||||||
#include "auth/rpc.hpp"
|
|
||||||
|
|
||||||
#include <json/json.hpp>
|
|
||||||
#include "auth/auth.hpp"
|
|
||||||
#include "slk/serialization.hpp"
|
|
||||||
#include "slk/streams.hpp"
|
|
||||||
#include "utils/enum.hpp"
|
|
||||||
|
|
||||||
namespace memgraph::slk {
|
|
||||||
// Serialize code for auth::Role
|
|
||||||
void Save(const auth::Role &self, Builder *builder) { memgraph::slk::Save(self.Serialize().dump(), builder); }
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
auth::Role LoadAuthRole(memgraph::slk::Reader *reader) {
|
|
||||||
std::string tmp;
|
|
||||||
memgraph::slk::Load(&tmp, reader);
|
|
||||||
const auto json = nlohmann::json::parse(tmp);
|
|
||||||
return memgraph::auth::Role::Deserialize(json);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
// Deserialize code for auth::Role
|
|
||||||
void Load(auth::Role *self, memgraph::slk::Reader *reader) { *self = LoadAuthRole(reader); }
|
|
||||||
// Special case for optional<Role>
|
|
||||||
template <>
|
|
||||||
inline void Load<auth::Role>(std::optional<auth::Role> *obj, Reader *reader) {
|
|
||||||
bool exists = false;
|
|
||||||
Load(&exists, reader);
|
|
||||||
if (exists) {
|
|
||||||
obj->emplace(LoadAuthRole(reader));
|
|
||||||
} else {
|
|
||||||
*obj = std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize code for auth::User
|
|
||||||
void Save(const auth::User &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self.Serialize().dump(), builder);
|
|
||||||
std::optional<auth::Role> role{};
|
|
||||||
if (const auto *role_ptr = self.role(); role_ptr) {
|
|
||||||
role.emplace(*role_ptr);
|
|
||||||
}
|
|
||||||
memgraph::slk::Save(role, builder);
|
|
||||||
}
|
|
||||||
// Deserialize code for auth::User
|
|
||||||
void Load(auth::User *self, memgraph::slk::Reader *reader) {
|
|
||||||
std::string tmp;
|
|
||||||
memgraph::slk::Load(&tmp, reader);
|
|
||||||
const auto json = nlohmann::json::parse(tmp);
|
|
||||||
*self = memgraph::auth::User::Deserialize(json);
|
|
||||||
std::optional<auth::Role> role{};
|
|
||||||
memgraph::slk::Load(&role, reader);
|
|
||||||
if (role)
|
|
||||||
self->SetRole(*role);
|
|
||||||
else
|
|
||||||
self->ClearRole();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize code for auth::Auth::Config
|
|
||||||
void Save(const auth::Auth::Config &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self.name_regex_str, builder);
|
|
||||||
memgraph::slk::Save(self.password_regex_str, builder);
|
|
||||||
memgraph::slk::Save(self.password_permit_null, builder);
|
|
||||||
}
|
|
||||||
// Deserialize code for auth::Auth::Config
|
|
||||||
void Load(auth::Auth::Config *self, memgraph::slk::Reader *reader) {
|
|
||||||
std::string name_regex_str{};
|
|
||||||
std::string password_regex_str{};
|
|
||||||
bool password_permit_null{};
|
|
||||||
|
|
||||||
memgraph::slk::Load(&name_regex_str, reader);
|
|
||||||
memgraph::slk::Load(&password_regex_str, reader);
|
|
||||||
memgraph::slk::Load(&password_permit_null, reader);
|
|
||||||
|
|
||||||
*self = auth::Auth::Config{std::move(name_regex_str), std::move(password_regex_str), password_permit_null};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize code for UpdateAuthDataReq
|
|
||||||
void Save(const memgraph::replication::UpdateAuthDataReq &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self.main_uuid, builder);
|
|
||||||
memgraph::slk::Save(self.epoch_id, builder);
|
|
||||||
memgraph::slk::Save(self.expected_group_timestamp, builder);
|
|
||||||
memgraph::slk::Save(self.new_group_timestamp, builder);
|
|
||||||
memgraph::slk::Save(self.user, builder);
|
|
||||||
memgraph::slk::Save(self.role, builder);
|
|
||||||
}
|
|
||||||
void Load(memgraph::replication::UpdateAuthDataReq *self, memgraph::slk::Reader *reader) {
|
|
||||||
memgraph::slk::Load(&self->main_uuid, reader);
|
|
||||||
memgraph::slk::Load(&self->epoch_id, reader);
|
|
||||||
memgraph::slk::Load(&self->expected_group_timestamp, reader);
|
|
||||||
memgraph::slk::Load(&self->new_group_timestamp, reader);
|
|
||||||
memgraph::slk::Load(&self->user, reader);
|
|
||||||
memgraph::slk::Load(&self->role, reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize code for UpdateAuthDataRes
|
|
||||||
void Save(const memgraph::replication::UpdateAuthDataRes &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self.success, builder);
|
|
||||||
}
|
|
||||||
void Load(memgraph::replication::UpdateAuthDataRes *self, memgraph::slk::Reader *reader) {
|
|
||||||
memgraph::slk::Load(&self->success, reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize code for DropAuthDataReq
|
|
||||||
void Save(const memgraph::replication::DropAuthDataReq &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self.main_uuid, builder);
|
|
||||||
memgraph::slk::Save(self.epoch_id, builder);
|
|
||||||
memgraph::slk::Save(self.expected_group_timestamp, builder);
|
|
||||||
memgraph::slk::Save(self.new_group_timestamp, builder);
|
|
||||||
memgraph::slk::Save(utils::EnumToNum<2, uint8_t>(self.type), builder);
|
|
||||||
memgraph::slk::Save(self.name, builder);
|
|
||||||
}
|
|
||||||
void Load(memgraph::replication::DropAuthDataReq *self, memgraph::slk::Reader *reader) {
|
|
||||||
memgraph::slk::Load(&self->main_uuid, reader);
|
|
||||||
memgraph::slk::Load(&self->epoch_id, reader);
|
|
||||||
memgraph::slk::Load(&self->expected_group_timestamp, reader);
|
|
||||||
memgraph::slk::Load(&self->new_group_timestamp, reader);
|
|
||||||
uint8_t type_tmp = 0;
|
|
||||||
memgraph::slk::Load(&type_tmp, reader);
|
|
||||||
if (!utils::NumToEnum<2>(type_tmp, self->type)) {
|
|
||||||
throw SlkReaderException("Unexpected result line:{}!", __LINE__);
|
|
||||||
}
|
|
||||||
memgraph::slk::Load(&self->name, reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize code for DropAuthDataRes
|
|
||||||
void Save(const memgraph::replication::DropAuthDataRes &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self.success, builder);
|
|
||||||
}
|
|
||||||
void Load(memgraph::replication::DropAuthDataRes *self, memgraph::slk::Reader *reader) {
|
|
||||||
memgraph::slk::Load(&self->success, reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace memgraph::slk
|
|
||||||
|
|
||||||
namespace memgraph::replication {
|
|
||||||
|
|
||||||
constexpr utils::TypeInfo UpdateAuthDataReq::kType{utils::TypeId::REP_UPDATE_AUTH_DATA_REQ, "UpdateAuthDataReq",
|
|
||||||
nullptr};
|
|
||||||
|
|
||||||
constexpr utils::TypeInfo UpdateAuthDataRes::kType{utils::TypeId::REP_UPDATE_AUTH_DATA_RES, "UpdateAuthDataRes",
|
|
||||||
nullptr};
|
|
||||||
|
|
||||||
constexpr utils::TypeInfo DropAuthDataReq::kType{utils::TypeId::REP_DROP_AUTH_DATA_REQ, "DropAuthDataReq", nullptr};
|
|
||||||
|
|
||||||
constexpr utils::TypeInfo DropAuthDataRes::kType{utils::TypeId::REP_DROP_AUTH_DATA_RES, "DropAuthDataRes", nullptr};
|
|
||||||
|
|
||||||
void UpdateAuthDataReq::Save(const UpdateAuthDataReq &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self, builder);
|
|
||||||
}
|
|
||||||
void UpdateAuthDataReq::Load(UpdateAuthDataReq *self, memgraph::slk::Reader *reader) {
|
|
||||||
memgraph::slk::Load(self, reader);
|
|
||||||
}
|
|
||||||
void UpdateAuthDataRes::Save(const UpdateAuthDataRes &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self, builder);
|
|
||||||
}
|
|
||||||
void UpdateAuthDataRes::Load(UpdateAuthDataRes *self, memgraph::slk::Reader *reader) {
|
|
||||||
memgraph::slk::Load(self, reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DropAuthDataReq::Save(const DropAuthDataReq &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self, builder);
|
|
||||||
}
|
|
||||||
void DropAuthDataReq::Load(DropAuthDataReq *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); }
|
|
||||||
void DropAuthDataRes::Save(const DropAuthDataRes &self, memgraph::slk::Builder *builder) {
|
|
||||||
memgraph::slk::Save(self, builder);
|
|
||||||
}
|
|
||||||
void DropAuthDataRes::Load(DropAuthDataRes *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); }
|
|
||||||
|
|
||||||
} // namespace memgraph::replication
|
|
||||||
127
src/auth/rpc.hpp
127
src/auth/rpc.hpp
@@ -1,127 +0,0 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
|
||||||
//
|
|
||||||
// Use of this software is governed by the Business Source License
|
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
|
||||||
// License, and you may not use this file except in compliance with the Business Source License.
|
|
||||||
//
|
|
||||||
// As of the Change Date specified in that file, in accordance with
|
|
||||||
// the Business Source License, use of this software will be governed
|
|
||||||
// by the Apache License, Version 2.0, included in the file
|
|
||||||
// licenses/APL.txt.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include "auth/auth.hpp"
|
|
||||||
#include "auth/models.hpp"
|
|
||||||
#include "rpc/messages.hpp"
|
|
||||||
#include "slk/streams.hpp"
|
|
||||||
|
|
||||||
namespace memgraph::replication {
|
|
||||||
|
|
||||||
struct UpdateAuthDataReq {
|
|
||||||
static const utils::TypeInfo kType;
|
|
||||||
static const utils::TypeInfo &GetTypeInfo() { return kType; }
|
|
||||||
|
|
||||||
static void Load(UpdateAuthDataReq *self, memgraph::slk::Reader *reader);
|
|
||||||
static void Save(const UpdateAuthDataReq &self, memgraph::slk::Builder *builder);
|
|
||||||
UpdateAuthDataReq() = default;
|
|
||||||
UpdateAuthDataReq(const utils::UUID &main_uuid, std::string epoch_id, uint64_t expected_ts, uint64_t new_ts,
|
|
||||||
auth::User user)
|
|
||||||
: main_uuid(main_uuid),
|
|
||||||
epoch_id{std::move(epoch_id)},
|
|
||||||
expected_group_timestamp{expected_ts},
|
|
||||||
new_group_timestamp{new_ts},
|
|
||||||
user{std::move(user)} {}
|
|
||||||
UpdateAuthDataReq(const utils::UUID &main_uuid, std::string epoch_id, uint64_t expected_ts, uint64_t new_ts,
|
|
||||||
auth::Role role)
|
|
||||||
: main_uuid(main_uuid),
|
|
||||||
epoch_id{std::move(epoch_id)},
|
|
||||||
expected_group_timestamp{expected_ts},
|
|
||||||
new_group_timestamp{new_ts},
|
|
||||||
role{std::move(role)} {}
|
|
||||||
|
|
||||||
utils::UUID main_uuid;
|
|
||||||
std::string epoch_id;
|
|
||||||
uint64_t expected_group_timestamp;
|
|
||||||
uint64_t new_group_timestamp;
|
|
||||||
std::optional<auth::User> user;
|
|
||||||
std::optional<auth::Role> role;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UpdateAuthDataRes {
|
|
||||||
static const utils::TypeInfo kType;
|
|
||||||
static const utils::TypeInfo &GetTypeInfo() { return kType; }
|
|
||||||
|
|
||||||
static void Load(UpdateAuthDataRes *self, memgraph::slk::Reader *reader);
|
|
||||||
static void Save(const UpdateAuthDataRes &self, memgraph::slk::Builder *builder);
|
|
||||||
UpdateAuthDataRes() = default;
|
|
||||||
explicit UpdateAuthDataRes(bool success) : success{success} {}
|
|
||||||
|
|
||||||
bool success;
|
|
||||||
};
|
|
||||||
|
|
||||||
using UpdateAuthDataRpc = rpc::RequestResponse<UpdateAuthDataReq, UpdateAuthDataRes>;
|
|
||||||
|
|
||||||
struct DropAuthDataReq {
|
|
||||||
static const utils::TypeInfo kType;
|
|
||||||
static const utils::TypeInfo &GetTypeInfo() { return kType; }
|
|
||||||
|
|
||||||
static void Load(DropAuthDataReq *self, memgraph::slk::Reader *reader);
|
|
||||||
static void Save(const DropAuthDataReq &self, memgraph::slk::Builder *builder);
|
|
||||||
DropAuthDataReq() = default;
|
|
||||||
|
|
||||||
enum class DataType { USER, ROLE };
|
|
||||||
|
|
||||||
DropAuthDataReq(const utils::UUID &main_uuid, std::string epoch_id, uint64_t expected_ts, uint64_t new_ts,
|
|
||||||
DataType type, std::string_view name)
|
|
||||||
: main_uuid(main_uuid),
|
|
||||||
epoch_id{std::move(epoch_id)},
|
|
||||||
expected_group_timestamp{expected_ts},
|
|
||||||
new_group_timestamp{new_ts},
|
|
||||||
type{type},
|
|
||||||
name{name} {}
|
|
||||||
|
|
||||||
utils::UUID main_uuid;
|
|
||||||
std::string epoch_id;
|
|
||||||
uint64_t expected_group_timestamp;
|
|
||||||
uint64_t new_group_timestamp;
|
|
||||||
DataType type;
|
|
||||||
std::string name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DropAuthDataRes {
|
|
||||||
static const utils::TypeInfo kType;
|
|
||||||
static const utils::TypeInfo &GetTypeInfo() { return kType; }
|
|
||||||
|
|
||||||
static void Load(DropAuthDataRes *self, memgraph::slk::Reader *reader);
|
|
||||||
static void Save(const DropAuthDataRes &self, memgraph::slk::Builder *builder);
|
|
||||||
DropAuthDataRes() = default;
|
|
||||||
explicit DropAuthDataRes(bool success) : success{success} {}
|
|
||||||
|
|
||||||
bool success;
|
|
||||||
};
|
|
||||||
|
|
||||||
using DropAuthDataRpc = rpc::RequestResponse<DropAuthDataReq, DropAuthDataRes>;
|
|
||||||
|
|
||||||
} // namespace memgraph::replication
|
|
||||||
|
|
||||||
namespace memgraph::slk {
|
|
||||||
|
|
||||||
void Save(const auth::Role &self, memgraph::slk::Builder *builder);
|
|
||||||
void Load(auth::Role *self, memgraph::slk::Reader *reader);
|
|
||||||
void Save(const auth::User &self, memgraph::slk::Builder *builder);
|
|
||||||
void Load(auth::User *self, memgraph::slk::Reader *reader);
|
|
||||||
void Save(const auth::Auth::Config &self, memgraph::slk::Builder *builder);
|
|
||||||
void Load(auth::Auth::Config *self, memgraph::slk::Reader *reader);
|
|
||||||
|
|
||||||
void Save(const memgraph::replication::UpdateAuthDataRes &self, memgraph::slk::Builder *builder);
|
|
||||||
void Load(memgraph::replication::UpdateAuthDataRes *self, memgraph::slk::Reader *reader);
|
|
||||||
void Save(const memgraph::replication::UpdateAuthDataReq & /*self*/, memgraph::slk::Builder * /*builder*/);
|
|
||||||
void Load(memgraph::replication::UpdateAuthDataReq * /*self*/, memgraph::slk::Reader * /*reader*/);
|
|
||||||
void Save(const memgraph::replication::DropAuthDataRes &self, memgraph::slk::Builder *builder);
|
|
||||||
void Load(memgraph::replication::DropAuthDataRes *self, memgraph::slk::Reader *reader);
|
|
||||||
void Save(const memgraph::replication::DropAuthDataReq & /*self*/, memgraph::slk::Builder * /*builder*/);
|
|
||||||
void Load(memgraph::replication::DropAuthDataReq * /*self*/, memgraph::slk::Reader * /*reader*/);
|
|
||||||
} // namespace memgraph::slk
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -15,9 +15,6 @@
|
|||||||
#include "communication/bolt/v1/value.hpp"
|
#include "communication/bolt/v1/value.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
#include "communication/bolt/v1/fmt.hpp"
|
|
||||||
#include "io/network/fmt.hpp"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr uint8_t kBoltV43Version[4] = {0x00, 0x00, 0x03, 0x04};
|
constexpr uint8_t kBoltV43Version[4] = {0x00, 0x00, 0x03, 0x04};
|
||||||
constexpr uint8_t kEmptyBoltVersion[4] = {0x00, 0x00, 0x00, 0x00};
|
constexpr uint8_t kEmptyBoltVersion[4] = {0x00, 0x00, 0x00, 0x00};
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "communication/bolt/v1/codes.hpp"
|
#include "communication/bolt/v1/codes.hpp"
|
||||||
@@ -35,8 +34,8 @@ class FailureResponseException : public utils::BasicException {
|
|||||||
|
|
||||||
explicit FailureResponseException(const std::string &message) : utils::BasicException{message} {}
|
explicit FailureResponseException(const std::string &message) : utils::BasicException{message} {}
|
||||||
|
|
||||||
FailureResponseException(std::string code, const std::string &message)
|
FailureResponseException(const std::string &code, const std::string &message)
|
||||||
: utils::BasicException{message}, code_{std::move(code)} {}
|
: utils::BasicException{message}, code_{code} {}
|
||||||
|
|
||||||
const std::string &code() const { return code_; }
|
const std::string &code() const { return code_; }
|
||||||
SPECIALIZE_GET_EXCEPTION_NAME(FailureResponseException)
|
SPECIALIZE_GET_EXCEPTION_NAME(FailureResponseException)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -51,7 +51,7 @@ enum class ChunkState : uint8_t {
|
|||||||
template <typename TBuffer>
|
template <typename TBuffer>
|
||||||
class ChunkedDecoderBuffer {
|
class ChunkedDecoderBuffer {
|
||||||
public:
|
public:
|
||||||
explicit ChunkedDecoderBuffer(TBuffer &buffer) : buffer_(buffer) { data_.reserve(kChunkMaxDataSize); }
|
ChunkedDecoderBuffer(TBuffer &buffer) : buffer_(buffer) { data_.reserve(kChunkMaxDataSize); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads data from the internal buffer.
|
* Reads data from the internal buffer.
|
||||||
|
|||||||
@@ -401,11 +401,11 @@ class Decoder {
|
|||||||
}
|
}
|
||||||
auto &labels = dv.ValueList();
|
auto &labels = dv.ValueList();
|
||||||
vertex.labels.reserve(labels.size());
|
vertex.labels.reserve(labels.size());
|
||||||
for (auto &label : labels) {
|
for (size_t i = 0; i < labels.size(); ++i) {
|
||||||
if (label.type() != Value::Type::String) {
|
if (labels[i].type() != Value::Type::String) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
vertex.labels.emplace_back(std::move(label.ValueString()));
|
vertex.labels.emplace_back(std::move(labels[i].ValueString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// read properties
|
// read properties
|
||||||
|
|||||||
@@ -111,12 +111,12 @@ class BaseEncoder {
|
|||||||
|
|
||||||
void WriteList(const std::vector<Value> &value) {
|
void WriteList(const std::vector<Value> &value) {
|
||||||
WriteTypeSize(value.size(), MarkerList);
|
WriteTypeSize(value.size(), MarkerList);
|
||||||
for (const auto &x : value) WriteValue(x);
|
for (auto &x : value) WriteValue(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMap(const std::map<std::string, Value> &value) {
|
void WriteMap(const std::map<std::string, Value> &value) {
|
||||||
WriteTypeSize(value.size(), MarkerMap);
|
WriteTypeSize(value.size(), MarkerMap);
|
||||||
for (const auto &x : value) {
|
for (auto &x : value) {
|
||||||
WriteString(x.first);
|
WriteString(x.first);
|
||||||
WriteValue(x.second);
|
WriteValue(x.second);
|
||||||
}
|
}
|
||||||
@@ -205,11 +205,11 @@ class BaseEncoder {
|
|||||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + 3);
|
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + 3);
|
||||||
WriteRAW(utils::UnderlyingCast(Signature::Path));
|
WriteRAW(utils::UnderlyingCast(Signature::Path));
|
||||||
WriteTypeSize(path.vertices.size(), MarkerList);
|
WriteTypeSize(path.vertices.size(), MarkerList);
|
||||||
for (const auto &v : path.vertices) WriteVertex(v);
|
for (auto &v : path.vertices) WriteVertex(v);
|
||||||
WriteTypeSize(path.edges.size(), MarkerList);
|
WriteTypeSize(path.edges.size(), MarkerList);
|
||||||
for (const auto &e : path.edges) WriteEdge(e);
|
for (auto &e : path.edges) WriteEdge(e);
|
||||||
WriteTypeSize(path.indices.size(), MarkerList);
|
WriteTypeSize(path.indices.size(), MarkerList);
|
||||||
for (const auto &i : path.indices) WriteInt(i);
|
for (auto &i : path.indices) WriteInt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteDate(const utils::Date &date) {
|
void WriteDate(const utils::Date &date) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -48,7 +48,7 @@ namespace memgraph::communication::bolt {
|
|||||||
template <class TOutputStream>
|
template <class TOutputStream>
|
||||||
class ChunkedEncoderBuffer {
|
class ChunkedEncoderBuffer {
|
||||||
public:
|
public:
|
||||||
explicit ChunkedEncoderBuffer(TOutputStream &output_stream) : output_stream_(output_stream) {}
|
ChunkedEncoderBuffer(TOutputStream &output_stream) : output_stream_(output_stream) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes n values into the buffer. If n is bigger than whole chunk size
|
* Writes n values into the buffer. If n is bigger than whole chunk size
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class ClientEncoder : private BaseEncoder<Buffer> {
|
|||||||
using BaseEncoder<Buffer>::buffer_;
|
using BaseEncoder<Buffer>::buffer_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ClientEncoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
ClientEncoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
||||||
|
|
||||||
using BaseEncoder<Buffer>::UpdateVersion;
|
using BaseEncoder<Buffer>::UpdateVersion;
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class Encoder : private BaseEncoder<Buffer> {
|
|||||||
using BaseEncoder<Buffer>::buffer_;
|
using BaseEncoder<Buffer>::buffer_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Encoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
Encoder(Buffer &buffer) : BaseEncoder<Buffer>(buffer) {}
|
||||||
|
|
||||||
using BaseEncoder<Buffer>::UpdateVersion;
|
using BaseEncoder<Buffer>::UpdateVersion;
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
|
||||||
//
|
|
||||||
// Use of this software is governed by the Business Source License
|
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
|
||||||
// License, and you may not use this file except in compliance with the Business Source License.
|
|
||||||
//
|
|
||||||
// As of the Change Date specified in that file, in accordance with
|
|
||||||
// the Business Source License, use of this software will be governed
|
|
||||||
// by the Apache License, Version 2.0, included in the file
|
|
||||||
// licenses/APL.txt.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if FMT_VERSION > 90000
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "communication/bolt/v1/value.hpp"
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class fmt::formatter<memgraph::communication::bolt::Value> : public fmt::ostream_formatter {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class fmt::formatter<std::vector<memgraph::communication::bolt::Value>> : public fmt::ostream_formatter {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class fmt::formatter<std::map<std::string, memgraph::communication::bolt::Value>> : public fmt::ostream_formatter {};
|
|
||||||
#endif
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -93,7 +93,7 @@ State HandlePullDiscard(TSession &session, std::optional<int> n, std::optional<i
|
|||||||
return State::Close;
|
return State::Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summary.contains("has_more") && summary.at("has_more").ValueBool()) {
|
if (summary.count("has_more") && summary.at("has_more").ValueBool()) {
|
||||||
return State::Result;
|
return State::Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,13 +148,13 @@ State HandlePullDiscardV4(TSession &session, const State state, const Marker mar
|
|||||||
spdlog::trace("Couldn't read extra field!");
|
spdlog::trace("Couldn't read extra field!");
|
||||||
}
|
}
|
||||||
const auto &extra_map = extra.ValueMap();
|
const auto &extra_map = extra.ValueMap();
|
||||||
if (extra_map.contains("n")) {
|
if (extra_map.count("n")) {
|
||||||
if (const auto n_value = extra_map.at("n").ValueInt(); n_value != kPullAll) {
|
if (const auto n_value = extra_map.at("n").ValueInt(); n_value != kPullAll) {
|
||||||
n = n_value;
|
n = n_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extra_map.contains("qid")) {
|
if (extra_map.count("qid")) {
|
||||||
if (const auto qid_value = extra_map.at("qid").ValueInt(); qid_value != kPullLast) {
|
if (const auto qid_value = extra_map.at("qid").ValueInt(); qid_value != kPullLast) {
|
||||||
qid = qid_value;
|
qid = qid_value;
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,6 @@ inline State HandleFailure(TSession &session, const std::exception &e) {
|
|||||||
spdlog::trace("Error trace: {}", p->trace());
|
spdlog::trace("Error trace: {}", p->trace());
|
||||||
}
|
}
|
||||||
session.encoder_buffer_.Clear();
|
session.encoder_buffer_.Clear();
|
||||||
|
|
||||||
auto code_message = ExceptionToErrorMessage(e);
|
auto code_message = ExceptionToErrorMessage(e);
|
||||||
bool fail_sent = session.encoder_.MessageFailure({{"code", code_message.first}, {"message", code_message.second}});
|
bool fail_sent = session.encoder_.MessageFailure({{"code", code_message.first}, {"message", code_message.second}});
|
||||||
if (!fail_sent) {
|
if (!fail_sent) {
|
||||||
@@ -368,16 +367,14 @@ State HandleReset(TSession &session, const Marker marker) {
|
|||||||
return State::Close;
|
return State::Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (!session.encoder_.MessageSuccess()) {
|
||||||
session.Abort();
|
spdlog::trace("Couldn't send success message!");
|
||||||
if (!session.encoder_.MessageSuccess({})) {
|
return State::Close;
|
||||||
spdlog::trace("Couldn't send success message!");
|
|
||||||
return State::Close;
|
|
||||||
}
|
|
||||||
return State::Idle;
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
return HandleFailure(session, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session.Abort();
|
||||||
|
|
||||||
|
return State::Idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSession>
|
template <typename TSession>
|
||||||
@@ -400,17 +397,19 @@ State HandleBegin(TSession &session, const State state, const Marker marker) {
|
|||||||
|
|
||||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||||
|
|
||||||
|
if (!session.encoder_.MessageSuccess({})) {
|
||||||
|
spdlog::trace("Couldn't send success message!");
|
||||||
|
return State::Close;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
session.Configure(extra.ValueMap());
|
session.Configure(extra.ValueMap());
|
||||||
session.BeginTransaction(extra.ValueMap());
|
session.BeginTransaction(extra.ValueMap());
|
||||||
if (!session.encoder_.MessageSuccess({})) {
|
|
||||||
spdlog::trace("Couldn't send success message!");
|
|
||||||
return State::Close;
|
|
||||||
}
|
|
||||||
return State::Idle;
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
return HandleFailure(session, e);
|
return HandleFailure(session, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return State::Idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSession>
|
template <typename TSession>
|
||||||
@@ -428,11 +427,11 @@ State HandleCommit(TSession &session, const State state, const Marker marker) {
|
|||||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
session.CommitTransaction();
|
|
||||||
if (!session.encoder_.MessageSuccess({})) {
|
if (!session.encoder_.MessageSuccess({})) {
|
||||||
spdlog::trace("Couldn't send success message!");
|
spdlog::trace("Couldn't send success message!");
|
||||||
return State::Close;
|
return State::Close;
|
||||||
}
|
}
|
||||||
|
session.CommitTransaction();
|
||||||
return State::Idle;
|
return State::Idle;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
return HandleFailure(session, e);
|
return HandleFailure(session, e);
|
||||||
@@ -454,11 +453,11 @@ State HandleRollback(TSession &session, const State state, const Marker marker)
|
|||||||
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
DMG_ASSERT(!session.encoder_buffer_.HasData(), "There should be no data to write in this state");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
session.RollbackTransaction();
|
|
||||||
if (!session.encoder_.MessageSuccess({})) {
|
if (!session.encoder_.MessageSuccess({})) {
|
||||||
spdlog::trace("Couldn't send success message!");
|
spdlog::trace("Couldn't send success message!");
|
||||||
return State::Close;
|
return State::Close;
|
||||||
}
|
}
|
||||||
|
session.RollbackTransaction();
|
||||||
return State::Idle;
|
return State::Idle;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
return HandleFailure(session, e);
|
return HandleFailure(session, e);
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ std::optional<State> AuthenticateUser(TSession &session, Value &metadata) {
|
|||||||
std::string username;
|
std::string username;
|
||||||
std::string password;
|
std::string password;
|
||||||
if (data["scheme"].ValueString() == "basic") {
|
if (data["scheme"].ValueString() == "basic") {
|
||||||
if (!data.contains("principal")) { // Special case principal = ""
|
if (!data.count("principal")) { // Special case principal = ""
|
||||||
spdlog::warn("The client didn't supply the principal field! Trying with \"\"...");
|
spdlog::warn("The client didn't supply the principal field! Trying with \"\"...");
|
||||||
data["principal"] = "";
|
data["principal"] = "";
|
||||||
}
|
}
|
||||||
if (!data.contains("credentials")) { // Special case credentials = ""
|
if (!data.count("credentials")) { // Special case credentials = ""
|
||||||
spdlog::warn("The client didn't supply the credentials field! Trying with \"\"...");
|
spdlog::warn("The client didn't supply the credentials field! Trying with \"\"...");
|
||||||
data["credentials"] = "";
|
data["credentials"] = "";
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ std::optional<Value> GetMetadataV4(TSession &session, const Marker marker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto &data = metadata.ValueMap();
|
auto &data = metadata.ValueMap();
|
||||||
if (!data.contains("user_agent")) {
|
if (!data.count("user_agent")) {
|
||||||
spdlog::warn("The client didn't supply the user agent!");
|
spdlog::warn("The client didn't supply the user agent!");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ std::optional<Value> GetInitDataV5(TSession &session, const Marker marker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto &data = metadata.ValueMap();
|
const auto &data = metadata.ValueMap();
|
||||||
if (!data.contains("user_agent")) {
|
if (!data.count("user_agent")) {
|
||||||
spdlog::warn("The client didn't supply the user agent!");
|
spdlog::warn("The client didn't supply the user agent!");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ struct UnboundedEdge {
|
|||||||
* The decoder writes data into this structure.
|
* The decoder writes data into this structure.
|
||||||
*/
|
*/
|
||||||
struct Path {
|
struct Path {
|
||||||
Path() = default;
|
Path() {}
|
||||||
|
|
||||||
Path(const std::vector<Vertex> &vertices, const std::vector<Edge> &edges) {
|
Path(const std::vector<Vertex> &vertices, const std::vector<Edge> &edges) {
|
||||||
// Helper function. Looks for the given element in the collection. If found,
|
// Helper function. Looks for the given element in the collection. If found,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "communication/client.hpp"
|
#include "communication/client.hpp"
|
||||||
|
|
||||||
#include "communication/helpers.hpp"
|
#include "communication/helpers.hpp"
|
||||||
#include "io/network/network_error.hpp"
|
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
namespace memgraph::communication {
|
namespace memgraph::communication {
|
||||||
@@ -26,9 +25,7 @@ Client::~Client() {
|
|||||||
|
|
||||||
bool Client::Connect(const io::network::Endpoint &endpoint) {
|
bool Client::Connect(const io::network::Endpoint &endpoint) {
|
||||||
// Try to establish a socket connection.
|
// Try to establish a socket connection.
|
||||||
if (!socket_.Connect(endpoint)) {
|
if (!socket_.Connect(endpoint)) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable TCP keep alive for all connections.
|
// Enable TCP keep alive for all connections.
|
||||||
// Because we manually always set the `have_more` flag to the socket
|
// Because we manually always set the `have_more` flag to the socket
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class Client final {
|
|||||||
*/
|
*/
|
||||||
class ClientInputStream final {
|
class ClientInputStream final {
|
||||||
public:
|
public:
|
||||||
explicit ClientInputStream(Client &client);
|
ClientInputStream(Client &client);
|
||||||
|
|
||||||
ClientInputStream(const ClientInputStream &) = delete;
|
ClientInputStream(const ClientInputStream &) = delete;
|
||||||
ClientInputStream(ClientInputStream &&) = delete;
|
ClientInputStream(ClientInputStream &&) = delete;
|
||||||
@@ -156,7 +156,7 @@ class ClientInputStream final {
|
|||||||
*/
|
*/
|
||||||
class ClientOutputStream final {
|
class ClientOutputStream final {
|
||||||
public:
|
public:
|
||||||
explicit ClientOutputStream(Client &client);
|
ClientOutputStream(Client &client);
|
||||||
|
|
||||||
ClientOutputStream(const ClientOutputStream &) = delete;
|
ClientOutputStream(const ClientOutputStream &) = delete;
|
||||||
ClientOutputStream(ClientOutputStream &&) = delete;
|
ClientOutputStream(ClientOutputStream &&) = delete;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -34,7 +34,7 @@ ClientContext::ClientContext(bool use_ssl) : use_ssl_(use_ssl), ctx_(nullptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClientContext::ClientContext(const std::string &key_file, const std::string &cert_file) : ClientContext(true) {
|
ClientContext::ClientContext(const std::string &key_file, const std::string &cert_file) : ClientContext(true) {
|
||||||
if (!key_file.empty() && !cert_file.empty()) {
|
if (key_file != "" && cert_file != "") {
|
||||||
MG_ASSERT(SSL_CTX_use_certificate_file(ctx_, cert_file.c_str(), SSL_FILETYPE_PEM) == 1,
|
MG_ASSERT(SSL_CTX_use_certificate_file(ctx_, cert_file.c_str(), SSL_FILETYPE_PEM) == 1,
|
||||||
"Couldn't load client certificate from file: {}", cert_file);
|
"Couldn't load client certificate from file: {}", cert_file);
|
||||||
MG_ASSERT(SSL_CTX_use_PrivateKey_file(ctx_, key_file.c_str(), SSL_FILETYPE_PEM) == 1,
|
MG_ASSERT(SSL_CTX_use_PrivateKey_file(ctx_, key_file.c_str(), SSL_FILETYPE_PEM) == 1,
|
||||||
@@ -124,7 +124,7 @@ ServerContext &ServerContext::operator=(ServerContext &&other) noexcept {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerContext::~ServerContext() = default;
|
ServerContext::~ServerContext() {}
|
||||||
|
|
||||||
SSL_CTX *ServerContext::context() {
|
SSL_CTX *ServerContext::context() {
|
||||||
MG_ASSERT(ctx_);
|
MG_ASSERT(ctx_);
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
|
||||||
//
|
|
||||||
// Use of this software is governed by the Business Source License
|
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
|
||||||
// License, and you may not use this file except in compliance with the Business Source License.
|
|
||||||
//
|
|
||||||
// As of the Change Date specified in that file, in accordance with
|
|
||||||
// the Business Source License, use of this software will be governed
|
|
||||||
// by the Apache License, Version 2.0, included in the file
|
|
||||||
// licenses/APL.txt.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if FMT_VERSION > 90000
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class fmt::formatter<boost::asio::ip::tcp::endpoint> : public fmt::ostream_formatter {};
|
|
||||||
#endif
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
namespace memgraph::communication {
|
namespace memgraph::communication {
|
||||||
|
|
||||||
std::string SslGetLastError() {
|
const std::string SslGetLastError() {
|
||||||
char buff[2048];
|
char buff[2048];
|
||||||
auto err = ERR_get_error();
|
auto err = ERR_get_error();
|
||||||
ERR_error_string_n(err, buff, sizeof(buff));
|
ERR_error_string_n(err, buff, sizeof(buff));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -18,6 +18,6 @@ namespace memgraph::communication {
|
|||||||
/**
|
/**
|
||||||
* This function reads and returns a string describing the last OpenSSL error.
|
* This function reads and returns a string describing the last OpenSSL error.
|
||||||
*/
|
*/
|
||||||
std::string SslGetLastError();
|
const std::string SslGetLastError();
|
||||||
|
|
||||||
} // namespace memgraph::communication
|
} // namespace memgraph::communication
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -21,7 +21,6 @@
|
|||||||
#include <boost/beast/core.hpp>
|
#include <boost/beast/core.hpp>
|
||||||
|
|
||||||
#include "communication/context.hpp"
|
#include "communication/context.hpp"
|
||||||
#include "communication/fmt.hpp"
|
|
||||||
#include "communication/http/session.hpp"
|
#include "communication/http/session.hpp"
|
||||||
#include "utils/spin_lock.hpp"
|
#include "utils/spin_lock.hpp"
|
||||||
#include "utils/synchronized.hpp"
|
#include "utils/synchronized.hpp"
|
||||||
@@ -39,7 +38,7 @@ class Listener final : public std::enable_shared_from_this<Listener<TRequestHand
|
|||||||
Listener(Listener &&) = delete;
|
Listener(Listener &&) = delete;
|
||||||
Listener &operator=(const Listener &) = delete;
|
Listener &operator=(const Listener &) = delete;
|
||||||
Listener &operator=(Listener &&) = delete;
|
Listener &operator=(Listener &&) = delete;
|
||||||
~Listener() = default;
|
~Listener() {}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static std::shared_ptr<Listener> Create(Args &&...args) {
|
static std::shared_ptr<Listener> Create(Args &&...args) {
|
||||||
@@ -83,7 +82,7 @@ class Listener final : public std::enable_shared_from_this<Listener<TRequestHand
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::info("HTTP server is listening on {}", endpoint);
|
spdlog::info("HTTP server is listening on {}:{}", endpoint.address(), endpoint.port());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoAccept() {
|
void DoAccept() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -107,7 +107,7 @@ class Session : public std::enable_shared_from_this<Session<TRequestHandler, TSe
|
|||||||
void DoRead() {
|
void DoRead() {
|
||||||
req_ = {};
|
req_ = {};
|
||||||
|
|
||||||
ExecuteForStream([this](auto &stream) {
|
ExecuteForStream([this](auto &&stream) {
|
||||||
boost::beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(kSSLExpirySeconds));
|
boost::beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(kSSLExpirySeconds));
|
||||||
|
|
||||||
boost::beast::http::async_read(
|
boost::beast::http::async_read(
|
||||||
@@ -129,7 +129,7 @@ class Session : public std::enable_shared_from_this<Session<TRequestHandler, TSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto async_write = [this](boost::beast::http::response<boost::beast::http::string_body> msg) {
|
auto async_write = [this](boost::beast::http::response<boost::beast::http::string_body> msg) {
|
||||||
ExecuteForStream([this, &msg](auto &stream) {
|
ExecuteForStream([this, &msg](auto &&stream) {
|
||||||
// The lifetime of the message has to extend
|
// The lifetime of the message has to extend
|
||||||
// for the duration of the async operation so
|
// for the duration of the async operation so
|
||||||
// we use a shared_ptr to manage it.
|
// we use a shared_ptr to manage it.
|
||||||
@@ -171,7 +171,7 @@ class Session : public std::enable_shared_from_this<Session<TRequestHandler, TSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto GetExecutor() {
|
auto GetExecutor() {
|
||||||
return std::visit(utils::Overloaded{[](auto &stream) { return stream.get_executor(); }}, stream_);
|
return std::visit(utils::Overloaded{[](auto &&stream) { return stream.get_executor(); }}, stream_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -17,13 +17,11 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
#include "communication/session.hpp"
|
#include "communication/session.hpp"
|
||||||
#include "io/network/epoll.hpp"
|
#include "io/network/epoll.hpp"
|
||||||
#include "io/network/fmt.hpp"
|
|
||||||
#include "io/network/socket.hpp"
|
#include "io/network/socket.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
#include "utils/signals.hpp"
|
#include "utils/signals.hpp"
|
||||||
@@ -53,13 +51,13 @@ class Listener final {
|
|||||||
using SessionHandler = Session<TSession, TSessionContext>;
|
using SessionHandler = Session<TSession, TSessionContext>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Listener(TSessionContext *data, ServerContext *context, int inactivity_timeout_sec, std::string service_name,
|
Listener(TSessionContext *data, ServerContext *context, int inactivity_timeout_sec, const std::string &service_name,
|
||||||
size_t workers_count)
|
size_t workers_count)
|
||||||
: data_(data),
|
: data_(data),
|
||||||
alive_(false),
|
alive_(false),
|
||||||
context_(context),
|
context_(context),
|
||||||
inactivity_timeout_sec_(inactivity_timeout_sec),
|
inactivity_timeout_sec_(inactivity_timeout_sec),
|
||||||
service_name_(std::move(service_name)),
|
service_name_(service_name),
|
||||||
workers_count_(workers_count) {}
|
workers_count_(workers_count) {}
|
||||||
|
|
||||||
~Listener() {
|
~Listener() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -44,7 +44,7 @@ class ResultStreamFaker {
|
|||||||
std::vector<memgraph::communication::bolt::Value> bvalues;
|
std::vector<memgraph::communication::bolt::Value> bvalues;
|
||||||
bvalues.reserve(values.size());
|
bvalues.reserve(values.size());
|
||||||
for (const auto &value : values) {
|
for (const auto &value : values) {
|
||||||
auto maybe_value = memgraph::glue::ToBoltValue(value, store_, memgraph::storage::View::NEW);
|
auto maybe_value = memgraph::glue::ToBoltValue(value, *store_, memgraph::storage::View::NEW);
|
||||||
MG_ASSERT(maybe_value.HasValue());
|
MG_ASSERT(maybe_value.HasValue());
|
||||||
bvalues.push_back(std::move(*maybe_value));
|
bvalues.push_back(std::move(*maybe_value));
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ class ResultStreamFaker {
|
|||||||
void Summary(const std::map<std::string, memgraph::query::TypedValue> &summary) {
|
void Summary(const std::map<std::string, memgraph::query::TypedValue> &summary) {
|
||||||
std::map<std::string, memgraph::communication::bolt::Value> bsummary;
|
std::map<std::string, memgraph::communication::bolt::Value> bsummary;
|
||||||
for (const auto &item : summary) {
|
for (const auto &item : summary) {
|
||||||
auto maybe_value = memgraph::glue::ToBoltValue(item.second, store_, memgraph::storage::View::NEW);
|
auto maybe_value = memgraph::glue::ToBoltValue(item.second, *store_, memgraph::storage::View::NEW);
|
||||||
MG_ASSERT(maybe_value.HasValue());
|
MG_ASSERT(maybe_value.HasValue());
|
||||||
bsummary.insert({item.first, std::move(*maybe_value)});
|
bsummary.insert({item.first, std::move(*maybe_value)});
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ class ResultStreamFaker {
|
|||||||
std::transform(header.begin(), header.end(), column_widths.begin(), [](const auto &s) { return s.size(); });
|
std::transform(header.begin(), header.end(), column_widths.begin(), [](const auto &s) { return s.size(); });
|
||||||
|
|
||||||
// convert all the results into strings, and track max column width
|
// convert all the results into strings, and track max column width
|
||||||
const auto &results_data = results.GetResults();
|
auto &results_data = results.GetResults();
|
||||||
std::vector<std::vector<std::string>> result_strings(results_data.size(),
|
std::vector<std::vector<std::string>> result_strings(results_data.size(),
|
||||||
std::vector<std::string>(column_widths.size()));
|
std::vector<std::string>(column_widths.size()));
|
||||||
for (int row_ind = 0; row_ind < static_cast<int>(results_data.size()); ++row_ind) {
|
for (int row_ind = 0; row_ind < static_cast<int>(results_data.size()); ++row_ind) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include "communication/init.hpp"
|
#include "communication/init.hpp"
|
||||||
#include "communication/listener.hpp"
|
#include "communication/listener.hpp"
|
||||||
#include "io/network/fmt.hpp"
|
|
||||||
#include "io/network/socket.hpp"
|
#include "io/network/socket.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
#include "utils/message.hpp"
|
#include "utils/message.hpp"
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
@@ -52,8 +51,7 @@ using InputStream = Buffer::ReadEnd;
|
|||||||
*/
|
*/
|
||||||
class OutputStream final {
|
class OutputStream final {
|
||||||
public:
|
public:
|
||||||
explicit OutputStream(std::function<bool(const uint8_t *, size_t, bool)> write_function)
|
OutputStream(std::function<bool(const uint8_t *, size_t, bool)> write_function) : write_function_(write_function) {}
|
||||||
: write_function_(std::move(write_function)) {}
|
|
||||||
|
|
||||||
OutputStream(const OutputStream &) = delete;
|
OutputStream(const OutputStream &) = delete;
|
||||||
OutputStream(OutputStream &&) = delete;
|
OutputStream(OutputStream &&) = delete;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class Listener final : public std::enable_shared_from_this<Listener<TSession, TS
|
|||||||
Listener(Listener &&) = delete;
|
Listener(Listener &&) = delete;
|
||||||
Listener &operator=(const Listener &) = delete;
|
Listener &operator=(const Listener &) = delete;
|
||||||
Listener &operator=(Listener &&) = delete;
|
Listener &operator=(Listener &&) = delete;
|
||||||
~Listener() = default;
|
~Listener() {}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static std::shared_ptr<Listener> Create(Args &&...args) {
|
static std::shared_ptr<Listener> Create(Args &&...args) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -26,7 +26,6 @@
|
|||||||
#include <boost/asio/ip/tcp.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
|
||||||
#include "communication/context.hpp"
|
#include "communication/context.hpp"
|
||||||
#include "communication/fmt.hpp"
|
|
||||||
#include "communication/init.hpp"
|
#include "communication/init.hpp"
|
||||||
#include "communication/v2/listener.hpp"
|
#include "communication/v2/listener.hpp"
|
||||||
#include "communication/v2/pool.hpp"
|
#include "communication/v2/pool.hpp"
|
||||||
@@ -130,7 +129,7 @@ bool Server<TSession, TSessionContext>::Start() {
|
|||||||
listener_->Start();
|
listener_->Start();
|
||||||
|
|
||||||
spdlog::info("{} server is fully armed and operational", service_name_);
|
spdlog::info("{} server is fully armed and operational", service_name_);
|
||||||
spdlog::info("{} listening on {}", service_name_, endpoint_);
|
spdlog::info("{} listening on {}", service_name_, endpoint_.address());
|
||||||
context_thread_pool_.Run();
|
context_thread_pool_.Run();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -47,7 +47,6 @@
|
|||||||
#include "communication/buffer.hpp"
|
#include "communication/buffer.hpp"
|
||||||
#include "communication/context.hpp"
|
#include "communication/context.hpp"
|
||||||
#include "communication/exceptions.hpp"
|
#include "communication/exceptions.hpp"
|
||||||
#include "communication/fmt.hpp"
|
|
||||||
#include "dbms/global.hpp"
|
#include "dbms/global.hpp"
|
||||||
#include "utils/event_counter.hpp"
|
#include "utils/event_counter.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
@@ -77,7 +76,7 @@ using tcp = boost::asio::ip::tcp;
|
|||||||
class OutputStream final {
|
class OutputStream final {
|
||||||
public:
|
public:
|
||||||
explicit OutputStream(std::function<bool(const uint8_t *, size_t, bool)> write_function)
|
explicit OutputStream(std::function<bool(const uint8_t *, size_t, bool)> write_function)
|
||||||
: write_function_(std::move(write_function)) {}
|
: write_function_(write_function) {}
|
||||||
|
|
||||||
OutputStream(const OutputStream &) = delete;
|
OutputStream(const OutputStream &) = delete;
|
||||||
OutputStream(OutputStream &&) = delete;
|
OutputStream(OutputStream &&) = delete;
|
||||||
@@ -213,11 +212,14 @@ class WebsocketSession : public std::enable_shared_from_this<WebsocketSession<TS
|
|||||||
session_.Execute();
|
session_.Execute();
|
||||||
DoRead();
|
DoRead();
|
||||||
} catch (const SessionClosedException &e) {
|
} catch (const SessionClosedException &e) {
|
||||||
spdlog::info("{} client {} closed the connection.", service_name_, remote_endpoint_);
|
spdlog::info("{} client {}:{} closed the connection.", service_name_, remote_endpoint_.address(),
|
||||||
|
remote_endpoint_.port());
|
||||||
DoClose();
|
DoClose();
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
spdlog::error("Exception was thrown while processing event in {} session associated with {}", service_name_,
|
spdlog::error(
|
||||||
remote_endpoint_);
|
"Exception was thrown while processing event in {} session "
|
||||||
|
"associated with {}:{}",
|
||||||
|
service_name_, remote_endpoint_.address(), remote_endpoint_.port());
|
||||||
spdlog::debug("Exception message: {}", e.what());
|
spdlog::debug("Exception message: {}", e.what());
|
||||||
DoClose();
|
DoClose();
|
||||||
}
|
}
|
||||||
@@ -374,7 +376,8 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
socket.lowest_layer().non_blocking(false);
|
socket.lowest_layer().non_blocking(false);
|
||||||
});
|
});
|
||||||
timeout_timer_.expires_at(boost::asio::steady_timer::time_point::max());
|
timeout_timer_.expires_at(boost::asio::steady_timer::time_point::max());
|
||||||
spdlog::info("Accepted a connection from {}: {}", service_name_, remote_endpoint_);
|
spdlog::info("Accepted a connection from {}: {}:{}", service_name_, remote_endpoint_.address(),
|
||||||
|
remote_endpoint_.port());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoRead() {
|
void DoRead() {
|
||||||
@@ -434,11 +437,14 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
session_.Execute();
|
session_.Execute();
|
||||||
DoRead();
|
DoRead();
|
||||||
} catch (const SessionClosedException &e) {
|
} catch (const SessionClosedException &e) {
|
||||||
spdlog::info("{} client {} closed the connection.", service_name_, remote_endpoint_);
|
spdlog::info("{} client {}:{} closed the connection.", service_name_, remote_endpoint_.address(),
|
||||||
|
remote_endpoint_.port());
|
||||||
DoShutdown();
|
DoShutdown();
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
spdlog::error("Exception was thrown while processing event in {} session associated with {}", service_name_,
|
spdlog::error(
|
||||||
remote_endpoint_);
|
"Exception was thrown while processing event in {} session "
|
||||||
|
"associated with {}:{}",
|
||||||
|
service_name_, remote_endpoint_.address(), remote_endpoint_.port());
|
||||||
spdlog::debug("Exception message: {}", e.what());
|
spdlog::debug("Exception message: {}", e.what());
|
||||||
DoShutdown();
|
DoShutdown();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Memgraph Ltd.
|
// Copyright 2022 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@@ -12,44 +12,19 @@
|
|||||||
#include "communication/websocket/auth.hpp"
|
#include "communication/websocket/auth.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "utils/variant_helpers.hpp"
|
|
||||||
|
|
||||||
namespace memgraph::communication::websocket {
|
namespace memgraph::communication::websocket {
|
||||||
|
|
||||||
bool SafeAuth::Authenticate(const std::string &username, const std::string &password) const {
|
bool SafeAuth::Authenticate(const std::string &username, const std::string &password) const {
|
||||||
user_or_role_ = auth_->Lock()->Authenticate(username, password);
|
return auth_->Lock()->Authenticate(username, password).has_value();
|
||||||
return user_or_role_.has_value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafeAuth::HasPermission(const auth::Permission permission) const {
|
bool SafeAuth::HasUserPermission(const std::string &username, const auth::Permission permission) const {
|
||||||
auto locked_auth = auth_->ReadLock();
|
if (const auto user = auth_->ReadLock()->GetUser(username); user) {
|
||||||
// Update if cache invalidated
|
return user->GetPermissions().Has(permission) == auth::PermissionLevel::GRANT;
|
||||||
if (!locked_auth->UpToDate(auth_epoch_) && user_or_role_) {
|
|
||||||
bool success = true;
|
|
||||||
std::visit(utils::Overloaded{[&](auth::User &user) {
|
|
||||||
auto tmp = locked_auth->GetUser(user.username());
|
|
||||||
if (!tmp) success = false;
|
|
||||||
user = std::move(*tmp);
|
|
||||||
},
|
|
||||||
[&](auth::Role &role) {
|
|
||||||
auto tmp = locked_auth->GetRole(role.rolename());
|
|
||||||
if (!tmp) success = false;
|
|
||||||
role = std::move(*tmp);
|
|
||||||
}},
|
|
||||||
*user_or_role_);
|
|
||||||
// Missing user/role; delete from cache
|
|
||||||
if (!success) user_or_role_.reset();
|
|
||||||
}
|
}
|
||||||
// Check permissions
|
|
||||||
if (user_or_role_) {
|
|
||||||
return std::visit(utils::Overloaded{[&](auto &user_or_role) {
|
|
||||||
return user_or_role.GetPermissions().Has(permission) == auth::PermissionLevel::GRANT;
|
|
||||||
}},
|
|
||||||
*user_or_role_);
|
|
||||||
}
|
|
||||||
// NOTE: websocket authenticates only if there is a user, so no need to check if access controlled
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafeAuth::AccessControlled() const { return auth_->ReadLock()->AccessControlled(); }
|
bool SafeAuth::HasAnyUsers() const { return auth_->ReadLock()->HasUsers(); }
|
||||||
} // namespace memgraph::communication::websocket
|
} // namespace memgraph::communication::websocket
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user