diff --git a/fastapi_template/cli.py b/fastapi_template/cli.py index a5d3b461c4e3404a299ef37b8a913e54bfb77098..b715f3980bf1e26d8dc1f667507f582906d323d2 100644 --- a/fastapi_template/cli.py +++ b/fastapi_template/cli.py @@ -145,6 +145,7 @@ def read_user_input(current_context: BuilderContext) -> BuilderContext: current_context.project_name = prompt( "Project name: ", validator=SnakeCaseValidator() ) + current_context.kube_name = current_context.project_name.replace('_', '-') if current_context.project_description is None: current_context.project_description = prompt("Project description: ") if current_context.db is None: diff --git a/fastapi_template/input_model.py b/fastapi_template/input_model.py index 1c7f3bbf7bc3b89e395b50ba39d7f7854a46cd3f..5cbaf1fb0378bd572eef4f3f3363851c0c9dc406 100644 --- a/fastapi_template/input_model.py +++ b/fastapi_template/input_model.py @@ -30,6 +30,7 @@ class BuilderContext(BaseModel): """Options for project generation.""" project_name: Optional[str] + kube_name: Optional[str] project_description: Optional[str] db: Optional[DatabaseType] db_info: Optional[Database] diff --git a/fastapi_template/template/cookiecutter.json b/fastapi_template/template/cookiecutter.json index e974c3d0d02864e7ab4458aef948bb720a62a8a7..1b3d564524468fa1cfa76841e535e03e7b429fc8 100644 --- a/fastapi_template/template/cookiecutter.json +++ b/fastapi_template/template/cookiecutter.json @@ -20,7 +20,10 @@ "enable_kube": { "type": "bool" }, + "kube_name": { + "type": "string" + }, "_extensions": [ "cookiecutter.extensions.RandomStringExtension" ] -} +} \ No newline at end of file diff --git a/fastapi_template/template/hooks/pre_gen_project.py b/fastapi_template/template/hooks/pre_gen_project.py index b86829b0eaef47db09dea4b93d2c84bbed3d19e1..0ddf1f0f3ec8c41592ba0f6ed764acba50b6738a 100644 --- a/fastapi_template/template/hooks/pre_gen_project.py +++ b/fastapi_template/template/hooks/pre_gen_project.py @@ -1,8 +1,3 @@ """ Pre generation hooks -Currently only synchronizes passwords - - -{{ cookiecutter.update({"postgres_password": random_ascii_string(20) }) }} -{{ cookiecutter.update({"redis_password": random_ascii_string(20) }) }} """ \ No newline at end of file diff --git a/fastapi_template/template/{{cookiecutter.project_name}}/.dockerignore b/fastapi_template/template/{{cookiecutter.project_name}}/.dockerignore index 741c3d30d920e27a1f3d5e975890a5dab238a399..00ce79b200091d47e826608299284577052d9e39 100644 --- a/fastapi_template/template/{{cookiecutter.project_name}}/.dockerignore +++ b/fastapi_template/template/{{cookiecutter.project_name}}/.dockerignore @@ -3,6 +3,7 @@ deploy/ .idea/ .vscode/ +.git/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/fastapi_template/template/{{cookiecutter.project_name}}/.gitlab-ci.yml b/fastapi_template/template/{{cookiecutter.project_name}}/.gitlab-ci.yml index 5d18f16203a6fd05c520d6d549ec48cea0dbf7f6..b568e793c3343219b5e1867e323564dff828ec8a 100644 --- a/fastapi_template/template/{{cookiecutter.project_name}}/.gitlab-ci.yml +++ b/fastapi_template/template/{{cookiecutter.project_name}}/.gitlab-ci.yml @@ -39,7 +39,6 @@ pytest: {%- if cookiecutter.db_info.name != "sqlite" %} services: - name: {{ cookiecutter.db_info.image }} - alias: {{ cookiecutter.project_name }}-db {%- endif %} variables: {%- if cookiecutter.db_info.name == "postgresql" %} @@ -61,7 +60,7 @@ pytest: {%- if cookiecutter.db_info.name != "sqlite" %} - apt update - apt install -y wait-for-it - - wait-for-it -t 180 {{ cookiecutter.project_name }}-db:{{cookiecutter.db_info.port}} + - wait-for-it -t 180 ${{ cookiecutter.project_name | upper }}_DB_HOST:{{cookiecutter.db_info.port}} {%- endif %} {%- endif %} - pytest -vv --cov="{{cookiecutter.project_name}}" . {% if cookiecutter.enable_alembic %}--test-alembic{%- endif %} diff --git a/fastapi_template/template/{{cookiecutter.project_name}}/conditional_files.json b/fastapi_template/template/{{cookiecutter.project_name}}/conditional_files.json index eac8acc160561cfe817dee286176a469caca37af..0ce5340ca772c7496943e85d39b918394ecead24 100644 --- a/fastapi_template/template/{{cookiecutter.project_name}}/conditional_files.json +++ b/fastapi_template/template/{{cookiecutter.project_name}}/conditional_files.json @@ -23,6 +23,12 @@ "alembic.ini" ] }, + "Postgres and MySQL support": { + "enabled": "{{cookiecutter.db_info.name != 'sqlite'}}", + "resources": [ + "deploy/kube/db.yml" + ] + }, "Alembic": { "enabled": "{{cookiecutter.enable_alembic}}", "resources": [ diff --git a/fastapi_template/template/{{cookiecutter.project_name}}/deploy/docker-compose.yml b/fastapi_template/template/{{cookiecutter.project_name}}/deploy/docker-compose.yml index 5f465cbe07a58584ad32626c37ed110aeb485d2e..318833b4b9b35fd2535e71d3a98f67557a220bb8 100644 --- a/fastapi_template/template/{{cookiecutter.project_name}}/deploy/docker-compose.yml +++ b/fastapi_template/template/{{cookiecutter.project_name}}/deploy/docker-compose.yml @@ -5,7 +5,7 @@ services: build: context: . dockerfile: ./deploy/Dockerfile - image: {{cookiecutter.project_name}}:latest + image: {{cookiecutter.project_name}}:{{"${" }}{{cookiecutter.project_name | upper }}_VERSION:-latest{{"}"}} env_file: - .env environment: @@ -45,10 +45,7 @@ services: {% if cookiecutter.enable_alembic == 'True' %} migrator: - build: - context: . - dockerfile: ./deploy/Dockerfile - image: {{cookiecutter.project_name}}:latest + image: {{cookiecutter.project_name}}:{{"${" }}{{cookiecutter.project_name | upper }}_VERSION:-latest{{"}"}} {%- if cookiecutter.db_info.name == "sqlite" %} command: alembic upgrade head environment: diff --git a/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/app.yml b/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/app.yml index 8d9330c90949b740feaf69d973024579468eb2a0..8a29dc359d97eb4e5575f4445139f8183dc808f8 100644 --- a/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/app.yml +++ b/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/app.yml @@ -2,23 +2,40 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{cookiecutter.project_name}} + name: {{cookiecutter.kube_name}}-app spec: selector: matchLabels: - app: {{cookiecutter.project_name}} + app: {{cookiecutter.kube_name}}-app template: metadata: labels: - app: {{cookiecutter.project_name}} + app: {{cookiecutter.kube_name}}-app spec: containers: - - name: {{cookiecutter.project_name}} + - name: app image: {{cookiecutter.project_name}}:latest - imagePullPolicy: Always - envFrom: - - configMapRef: - name: {{cookiecutter.project_name}}-env + {%- if cookiecutter.db_info.name == "sqlite" %} + command: ["/bin/sh"] + args: + - -c + - >- + alembic upgrade head && + python -m {{cookiecutter.project_name }} + {%- endif %} + env: + - name: {{cookiecutter.project_name | upper }}_HOST + value: 0.0.0.0 + {%- if cookiecutter.db_info.name != "none" %} + {%- if cookiecutter.db_info.name != "sqlite" %} + - name: {{cookiecutter.project_name | upper }}_DB_HOST + value: {{cookiecutter.kube_name}}-db-service + {%- endif %} + {%- endif %} + {%- if cookiecutter.enable_redis %} + - name: {{cookiecutter.project_name | upper }}_REDIS_HOST + value: {{cookiecutter.kube_name}}-redis-service + {%- endif %} resources: limits: memory: "300Mi" @@ -29,10 +46,10 @@ spec: apiVersion: v1 kind: Service metadata: - name: {{cookiecutter.project_name}} + name: {{cookiecutter.kube_name}}-app-service spec: selector: - app: {{cookiecutter.project_name}} + app: {{cookiecutter.kube_name}}-app ports: - port: 80 targetPort: 8000 @@ -40,18 +57,18 @@ spec: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: {{cookiecutter.project_name}} + name: {{cookiecutter.kube_name}}-app labels: - name: {{cookiecutter.project_name}} + name: {{cookiecutter.kube_name}}-app spec: rules: - - host: {{cookiecutter.project_name}}.local + - host: {{ cookiecutter.kube_name }}.local http: paths: - pathType: Prefix path: "/" backend: service: - name: {{cookiecutter.project_name}} + name: {{cookiecutter.kube_name}}-app-service port: number: 80 diff --git a/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/db.yml b/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/db.yml index 5fe6ed1f6b25537782e0f3716694ab72022714a3..cd337fbdaa8250f135c10f07564dc0f7883269fb 100644 --- a/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/db.yml +++ b/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/db.yml @@ -1,15 +1,16 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - name: {{cookiecutter.project_name}}-db + name: {{cookiecutter.kube_name}}-db spec: selector: matchLabels: - app: {{cookiecutter.project_name}}-db + app: {{cookiecutter.kube_name}}-db template: metadata: labels: - app: {{cookiecutter.project_name}}-db + app: {{cookiecutter.kube_name}}-db spec: containers: - name: database @@ -18,16 +19,59 @@ spec: limits: memory: "300Mi" cpu: "200m" + env: + {%- if cookiecutter.db_info.name == 'postgresql' %} + - name: POSTGRES_PASSWORD + value: {{cookiecutter.project_name}} + - name: POSTGRES_USER + value: {{cookiecutter.project_name}} + - name: POSTGRES_DB + value: {{cookiecutter.project_name}} + {%- elif cookiecutter.db_info.name == 'mysql' %} + - name: MYSQL_PASSWORD + value: {{cookiecutter.project_name}} + - name: MYSQL_USER + value: {{cookiecutter.project_name}} + - name: MYSQL_DATABASE + value: {{cookiecutter.project_name}} + - name: ALLOW_EMPTY_PASSWORD + value: "yes" + {%- endif %} ports: - - containerPort: 5432 + - containerPort: {{cookiecutter.db_info.port}} --- apiVersion: v1 kind: Service metadata: - name: "{{cookiecutter.project_name}}-db" + name: "{{cookiecutter.kube_name}}-db-service" spec: selector: - app: {{cookiecutter.project_name}}-db + app: {{cookiecutter.kube_name}}-db ports: - port: {{cookiecutter.db_info.port}} targetPort: {{cookiecutter.db_info.port}} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{cookiecutter.kube_name}}-migrator +spec: + ttlSecondsAfterFinished: 100 + template: + spec: + containers: + - name: migrator + image: {{cookiecutter.project_name}}:latest + command: + - "wait-for-it" + - "-t" + - "180" + - "{{cookiecutter.kube_name}}-db-service:{{cookiecutter.db_info.port}}" + - "--" + - "alembic" + - "upgrade" + - "head" + env: + - name: {{cookiecutter.project_name | upper }}_DB_HOST + value: {{cookiecutter.kube_name}}-db-service + restartPolicy: Never diff --git a/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/redis.yml b/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/redis.yml index 4e1e3041373eeec8599ca27d6b85053482339713..6ad232f0f65a4e37e8360606bc4e2857c40ce09a 100644 --- a/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/redis.yml +++ b/fastapi_template/template/{{cookiecutter.project_name}}/deploy/kube/redis.yml @@ -1,19 +1,23 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - name: {{cookiecutter.project_name}}-redis + name: {{cookiecutter.kube_name}}-redis spec: selector: matchLabels: - app: {{cookiecutter.project_name}}-redis + app: {{cookiecutter.kube_name}}-redis template: metadata: labels: - app: {{cookiecutter.project_name}}-redis + app: {{cookiecutter.kube_name}}-redis spec: containers: - name: redis image: bitnami/redis:6.2.5 + env: + - name: ALLOW_EMPTY_PASSWORD + value: "yes" resources: limits: memory: "300Mi" @@ -24,10 +28,10 @@ spec: apiVersion: v1 kind: Service metadata: - name: "{{cookiecutter.project_name}}-redis" + name: "{{cookiecutter.kube_name}}-redis-service" spec: selector: - app: {{cookiecutter.project_name}}-redis + app: {{cookiecutter.kube_name}}-redis ports: - port: 6379 targetPort: 6379 diff --git a/fastapi_template/template/{{cookiecutter.project_name}}/{{cookiecutter.project_name}}/db/migrations/env.py b/fastapi_template/template/{{cookiecutter.project_name}}/{{cookiecutter.project_name}}/db/migrations/env.py index 7ab3146aab62006e8c79f45fbd1f831123047545..4e58cd7a6f315896ad04305f4859c1f0ecf6a42c 100644 --- a/fastapi_template/template/{{cookiecutter.project_name}}/{{cookiecutter.project_name}}/db/migrations/env.py +++ b/fastapi_template/template/{{cookiecutter.project_name}}/{{cookiecutter.project_name}}/db/migrations/env.py @@ -11,7 +11,7 @@ from {{cookiecutter.project_name}}.settings import settings # this is the Alembic Config object, which provides # access to the values within the .ini file in use. -config = context.config +config = context.config # type: ignore load_all_models() diff --git a/pyproject.toml b/pyproject.toml index d0c7b3b9f61360e427621d3720279799de998ca1..048a53ab67312f65d1ccd98bdfc398de6148efda 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "fastapi_template" -version = "2.1.4" +version = "2.1.5" description = "Feature-rich robust FastAPI template" authors = ["Pavel Kirilin <win10@list.ru>"] packages = [