diff --git a/.gitea/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml similarity index 50% rename from .gitea/workflows/deploy.yaml rename to .forgejo/workflows/deploy.yaml index 380f6be..25d7503 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -8,24 +8,24 @@ jobs: - name: setup env run: | . ./.env || true - if [ "${{ gitea.ref_name }}" == prod ] && [ -n "$PROD_URL" ]; then + if [ "${{ forgejo.ref_name }}" = prod ] && [ -n "$PROD_URL" ]; then BASE_URL="$PROD_URL" else - BASE_URL="${{ gitea.ref_name }}.$(tr / '\n' <<< "${{ gitea.repository }}" | tac | tr '\n' .)k8s.gmoker.com" + BASE_URL="${{ forgejo.ref_name }}.$(tr / '\n' <<< "${{ forgejo.repository }}" | tac | tr '\n' .)k3s.gmoker.com" fi - REGISTRY="$(sed 's .*:// ' <<< ${{ gitea.server_url }})" + REGISTRY="$(sed 's .*:// ' <<< ${{ forgejo.server_url }})" cat <> .env BASE_URL="$BASE_URL" REGISTRY="$REGISTRY" - IMAGEAPP="$REGISTRY/${{ gitea.repository }}:${{ gitea.ref_name }}" + IMAGEAPP="$REGISTRY/${{ forgejo.repository }}:${{ forgejo.ref_name }}" EOF cat .env - - uses: actions/kaniko@v1 + - uses: actions/buildkit@v1 with: password: "${{ secrets.PKGRW }}" - - uses: actions/k8sdeploy@v1 + - uses: actions/k8sdeploy@v2 with: - kubeconfig: "${{ secrets.K8S }}" + kubeconfig: "${{ secrets.K3S }}" registry_password: "${{ secrets.PKGRW }}" diff --git a/Dockerfile b/Dockerfile index 22f3387..c26e23a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.23 AS build +FROM docker.io/golang:1.25 AS build WORKDIR /build/ COPY go.mod go.sum . RUN go mod download @@ -11,5 +11,7 @@ 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 new file mode 100644 index 0000000..a46e4b2 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# yw5n.com diff --git a/aliases.txt b/aliases.txt new file mode 100644 index 0000000..4bdaea1 --- /dev/null +++ b/aliases.txt @@ -0,0 +1,4 @@ +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 a987a76..4e246ed 100644 --- a/css/resume.css +++ b/css/resume.css @@ -1,11 +1,19 @@ @media print { - @page { - size: A4; - size: portrait; - margin: 5mm; - } + @page { + size: A4; + size: portrait; + margin: 5mm; + } - #menu, #credits { - display: none; - } + #credits, #menu { + display: none; + } + + #main { + margin: 0; + } + + #nav { + float: right; + } } diff --git a/css/style.css b/css/style.css index 6a1fee0..765d4f1 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 3a3a5a6..1d1c419 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module main -go 1.23.3 +go 1.25 diff --git a/html/contact.html b/html/contact.html index 0fd8f2a..337f759 100644 --- a/html/contact.html +++ b/html/contact.html @@ -2,68 +2,66 @@ {{template "head.tmpl" .}} - + {{template "header.tmpl" .}}
-
- - - - - - + - + - + - + - + - + - +
Matrix (Element)@ange:gmoker.com
Discord@elrilio{{template "discord"}}
Phone (France)+33 5 82 95 16 23{{template "phone"}}
Emailange@yw5n.com{{template "email"}}
WhatsApp+62 853-3355-9453{{template "wa"}}
LinkedInwww.linkedin.com/in/angedhn{{template "in"}}
PGPpgp.asc{{template "pgp"}}
SSHssh{{template "ssh"}}
-
+
diff --git a/html/resume.html b/html/resume.html index 53ea72f..79905d4 100644 --- a/html/resume.html +++ b/html/resume.html @@ -8,14 +8,11 @@ {{template "header.tmpl" .}}
@@ -28,19 +25,22 @@

EXPERIENCE

-

Freelance - DevOps

+

Freelance - DevOps Engineer

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

Selfhost - DevOps

+

Selfhost - DevOps Engineer

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

EPITECH CodingClub association, Toulouse - Cobra

+

EPITECH CodingClub association, Toulouse - Trainer

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

    Predicloud, Toulouse - DevOps SRE

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

    COMPETENCES

    - - - - - - + + + + + +
    LANGUAGES SOFTWARE
    C/C++ *nix
    Python Git
    Bash Vim
    Go Docker
    JS K8S
    LANGUAGESSOFTWARE
    C/C++ *nix
    Python Git
    Bash Vim
    Go Docker
    JS K8S
