Skip to content

Commit e55a97c

Browse files
Adding requirements, adding settings file for future customization
1 parent e751767 commit e55a97c

File tree

5 files changed

+117
-26
lines changed

5 files changed

+117
-26
lines changed

README.md

+2-5
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ This project implements a custom HTTP backend for Terraform using FastAPI. It pr
1010

1111
## Requirements
1212

13-
- Python 3.7+
14-
- FastAPI
15-
- Uvicorn (for running the FastAPI application)
16-
- Pydantic
13+
see [requirements.txt](requirements.txt)
1714

1815
## Installation
1916

@@ -26,7 +23,7 @@ git clone [email protected]:mikelv702/simple-terraform-backend.git
2623
2. Install the required packages:
2724

2825
```bash
29-
pip install fastapi
26+
uv pip install -r requirements.txt
3027
```
3128

3229
## Usage

helpers/local_file_handler.py

+21-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
import os
22
import json
3+
import logging
4+
5+
from ..settings import settings
6+
7+
settings.configure_logging()
8+
logger = logging.getLogger(__name__)
39

410
def save_file(json_data) -> None:
5-
cwd = os.getcwd()
6-
file_path = os.path.join(cwd, 'data.json')
7-
with open(file_path, 'w', encoding='utf-8') as f:
8-
json.dump(json_data, f, ensure_ascii=False)
11+
logger.debug("Saving to disk")
12+
try:
13+
directory_path = os.path.join(os.getcwd(), settings.FILE_STORAGE_PATH)
14+
if not os.path.exists(directory_path):
15+
os.makedirs(directory_path)
16+
logger.info(f"Created directory: {directory_path}")
17+
file_path = os.path.join(directory_path, 'data.json')
18+
logger.info(f"Saving to {file_path}")
19+
with open(file_path, 'w', encoding='utf-8') as f:
20+
json.dump(json_data, f, ensure_ascii=False)
21+
except FileNotFoundError:
22+
logger.warn(f"File not found {file_path}")
923

1024
def read_file():
1125
try:
12-
cwd = os.getcwd()
13-
file_path = os.path.join(cwd, 'data.json')
26+
directory_path = os.path.join(os.getcwd(), settings.FILE_STORAGE_PATH)
27+
file_path = os.path.join(directory_path, 'data.json')
1428
f = open(file_path)
1529
json_data = json.load(f)
1630
return json_data
1731
except FileNotFoundError:
1832
print("File not found, returning empty")
19-
return {}
33+
return None

main.py

+17-14
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
1+
import logging
12
from pydantic import BaseModel, Field
23
from typing import List, Dict, Any, Optional
34

45
from fastapi import FastAPI, HTTPException, Response
56
from fastapi.responses import JSONResponse
67

8+
79
from .helpers.local_file_handler import save_file, read_file
810

9-
app = FastAPI()
11+
from .settings import settings
12+
13+
settings.configure_logging()
14+
logger = logging.getLogger(__name__)
1015

16+
app = FastAPI(title=settings.APP_NAME,
17+
version=settings.APP_VERSION,
18+
debug=settings.DEBUG)
1119

20+
# IN MEMORY LOCK FILE! DO NOT USE IN PRODUCTION
1221
lock_info = None
22+
1323
class LockInfo(BaseModel):
1424
ID: str
1525
Operation: str
@@ -65,21 +75,16 @@ async def get_lock():
6575

6676
@app.post("/tfstate")
6777
async def update_terraform_state(ID: str, state: TerraformState):
68-
print("Update State File")
69-
print(ID)
70-
71-
78+
logging.info(f"Update state file {ID}")
7279
save_file(state.model_dump())
73-
print(state)
80+
logging.debug(state)
7481
return JSONResponse(content=state.model_dump())
7582

7683
@app.get("/tfstate")
7784
async def get_terraform_state():
78-
print("Getting State File")
79-
# Here you would typically retrieve the state from your storage system
80-
# For this example, we'll just return a dummy state
85+
logging.info("Requesting State File")
8186
state_returned = read_file()
82-
if len(state_returned) < 4:
87+
if state_returned is None:
8388
dummy_state = TerraformState(
8489
version=4,
8590
terraform_version="1.0.0",
@@ -90,7 +95,5 @@ async def get_terraform_state():
9095
)
9196
return dummy_state
9297
else:
93-
dummy_state = TerraformState(**state_returned)
94-
95-
print(dummy_state)
96-
return JSONResponse(content=dummy_state.model_dump())
98+
returned_state = TerraformState(**state_returned)
99+
return JSONResponse(content=returned_state.model_dump())

requirements.txt

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
annotated-types==0.7.0
2+
anyio==4.4.0
3+
certifi==2024.6.2
4+
click==8.1.7
5+
dnspython==2.6.1
6+
email-validator==2.2.0
7+
fastapi==0.111.0
8+
fastapi-cli==0.0.4
9+
h11==0.14.0
10+
httpcore==1.0.5
11+
httptools==0.6.1
12+
httpx==0.27.0
13+
idna==3.7
14+
jinja2==3.1.4
15+
markdown-it-py==3.0.0
16+
markupsafe==2.1.5
17+
mdurl==0.1.2
18+
orjson==3.10.5
19+
pydantic==2.7.4
20+
pydantic-core==2.18.4
21+
pydantic-settings==2.3.4
22+
pygments==2.18.0
23+
python-dotenv==1.0.1
24+
python-multipart==0.0.9
25+
pyyaml==6.0.1
26+
rich==13.7.1
27+
shellingham==1.5.4
28+
sniffio==1.3.1
29+
starlette==0.37.2
30+
typer==0.12.3
31+
typing-extensions==4.12.2
32+
ujson==5.10.0
33+
uvicorn==0.30.1
34+
uvloop==0.19.0
35+
watchfiles==0.22.0
36+
websockets==12.0

settings.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from pydantic import Field
2+
from pydantic_settings import BaseSettings
3+
from typing import Optional
4+
import logging
5+
6+
class Settings(BaseSettings):
7+
# App settings
8+
APP_NAME: str = "mikelv702-terraform backend"
9+
APP_VERSION: str = "0.1.0"
10+
DEBUG: bool = False
11+
12+
# Server settings
13+
HOST: str = "0.0.0.0"
14+
PORT: int = 8000
15+
16+
# Logging settings
17+
LOG_LEVEL: str = Field(default="INFO", env="LOG_LEVEL")
18+
LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
19+
20+
# Storage settings
21+
STORAGE_TYPE: str = Field(default="file",
22+
env="STORAGE_TYPE") # Options: "file", "database"
23+
FILE_STORAGE_PATH: str = Field(default="terraform_states",
24+
env="FILE_STORAGE_PATH")
25+
# TODO: Implment Database backend
26+
# DATABASE_URL: Optional[str] = Field(default=None, env="DATABASE_URL")
27+
28+
# Lock settings
29+
LOCK_TIMEOUT: int = Field(default=300, env="LOCK_TIMEOUT")
30+
31+
class Config:
32+
env_file = ".env"
33+
env_file_encoding = "utf-8"
34+
35+
def configure_logging(self):
36+
logging.basicConfig(
37+
level=getattr(logging, self.LOG_LEVEL),
38+
format=self.LOG_FORMAT
39+
)
40+
41+
settings = Settings()

0 commit comments

Comments
 (0)