Skip to content
This repository has been archived by the owner on Mar 16, 2024. It is now read-only.

Commit

Permalink
Change example (#4)
Browse files Browse the repository at this point in the history
* Cleanup secret using limited charset feature

* More details in README

* Add button to launch example app

* Use acorn.io in Button

* Use simple counter app as an example
  • Loading branch information
lucj authored Oct 24, 2023
1 parent 22e2590 commit 2588b65
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 43 deletions.
1 change: 1 addition & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ jobs:
USER=${{ github.repository_owner }}
REPO=${{ github.event.repository.name }}
acorn build --platform linux/amd64 --push -t ghcr.io/$USER/$REPO:$TAG .
acorn build --platform linux/amd64 --push -t ghcr.io/$USER/$REPO/examples:$TAG examples
35 changes: 12 additions & 23 deletions Acornfile
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,19 @@ volumes: {
"db-data": {}
}

jobs: "create-admin-secret": {
build: context: "."
env: {
DB_USER: args.dbUser
DB_PASS: "secret://password/token"
}
}

secrets: {
password: {
type: "token"
params: {
length: 16
characters: "abcdedfhifj01234567890"
admin: {
name: "credentials of the admin user"
type: "basic"
params: {
passwordLength: 10
passwordCharacters: "A-Za-z0-9"
}
data: {
username: std.ifelse(args.dbUser != "", args.dbUser, "")
password: ""
}
}
data: token: ""
}
}

secrets: {
"admin": {
type: "generated"
params: job: "create-admin-secret"
}
}

localData: readinessProbeCommand: [
Expand All @@ -95,7 +84,7 @@ localData: info: """
## Usage

services: db: {
external: "@{acorn.name}"
image: "ghcr.io/acorn-io/postgres:v#.#-#"
}

containers: app: {
Expand Down
3 changes: 0 additions & 3 deletions Dockerfile

This file was deleted.

77 changes: 74 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,76 @@
# Postgres
## Postgres Database

This Acorn provides a Postgres database as an Acorn Service. This Acorn can be used to create a database for your application during development. It runs a single Postgres container backed by a persistent volume.
PostgreSQL is an open-source object-relational database system that uses and extends the SQL language. Known for its robustness and reliability, it supports advanced data types and advanced performance optimization, offering features like complex queries, atomic transactions, and concurrent connections.

A default user is automatically generated during the creation process.
## Postgres as an Acorn Service

This Acorn provides a Postgres database as an Acorn Service. It can be used to easily get a Postgres database for your application during development. The current service runs a single Postgres container backed by a persistent volume and define credentials for an admin user.

This Postgres instance:
- is backed by a persistent volume
- generate credentials for an admin user

The Acorn image of this service is hosted in GitHub container registry at [ghcr.io/acorn-io/postgres](ghcr.io/acorn-io/postgres).

Currently this Acorn has the following configuration options:
- *dbName*: name of the database (*postgres* by default)
- *dbUser*: name of the admin user (*postgres* by default)

## Usage

The [examples folder](https://github.com/acorn-io/postgres/tree/main/examples) contains a sample application using this Service. This app consists in a Python backend based on the FastAPI library, it displays a web page indicating the number of times the application was called, a counter is saved in the underlying Postgres database and incremented with each request. The screenshot below shows the UI of the example application.

![UI](./examples/images/ui.png)

To use the Postgres Service, we first define a *service* property in the Acornfile of the example app:

```
services: db: image: "ghcr.io/acorn-io/postgres:v#.#-#"
```

Next we define the application container:

```
containers: app: {
build: {
context: "."
target: "dev"
}
consumes: ["db"]
ports: publish: "8000/http"
env: {
POSTGRES_HOST: "@{service.db.address}"
POSTGRES_DB: "@{service.db.data.dbName}"
POSTGRES_USER: "@{service.db.secrets.admin.username}"
POSTGRES_PASSWORD: "@{service.db.secrets.admin.password}"
}
}
```

This container is built using the Dockerfile in the examples folder. Once built, the container consumes the Postgres service using properties provided by the service:
- @{service.db.address} : URL to connect to the postgres service
- @{service.db.data.dbName}: database name
- @{service.db.secrets.admin.username}: username of the admin user
- @{service.db.secrets.admin.password}: password of the admin user

This example can be run with the following command (to be run from the *examples* folder)

```
acorn run -n app
```

After a few tens of seconds an http endpoint will be returned. Using this endpoint we can access the application and see the counter incremented on each reload of the page.

Once we're done, we can remove the app:

```
acorn rm -af app
```

## Deploy the app to your Acorn Sandbox

Instead of managing your own Acorn installation, you can deploy this application in the Acorn Sandbox, the free SaaS offering provided by Acorn. Access to the sandbox requires only a GitHub account, which is used for authentication.

[![Run in Acorn](https://acorn.io/v1-ui/run/badge?image=ghcr.io+acorn-io+postgres+examples:v%23.%23-%23)](https://acorn.io/run/ghcr.io/acorn-io/postgres/examples:v%23.%23-%23)

An application running in the Sandbox will automatically shut down after 2 hours, but you can use the Acorn Pro plan to remove the time limit and gain additional functionalities.
9 changes: 6 additions & 3 deletions examples/Acornfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
services: db: image: "ghcr.io/acorn-io/postgres:v#.#-#"

containers: nextcloud: {
image: "nextcloud"
ports: publish: "80/http"
containers: app: {
build: {
context: "."
target: "dev"
}
consumes: ["db"]
ports: publish: "8000/http"
env: {
POSTGRES_HOST: "@{service.db.address}"
POSTGRES_DB: "@{service.db.data.dbName}"
Expand Down
15 changes: 15 additions & 0 deletions examples/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.9 as base
WORKDIR /app

FROM base as build
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt
COPY . .

FROM build as dev
EXPOSE 8000
CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers"]

FROM build as production
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Binary file added examples/images/ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 74 additions & 0 deletions examples/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
import os
import psycopg2

# Configuration
POSTGRES_HOST = os.environ.get('POSTGRES_HOST')
POSTGRES_DB = os.environ.get('POSTGRES_DB')
POSTGRES_USER = os.environ.get('POSTGRES_USER')
POSTGRES_PASSWORD = os.environ.get('POSTGRES_PASSWORD')

# FastAPI application
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

def get_db_connection():
conn = psycopg2.connect(
user=POSTGRES_USER,
password=POSTGRES_PASSWORD,
host=POSTGRES_HOST,
database=POSTGRES_DB
)
return conn

def setup_database():
# Establishing a new connection to our database
conn = get_db_connection()
try:
with conn.cursor() as cursor:
# Create table if it doesn't exist
cursor.execute("""
CREATE TABLE IF NOT EXISTS visit_counter (
counter_name VARCHAR PRIMARY KEY,
count_value INT NOT NULL
);
""")
# Initialize the counter if it doesn't exist
cursor.execute("""
INSERT INTO visit_counter (counter_name, count_value)
VALUES ('hits', 0)
ON CONFLICT (counter_name) DO NOTHING;
""")
# Committing any changes and closing the transaction
conn.commit()
finally:
# Closing the database connection
conn.close()

@app.on_event("startup")
async def startup_event():
# Setting up database during startup
setup_database()

@app.get('/', response_class=HTMLResponse)
async def read_root(request: Request):
# Each request gets a new database connection
conn = get_db_connection()
try:
with conn.cursor() as cursor:
# Increment the counter and retrieve its value
cursor.execute("UPDATE visit_counter SET count_value = count_value + 1 WHERE counter_name = 'hits';")
cursor.execute("SELECT count_value FROM visit_counter WHERE counter_name = 'hits';")
count = cursor.fetchone()[0]
# Committing the update
conn.commit()
finally:
# Closing the connection
conn.close()

# Returning the current counter value within the rendered HTML
return templates.TemplateResponse("index.html", {"request": request, "counter": count})
4 changes: 4 additions & 0 deletions examples/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fastapi == 0.101.0
uvicorn[standard] == 0.23.2
psycopg2-binary == 2.9.9
Jinja2 == 3.1.2
Binary file added examples/static/acorn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions examples/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
html, body {
height: 100%;
margin: 0;
padding: 0;
background: #483285;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: white;
font-family: Arial, sans-serif;
}
.content {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
}
img {
width: 100%;
max-width: 100%;
height: auto;
margin-bottom: 20px;
}
.counter {
font-size: 4rem;
width: 100%;
margin-top: 0;
}
16 changes: 16 additions & 0 deletions examples/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stylish Counter</title>
<link href="/static/style.css" rel="stylesheet">
</head>
<body>
<div class="content">
<img src="/static/acorn.png" alt="Acorn logo" />
<div class="counter">Page views: {{counter}}</div>
</div>
</body>
</html>
11 changes: 0 additions & 11 deletions scripts/render.sh

This file was deleted.

0 comments on commit 2588b65

Please sign in to comment.