Skip to content

Commit

Permalink
Add tiler microservice
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeh committed Feb 14, 2023
1 parent 39e686e commit 1933641
Show file tree
Hide file tree
Showing 24 changed files with 235 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.py]
indent_size = 4

[*.md]
indent_style = tab
indent_size = 4
Expand Down
34 changes: 34 additions & 0 deletions .github/workflows/testing-tiler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Tiler Tests

on:

push:
paths:
- 'tiler/**'

workflow_dispatch:

jobs:
test:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.10]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Tiler tests
env:
# add environment variables for tests
run: |
pytest
5 changes: 5 additions & 0 deletions api/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
"cachePort": "DB_CACHE_PORT",
"cacheDatabase": "DB_CACHE_DATABASE"
},

"tiler": {
"host": "TILER_HOST",
"port": "TILER_PORT"
},
"fileUploads": {
"sizeLimit": "FILE_SIZE_LIMIT",
"storagePath": "FILE_STORAGE_PATH"
Expand Down
6 changes: 6 additions & 0 deletions api/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@
"cacheHost": "localhost",
"cacheDatabase": 3
},

"tiler": {
"host": "localhost",
"port": 4000
},

"fileUploads": {
"sizeLimit": 8388608,
"storagePath": "/tmp/csv-uploads"
Expand Down
5 changes: 5 additions & 0 deletions api/config/development.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"log"
]
},

