Skip to content

Commit d725ae6

Browse files
committed
feat(lab-03): Mattermost Advanced -- MinIO S3, resource limits, file size, perf tuning
1 parent 8c4bf14 commit d725ae6

3 files changed

Lines changed: 267 additions & 76 deletions

File tree

.github/workflows/ci.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,29 @@ jobs:
143143
- name: Cleanup
144144
if: always()
145145
run: docker compose -f docker/docker-compose.lan.yml down -v
146+
147+
lab-03-smoke:
148+
name: Lab 03 - Mattermost Advanced (resource limits, file size, perf tuning)
149+
runs-on: ubuntu-latest
150+
needs: validate
151+
continue-on-error: true
152+
steps:
153+
- uses: actions/checkout@v4
154+
- name: Install tools
155+
run: sudo apt-get install -y curl
156+
- name: Validate advanced compose
157+
run: docker compose -f docker/docker-compose.advanced.yml config -q && echo "Advanced compose valid"
158+
- name: Start advanced stack
159+
run: docker compose -f docker/docker-compose.advanced.yml up -d
160+
- name: Wait for PostgreSQL
161+
run: timeout 60 bash -c 'until docker compose -f docker/docker-compose.advanced.yml exec -T db pg_isready -U mmuser -d mattermost; do sleep 3; done'
162+
- name: Wait for Mattermost API
163+
run: timeout 120 bash -c 'until curl -sf http://localhost:8065/api/v4/system/ping | grep -q status; do sleep 5; done'
164+
- name: Run Lab 07-03 test script
165+
run: bash tests/labs/test-lab-07-03.sh
166+
- name: Collect logs on failure
167+
if: failure()
168+
run: docker compose -f docker/docker-compose.advanced.yml logs
169+
- name: Cleanup
170+
if: always()
171+
run: docker compose -f docker/docker-compose.advanced.yml down -v

docker/docker-compose.advanced.yml

Lines changed: 123 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,134 @@
1-
# Lab 03 — Advanced Features: mattermost with TLS, resource limits, logging
2-
---
1+
# docker-compose.advanced.yml — Lab 07-03: Advanced Features
2+
# Mattermost with PostgreSQL, Redis, mailhog, MinIO S3 storage, resource limits
3+
name: mattermost-advanced
4+
35
services:
4-
mattermost:
5-
image: mattermost/mattermost-team-edition:9
6-
container_name: it-stack-mattermost
6+
db:
7+
image: postgres:16-alpine
8+
container_name: mm-adv-db
9+
environment:
10+
POSTGRES_DB: mattermost
11+
POSTGRES_USER: mmuser
12+
POSTGRES_PASSWORD: Lab03Password!
13+
volumes:
14+
- mm_adv_db:/var/lib/postgresql/data
15+
networks:
16+
- mm-data-net
17+
healthcheck:
18+
test: ["CMD-SHELL", "pg_isready -U mmuser -d mattermost"]
19+
interval: 10s
20+
timeout: 5s
21+
retries: 5
22+
start_period: 20s
23+
deploy:
24+
resources:
25+
limits:
26+
cpus: "0.5"
27+
memory: 512M
728
restart: unless-stopped
8-
ports:
9-
- "8065:$firstPort"
29+
30+
redis:
31+
image: redis:7-alpine
32+
container_name: mm-adv-redis
33+
command: redis-server --save 60 1 --maxmemory 128mb --maxmemory-policy allkeys-lru
34+
networks:
35+
- mm-data-net
36+
deploy:
37+
resources:
38+
limits:
39+
cpus: "0.25"
40+
memory: 192M
41+
restart: unless-stopped
42+
43+
minio:
44+
image: minio/minio:RELEASE.2024-01-16T16-07-38Z
45+
container_name: mm-adv-minio
46+
command: server /data --console-address ":9001"
1047
environment:
11-
- IT_STACK_ENV=lab-03-advanced
12-
- TLS_ENABLED=true
48+
MINIO_ROOT_USER: minioadmin
49+
MINIO_ROOT_PASSWORD: Lab03Minio!
50+
ports:
51+
- "9000:9000"
52+
- "9001:9001"
1353
volumes:
14-
- mattermost_data:/var/lib/mattermost
15-
- ./certs:/etc/ssl/certs:ro
54+
- mm_adv_minio:/data
55+
networks:
56+
- mm-data-net
57+
healthcheck:
58+
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
59+
interval: 15s
60+
timeout: 5s
61+
retries: 5
62+
start_period: 10s
1663
deploy:
1764
resources:
1865
limits:
19-
cpus: "2.0"
20-
memory: G
21-
logging:
22-
driver: json-file
23-
options:
24-
max-size: "100m"
25-
max-file: "5"
66+
cpus: "0.5"
67+
memory: 512M
68+
restart: unless-stopped
69+
70+
smtp:
71+
image: mailhog/mailhog:v1.0.1
72+
container_name: mm-adv-smtp
73+
ports:
74+
- "8025:8025"
2675
networks:
27-
- it-stack-net
76+
- mm-app-net
77+
restart: unless-stopped
2878

