diff --git a/.forgejo/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml similarity index 50% rename from .forgejo/workflows/deploy.yaml rename to .gitea/workflows/deploy.yaml index 25d7503..380f6be 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -8,24 +8,24 @@ jobs: - name: setup env run: | . ./.env || true - if [ "${{ forgejo.ref_name }}" = prod ] && [ -n "$PROD_URL" ]; then + if [ "${{ gitea.ref_name }}" == prod ] && [ -n "$PROD_URL" ]; then BASE_URL="$PROD_URL" else - BASE_URL="${{ forgejo.ref_name }}.$(tr / '\n' <<< "${{ forgejo.repository }}" | tac | tr '\n' .)k3s.gmoker.com" + BASE_URL="${{ gitea.ref_name }}.$(tr / '\n' <<< "${{ gitea.repository }}" | tac | tr '\n' .)k8s.gmoker.com" fi - REGISTRY="$(sed 's .*:// ' <<< ${{ forgejo.server_url }})" + REGISTRY="$(sed 's .*:// ' <<< ${{ gitea.server_url }})" cat <> .env BASE_URL="$BASE_URL" REGISTRY="$REGISTRY" - IMAGEAPP="$REGISTRY/${{ forgejo.repository }}:${{ forgejo.ref_name }}" + IMAGEAPP="$REGISTRY/${{ gitea.repository }}:${{ gitea.ref_name }}" EOF cat .env - - uses: actions/buildkit@v1 + - uses: actions/kaniko@v1 with: password: "${{ secrets.PKGRW }}" - - uses: actions/k8sdeploy@v2 + - uses: actions/k8sdeploy@v1 with: - kubeconfig: "${{ secrets.K3S }}" + kubeconfig: "${{ secrets.K8S }}" registry_password: "${{ secrets.PKGRW }}" diff --git a/Dockerfile b/Dockerfile index c26e23a..22f3387 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.25 AS build +FROM docker.io/golang:1.23 AS build WORKDIR /build/ COPY go.mod go.sum . RUN go mod download @@ -11,7 +11,5 @@ COPY html/ html/ COPY css/ css/ COPY static/ static/ COPY tmpl/ tmpl/ -COPY ssh pgp.asc . -COPY aliases.txt aliases.txt EXPOSE 3000 CMD ["./app"] diff --git a/README.md b/README.md deleted file mode 100644 index a46e4b2..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# yw5n.com diff --git a/aliases.txt b/aliases.txt deleted file mode 100644 index 4bdaea1..0000000 --- a/aliases.txt +++ /dev/null @@ -1,4 +0,0 @@ -termux.sh https://git.gmoker.com/ange/termux/raw/branch/main/install.sh -dotfiles https://git.gmoker.com/ange/dotfiles -arch https://git.gmoker.com/ange/archinstall -wg.sh https://git.gmoker.com/ange/wg/raw/branch/main/install.sh diff --git a/css/resume.css b/css/resume.css index 4e246ed..a987a76 100644 --- a/css/resume.css +++ b/css/resume.css @@ -1,19 +1,11 @@ @media print { - @page { - size: A4; - size: portrait; - margin: 5mm; - } + @page { + size: A4; + size: portrait; + margin: 5mm; + } - #credits, #menu { - display: none; - } - - #main { - margin: 0; - } - - #nav { - float: right; - } + #menu, #credits { + display: none; + } } diff --git a/css/style.css b/css/style.css index 765d4f1..6a1fee0 100644 --- a/css/style.css +++ b/css/style.css @@ -1,176 +1,176 @@ /* https://suckless.org/pub/style.css */ html { - overflow-y: scroll; + overflow-y: scroll; } body { - background-color: #fff; - color: #000; - font-family: sans-serif; - padding: 0; - margin: 0; + background-color: #fff; + color: #000; + font-family: sans-serif; + padding: 0; + margin: 0; } pre, code { - margin: 0; + margin: 0; } a { - color: #005386; + color: #005386; } #header a, #nav a, #menu a { - text-decoration: none; + text-decoration: none; } #nav a:hover { - background-color: #ddd; + background-color: #ddd; } #menu { - clear: both; - color: #069; - overflow: hidden; - background-color: #17a; - padding: 0.7ex; - border-top: 1px solid #ccc; - border-bottom: 1px solid #069; + clear: both; + color: #069; + overflow: hidden; + background-color: #17a; + padding: 0.7ex; + border-top: 1px solid #ccc; + border-bottom: 1px solid #069; } #menu a { - padding: 0.5ex 1ex; - color: #fff; + padding: 0.5ex 1ex; + color: #fff; } #menu a:hover { - background-color: #069; + background-color: #069; } #header { - background-color: #eee; - clear: both; - color: #555; - font-size: 1.78em; - padding: 0.7ex 0.7ex 0.7ex 0.7em; + background-color: #eee; + clear: both; + color: #555; + font-size: 1.78em; + padding: 0.7ex 0.7ex 0.7ex 0.7em; } #headerLink { - color: #17a; - margin-left: 5px; + color: #17a; + margin-left: 5px; } h1 { - margin: 1em 1ex 0.5ex 0; - font-size: 1.4em; + margin: 1em 1ex 0.5ex 0; + font-size: 1.4em; } h2 { - margin: 1em 1ex 0.5ex 0; - font-size: 1.3em; + margin: 1em 1ex 0.5ex 0; + font-size: 1.3em; } h3 { - margin: 1em 1ex 0.5ex 0; - font-size: 1.0em; + margin: 1em 1ex 0.5ex 0; + font-size: 1.0em; } h4 { - margin: 1em 1ex 0.5ex 0; - font-size: 0.9em; + margin: 1em 1ex 0.5ex 0; + font-size: 0.9em; } #headerSubtitle { - font-size: 0.75em; - font-style: italic; - margin-left: 1em; - color: #fff; + font-size: 0.75em; + font-style: italic; + margin-left: 1em; + color: #fff; } #content { - clear: both; - margin: 0; - padding: 0; + clear: both; + margin: 0; + padding: 0; } #nav { - float: left; - margin: 0 1px 0 0; - padding: 1em 0; - border-right: 1px dotted #ccc; - width: 200px; + float: left; + margin: 0 1px 0 0; + padding: 1em 0; + border-right: 1px dotted #ccc; + width: 200px; } #nav ul { - margin: 0; - padding: 0; + margin: 0; + padding: 0; } #nav li { - list-style: none; - padding: 0; - margin: 0; + list-style: none; + padding: 0; + margin: 0; } #nav li ul { - padding-left: 0.6em !important; + padding-left: 0.6em !important; } #nav li a { - display: block; - margin: 0; - padding: 0.8ex 2em 0.8ex 1em; + display: block; + margin: 0; + padding: 0.8ex 2em 0.8ex 1em; } #main { - margin: 0 0 0 200px; - max-width: 50em; - padding: 1.5em; + margin: 0 0 0 200px; + max-width: 50em; + padding: 1.5em; } .left { - float: left; - margin: 0; - padding: 0; + float: left; + margin: 0; + padding: 0; } .right { - float: right; - margin: 0; - padding: 0; + float: right; + margin: 0; + padding: 0; } .hidden { - display: none; + display: none; } @media (prefers-color-scheme: dark) { - body { - background-color: #000; - color: #bdbdbd; - } - #menu { - border-top: 1px solid #222; - } - #header { - background-color: #111; - } - #nav a:hover { - background-color: #222; - } - blockquote, pre, code { - background-color: #111; - border-color: #222; - } - a { - color: #56c8ff; - } - #main img[src$=svg] { - filter: invert(1); - } + body { + background-color: #000; + color: #bdbdbd; + } + #menu { + border-top: 1px solid #222; + } + #header { + background-color: #111; + } + #nav a:hover { + background-color: #222; + } + blockquote, pre, code { + background-color: #111; + border-color: #222; + } + a { + color: #56c8ff; + } + #main img[src$=svg] { + filter: invert(1); + } } footer { - position: fixed; - bottom: 0; + position: fixed; + bottom: 0; } diff --git a/go.mod b/go.mod index 1d1c419..3a3a5a6 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module main -go 1.25 +go 1.23.3 diff --git a/html/contact.html b/html/contact.html index 337f759..0fd8f2a 100644 --- a/html/contact.html +++ b/html/contact.html @@ -2,66 +2,68 @@ {{template "head.tmpl" .}} - + {{template "header.tmpl" .}}
+
+ + + + + - + - + - + - + - + - + - +
Matrix (Element)@ange:gmoker.com
Discord{{template "discord"}}@elrilio
Phone (France){{template "phone"}}+33 5 82 95 16 23
Email{{template "email"}}ange@yw5n.com
WhatsApp{{template "wa"}}+62 853-3355-9453
LinkedIn{{template "in"}}www.linkedin.com/in/angedhn
PGP{{template "pgp"}}pgp.asc
SSH{{template "ssh"}}ssh
-
+
diff --git a/html/resume.html b/html/resume.html index 79905d4..53ea72f 100644 --- a/html/resume.html +++ b/html/resume.html @@ -8,11 +8,14 @@ {{template "header.tmpl" .}}
@@ -25,22 +28,19 @@