"tiler": {
"host": "localhost",
"port": 4000
},
"auth": {
"requireUserAccountActivation": false,
"jwt": {
Expand Down
5 changes: 5 additions & 0 deletions api/config/test.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
"logging": false,
"cacheEnabled": false
},

"tiler": {
"host": "localhost",
"port": 4000
},
"server": {
"loggerLevel": [
"error",
Expand Down
9 changes: 9 additions & 0 deletions api/src/modules/authentication/authentication.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ export class AuthenticationController {
await this.authenticationService.validateActivationToken(activationToken);
}

/**
* @description: This endpoint is exclusively to validate requests sent to the tiler
* service
*/
@Get('validate-token')
async validateToken(): Promise<any> {
return { message: 'valid token' };
}

/**
* @debt Make sure (and add e2e tests to check for regressions) that we
* gracefully handle situations where a user's username has changed between
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Repository } from 'typeorm';
import { Scenario } from 'modules/scenarios/scenario.entity';

/**
* @desciption: Service extending base AccessControl which receives a fresh request object from it each time.
* @description: Service extending base AccessControl which receives a fresh request object from it each time.
* Use this class ta perform user's specific authorisation over scenarios, based on roles/permissions
*/

Expand Down
7 changes: 5 additions & 2 deletions api/src/modules/scenarios/scenario.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ export class Scenario extends TimestampedBaseEntity {
@Column({ nullable: true })
description?: string;

@ApiPropertyOptional()
@ApiPropertyOptional({
type: 'boolean',
description: 'Make a Scenario public to all users',
})
@Column({ type: 'boolean', default: false, nullable: false })
isPublic!: boolean;

@ApiProperty()
@ApiProperty({ enum: SCENARIO_STATUS })
@Column({
type: 'enum',
enum: SCENARIO_STATUS,
Expand Down
18 changes: 18 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ services:
- postgresql
- redis

tiler:
container_name: landgriffon-tiler
build:
context: ./tiler
args:
- TILER_TEST_COG_FILENAME=${TILER_TEST_COG_FILENAME}

env_file: ${ENVFILE}
environment:
- API_URL=${API_URL}
- API_PORT=${API_PORT}
- S3_BUCKET_URL=${S3_BUCKET_URL}
ports:
- "${TILER_SERVICE_PORT}:4000"
volumes:
- ./tiler:/opt/landgriffon-tiler/data/local-dev
restart: unless-stopped

redis:
build:
context: ./redis
Expand Down
9 changes: 9 additions & 0 deletions infrastructure/kubernetes/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions tiler/.env.default
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# TILER
REQUIRE_AUTH=
API_HOST=
S3_BUCKET_URL=
35 changes: 35 additions & 0 deletions tiler/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM python:3.11
LABEL maintainer="[email protected]"

ENV NAME landgriffon-tiler
ENV USER $NAME
ENV APP_HOME /opt/$NAME

ARG TILE_LANDGRIFFON_COG_FILENAME
# @todo: The data should be retrieved from a S3 bucket in LG World
#ARG DATA_CORE_COG_SOURCE_URL

#ARG DATA_CORE_COG_CHECKSUM

RUN addgroup $USER && adduser --shell /bin/bash --disabled-password --ingroup $USER $USER

WORKDIR $APP_HOME
RUN chown $USER:$USER $APP_HOME

COPY requirements.txt requirements.txt

RUN pip install --no-cache-dir --upgrade -r ./requirements.txt


COPY --chown=$USER:$USER app ./app

#ADD --chown=$USER:$USER --checksum=${DATA_CORE_COG_CHECKSUM} ${DATA_CORE_COG_SOURCE_URL} ./data/${TILE_LANDGRIFFON_COG_FILENAME}
#RUN find ./data -type f -exec chmod ugo-w '{}' \;

EXPOSE 4000
USER $USER

# @todo Consider whether to use a shell script as entrypoint to allow for
# different run modes (e.g. debug, dev, prod, etc.) via Docker commands

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "4000"]
Empty file added tiler/__init__.py
Empty file.
Empty file added tiler/app/__init__.py
Empty file.
Empty file added tiler/app/config/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions tiler/app/config/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from pydantic import BaseSettings
from os import getenv
from functools import lru_cache


class Settings(BaseSettings):
api_url: str = getenv('API_HOST')
api_port: str = getenv('API_PORT')
s3_bucket_url: str = getenv('S3_BUCKET_URL')
require_auth: str = getenv('REQUIRE_AUTH')


@lru_cache()
def get_settings():
return Settings()
26 changes: 26 additions & 0 deletions tiler/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from fastapi import FastAPI, Query
from fastapi.middleware.cors import CORSMiddleware
from titiler.core import TilerFactory
from titiler.core.errors import DEFAULT_STATUS_CODES, add_exception_handlers
from titiler.core.middleware import TotalTimeMiddleware, LoggerMiddleware
from .middlewares.auth_middleware import AuthMiddleware
from .middlewares.url_injector import inject_s3_url

app = FastAPI(title="LandGriffon Tiler! Because why keep life simple?")
app.add_middleware(TotalTimeMiddleware)
app.add_middleware(LoggerMiddleware)
app.add_middleware(AuthMiddleware)
app.add_middleware(CORSMiddleware, allow_origins=["*"],
allow_methods=["GET"],
allow_headers=["*"], )

# single COG tiler. One file can have multiple bands
cog = TilerFactory(router_prefix="/cog", path_dependency=inject_s3_url)
app.include_router(cog.router, tags=["Cloud Optimized GeoTIFF"], prefix="/cog", )
add_exception_handlers(app, DEFAULT_STATUS_CODES)


@app.get("/health", description="Health Check", tags=["Health Check"])
def ping():
"""Health check."""
return {"ping": "pong"}
Empty file.
32 changes: 32 additions & 0 deletions tiler/app/middlewares/auth_middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import requests
from fastapi import Request, Response, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
import os
from app.config.config import get_settings

api_url = get_settings().api_url
api_port = get_settings().api_port


class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
env = os.environ.get('PYTHON_ENV')
if env == 'dev':
return await call_next(request)
else:
try:
token = request.headers.get("Authorization")
if not token:
return Response(status_code=400, content="No token found")
headers = {
"Authorization": token
}
response = requests.get(f"{api_url}:{api_port}/auth/validate-token", headers=headers)
if response.status_code != 200:
return Response(status_code=401, content="Unauthorized")
return await call_next(request)


except Exception as e:
print(e)
raise HTTPException(status_code=500, detail=str(e))
8 changes: 8 additions & 0 deletions tiler/app/middlewares/url_injector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from fastapi.params import Query

from ..config.config import get_settings


def inject_s3_url(url: str | None = Query(default=None, description="Optional dataset URL")) -> str:
s3_url = get_settings().s3_bucket_url
return s3_url + url
Empty file added tiler/app/test/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions tiler/app/test/test_health.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from fastapi.testclient import TestClient
from ..main import app

client = TestClient(app)


def test_auth_middleware():
"""Should throw a Unauthorized Exception if no token has been provided"""
response = client.get("/cog/info")
assert response.status_code == 400
assert response.text == 'No token found'
4 changes: 4 additions & 0 deletions tiler/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
titiler.application==0.11.0
uvicorn
requests~=2.28.2
pytest~=7.2.1

0 comments on commit 1933641

Please sign in to comment.