exordos-mail 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- exordos_mail-0.0.2/.github/workflows/build.yml +125 -0
- exordos_mail-0.0.2/.github/workflows/publish-to-pypi.yml +97 -0
- exordos_mail-0.0.2/.github/workflows/tests.yaml +29 -0
- exordos_mail-0.0.2/.gitignore +12 -0
- exordos_mail-0.0.2/Makefile +48 -0
- exordos_mail-0.0.2/PKG-INFO +254 -0
- exordos_mail-0.0.2/README.md +223 -0
- exordos_mail-0.0.2/etc/exordos_metapaas/logging.yaml +29 -0
- exordos_mail-0.0.2/etc/exordos_metapaas/metapaas_mail_agent.conf +10 -0
- exordos_mail-0.0.2/etc/systemd/exordos-metapaas-mail-agent.service +14 -0
- exordos_mail-0.0.2/etc/systemd/exordos-metapaas-mail-configure.service +14 -0
- exordos_mail-0.0.2/exordos/exordos.yaml +42 -0
- exordos_mail-0.0.2/exordos/images/dp_bootstrap.sh +36 -0
- exordos_mail-0.0.2/exordos/images/dp_install.sh +177 -0
- exordos_mail-0.0.2/exordos/manifests/example_mail.yaml.j2 +36 -0
- exordos_mail-0.0.2/exordos/manifests/mailaas.yaml.j2 +102 -0
- exordos_mail-0.0.2/exordos_mail/__init__.py +13 -0
- exordos_mail-0.0.2/exordos_mail/constants.py +29 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/api/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/api/controllers.py +97 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/api/routes.py +44 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/dm/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/dm/models.py +151 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/infra/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/infra/dm/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/infra/dm/models.py +106 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/infra/services/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/infra/services/builder.py +168 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/paas/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/paas/dm/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/paas/dm/models.py +88 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/paas/services/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/controlplane/paas/services/builder.py +131 -0
- exordos_mail-0.0.2/exordos_mail/dataplane/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/dataplane/driver.py +190 -0
- exordos_mail-0.0.2/exordos_mail/definition.py +71 -0
- exordos_mail-0.0.2/exordos_mail/migrations/0000-init-mail.py +102 -0
- exordos_mail-0.0.2/exordos_mail/migrations/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/tests/__init__.py +1 -0
- exordos_mail-0.0.2/exordos_mail/tests/functional/__init__.py +1 -0
- exordos_mail-0.0.2/exordos_mail/tests/functional/conftest.py +239 -0
- exordos_mail-0.0.2/exordos_mail/tests/functional/prepare_env.py +421 -0
- exordos_mail-0.0.2/exordos_mail/tests/functional/test_mail_provision.py +137 -0
- exordos_mail-0.0.2/exordos_mail/tests/functional/test_smtp_auth.py +436 -0
- exordos_mail-0.0.2/exordos_mail/tests/unit/__init__.py +0 -0
- exordos_mail-0.0.2/exordos_mail/tests/unit/test_driver.py +102 -0
- exordos_mail-0.0.2/exordos_mail/tests/unit/test_models.py +37 -0
- exordos_mail-0.0.2/exordos_mail/utils.py +29 -0
- exordos_mail-0.0.2/exordos_mail.egg-info/PKG-INFO +254 -0
- exordos_mail-0.0.2/exordos_mail.egg-info/SOURCES.txt +57 -0
- exordos_mail-0.0.2/exordos_mail.egg-info/dependency_links.txt +1 -0
- exordos_mail-0.0.2/exordos_mail.egg-info/entry_points.txt +5 -0
- exordos_mail-0.0.2/exordos_mail.egg-info/requires.txt +25 -0
- exordos_mail-0.0.2/exordos_mail.egg-info/top_level.txt +1 -0
- exordos_mail-0.0.2/pyproject.toml +103 -0
- exordos_mail-0.0.2/setup.cfg +4 -0
- exordos_mail-0.0.2/tox.ini +69 -0
- exordos_mail-0.0.2/uv.lock +2283 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
name: build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
types: [opened]
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
PACKER_VERSION: "1.9.2"
|
|
10
|
+
PYTHON_VERSION: "3.12"
|
|
11
|
+
CORE_ENDPOINT_URL: http://10.20.0.2:80/api/core
|
|
12
|
+
CORE_USERNAME: "admin"
|
|
13
|
+
CORE_PASSWORD: "admin"
|
|
14
|
+
ELEMENT_NAME: mailaas
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
Build:
|
|
18
|
+
runs-on: ubuntu-24.04
|
|
19
|
+
if: ${{ github.actor != 'dependabot[bot]' }}
|
|
20
|
+
steps:
|
|
21
|
+
- name: Setup packer
|
|
22
|
+
uses: hashicorp/setup-packer@main
|
|
23
|
+
with:
|
|
24
|
+
version: ${{ env.PACKER_VERSION }}
|
|
25
|
+
|
|
26
|
+
- name: Install exordos CLI
|
|
27
|
+
run: curl -fsSL https://repo.exordos.com/install.sh | sudo sh
|
|
28
|
+
|
|
29
|
+
- name: Install hypervisor
|
|
30
|
+
run: |
|
|
31
|
+
sudo exordos compute hypervisors init
|
|
32
|
+
sudo chmod 666 /dev/kvm
|
|
33
|
+
|
|
34
|
+
- uses: actions/checkout@v6
|
|
35
|
+
with:
|
|
36
|
+
fetch-depth: 0
|
|
37
|
+
|
|
38
|
+
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
|
39
|
+
uses: actions/setup-python@v6
|
|
40
|
+
with:
|
|
41
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
42
|
+
|
|
43
|
+
- name: Install uv + tox + build
|
|
44
|
+
uses: astral-sh/setup-uv@v7
|
|
45
|
+
- run: |
|
|
46
|
+
uv tool install tox --with tox-uv
|
|
47
|
+
pip install build
|
|
48
|
+
|
|
49
|
+
- name: Build and push exordos_mail
|
|
50
|
+
timeout-minutes: 20
|
|
51
|
+
env:
|
|
52
|
+
PUSH_EXORDOS_CFG: ${{ secrets.PUSH_EXORDOS_CFG }}
|
|
53
|
+
run: |
|
|
54
|
+
set -eux
|
|
55
|
+
|
|
56
|
+
VERSION="$(exordos get-version .)"
|
|
57
|
+
|
|
58
|
+
exordos build $(pwd)
|
|
59
|
+
|
|
60
|
+
echo "$PUSH_EXORDOS_CFG" | base64 -d > exordos/exordos.push.yaml
|
|
61
|
+
exordos push -c exordos/exordos.push.yaml -t exordos_repo -f --latest
|
|
62
|
+
|
|
63
|
+
echo "MAILAAS_VERSION=${VERSION}" >> $GITHUB_ENV
|
|
64
|
+
|
|
65
|
+
- name: Configure exordos settings
|
|
66
|
+
run: |
|
|
67
|
+
exordos settings set-realm default --endpoint $CORE_ENDPOINT_URL
|
|
68
|
+
exordos settings set-context default --name default --user $CORE_USERNAME --password $CORE_PASSWORD
|
|
69
|
+
|
|
70
|
+
- name: Bootstrap exordos_core
|
|
71
|
+
run: exordos bootstrap -i latest -f -m core --admin-password $CORE_PASSWORD --cidr 10.20.0.0/22
|
|
72
|
+
|
|
73
|
+
- name: Wait for Exordos Core API
|
|
74
|
+
run: |
|
|
75
|
+
for i in {1..60}; do
|
|
76
|
+
if exordos ready_api; then
|
|
77
|
+
echo "Exordos Core API is ready"
|
|
78
|
+
break
|
|
79
|
+
fi
|
|
80
|
+
echo "Waiting for Exordos Core API... ($i/60)"
|
|
81
|
+
sleep 5
|
|
82
|
+
done
|
|
83
|
+
|
|
84
|
+
- name: Set hypervisor with overbooking
|
|
85
|
+
run: |
|
|
86
|
+
HYPER_UUID="$(exordos c h l -o json | jq -r .[0]."UUID")"
|
|
87
|
+
exordos compute hypervisors update $HYPER_UUID --cores-ratio 10.0 --ram-ratio 10.0
|
|
88
|
+
|
|
89
|
+
- name: Build + serve + install (prepare_env.py)
|
|
90
|
+
run: |
|
|
91
|
+
tox -e develop
|
|
92
|
+
|
|
93
|
+
.tox/develop/bin/python \
|
|
94
|
+
exordos_mail/tests/functional/prepare_env.py \
|
|
95
|
+
--project-dir . \
|
|
96
|
+
--output-dir /tmp/metapaas-mail-build \
|
|
97
|
+
--endpoint $CORE_ENDPOINT_URL \
|
|
98
|
+
--username $CORE_USERNAME \
|
|
99
|
+
--password "${CORE_PASSWORD}" \
|
|
100
|
+
--wait-timeout 600 \
|
|
101
|
+
2>&1 | tee /tmp/prepare_env.log
|
|
102
|
+
|
|
103
|
+
grep "^ export " /tmp/prepare_env.log | sed 's/^ export //' >> $GITHUB_ENV
|
|
104
|
+
|
|
105
|
+
- name: Wait for Mail API
|
|
106
|
+
run: |
|
|
107
|
+
CP_URL=$(grep "EXORDOS_MAIL_CP_URL" $GITHUB_ENV | cut -d= -f2)
|
|
108
|
+
for i in {1..30}; do
|
|
109
|
+
CODE=$(curl -s -o /dev/null -w "%{http_code}" "${CP_URL}/v1/")
|
|
110
|
+
if echo "$CODE" | grep -qE "200|404"; then
|
|
111
|
+
echo "MetaPaaS user-api ready (HTTP $CODE)"; exit 0
|
|
112
|
+
fi
|
|
113
|
+
echo "Waiting ($i/30) for user-api…"; sleep 10
|
|
114
|
+
done
|
|
115
|
+
exit 1
|
|
116
|
+
|
|
117
|
+
- name: Run functional tests
|
|
118
|
+
run: tox -e ${{ env.PYTHON_VERSION }}-functional
|
|
119
|
+
|
|
120
|
+
- name: Debug session on failure
|
|
121
|
+
uses: owenthereal/action-upterm@v1
|
|
122
|
+
if: failure()
|
|
123
|
+
with:
|
|
124
|
+
limit-access-to-actor: true
|
|
125
|
+
wait-timeout-minutes: 30
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
name: Publish Python 🐍 distribution 📦 to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- '*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: Build distribution 📦
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v6
|
|
15
|
+
with:
|
|
16
|
+
persist-credentials: false
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
- name: Install pypa/build
|
|
22
|
+
run: >-
|
|
23
|
+
python3 -m
|
|
24
|
+
pip install
|
|
25
|
+
build
|
|
26
|
+
--user
|
|
27
|
+
- name: Build a binary wheel and a source tarball
|
|
28
|
+
run: python3 -m build
|
|
29
|
+
- name: Store the distribution packages
|
|
30
|
+
uses: actions/upload-artifact@v7
|
|
31
|
+
with:
|
|
32
|
+
name: python-package-distributions
|
|
33
|
+
path: dist/
|
|
34
|
+
|
|
35
|
+
publish-to-pypi:
|
|
36
|
+
name: >-
|
|
37
|
+
Publish Python 🐍 distribution 📦 to PyPI
|
|
38
|
+
needs:
|
|
39
|
+
- build
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
environment:
|
|
42
|
+
name: pypi
|
|
43
|
+
url: https://pypi.org/p/exordos_mail
|
|
44
|
+
permissions:
|
|
45
|
+
id-token: write # IMPORTANT: mandatory for trusted publishing
|
|
46
|
+
|
|
47
|
+
steps:
|
|
48
|
+
- name: Download all the dists
|
|
49
|
+
uses: actions/download-artifact@v8
|
|
50
|
+
with:
|
|
51
|
+
name: python-package-distributions
|
|
52
|
+
path: dist/
|
|
53
|
+
- name: Publish distribution 📦 to PyPI
|
|
54
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
55
|
+
|
|
56
|
+
github-release:
|
|
57
|
+
name: >-
|
|
58
|
+
Sign the Python 🐍 distribution 📦 with Sigstore
|
|
59
|
+
and upload them to GitHub Release
|
|
60
|
+
needs:
|
|
61
|
+
- publish-to-pypi
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
|
|
64
|
+
permissions:
|
|
65
|
+
contents: write # IMPORTANT: mandatory for making GitHub Releases
|
|
66
|
+
id-token: write # IMPORTANT: mandatory for sigstore
|
|
67
|
+
|
|
68
|
+
steps:
|
|
69
|
+
- name: Download all the dists
|
|
70
|
+
uses: actions/download-artifact@v8
|
|
71
|
+
with:
|
|
72
|
+
name: python-package-distributions
|
|
73
|
+
path: dist/
|
|
74
|
+
- name: Sign the dists with Sigstore
|
|
75
|
+
uses: sigstore/gh-action-sigstore-python@v3.3.0
|
|
76
|
+
with:
|
|
77
|
+
inputs: >-
|
|
78
|
+
./dist/*.tar.gz
|
|
79
|
+
./dist/*.whl
|
|
80
|
+
- name: Create GitHub Release
|
|
81
|
+
env:
|
|
82
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
83
|
+
run: >-
|
|
84
|
+
gh release create
|
|
85
|
+
"$GITHUB_REF_NAME"
|
|
86
|
+
--repo "$GITHUB_REPOSITORY"
|
|
87
|
+
--notes ""
|
|
88
|
+
- name: Upload artifact signatures to GitHub Release
|
|
89
|
+
env:
|
|
90
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
91
|
+
# Upload to GitHub Release using the `gh` CLI.
|
|
92
|
+
# `dist/` contains the built packages, and the
|
|
93
|
+
# sigstore-produced signatures and certificates.
|
|
94
|
+
run: >-
|
|
95
|
+
gh release upload
|
|
96
|
+
"$GITHUB_REF_NAME" dist/**
|
|
97
|
+
--repo "$GITHUB_REPOSITORY"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
types: [opened]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
Lint:
|
|
10
|
+
runs-on: ubuntu-24.04
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: true
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: [ "3.12" ]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
18
|
+
uses: actions/setup-python@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python-version }}
|
|
21
|
+
- name: Install requirements
|
|
22
|
+
run: sudo apt update && sudo apt install --yes libev-dev libvirt-dev
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v7
|
|
25
|
+
- name: Install tox-uv
|
|
26
|
+
run: uv tool install tox --with tox-uv
|
|
27
|
+
- name: ruff
|
|
28
|
+
run: |
|
|
29
|
+
tox -e ruff-check
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
SHELL := bash
|
|
2
|
+
SSH_KEY ?= ~/.ssh/id_ed25519.pub
|
|
3
|
+
REPOSITORY ?= http://10.20.0.1:8080/exordos-elements
|
|
4
|
+
INDEX_URL ?= http://10.20.0.1:8080/simple/
|
|
5
|
+
PKG_VERSION ?=
|
|
6
|
+
|
|
7
|
+
all: help
|
|
8
|
+
|
|
9
|
+
help:
|
|
10
|
+
@echo "build - build the mailaas element manifest + DP image"
|
|
11
|
+
@echo "install - install mailaas element into Core"
|
|
12
|
+
@echo "wheel - build Python wheel for exordos_mail"
|
|
13
|
+
@echo "publish-wheel - copy wheel to local pip index"
|
|
14
|
+
@echo "lint - run ruff check"
|
|
15
|
+
@echo "format - run ruff format"
|
|
16
|
+
@echo "test - run unit tests via tox"
|
|
17
|
+
@echo "functional - run functional tests (needs live stand)"
|
|
18
|
+
@echo "typecheck - run mypy"
|
|
19
|
+
|
|
20
|
+
build:
|
|
21
|
+
exordos build -c exordos/exordos.yaml -i $(SSH_KEY) -f \
|
|
22
|
+
--manifest-var repository=$(REPOSITORY) \
|
|
23
|
+
--manifest-var index_url=$(INDEX_URL) \
|
|
24
|
+
$(if $(PKG_VERSION),--manifest-var pkg_version=$(PKG_VERSION),)
|
|
25
|
+
|
|
26
|
+
install:
|
|
27
|
+
exordos em elements install output/manifests/mailaas.yaml
|
|
28
|
+
|
|
29
|
+
wheel:
|
|
30
|
+
python -m build --wheel
|
|
31
|
+
|
|
32
|
+
publish-wheel: wheel
|
|
33
|
+
cp dist/exordos_mail-*.whl /srv/exordos-local-repo/simple/
|
|
34
|
+
|
|
35
|
+
lint:
|
|
36
|
+
tox -e ruff-check
|
|
37
|
+
|
|
38
|
+
format:
|
|
39
|
+
tox -e ruff
|
|
40
|
+
|
|
41
|
+
test:
|
|
42
|
+
tox -e py312
|
|
43
|
+
|
|
44
|
+
functional:
|
|
45
|
+
tox -e py312-functional
|
|
46
|
+
|
|
47
|
+
typecheck:
|
|
48
|
+
tox -e mypy
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exordos_mail
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: SMTP relay PaaS plugin for the Exordos MetaPaaS runtime (exim4)
|
|
5
|
+
Author-email: Genesis Corporation <mail@gmelikov.ru>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: homepage, https://github.com/infraguys/metapaas_mail/
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: oslo.config<10.0.0,>=3.22.2
|
|
11
|
+
Requires-Dist: restalchemy<16.0.0,>=15.0.0
|
|
12
|
+
Requires-Dist: gcl_iam<2.0.0,>=1.0.3
|
|
13
|
+
Requires-Dist: gcl_looper<2.0.0,>=1.2.3
|
|
14
|
+
Requires-Dist: gcl_sdk<4.0.0,>=3.0.5
|
|
15
|
+
Requires-Dist: exordos_metapaas>=0.0.1
|
|
16
|
+
Requires-Dist: passlib>=1.7.0
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: tox>=4.0.0; extra == "dev"
|
|
19
|
+
Requires-Dist: tox-uv; extra == "dev"
|
|
20
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: coverage>=4.0; extra == "test"
|
|
23
|
+
Requires-Dist: mock<4.0.0,>=3.0.5; extra == "test"
|
|
24
|
+
Requires-Dist: pytest<9.0.0,>=8.0.0; extra == "test"
|
|
25
|
+
Requires-Dist: pytest-timer<2.0.0,>=1.0.0; extra == "test"
|
|
26
|
+
Requires-Dist: exordos<3.0.0,>=2.0.0; extra == "test"
|
|
27
|
+
Provides-Extra: ruff
|
|
28
|
+
Requires-Dist: ruff; extra == "ruff"
|
|
29
|
+
Provides-Extra: mypy
|
|
30
|
+
Requires-Dist: mypy; extra == "mypy"
|
|
31
|
+
|
|
32
|
+
# mailaas: SMTP Relay PaaS Plugin for MetaPaaS
|
|
33
|
+
|
|
34
|
+
exim4 SMTP submission server packaged as a MetaPaaS plugin,
|
|
35
|
+
following the same pattern as `metapaas_s3`.
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
metapaas-cp
|
|
41
|
+
└── mail plugin (exordos_paas_mail)
|
|
42
|
+
├── CP: MailInstance + MailAccount models, REST API, migrations
|
|
43
|
+
├── infra_builder: CoreInfraBuilder → NodeSet + Config on core
|
|
44
|
+
└── paas_builder: MailInstanceBuilder → MailInstanceNode → DP agent
|
|
45
|
+
|
|
46
|
+
mailaas-dp-<uuid> (VM)
|
|
47
|
+
└── exim4 (SMTP 25/465/587 — STARTTLS + auth)
|
|
48
|
+
├── /etc/exordos_metapaas/mail.env ← delivered by CP (MAIL_DOMAIN)
|
|
49
|
+
├── /etc/exim4/passwd ← managed by DP agent (lsearch auth)
|
|
50
|
+
└── exordos-universal-agent ← MailCapabilityDriver
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### Build
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
make build \
|
|
59
|
+
REPOSITORY=http://10.20.0.1:8080/exordos-elements \
|
|
60
|
+
INDEX_URL=http://10.20.0.1:8080/simple/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Produces:
|
|
64
|
+
- `output/images/exordos-metapaas-mail-dp.raw.zst` (DP image)
|
|
65
|
+
- `output/manifests/mailaas.yaml` (element manifest)
|
|
66
|
+
|
|
67
|
+
### Install on running metapaas
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
make install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
PluginReconciler on metapaas-cp installs `exordos_paas_mail` via pip and
|
|
74
|
+
activates the `/v1/types/mail/` route.
|
|
75
|
+
|
|
76
|
+
### Create Instance
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
curl -X POST http://metapaas-cp:8080/v1/types/mail/instances/ \
|
|
80
|
+
-H 'Content-Type: application/json' \
|
|
81
|
+
-H 'Authorization: Bearer <token>' \
|
|
82
|
+
-d '{
|
|
83
|
+
"name": "mail-prod",
|
|
84
|
+
"project_id": "4d657461-0000-0000-0000-000000000002",
|
|
85
|
+
"domain": "example.com",
|
|
86
|
+
"cpu": 2,
|
|
87
|
+
"ram": 2048,
|
|
88
|
+
"disk_size": 20,
|
|
89
|
+
"version": "/v1/types/mail/versions/<version-uuid>"
|
|
90
|
+
}'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Create SMTP Account
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Generate SHA512-crypt hash (compatible with exim4 crypteq)
|
|
97
|
+
HASH=$(openssl passwd -6 "mypassword")
|
|
98
|
+
|
|
99
|
+
curl -X POST http://metapaas-cp:8080/v1/types/mail/instances/<uuid>/accounts/ \
|
|
100
|
+
-H 'Content-Type: application/json' \
|
|
101
|
+
-H 'Authorization: Bearer <token>' \
|
|
102
|
+
-d "{
|
|
103
|
+
\"username\": \"alice\",
|
|
104
|
+
\"password_hash\": \"${HASH}\",
|
|
105
|
+
\"project_id\": \"4d657461-0000-0000-0000-000000000002\",
|
|
106
|
+
\"instance\": \"/v1/types/mail/instances/<uuid>\"
|
|
107
|
+
}"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Within seconds the DP agent writes the account to `/etc/exim4/passwd` and
|
|
111
|
+
reloads exim4. The user can then authenticate via SMTP AUTH (PLAIN/LOGIN over
|
|
112
|
+
STARTTLS on port 587 or SMTPS on port 465).
|
|
113
|
+
|
|
114
|
+
Hashes stored with a Dovecot `{SHA512-CRYPT}` scheme prefix are accepted — the
|
|
115
|
+
driver strips the prefix before writing to exim4's passwd file.
|
|
116
|
+
|
|
117
|
+
### Configure DNS
|
|
118
|
+
|
|
119
|
+
For mail to be accepted by other servers you must publish a few DNS records for
|
|
120
|
+
your domain (referred to below as `$1`, e.g. `example.com`).
|
|
121
|
+
|
|
122
|
+
- **DKIM** — the key is generated on the node by the configure script. Once the
|
|
123
|
+
instance is `ACTIVE`, read it from the API:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
curl -s http://metapaas-cp:8080/v1/types/mail/instances/<uuid> \
|
|
127
|
+
-H 'Authorization: Bearer <token>' | jq -r '{dkim_selector, dkim_public_key}'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Publish it as a `TXT` record at `<dkim_selector>._domainkey.$1`
|
|
131
|
+
(default selector: `platform`), with the `dkim_public_key` value as data.
|
|
132
|
+
The raw record is also on the node at `/etc/exim4/dkim/platform.txt`.
|
|
133
|
+
- **SPF** — name: `@` (the domain itself), type: `TXT`, TTL: 3600,
|
|
134
|
+
data: `"v=spf1 ip4:YOUR_SERVER_IP/32 a mx ~all"`
|
|
135
|
+
- **DMARC** — name: `_dmarc`, type: `TXT`, TTL: 3600,
|
|
136
|
+
data: `"v=DMARC1; p=none; pct=100; adkim=s; aspf=s"`
|
|
137
|
+
- **PTR** — set the reverse record for your server IP to `$1`
|
|
138
|
+
- **MX** — ensure an `MX` record exists (e.g. name: `@`, type: `MX`, data: `$1`)
|
|
139
|
+
|
|
140
|
+
## API Endpoints
|
|
141
|
+
|
|
142
|
+
| Method | Path | Description |
|
|
143
|
+
|--------|------|-------------|
|
|
144
|
+
| POST | `/v1/types/mail/instances/` | Create mail server |
|
|
145
|
+
| GET | `/v1/types/mail/instances/` | List instances |
|
|
146
|
+
| GET | `/v1/types/mail/instances/<uuid>` | Get instance |
|
|
147
|
+
| PATCH | `/v1/types/mail/instances/<uuid>` | Update (cpu/ram/disk_size) |
|
|
148
|
+
| DELETE | `/v1/types/mail/instances/<uuid>` | Delete |
|
|
149
|
+
| GET | `/v1/types/mail/versions/` | List DP image versions |
|
|
150
|
+
| POST | `/v1/types/mail/instances/<uuid>/accounts/` | Create account |
|
|
151
|
+
| GET | `/v1/types/mail/instances/<uuid>/accounts/` | List accounts |
|
|
152
|
+
| PATCH | `/v1/types/mail/instances/<uuid>/accounts/<uuid>` | Update (active, password_hash) |
|
|
153
|
+
| DELETE | `/v1/types/mail/instances/<uuid>/accounts/<uuid>` | Delete account |
|
|
154
|
+
|
|
155
|
+
### Field permissions
|
|
156
|
+
|
|
157
|
+
| Field | Create | Read | Update |
|
|
158
|
+
|-------|--------|------|--------|
|
|
159
|
+
| `domain` | RW | RO | RO |
|
|
160
|
+
| `status` | — | RO | RO |
|
|
161
|
+
| `ipsv4` | — | RO | RO |
|
|
162
|
+
| `dkim_public_key` | — | RO | RO |
|
|
163
|
+
| `dkim_selector` | — | RO | RO |
|
|
164
|
+
| `password_hash` | RW | hidden | RW |
|
|
165
|
+
| `username` | RW | RO | RO |
|
|
166
|
+
| `active` | RW | RW | RW |
|
|
167
|
+
|
|
168
|
+
## Repository Layout
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
.
|
|
172
|
+
├── exordos_paas_mail/
|
|
173
|
+
│ ├── constants.py # MAIL_ENV_FILE, EXIM4_PASSWD_FILE paths
|
|
174
|
+
│ ├── models.py # MailVersion, MailInstance, MailAccount (restalchemy)
|
|
175
|
+
│ ├── controllers.py # REST controllers (gcl_iam policy-based)
|
|
176
|
+
│ ├── routes.py # Route tree (instances/accounts, versions)
|
|
177
|
+
│ ├── definition.py # MailDefinition (PaaSDefinition contract)
|
|
178
|
+
│ ├── infra_models.py # MailInstance + infra (NodeSet + Config)
|
|
179
|
+
│ ├── infra_builder.py # CoreInfraBuilder (creates VMs + delivers mail.env)
|
|
180
|
+
│ ├── paas_models.py # MailInstanceNode (target resource for DP agent)
|
|
181
|
+
│ ├── paas_builder.py # MailInstanceBuilder (maps accounts → DP payload)
|
|
182
|
+
│ ├── driver.py # MailCapabilityDriver: writes /etc/exim4/passwd
|
|
183
|
+
│ ├── utils.py # remove_nested_dm helper
|
|
184
|
+
│ ├── migrations/
|
|
185
|
+
│ │ ├── 0000-init-mail.py # Creates mail_versions, mail_instances, mail_accounts
|
|
186
|
+
│ │ └── 0001-drop-root-password.py
|
|
187
|
+
│ └── tests/
|
|
188
|
+
│ ├── unit/ # Unit tests (models, driver)
|
|
189
|
+
│ └── functional/ # E2E tests (prepare_env.py + SMTP auth tests)
|
|
190
|
+
├── exordos/
|
|
191
|
+
│ ├── exordos.yaml # Build config (deps + elements + DP image)
|
|
192
|
+
│ ├── images/
|
|
193
|
+
│ │ ├── dp_install.sh # Packer: install exim4 + configure script + agent
|
|
194
|
+
│ │ └── dp_bootstrap.sh # First-boot: persistent disk + start configure service
|
|
195
|
+
│ └── manifests/
|
|
196
|
+
│ ├── mailaas.yaml.j2 # Element manifest: type reg + IAM + DP version
|
|
197
|
+
│ └── example_mail.yaml.j2 # Example consumer element
|
|
198
|
+
├── etc/
|
|
199
|
+
│ ├── systemd/
|
|
200
|
+
│ │ ├── exordos-metapaas-mail-configure.service # Configures exim4 from mail.env
|
|
201
|
+
│ │ └── exordos-metapaas-mail-agent.service # Universal agent (MailCapabilityDriver)
|
|
202
|
+
│ └── exordos_metapaas/
|
|
203
|
+
│ ├── logging.yaml
|
|
204
|
+
│ └── metapaas_mail_agent.conf
|
|
205
|
+
├── .github/workflows/
|
|
206
|
+
│ ├── tests.yaml # Lint (ruff) on every push
|
|
207
|
+
│ └── func_tests.yaml # Full e2e: bootstrap core + deploy + SMTP tests
|
|
208
|
+
├── pyproject.toml
|
|
209
|
+
├── tox.ini
|
|
210
|
+
└── Makefile
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Development
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
make test # Unit tests via tox
|
|
217
|
+
make lint # ruff check
|
|
218
|
+
make format # ruff format
|
|
219
|
+
make typecheck # mypy
|
|
220
|
+
make functional # E2E tests (needs live stand)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Running functional tests manually
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
python exordos_paas_mail/tests/functional/prepare_env.py \
|
|
227
|
+
--metapaas-dir ../exordos_metapaas \
|
|
228
|
+
--project-dir . \
|
|
229
|
+
--output-dir /tmp/mail-build \
|
|
230
|
+
--endpoint http://10.20.0.2:11010 \
|
|
231
|
+
--username admin --password <pass>
|
|
232
|
+
|
|
233
|
+
# Use env vars printed by prepare_env.py, then:
|
|
234
|
+
tox -e py312-functional
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Key differences from metapaas_s3
|
|
238
|
+
|
|
239
|
+
| Aspect | s3aas | mailaas |
|
|
240
|
+
|--------|-------|---------|
|
|
241
|
+
| DP software | RustFS | exim4 (SMTP relay) |
|
|
242
|
+
| Instance children | Bucket, Policy, User, AccessKey | Account |
|
|
243
|
+
| Replicas | 1–16 | Always 1 |
|
|
244
|
+
| Config delivered | `rustfs.env` | `mail.env` (domain only) |
|
|
245
|
+
| DP auth state | S3 access keys | `/etc/exim4/passwd` (SHA512-crypt) |
|
|
246
|
+
| On-change | `systemctl restart rustfs` | `systemctl restart mail-configure` |
|
|
247
|
+
| DP agent state file | `s3_meta.json` | `mail_meta.json` |
|
|
248
|
+
| uuid5 name | `s3aas` | `mailaas` |
|
|
249
|
+
|
|
250
|
+
## References
|
|
251
|
+
|
|
252
|
+
- MetaPaaS design: `../exordos_metapaas/DESIGN.md`
|
|
253
|
+
- How to build new PaaS: `../exordos_s3/HOW_TO_BUILD_NEW_PAAS.md`
|
|
254
|
+
- Working reference: `../exordos_s3/`
|