diff --git a/manifests/bin/deploy.sh b/manifests/bin/deploy.sh index 088dfbb..d82a9d7 100755 --- a/manifests/bin/deploy.sh +++ b/manifests/bin/deploy.sh @@ -1,34 +1,36 @@ #!/bin/bash -e set -o pipefail -function kapply() { +kapply() { for f in "$@"; do - kubectl apply -f \ - <(envsubst "$(env | xargs printf '$%s ')" < "manifests/$f") + kubectl apply --server-side \ + -f<(envsubst "$(env | sed 's/^/$/')" < "manifests/$f") done -} +}; export -f kapply -function kcreatesec() { - kubectl create secret generic --save-config --dry-run=client -oyaml "$@" | kubectl apply -f- -} +kcreatesec() { + kubectl apply --server-side \ + -f<(kubectl create secret generic --dry-run=client -oyaml "$@") +}; export -f kcreatesec -function kcreatecm() { - kubectl create configmap --dry-run=client -oyaml "$@" | kubectl apply -f- -} +kcreatecm() { + kubectl apply --server-side \ + -f<(kubectl create configmap --dry-run=client -oyaml "$@") +}; export -f kcreatecm -function kgseckey() { +kgseckey() { local sec="$1"; shift local key="$1"; shift - kubectl get secret "$sec" -o jsonpath="{.data.$key}" | base64 -d -} + kubectl get secret "$sec" -ojson | jq -re ".data.\"$key\"" | base64 -d +}; export -f kgseckey -function kgcmkey() { - local cm="$1"; shift +kgcmkey() { + local cm="$1"; shift local key="$1"; shift - kubectl get configmap "$cm" -o jsonpath="{.data.$key}" -} + kubectl get configmap "$cm" -ojson | jq -re ".data.\"$key\"" +}; export -f kgcmkey kapply common/app.yaml diff --git a/manifests/bin/devel.sh b/manifests/bin/devel.sh index 464c4d0..65675aa 100755 --- a/manifests/bin/devel.sh +++ b/manifests/bin/devel.sh @@ -1,4 +1,5 @@ #!/bin/bash -e +set -o pipefail export NB_REPLICAS=1 diff --git a/manifests/bin/prod.sh b/manifests/bin/prod.sh index c97fc9e..b7b5f83 100755 --- a/manifests/bin/prod.sh +++ b/manifests/bin/prod.sh @@ -1,4 +1,5 @@ #!/bin/bash -e +set -o pipefail export NB_REPLICAS=3 diff --git a/manifests/common/app.yaml b/manifests/common/app.yaml index 190b834..c0d1fc2 100644 --- a/manifests/common/app.yaml +++ b/manifests/common/app.yaml @@ -6,7 +6,6 @@ metadata: annotations: cert-manager.io/cluster-issuer: letsencrypt-prod spec: - ingressClassName: nginx tls: - secretName: tls-app hosts: diff --git a/static/pgp.asc b/pgp.asc similarity index 100% rename from static/pgp.asc rename to pgp.asc diff --git a/src/main.go b/src/main.go index 823c600..bb5fca5 100644 --- a/src/main.go +++ b/src/main.go @@ -7,6 +7,7 @@ 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 43b8231..19ce2c3 100644 --- a/src/route.go +++ b/src/route.go @@ -16,6 +16,7 @@ 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}, @@ -42,8 +43,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 deleted file mode 100644 index 8f7932d..0000000 --- a/src/tmpl.go +++ /dev/null @@ -1,31 +0,0 @@ -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 new file mode 100644 index 0000000..9ba07b9 --- /dev/null +++ b/src/util.go @@ -0,0 +1,50 @@ +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 94f7f1a..cf8d4b5 100644 --- a/src/views.go +++ b/src/views.go @@ -1,9 +1,8 @@ package main import ( - "path/filepath" "net/http" - "fmt" + "path/filepath" ) func index(w http.ResponseWriter, r *http.Request) { @@ -15,12 +14,13 @@ 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 t, found := TMPL[getParam(r, 0)]; found { + if a, found := ALIASES[getParam(r, 0)]; found { + http.Redirect(w, r, a, http.StatusFound) + } else if t, found := TMPL[getParam(r, 0)]; found { w.Write(t) } else { http.NotFound(w, r) diff --git a/static/ssh b/ssh similarity index 67% rename from static/ssh rename to ssh index c78f7dd..70e736f 100644 --- a/static/ssh +++ b/ssh @@ -1 +1 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDUccdlgUHzV+AhWDyjwcG4QwSNbybIV8MF7c6XpKQl4 +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDUccdlgUHzV+AhWDyjwcG4QwSNbybIV8MF7c6XpKQl4 ange@yw5n.com diff --git a/static/copy.js b/static/copy.js deleted file mode 100644 index f323f72..0000000 --- a/static/copy.js +++ /dev/null @@ -1,13 +0,0 @@ -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/tmpl/head.tmpl b/tmpl/head.tmpl index 37f8360..c8cb210 100644 --- a/tmpl/head.tmpl +++ b/tmpl/head.tmpl @@ -1,3 +1,3 @@ -Ange DUHAYON +Ange DUHAYON - {{.page}} diff --git a/tmpl/header.tmpl b/tmpl/header.tmpl index 90fcadf..e39ba9f 100644 --- a/tmpl/header.tmpl +++ b/tmpl/header.tmpl @@ -1,14 +1,14 @@
diff --git a/tmpl/vars.tmpl b/tmpl/vars.tmpl new file mode 100644 index 0000000..d0067d2 --- /dev/null +++ b/tmpl/vars.tmpl @@ -0,0 +1,27 @@ +{{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}}