Skip to content

Commit

Permalink
feat: add deployment via docker and integration with nomad
Browse files Browse the repository at this point in the history
* feat: add initial dockerfile

* feat: add docker compose

* feat: update cors

* fix: update docker in prep for deployment

* feat: final changes before first try at pushing to prod
  • Loading branch information
WALLE-AXIOM authored Feb 14, 2025
1 parent a7f4435 commit 6008d81
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 37 deletions.
79 changes: 79 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
##
## ---------------build frontend-----------------------
##

FROM oven/bun:1 AS base
WORKDIR /usr/src/app

RUN apt update -y && apt upgrade -y && apt install -y unzip

FROM base AS install
RUN mkdir -p /temp/dev
COPY package.json bun.lockb /temp/dev/
RUN cd /temp/dev && bun install --frozen-lockfile

RUN mkdir -p /temp/prod
COPY package.json bun.lockb /temp/prod/
RUN cd /temp/prod && bun install --frozen-lockfile --production

FROM base AS prerelease
COPY --from=install /temp/dev/node_modules node_modules
COPY . .

ENV NODE_ENV=production
RUN bun test
RUN bun run build-only ## FIXME

##
## -------------build backend-------------------------
##

ENV APP_NAME=backend
ENV SQLX_OFFLINE=true

FROM rust:1.84-alpine AS build
WORKDIR /build


RUN apk update && apk add git alpine-sdk make libffi-dev openssl-dev pkgconfig bash sqlite

COPY backend/Cargo.lock backend/Cargo.toml ./

COPY backend/.sqlx .sqlx
COPY backend/dev_setup.sh dev_setup.sh

RUN ./dev_setup.sh
RUN mkdir /var/zaiko

COPY backend/src src
RUN cargo build --locked --release
RUN cp ./target/release/backend /bin/server
RUN cp ./db.sqlite /var/zaiko/db.sqlite

##
## -------------deploy-----------------------------
##

FROM alpine:3.18 AS final

ENV DATABASE_URL=sqlite://db.sqlite
ENV DATABASE_PATH=/var/zaiko/db.sqlite
ENV OIDC_PROVIDER=https://sso.datasektionen.se/op
ENV OIDC_ID=zaiko
ENV OIDC_SECRET=bccmIyRN3JfZWHog1AuujNEautrmi5Z_hV9qfgEG0pg=
ENV REDIRECT_URL=http://localhost:8080/api/oidc/callback
ENV PLS_URL=https://pls.datasektionen.se/api
ENV APP_URL=0.0.0.0
ENV PORT=8080

ENV APP_SECRET=s70wSM9Qz5oX3EHQdHzihIKe7vYBXW3G8f9JPZC2A0tx7qBuRztOCAKwjGbKTGVW
RUN mkdir /var/zaiko

COPY --from=prerelease /usr/src/app/dist dist

COPY --from=build /bin/server /bin/
COPY --from=build /var/zaiko/db.sqlite /var/zaiko/db.sqlite

EXPOSE 8000

CMD ["/bin/server"]
52 changes: 36 additions & 16 deletions backend/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ use openidconnect::{
CoreAuthDisplay, CoreAuthPrompt, CoreAuthenticationFlow, CoreErrorResponseType,
CoreGenderClaim, CoreJsonWebKey, CoreJweContentEncryptionAlgorithm,
CoreJwsSigningAlgorithm, CoreProviderMetadata, CoreRevocableToken, CoreTokenType,
}, reqwest, AccessTokenHash, AuthorizationCode, Client, ClientId, ClientSecret, CsrfToken, EmptyAdditionalClaims, EmptyExtraTokenFields, EndpointMaybeSet, EndpointNotSet, EndpointSet, IdTokenFields, IssuerUrl, Nonce, OAuth2TokenResponse, RedirectUrl, RevocationErrorResponseType, StandardErrorResponse, StandardTokenIntrospectionResponse, StandardTokenResponse, TokenResponse
},
reqwest, AccessTokenHash, AuthorizationCode, Client, ClientId, ClientSecret, CsrfToken,
EmptyAdditionalClaims, EmptyExtraTokenFields, EndpointMaybeSet, EndpointNotSet, EndpointSet,
IdTokenFields, IssuerUrl, Nonce, OAuth2TokenResponse, RedirectUrl, RevocationErrorResponseType,
StandardErrorResponse, StandardTokenIntrospectionResponse, StandardTokenResponse,
TokenResponse,
};
use serde::Deserialize;
use std::env;
Expand Down Expand Up @@ -114,7 +119,7 @@ pub async fn get_oidc() -> (OIDCData, String) {
(oidc, auth_url.to_string())
}