29-
networks:
30-
it-stack-net:
31-
driver: bridge
79+
mattermost:
80+
image: mattermost/mattermost-team-edition:9.3
81+
container_name: mm-adv-app
82+
ports:
83+
- "8065:8065"
84+
environment:
85+
MM_SQLSETTINGS_DRIVERNAME: postgres
86+
MM_SQLSETTINGS_DATASOURCE: "postgres://mmuser:Lab03Password!@db:5432/mattermost?sslmode=disable&connect_timeout=10"
87+
MM_EMAILSETTINGS_SMTPSERVER: smtp
88+
MM_EMAILSETTINGS_SMTPPORT: "1025"
89+
MM_EMAILSETTINGS_SENDEMAILNOTIFICATIONS: "true"
90+
MM_SERVICESETTINGS_SITEURL: "http://localhost:8065"
91+
MM_SERVICESETTINGS_READTIMEOUT: "300"
92+
MM_SERVICESETTINGS_WRITETIMEOUT: "300"
93+
MM_SERVICESETTINGS_MAXLOGINRETRIES: "3"
94+
MM_FILESETTINGS_DRIVERNAME: amazons3
95+
MM_FILESETTINGS_AMAZONS3ACCESSKEYID: minioadmin
96+
MM_FILESETTINGS_AMAZONS3SECRETACCESSKEY: Lab03Minio!
97+
MM_FILESETTINGS_AMAZONS3BUCKET: mattermost
98+
MM_FILESETTINGS_AMAZONS3ENDPOINT: "minio:9000"
99+
MM_FILESETTINGS_AMAZONS3SSL: "false"
100+
MM_FILESETTINGS_AMAZONS3PATHSTYLE: "true"
101+
MM_FILESETTINGS_MAXFILESIZE: "524288000"
102+
volumes:
103+
- mm_adv_config:/mattermost/config
104+
- mm_adv_logs:/mattermost/logs
105+
networks:
106+
- mm-app-net
107+
- mm-data-net
108+
depends_on:
109+
db:
110+
condition: service_healthy
111+
minio:
112+
condition: service_healthy
113+
healthcheck:
114+
test: ["CMD-SHELL", "curl -sf http://localhost:8065/api/v4/system/ping | grep -q status"]
115+
interval: 30s
116+
timeout: 10s
117+
retries: 10
118+
start_period: 60s
119+
deploy:
120+
resources:
121+
limits:
122+
cpus: "1.0"
123+
memory: 1G
124+
restart: unless-stopped
32125

33126
volumes:
34-
mattermost_data:
127+
mm_adv_db:
128+
mm_adv_minio:
129+
mm_adv_config:
130+
mm_adv_logs:
131+
132+
networks:
133+
mm-app-net:
134+
mm-data-net:

tests/labs/test-lab-07-03.sh

Lines changed: 118 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,136 @@
11
#!/usr/bin/env bash
2-
# test-lab-07-03.sh — Lab 07-03: Advanced Features
3-
# Module 07: Mattermost team messaging
4-
# mattermost with TLS, resource limits, and production-grade configuration
2+
# test-lab-07-03.sh — Lab 07-03: Mattermost Advanced Features
3+
# Tests: resource limits, MaxFileSize, S3 storage, perf settings, MinIO
54
set -euo pipefail
6-
7-
LAB_ID="07-03"
8-
LAB_NAME="Advanced Features"
9-
MODULE="mattermost"
105
COMPOSE_FILE="docker/docker-compose.advanced.yml"
11-
PASS=0
12-
FAIL=0
6+
PASS=0; FAIL=0
7+
pass() { echo " [PASS] $1"; PASS=$((PASS+1)); }
8+
fail() { echo " [FAIL] $1"; FAIL=$((FAIL+1)); }
9+
section() { echo; echo "=== $1 ==="; }
10+
MM_API="http://localhost:8065/api/v4"
1311