EXPERIENCE

-

Freelance - DevOps Engineer

+

Freelance - DevOps

SEPTEMBER 2023 - TODAY
    -
  • Docker / K8S
  • -
  • GitHub Actions
  • -
  • Prometheus
  • -
  • Python / Go backend
  • +
  • Server setup (Debian, Docker/K8S, web server, customer application)
  • +
  • CI/CD, real-time monitoring
-

Selfhost - DevOps Engineer

+

Selfhost - DevOps

JANUARY 2022 - TODAY
    -
  • Bare metal K8S
  • -
  • Gitea Actions
  • +
  • Debian, K8S, Gitea CI/CD
  • Nextcloud, Matrix.org, Jellyfin, SearXNG
-

EPITECH CodingClub association, Toulouse - Trainer

+

EPITECH CodingClub association, Toulouse - Cobra

JANUARY 2021 - JUNE 2024
  • Coding workshops for high school students
  • @@ -48,21 +48,20 @@

    Predicloud, Toulouse - DevOps SRE

    JUNE 2022 - JULY 2023
      -
    • GitLab CI
    • -
    • Prometheus, Grafana
    • -
    • OpenLDAP + Python frontend, Keycloak, K8S webhook
    • -
    • Postfix, Dovecot
    • -
    • Customer troubleshooting
    • +
    • CI/CD, K8S monitoring
    • +
    • Authentication solution (LDAP, SSO, Webhook) + Python backend
    • +
    • Mail server (Postfix, Dovecot)
    • +
    • Customer communication and troubleshooting

    COMPETENCES

    - - - - - - + + + + + +
    LANGUAGESSOFTWARE
    C/C++ *nix
    Python Git
    Bash Vim
    Go Docker
    JS K8S
    LANGUAGES SOFTWARE
    C/C++ *nix
    Python Git
    Bash Vim
    Go Docker
    JS K8S