#[get("oidc/callback")]
#[get("/oidc/callback")]
pub async fn auth_callback(
req: HttpRequest,
session: Session,
Expand All @@ -133,12 +138,12 @@ pub async fn auth_callback(
Ok(request) => match request.request_async(&oidc.http_client).await {
Ok(token) => token,
Err(err) => {
log::error!("{}", err);
log::error!("token request error: {}", err);
return HttpResponse::InternalServerError().finish();
}
},
Err(err) => {
log::error!("{}", err);
log::error!("token clinet request config error: {}", err);
return HttpResponse::InternalServerError().finish();
}
};
Expand All @@ -156,7 +161,7 @@ pub async fn auth_callback(
let claims = match id_token.claims(&id_token_verifier, &oidc.nonce) {
Ok(claims) => claims,
Err(err) => {
log::error!("{}", err);
log::error!("aquireing claims error: {}", err);
return HttpResponse::InternalServerError().finish();
}
};
Expand All @@ -167,21 +172,21 @@ pub async fn auth_callback(
match id_token.signing_alg() {
Ok(alg) => alg,
Err(err) => {
log::error!("{}", err);
log::error!("aquireing signing algorithm: {}", err);
return HttpResponse::InternalServerError().finish();
}
},
match id_token.signing_key(&id_token_verifier) {
Ok(key) => key,
Err(err) => {
log::error!("{}", err);
log::error!("aquireing signing key: {}", err);
return HttpResponse::InternalServerError().finish();
}
},
) {
Ok(hash) => hash,
Err(err) => {
log::error!("{}", err);
log::error!("checking hash error: {}", err);
return HttpResponse::InternalServerError().finish();
}
};
Expand All @@ -195,39 +200,51 @@ pub async fn auth_callback(
}

if let Err(err) = Identity::login(&req.extensions(), claims.subject().to_string()) {
log::error!("{}", err);
log::error!("fail to login error: {}", err);
return HttpResponse::InternalServerError().finish();
}

let pls_url = match env::var("PLS_URL") {
Ok(url) => url,
Err(err) => {
log::error!("getting pls url error: {}", err);
return HttpResponse::InternalServerError().finish();
}
};

log::debug!("{}", pls_url);
log::debug!("{}", claims.subject().as_str());

let res = match reqwest::get(format!(
"https://pls.datasektionen.se/api/user/{}/zaiko",
"{}/user/{}/zaiko",
pls_url,
claims.subject().as_str()
))
.await
{
Ok(res) => match res.text().await {
Ok(res) => res,
Err(err) => {
log::error!("{}", err);
log::error!("failed to get data from pls: {}", err);
return HttpResponse::InternalServerError().finish();
}
},
Err(err) => {
log::error!("{}", err);
log::error!("failed to query pls: {}", err);
return HttpResponse::InternalServerError().finish();
}
};

let privlages: Vec<String> = match serde_json::from_str(&res) {
Ok(privlages) => privlages,
Err(err) => {
log::error!("{}", err);
log::error!("failed to parse data from pls: {}", err);
return HttpResponse::InternalServerError().finish();
}
};

if let Err(err) = session.insert("privlages", privlages) {
log::error!("{}", err);
log::error!("failed to add privlages to session: {}", err);
return HttpResponse::InternalServerError().finish();
}

Expand All @@ -240,8 +257,11 @@ pub async fn auth_callback(
pub async fn get_clubs(id: Option<Identity>, session: Session) -> HttpResponse {
if id.is_some() {
let clubs = match session.get::<Vec<String>>("privlages") {
Ok(clubs) => {clubs},
Err(err) => {log::error!("{}", err); return HttpResponse::InternalServerError().finish();},
Ok(clubs) => clubs,
Err(err) => {
log::error!("{}", err);
return HttpResponse::InternalServerError().finish();
}
};
return HttpResponse::Ok().json(clubs);
}
Expand Down
39 changes: 29 additions & 10 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::env;

use actix_cors::Cors;
use actix_identity::{IdentityExt, IdentityMiddleware};
use actix_session::{config::PersistentSession, storage::CookieSessionStore, SessionMiddleware};
use actix_web::{
cookie::{time::Duration, Key},
guard::Guard,
http::Method,
web::{self, scope, Data},
App, HttpServer,
};
Expand All @@ -13,12 +16,12 @@ use sqlx::SqlitePool;
use supplier::get_suppliers;

mod auth;
mod error;
mod item;
mod log;
mod serve;
mod shortage;
mod supplier;
mod error;

use crate::item::{add_item, delete_item, get_item, update_item};
use crate::log::get_log;
Expand All @@ -29,10 +32,12 @@ use crate::supplier::{add_supplier, delete_supplier, get_supplier, update_suppli
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init();
dotenv().expect(".env to exist");
if env::var("APP_ENV") == Ok(String::from("development")) {
dotenv().expect(".env to exist");
}

let pool = web::Data::new(
SqlitePool::connect("db.sqlite")
SqlitePool::connect(&env::var("DATABASE_PATH").expect("DATABASE_PATH in .env"))
.await
.expect("Expected sqlite database with name db.sqlite"),
);
Expand All @@ -41,22 +46,30 @@ async fn main() -> std::io::Result<()> {
let oidc = Data::new(oidc);
let auth_url = Data::new(auth_path.clone());

let session_secret = Key::generate();
let session_secret = Key::from(
env::var("APP_SECRET")
.expect("APP_SECRET in .env")
.as_bytes(),
);

HttpServer::new(move || {
let cors = Cors::default()
.allow_any_origin()
.allow_any_method()
.allowed_methods(vec![
Method::GET,
Method::POST,
Method::PATCH,
Method::DELETE,
])
.allow_any_header();

App::new()
.wrap(IdentityMiddleware::default())
.wrap(
SessionMiddleware::builder(CookieSessionStore::default(), session_secret.clone())
.cookie_name(String::from("session"))
.cookie_secure(false)
.cookie_secure(true)
.session_lifecycle(
PersistentSession::default().session_ttl(Duration::minutes(5)),
PersistentSession::default().session_ttl(Duration::minutes(15)),
)
.build(),
)
Expand All @@ -78,9 +91,9 @@ async fn main() -> std::io::Result<()> {
.service(get_shortage)
.service(take_stock)
.service(get_log)
.service(auth_callback),
.service(get_clubs)
)
.service(auth_callback)
.service(serve_frontend)
.service(
actix_files::Files::new("/", "../dist/")
Expand All @@ -89,7 +102,13 @@ async fn main() -> std::io::Result<()> {
)
.service(web::redirect("/", auth_path.to_string()))
})
.bind(("localhost", 8080))?
.bind((
env::var("APP_URL").expect("APP_URL in .env"),
env::var("PORT")
.expect("PORT in .env")
.parse()
.expect("PORT to be a number"),
))?
.run()
.await
}
Expand Down
7 changes: 7 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
app:
build: .
ports:
- 8080:8080
volumes:
- ./backend/db.sqlite:/var/zaiko/db.sqlite
11 changes: 0 additions & 11 deletions src/components/__tests__/HelloWorld.spec.ts

This file was deleted.

0 comments on commit 6008d81

Please sign in to comment.