14-
# ── Colors ────────────────────────────────────────────────────────────────────
15-
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
16-
CYAN='\033[0;36m'; NC='\033[0m'
12+
section "Container health"
13+
for c in mm-adv-db mm-adv-redis mm-adv-minio mm-adv-smtp mm-adv-app; do
14+
if docker inspect --format '{{.State.Running}}' "$c" 2>/dev/null | grep -q true; then
15+
pass "Container $c is running"
16+
else
17+
fail "Container $c is not running"
18+
fi
19+
done
1720

18-
pass() { echo -e "${GREEN}[PASS]${NC} $1"; ((PASS++)); }
19-
fail() { echo -e "${RED}[FAIL]${NC} $1"; ((FAIL++)); }
20-
info() { echo -e "${CYAN}[INFO]${NC} $1"; }
21-
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
21+
section "PostgreSQL connectivity"
22+
if docker compose -f "$COMPOSE_FILE" exec -T db pg_isready -U mmuser -d mattermost 2>/dev/null | grep -q "accepting"; then
23+
pass "PostgreSQL accepting connections"
24+
else
25+
fail "PostgreSQL not ready"
26+
fi
2227

23-
echo -e "${CYAN}======================================${NC}"
24-
echo -e "${CYAN} Lab ${LAB_ID}: ${LAB_NAME}${NC}"
25-
echo -e "${CYAN} Module: ${MODULE}${NC}"
26-
echo -e "${CYAN}======================================${NC}"
27-
echo ""
28+
section "MinIO S3 health"
29+
MINIO_STATUS=$(curl -sf http://localhost:9000/minio/health/live 2>/dev/null; echo $?) || MINIO_STATUS=1
30+
if [ "$MINIO_STATUS" = "0" ]; then
31+
pass "MinIO S3 health endpoint reachable"
32+
else
33+
HTTP_MINIO=$(curl -sw '%{http_code}' -o /dev/null http://localhost:9000/minio/health/live 2>/dev/null) || HTTP_MINIO="000"
34+
if [ "$HTTP_MINIO" = "200" ]; then
35+
pass "MinIO S3 health endpoint HTTP 200"
36+
else
37+
fail "MinIO S3 health endpoint returned $HTTP_MINIO"
38+
fi
39+
fi
2840

29-
# ── PHASE 1: Setup ────────────────────────────────────────────────────────────
30-
info "Phase 1: Setup"
31-
docker compose -f "${COMPOSE_FILE}" up -d
32-
info "Waiting 30s for ${MODULE} to initialize..."
33-
sleep 30
41+
section "Mattermost API ping"
42+
PING=$(curl -sf "$MM_API/system/ping" 2>/dev/null) || PING=""
43+
if echo "$PING" | grep -q "status"; then
44+
pass "Mattermost API /system/ping reachable"
45+
else
46+
fail "Mattermost API /system/ping failed"
47+
fi
3448

35-
# ── PHASE 2: Health Checks ────────────────────────────────────────────────────
36-
info "Phase 2: Health Checks"
49+
section "Admin user creation"
50+
REGISTER=$(curl -sf -X POST "$MM_API/users" \
51+
-H "Content-Type: application/json" \
52+
-d '{"email":"admin@lab.local","username":"admin03","password":"Lab03Admin!","first_name":"Admin","last_name":"Lab03"}' 2>/dev/null) || REGISTER=""
53+
if echo "$REGISTER" | grep -q '"id"'; then
54+
pass "Admin user created"
55+
elif echo "$REGISTER" | grep -q "already"; then
56+
pass "Admin user already exists"
57+
else
58+
fail "Admin user registration failed: $REGISTER"
59+
fi
3760

38-
if docker compose -f "${COMPOSE_FILE}" ps | grep -q "running\|Up"; then
39-
pass "Container is running"
61+
section "Admin login"
62+
TOKEN_RESP=$(curl -si -X POST "$MM_API/users/login" \
63+
-H "Content-Type: application/json" \
64+
-d '{"login_id":"admin03","password":"Lab03Admin!"}' 2>/dev/null) || TOKEN_RESP=""
65+
MM_TOKEN=$(echo "$TOKEN_RESP" | grep -i "^Token:" | awk '{print $2}' | tr -d '[:space:]') || MM_TOKEN=""
66+
if [ -n "$MM_TOKEN" ]; then
67+
pass "Admin login successful, token obtained"
4068
else
41-
fail "Container is not running"
69+
fail "Admin login failed"
4270
fi
4371

44-
# ── PHASE 3: Functional Tests ─────────────────────────────────────────────────
45-
info "Phase 3: Functional Tests (Lab 03 — Advanced Features)"
72+
section "MaxFileSize in container env"
73+
MM_ENV=$(docker inspect mm-adv-app --format '{{json .Config.Env}}' 2>/dev/null) || MM_ENV="[]"
74+
if echo "$MM_ENV" | grep -q "MM_FILESETTINGS_MAXFILESIZE=524288000"; then
75+
pass "MM_FILESETTINGS_MAXFILESIZE=524288000 set in container"
76+
else
77+
fail "MM_FILESETTINGS_MAXFILESIZE=524288000 not found in container env"
78+
fi
4679

47-
# TODO: Add module-specific functional tests here
48-
# Example:
49-
# if curl -sf http://localhost:8065/health > /dev/null 2>&1; then
50-
# pass "Health endpoint responds"
51-
# else
52-
# fail "Health endpoint not reachable"
53-
# fi
80+
section "Performance settings in container env"
81+
if echo "$MM_ENV" | grep -q "MM_SERVICESETTINGS_READTIMEOUT=300"; then
82+
pass "MM_SERVICESETTINGS_READTIMEOUT=300 set"
83+
else
84+
fail "MM_SERVICESETTINGS_READTIMEOUT=300 not found"
85+
fi
86+
if echo "$MM_ENV" | grep -q "MM_SERVICESETTINGS_MAXLOGINRETRIES=3"; then
87+
pass "MM_SERVICESETTINGS_MAXLOGINRETRIES=3 set"
88+
else
89+
fail "MM_SERVICESETTINGS_MAXLOGINRETRIES=3 not found"
90+
fi
5491

55-
warn "Functional tests for Lab 07-03 pending implementation"
92+
section "Resource limits check"
93+
MM_MEM=$(docker inspect mm-adv-app --format '{{.HostConfig.Memory}}' 2>/dev/null) || MM_MEM="0"
94+
if [ "$MM_MEM" = "1073741824" ]; then
95+
pass "mm-adv-app memory limit = 1G (1073741824 bytes)"
96+
else
97+
fail "mm-adv-app memory limit: expected 1073741824, got $MM_MEM"
98+
fi
5699

57-
# ── PHASE 4: Cleanup ──────────────────────────────────────────────────────────
58-
info "Phase 4: Cleanup"
59-
docker compose -f "${COMPOSE_FILE}" down -v --remove-orphans
60-
info "Cleanup complete"
100+
section "MaxFileSize via API config"
101+
if [ -n "$MM_TOKEN" ]; then
102+
CONFIG=$(curl -sf -H "Authorization: Bearer $MM_TOKEN" "$MM_API/config" 2>/dev/null) || CONFIG=""
103+
if echo "$CONFIG" | grep -q '"MaxFileSize":524288000'; then
104+
pass "API config MaxFileSize = 524288000"
105+
else
106+
fail "API config MaxFileSize not 524288000"
107+
fi
108+
else
109+
fail "Skipping API config check (no token)"
110+
fi
61111

62-
# ── Results ───────────────────────────────────────────────────────────────────
63-
echo ""
64-
echo -e "${CYAN}======================================${NC}"
65-
echo -e " Lab ${LAB_ID} Complete"
66-
echo -e " ${GREEN}PASS: ${PASS}${NC} | ${RED}FAIL: ${FAIL}${NC}"
67-
echo -e "${CYAN}======================================${NC}"
112+
section "S3 file settings via API"
113+
if [ -n "$MM_TOKEN" ] && [ -n "$CONFIG" ]; then
114+
if echo "$CONFIG" | grep -q '"DriverName":"amazons3"'; then
115+
pass "FileSettings DriverName = amazons3"
116+
else
117+
fail "FileSettings DriverName not amazons3"
118+
fi
119+
else
120+
fail "Skipping S3 API check (no token or config)"
121+
fi
68122

69-
if [ "${FAIL}" -gt 0 ]; then
70-
exit 1
123+
section "Redis connectivity"
124+
REDIS_PONG=$(docker compose -f "$COMPOSE_FILE" exec -T redis redis-cli PING 2>/dev/null | tr -d '[:space:]') || REDIS_PONG=""
125+
if [ "$REDIS_PONG" = "PONG" ]; then
126+
pass "Redis PING responded"
127+
else
128+
fail "Redis PING failed"
71129
fi
130+
131+
echo
132+
echo "====================================="
133+
echo " Mattermost Lab 07-03 Results"
134+
echo " PASS: $PASS FAIL: $FAIL"
135+
echo "====================================="
136+
[ "$FAIL" -eq 0 ] && exit 0 || exit 1

0 commit comments

Comments
 (0)