Skip to content

Commit f3dd9a9

Browse files
authored
feat: add mssql support (#21)
* feat: add mssql support (beta) * ci: fix typo with variables * ci: adjust variable names * fix: add missing drivers * docs: add mssql docs * ci: temp hardcode sa password * ci: add more mssql healtcheck retries * ci: add more mssql healtcheck retries * ci: rewrite mssql healthcheck * ci: temp remove mssql healthcheck * fix: add `app_mssql` to installed apps * ci: exclude mssql from python 3.7 * ci: adjust router to support python 3.6 * ci: add right db router for mssql * ci: fix mssql port number * feat: add msodbcsql17 and msodbcsql18 * ci: temp remove odbc 17 for testing * ci: add odbc 17 * docs: fix mssql link * docs: add `Microsoft ODBC Driver 18 for SQL Server` notes
1 parent 2dca634 commit f3dd9a9

12 files changed

+139
-34
lines changed

.github/workflows/release.yml

+25-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
push:
1010
branches:
1111
- 'main'
12+
- 'feature/*'
1213

1314
jobs:
1415
build:
@@ -24,16 +25,35 @@ jobs:
2425
MARIADB_DATABASE: test_db
2526
MARIADB_USER: test_user
2627
MARIADB_PASSWORD: password
27-
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD : 'yes'
28+
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 'yes'
2829
MARIADB_PORT: 33062
2930
MARIADB_MYSQL_LOCALHOST_USER: true
3031
POSTGRES_HOST: 127.0.0.1
3132
POSTGRES_DB: test_db
3233
POSTGRES_USER: test_user
3334
POSTGRES_PASSWORD: password
3435
POSTGRES_PORT: 5432
36+
MSSQL_HOST: 127.0.0.1
37+
MSSQL_DATABASE: test_db
38+
MSSQL_USER: sa
39+
MSSQL_PASSWORD: yourStrong(!)Password
40+
MSSQL_PORT: 1433
3541
services:
3642
# Label used to access the service container
43+
mssql:
44+
image: mcr.microsoft.com/mssql/server:2019-latest
45+
env:
46+
MSSQL_SA_PASSWORD: ${{env.MSSQL_PASSWORD}}
47+
ACCEPT_EULA: Y
48+
ports:
49+
- 1433:1433
50+
# todo: dont hardcode password
51+
# options: >-
52+
# --health-cmd "/opt/mssql-tools/bin/sqlcmd -U sa -P yourStrong(!)Password -Q 'SELECT 1' -b -o /dev/null"
53+
# --health-interval 60s
54+
# --health-timeout 30s
55+
# --health-start-period 20s
56+
# --health-retries 3
3757
mysql:
3858
image: mysql
3959
env:
@@ -48,11 +68,11 @@ jobs:
4868
mariadb:
4969
image: mariadb
5070
env:
51-
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD : ${{env.MARIADB_ALLOW_EMPTY_ROOT_PASSWORD}}
71+
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: ${{env.MARIADB_ALLOW_EMPTY_ROOT_PASSWORD}}
5272
MARIADB_USER: ${{env.MARIADB_USER}}
5373
MARIADB_PASSWORD: ${{env.MARIADB_PASSWORD}}
5474
MARIADB_DATABASE: ${{env.MARIADB_DATABASE}}
55-
MARIADB_MYSQL_LOCALHOST_USER: ${{env.MARIADB_MYSQL_LOCALHOST_USER}}
75+
MARIADB_MYSQL_LOCALHOST_USER: ${{env.MARIADB_MYSQL_LOCALHOST_USER}}
5676
ports:
5777
- 33062:3306
5878
options: --health-cmd="healthcheck.sh --su-mysql --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3
@@ -110,7 +130,7 @@ jobs:
110130
- name: Test Databases
111131
if: steps.changes.outputs.src == 'true' || steps.changes.outputs.docker == 'true' || github.event.inputs.version == 'all' || github.event.inputs.version == matrix.version
112132
run: |
113-
docker run --network host -v /"$(pwd)/tests":/app -w /app -e MYSQL_HOST=$MYSQL_HOST -e MYSQL_DATABASE=$MYSQL_DATABASE -e MYSQL_USER=$MYSQL_USER -e MYSQL_PORT=$MYSQL_PORT -e MYSQL_PASSWORD=$MYSQL_PASSWORD -e MARIADB_HOST=$MARIADB_HOST -e MARIADB_DATABASE=$MARIADB_DATABASE -e MARIADB_USER=$MARIADB_USER -e MARIADB_PORT=$MARIADB_PORT -e MARIADB_PASSWORD=$MARIADB_PASSWORD -e POSTGRES_HOST=$POSTGRES_HOST -e POSTGRES_DB=$POSTGRES_DB -e POSTGRES_USER=$POSTGRES_USER -e POSTGRES_PORT=$POSTGRES_PORT -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD orbisk/django-test:${{env.PYTHON_VERSION}} sh -c "cd /app && pip install -r requirements.txt && python manage.py test"
133+
docker run --network host -v /"$(pwd)/tests":/app -w /app -e MYSQL_HOST=$MYSQL_HOST -e MYSQL_DATABASE=$MYSQL_DATABASE -e MYSQL_USER=$MYSQL_USER -e MYSQL_PORT=$MYSQL_PORT -e MYSQL_PASSWORD=$MYSQL_PASSWORD -e MARIADB_HOST=$MARIADB_HOST -e MARIADB_DATABASE=$MARIADB_DATABASE -e MARIADB_USER=$MARIADB_USER -e MARIADB_PORT=$MARIADB_PORT -e MARIADB_PASSWORD=$MARIADB_PASSWORD -e POSTGRES_HOST=$POSTGRES_HOST -e POSTGRES_DB=$POSTGRES_DB -e POSTGRES_USER=$POSTGRES_USER -e POSTGRES_PORT=$POSTGRES_PORT -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD -e MSSQL_HOST -e MSSQL_PORT -e MSSQL_DATABASE -e MSSQL_USER -e MSSQL_PASSWORD orbisk/django-test:${{env.PYTHON_VERSION}} sh -c "cd /app && pip install -r requirements.txt && python manage.py test"
114134
- name: Push Image
115-
if: steps.changes.outputs.src == 'true' || steps.changes.outputs.docker == 'true' || github.event.inputs.version == 'all' || github.event.inputs.version == matrix.version
135+
if: (steps.changes.outputs.src == 'true' || steps.changes.outputs.docker == 'true' || github.event.inputs.version == 'all' || github.event.inputs.version == matrix.version) && github.ref == 'refs/heads/main'
116136
run: docker push -a orbisk/django-test

Dockerfile

+8
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,11 @@ RUN apt-get -y install net-tools mysql-client default-libmysqlclient-dev
2121

2222
# MariaDB
2323
RUN apt-get -y install libmariadb-dev libssl-dev
24+
25+
# MSSQL (beta)
26+
RUN curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
27+
RUN curl https://packages.microsoft.com/config/debian/12/prod.list | tee /etc/apt/sources.list.d/mssql-release.list
28+
29+
RUN apt-get update
30+
RUN ACCEPT_EULA=Y apt-get -y install msodbcsql17 msodbcsql18
31+
RUN apt-get install -y unixodbc-dev

README.md

+46-27
Original file line numberDiff line numberDiff line change
@@ -31,46 +31,55 @@ started.
3131

3232
- 🟢 Supported/Tested
3333
- 🟡 Unknown/Untested
34+
- 🟠 Beta/Experimental (please share your experiences)
3435
- 🔴 Currently not Supported (open an Issue or Pull request if needed)
3536

36-
| Python version | |
37-
|----------------|-----|
38-
| `^2.x` | 🔴 |
39-
| `^3.7.16` | 🟢 |
40-
| `^3.8.16` | 🟢 |
41-
| `^3.9.16` | 🟢 |
42-
| `^3.10.10` | 🟢 |
43-
| `^3.11.2` | 🟢 |
44-
45-
| MySQL*️⃣ | |
46-
|----------|-----|
47-
| `^8.0.0` | 🟢 |
48-
| `<=5.7` | 🟡 |
49-
50-
| MariaDB*️⃣ | |
51-
|------------|-----|
52-
| `^11.0.0` | 🟡 |
53-
| `^10.7.8` | 🟢 |
54-
| `<10.7.8` | 🟡 |
55-
56-
| Postgres | |
57-
|----------|-----|
58-
| `^15.2` | 🟢 |
59-
| `<15.2` | 🟡 |
37+
| Python version | |
38+
|----------------|----|
39+
| `^3.12` | 🔴 |
40+
| `^3.11.2` | 🟢 |
41+
| `^3.10.10` | 🟢 |
42+
| `^3.9.16` | 🟢 |
43+
| `^3.8.16` | 🟢 |
44+
| `^3.7.16` | 🟢 |
45+
| `^2.x` | 🔴 |
46+
47+
| MySQL*️⃣ | |
48+
|----------|----|
49+
| `^8.0.0` | 🟢 |
50+
| `<=5.7` | 🟡 |
51+
52+
| MariaDB*️⃣ | |
53+
|------------|----|
54+
| `^11.0.0` | 🟡 |
55+
| `^10.7.8` | 🟢 |
56+
| `<10.7.8` | 🟡 |
57+
58+
| Postgres | |
59+
|----------|----|
60+
| `^15.2` | 🟢 |
61+
| `<15.2` | 🟡 |
62+
63+
| MSSQL ([see](#mssql-beta)) | |
64+
|----------------------------|----|
65+
| `>=2022` | 🟠 |
66+
| `^2019-CU23-ubuntu-20.04` | 🟠 |
67+
| `<=2017` | 🟠 |
6068

6169
*️⃣ Additional step required see: [Error creating the test database](#error-creating-the-test-database)
6270

6371
## Common issues
6472

6573
### Error creating the test database
74+
6675
`Got an error creating the test database: (1044, "1044 (42000): Access denied for user '<test_user>'@'%' to database 'test_<my_db>'", '42000')`
6776

68-
The MYSQL user is only granted permissions for the MYSQL_DB, which means that Django is unable to create a test database.
77+
The MYSQL user is only granted permissions for the MYSQL_DB, which means that Django is unable to create a test
78+
database.
6979
To use MySQL and MariaDB with a non-root user, you need to grant privileges to your test user.
7080

7181
`echo "GRANT ALL on *.* to '$MYSQL_USER';"| mysql -u root --password="$MYSQL_ROOT_PASSWORD" -h <host> -p <port>`
7282

73-
7483
## CI Examples
7584

7685
### GitLab CI
@@ -98,6 +107,16 @@ django-tests:
98107

99108
## Feedback
100109

110+
If you have any problems with or questions about this image, please open an issue on GitHub.
101111

112+
## MSSQL Beta
113+
114+
⚠️ The MSSQL support is currently in beta. If you have any problems with or questions about this image, please open an
115+
issue on GitHub.
116+
117+
MSSQL is currently only supported/tested with the following versions:
118+
119+
- [`^mssql-server-linux:2019-CU23-ubuntu-20.04`](https://hub.docker.com/_/microsoft-mssql-server)
120+
- [`mssql-django===1.3`](https://pypi.org/project/mssql-django/)
121+
- [`Microsoft ODBC Driver 17 for SQL Server` & `Microsoft ODBC Driver 18 for SQL Server`](https://learn.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver16&tabs=debian18-install%2Calpine17-install%2Cdebian8-install%2Credhat7-13-install%2Crhel7-offline) ('Microsoft ODBC Driver 18 for SQL Server' does currently not work with mssql as ci service with self-signed ssl certs. If you have any solution, feel free to open an Issue or PR)
102122

103-
If you have any problems with or questions about this image, please open an issue on GitHub.

tests/app_mssql/__init__.py

Whitespace-only changes.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Generated by Django 4.1.7 on 2023-03-14 13:46
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
initial = True
9+
10+
dependencies = [
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='TestModel',
16+
fields=[
17+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18+
('value', models.IntegerField()),
19+
],
20+
),
21+
]

tests/app_mssql/migrations/__init__.py

Whitespace-only changes.

tests/app_mssql/models.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from django.db import models
2+
3+
4+
# Create your models here.
5+
6+
7+
class TestModel(models.Model):
8+
value = models.IntegerField()

tests/app_mssql/router.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from django.conf import settings
2+
3+
from tests.base_db_router import BaseDBRouter
4+
5+
6+
class DBRouter(BaseDBRouter):
7+
route_app_labels = {"app_mssql"}
8+
db = settings.DB_MSSQL

tests/app_mssql/tests.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.conf import settings
2+
from django.test import TestCase
3+
4+
5+
class Test(TestCase):
6+
databases = ['default', settings.DB_MSSQL]
7+
8+
def test(self):
9+
self.assertTrue(True)

tests/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ coverage
33
mysqlclient
44
django-environ
55
psycopg2
6+
mssql-django

tests/tests/base_db_router.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ class BaseDBRouter:
77

88
def __init__(self):
99
if self.route_app_labels is None:
10-
warnings.warn(f"Router {self.__class__.__name__}: {self.route_app_labels=}")
10+
warnings.warn(f"Router {self.__class__.__name__}: {self.route_app_labels}")
1111
if self.db is None:
12-
warnings.warn(f"Router {self.__class__.__name__}: {self.db=}")
12+
warnings.warn(f"Router {self.__class__.__name__}: {self.db}")
1313

1414
def db_for_read(self, model, **hints):
1515
if model._meta.app_label in self.route_app_labels:

tests/tests/settings.py

+11
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"app_mysql",
4242
"app_mariadb",
4343
"app_postgres",
44+
"app_mssql",
4445
]
4546

4647
MIDDLEWARE = [
@@ -112,11 +113,21 @@
112113
"USER": env.str("POSTGRES_USER"),
113114
"PASSWORD": env.str("POSTGRES_PASSWORD"),
114115
},
116+
DB_MSSQL: {
117+
"ENGINE": "mssql",
118+
"HOST": env.str("MSSQL_HOST"),
119+
"PORT": env.int("MSSQL_PORT"),
120+
"NAME": env.str("MSSQL_DATABASE"),
121+
"USER": env.str("MSSQL_USER"),
122+
"PASSWORD": env.str("MSSQL_PASSWORD"),
123+
}
115124
}
116125

117126
DATABASE_ROUTERS = [
118127
'app_mysql.router.DBRouter',
119128
'app_mariadb.router.DBRouter',
129+
'app_postgres.router.DBRouter',
130+
'app_mssql.router.DBRouter',
120131
]
121132

122133
# Password validation

0 commit comments

Comments
 (0)