diff --git a/manifests/bin/deploy.sh b/manifests/bin/deploy.sh index d82a9d7..088dfbb 100755 --- a/manifests/bin/deploy.sh +++ b/manifests/bin/deploy.sh @@ -1,36 +1,34 @@ #!/bin/bash -e set -o pipefail -kapply() { +function kapply() { for f in "$@"; do - kubectl apply --server-side \ - -f<(envsubst "$(env | sed 's/^/$/')" < "manifests/$f") + kubectl apply -f \ + <(envsubst "$(env | xargs printf '$%s ')" < "manifests/$f") done -}; export -f kapply +} -kcreatesec() { - kubectl apply --server-side \ - -f<(kubectl create secret generic --dry-run=client -oyaml "$@") -}; export -f kcreatesec +function kcreatesec() { + kubectl create secret generic --save-config --dry-run=client -oyaml "$@" | kubectl apply -f- +} -kcreatecm() { - kubectl apply --server-side \ - -f<(kubectl create configmap --dry-run=client -oyaml "$@") -}; export -f kcreatecm +function kcreatecm() { + kubectl create configmap --dry-run=client -oyaml "$@" | kubectl apply -f- +} -kgseckey() { +function kgseckey() { local sec="$1"; shift local key="$1"; shift - kubectl get secret "$sec" -ojson | jq -re ".data.\"$key\"" | base64 -d -}; export -f kgseckey + kubectl get secret "$sec" -o jsonpath="{.data.$key}" | base64 -d +} -kgcmkey() { - local cm="$1"; shift +function kgcmkey() { + local cm="$1"; shift local key="$1"; shift - kubectl get configmap "$cm" -ojson | jq -re ".data.\"$key\"" -}; export -f kgcmkey + kubectl get configmap "$cm" -o jsonpath="{.data.$key}" +} kapply common/app.yaml diff --git a/manifests/bin/devel.sh b/manifests/bin/devel.sh index 65675aa..464c4d0 100755 --- a/manifests/bin/devel.sh +++ b/manifests/bin/devel.sh @@ -1,5 +1,4 @@ #!/bin/bash -e -set -o pipefail export NB_REPLICAS=1 diff --git a/manifests/bin/prod.sh b/manifests/bin/prod.sh index b7b5f83..c97fc9e 100755 --- a/manifests/bin/prod.sh +++ b/manifests/bin/prod.sh @@ -1,5 +1,4 @@ #!/bin/bash -e -set -o pipefail export NB_REPLICAS=3 diff --git a/manifests/common/app.yaml b/manifests/common/app.yaml index c0d1fc2..190b834 100644 --- a/manifests/common/app.yaml +++ b/manifests/common/app.yaml @@ -6,6 +6,7 @@ metadata: annotations: cert-manager.io/cluster-issuer: letsencrypt-prod spec: + ingressClassName: nginx tls: - secretName: tls-app hosts: diff --git a/src/main.go b/src/main.go index bb5fca5..823c600 100644 --- a/src/main.go +++ b/src/main.go @@ -7,7 +7,6 @@ import ( func main() { http.HandleFunc("/", route) - generateAliases() generateTmpl() if err := http.ListenAndServe(":3000", nil); err != nil { log.Fatal(err) diff --git a/src/route.go b/src/route.go index 19ce2c3..43b8231 100644 --- a/src/route.go +++ b/src/route.go @@ -16,7 +16,6 @@ var routes = []struct { handler http.HandlerFunc }{ {[]string{"GET"}, url(""), index}, - {[]string{"GET"}, url("/(pgp.asc|ssh)"), static}, {[]string{"GET"}, url("/static/.+"), static}, {[]string{"GET"}, url("/(.+\\.css)"), css}, {[]string{"GET"}, url("/([^/]+)"), html}, @@ -43,8 +42,8 @@ func route(w http.ResponseWriter, r *http.Request) { } fmt.Println(r.Method, r.URL.Path) rt.handler(w, r.WithContext( - context.WithValue(r.Context(), URLParam{}, matches[1:]), - )) + context.WithValue(r.Context(), URLParam{}, matches[1:])), + ) return } } diff --git a/src/tmpl.go b/src/tmpl.go new file mode 100644 index 0000000..8f7932d --- /dev/null +++ b/src/tmpl.go @@ -0,0 +1,31 @@ +package main + +import ( + "bytes" + "html/template" + "path/filepath" + "regexp" +) + +var TMPL map[string][]byte + +func generateTmpl() { + files, _ := filepath.Glob("html/*.html") + re := regexp.MustCompile("html/(.+).html") + names := make([]string, len(files)) + + for i, f := range files { + names[i] = re.FindStringSubmatch(f)[1] + } + TMPL = make(map[string][]byte, len(files)) + for i, f := range files { + b := new(bytes.Buffer) + t, _ := template.ParseFiles(f) + t.ParseGlob("tmpl/*.tmpl") + t.Execute(b, map[string]any{ + "name": names[i], + "names": names, + }) + TMPL[names[i]] = b.Bytes() + } +} diff --git a/src/util.go b/src/util.go deleted file mode 100644 index 9ba07b9..0000000 --- a/src/util.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "bytes" - "html/template" - "log" - "os" - "path/filepath" - "regexp" - "strings" -) - -var ALIASES map[string]string -func generateAliases() { - f, err := os.ReadFile("aliases.txt") - if err != nil { - log.Fatal(err) - } - - ALIASES = make(map[string]string) - for l := range strings.SplitSeq(string(f), "\n") { - sp := strings.Fields(l) - - if len(sp) == 2 { - ALIASES[sp[0]] = sp[1] - } - } -} - -var TMPL map[string][]byte -func generateTmpl() { - files, _ := filepath.Glob("html/*.html") - re := regexp.MustCompile("html/(.+).html") - pages := make([]string, len(files)) - - for i, f := range files { - pages[i] = re.FindStringSubmatch(f)[1] - } - TMPL = make(map[string][]byte, len(files)) - for i, f := range files { - b := new(bytes.Buffer) - t, _ := template.ParseFiles(f) - t.ParseGlob("tmpl/*.tmpl") - t.Execute(b, map[string]any{ - "page": pages[i], - "pages": pages, - }) - TMPL[pages[i]] = b.Bytes() - } -} diff --git a/src/views.go b/src/views.go index cf8d4b5..94f7f1a 100644 --- a/src/views.go +++ b/src/views.go @@ -1,8 +1,9 @@ package main import ( - "net/http" "path/filepath" + "net/http" + "fmt" ) func index(w http.ResponseWriter, r *http.Request) { @@ -14,13 +15,12 @@ func static(w http.ResponseWriter, r *http.Request) { } func css(w http.ResponseWriter, r *http.Request) { + fmt.Println(filepath.Join("css", getParam(r, 0))) http.ServeFile(w, r, filepath.Join("css", getParam(r, 0))) } func html(w http.ResponseWriter, r *http.Request) { - if a, found := ALIASES[getParam(r, 0)]; found { - http.Redirect(w, r, a, http.StatusFound) - } else if t, found := TMPL[getParam(r, 0)]; found { + if t, found := TMPL[getParam(r, 0)]; found { w.Write(t) } else { http.NotFound(w, r) diff --git a/static/copy.js b/static/copy.js new file mode 100644 index 0000000..f323f72 --- /dev/null +++ b/static/copy.js @@ -0,0 +1,13 @@ +function copyElem(id, r='') { + navigator.clipboard.writeText( + document.getElementById(id).innerText.replaceAll(r, ''), + ); +} + +function copyFile(id) { + fetch(document.getElementById(id).childNodes[0].href).then(f => { + f.text().then(t => { + navigator.clipboard.writeText(t); + }) + }) +} diff --git a/pgp.asc b/static/pgp.asc similarity index 100% rename from pgp.asc rename to static/pgp.asc diff --git a/ssh b/static/ssh similarity index 67% rename from ssh rename to static/ssh index 70e736f..c78f7dd 100644 --- a/ssh +++ b/static/ssh @@ -1 +1 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDUccdlgUHzV+AhWDyjwcG4QwSNbybIV8MF7c6XpKQl4 ange@yw5n.com +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDUccdlgUHzV+AhWDyjwcG4QwSNbybIV8MF7c6XpKQl4 diff --git a/tmpl/head.tmpl b/tmpl/head.tmpl index c8cb210..37f8360 100644 --- a/tmpl/head.tmpl +++ b/tmpl/head.tmpl @@ -1,3 +1,3 @@ -Ange DUHAYON - {{.page}} +Ange DUHAYON diff --git a/tmpl/header.tmpl b/tmpl/header.tmpl index e39ba9f..90fcadf 100644 --- a/tmpl/header.tmpl +++ b/tmpl/header.tmpl @@ -1,14 +1,14 @@
diff --git a/tmpl/vars.tmpl b/tmpl/vars.tmpl deleted file mode 100644 index d0067d2..0000000 --- a/tmpl/vars.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -{{define "discord"}} -@elrilio -{{end}} - -{{define "phone"}} -+33 5 82 95 16 23 -{{end}} - -{{define "email"}} -ange@yw5n.com -{{end}} - -{{define "wa"}} -+62 853-3355-9453 -{{end}} - -{{define "in"}} -angedhn -{{end}} - -{{define "pgp"}} -pgp.asc -{{end}} - -{{define "ssh"}} -ssh -{{end}}