Compare commits

...

2 Commits

Author SHA1 Message Date
e4f265781d added base code 2024-08-17 10:27:36 +02:00
0078e38e2f added make script and vars 2024-08-17 10:25:11 +02:00
13 changed files with 376 additions and 0 deletions

15
.vars Normal file
View File

@ -0,0 +1,15 @@
#/usr/bin/env bash
export GIT_HOST=git.bjphoster.com
export DEPLOYMENT_HOST=docker.infra.bjphoster.cloud
export DEPLOYMENT_PATHS=/opt/yaskm.bjphoster.com
export GO_BUILDER=git.bjphoster.com/docker/gobuilder
export GO_VERSION=1.22.2-alpine3.19
export GOOS=linux
export GOARCH=amd64
export REPO_ORG=source
export REPO_NAME=yaskm
export CONTAINER_ORG=git.bjphoster.com/source
export CONTAINER_IMAGE=yaskm
export CONTAINER_IP=127.0.0.1
export CONTAINER_PORT=3000

4
config.yml Normal file
View File

@ -0,0 +1,4 @@
---
listen:
address: 0.0.0.0
port: 80

59
deploy.sh Executable file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env bash
###
# FLOW
###
#
# convert deployment paths (string) into array of strings
# if path is not already set
# if number of paths > 1 print the strings with corresponding index
# get deployment path index from user
# in every case (number of paths = 1 OR index left blank from user), index is 0
# if version is not already set
# get version from user
# if version is left balnk, version is "latest"
# get deployment path from index X of deployments
# ssh into deployment host
# cd into deployment path
# git pull last changes
# set correct version in .env file
# pull latest docker image and spin up containers
#
# Convert deployment paths into array
ENVIRONMENTS=($DEPLOYMENT_PATHS)
# Check if the DEPLOYMENT_PATH is not already set
if [ -z "${DEPLOYMENT_PATH}" ]; then
# Print and ask for deployment environment (if more than one)
if [ "${#ENVIRONMENTS[@]}" -gt 1 ]; then
for i in "${!ENVIRONMENTS[@]}"; do
echo "$i: ${ENVIRONMENTS[$i]}"
done
read -p "Deployment environment: " DEPLOYMENT_ENVIRONMENT
fi
if [ -z "${DEPLOYMENT_ENVIRONMENT}" ]; then
DEPLOYMENT_ENVIRONMENT=0
fi
# Select correct path
DEPLOYMENT_PATH="${ENVIRONMENTS[$DEPLOYMENT_ENVIRONMENT]}"
fi
# Check if the DEPLOYMENT_VERSION is not already set
if [ -z "${DEPLOYMENT_VERSION}" ]; then
# Ask for deployment version
read -p "Version [latest]: " DEPLOYMENT_VERSION
if [ -z "${DEPLOYMENT_VERSION}" ]; then
DEPLOYMENT_VERSION=latest
fi
fi
echo "${DEPLOYMENT_PATH}"
echo "${DEPLOYMENT_VERSION}"
ssh $DEPLOYMENT_HOST \
"cd ${DEPLOYMENT_PATH} && \
git pull && \
sed -i "s/VERSION=.*/VERSION=${DEPLOYMENT_VERSION}/" .env && \
docker compose pull && \
docker compose up -d"

33
dockerfile Normal file
View File

@ -0,0 +1,33 @@
# Stage 1 · go builder
ARG GO_BUILDER=golang
ARG GO_VERSION=latest
FROM ${GO_BUILDER}:${GO_VERSION} AS build
ARG GO_OS
ARG GO_ARCH
ARG GIT_HOST
ARG REPO_ORG
ARG REPO_NAME
ARG APP_VERSION
# Copy the project inside the builder container
WORKDIR $GOPATH/src/${GIT_HOST}/$REPO_ORG/$REPO_NAME/
COPY . .
# Build the binary
RUN CGO_ENABLED=0 GOOS=${GO_OS} GOARCH=${GO_ARCH} \
go build \
-installsuffix cgo \
-ldflags="-w -s -X 'main.APP_VERSION=${APP_VERSION}' -X 'main.COMMIT_ID=$(git log HEAD --oneline | awk '{print $1}' | head -n1)'" \
--o /app
# Stage 2 · scratch image
FROM scratch
# Copy the necessary stuff from the build stage
COPY --from=build /app /app
# Copy the certificates - in case of fetches
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/cert.pem
# Execute the binary
ENTRYPOINT ["/app"]

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module git.bjphoster.com/source/yaskm
go 1.22.2
require (
github.com/gorilla/mux v1.8.1
gopkg.in/yaml.v2 v2.4.0
)

6
go.sum Normal file
View File

@ -0,0 +1,6 @@
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

43
main.go Normal file
View File

@ -0,0 +1,43 @@
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
var APP_VERSION string = "latest"
var COMMIT_ID string = "undefined"
var ws *WebServer
func main() {
// Create a channel to receive the OS signals
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM)
// Initialize the WebService structure
ws = new(WebServer)
ws.Initialize()
// Start the WebService
go ws.Start()
// Wait for a signal
<-sc
fmt.Println("Shutting down...")
// Create a context with a timeout for graceful shutdown
shCtx, shCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shCancel()
// Shutdown the HTTP server
err := ws.HTTPServer.Shutdown(shCtx)
if err != nil {
fmt.Printf("Server shutdown error: %s", err)
os.Exit(1)
}
}

54
makefile Normal file
View File

@ -0,0 +1,54 @@
#!make
include .vars
default: version
clean:
if [ "$$(docker images "$${CONTAINER_ORG}/$${CONTAINER_IMAGE}" --format "{{.Repository}}:{{.Tag}}")" != "" ]; then \
docker image rm $$(docker images "$${CONTAINER_ORG}/$${CONTAINER_IMAGE}" --all --format "{{.Repository}}:{{.Tag}}"); \
fi
docker: clean
docker build \
--build-arg GO_BUILDER=$${GO_BUILDER} \
--build-arg GO_VERSION=$${GO_VERSION} \
--build-arg GO_OS=$${GO_OS} \
--build-arg GO_ARCH=$${GO_ARCH} \
--build-arg GIT_HOST=$${GIT_HOST} \
--build-arg REPO_ORG=$${REPO_ORG} \
--build-arg REPO_NAME=$${REPO_NAME} \
--build-arg APP_VERSION=$${APP_VERSION} \
-t $${CONTAINER_ORG}/$${CONTAINER_IMAGE}:$${APP_VERSION} .; \
if [ "$$(docker images --filter "dangling=true" --quiet --no-trunc)" != "" ]; then \
docker image rm $$(docker images --filter "dangling=true" --quiet --no-trunc); \
fi
dockerpush:
docker push \
$${CONTAINER_ORG}/$${CONTAINER_IMAGE}:$${APP_VERSION}
deploy:
bash -c "./deploy.sh"
version:
bash -c "./version.sh"
run:
docker run \
--rm \
--tty \
--interactive \
--publish $${CONTAINER_IP}:$${CONTAINER_PORT}:80 \
--workdir /go/src/$${GIT_HOST}/$${REPO_ORG}/$${REPO_NAME} \
--volume $(shell pwd):/go/src/$${GIT_HOST}/$${REPO_ORG}/$${REPO_NAME} \
$${GO_BUILDER}:$${GO_VERSION} \
go run .
dockerrun:
docker run \
--rm \
--tty \
--interactive \
--publish $${CONTAINER_IP}:$${CONTAINER_PORT}:80 \
--volume $(shell pwd)/config.yml:/config.yml \
$${CONTAINER_ORG}/$${CONTAINER_IMAGE}:latest

7
routes.go Normal file
View File

@ -0,0 +1,7 @@
package main
import "github.com/gorilla/mux"
func (s *WebServer) Routes(r *mux.Router) {
r.HandleFunc("/version", handleVersion).Methods("GET")
}

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>{{.Name}}</title>
</head>
<body>
<p>
Version: {{.Version}}<br />
Commit ID: {{.CommitId}}
</p>
</body>
</html>

67
type_webserver.go Normal file
View File

@ -0,0 +1,67 @@
package main
import (
"fmt"
"net/http"
"os"
"github.com/gorilla/mux"
"gopkg.in/yaml.v2"
)
type WebServer struct {
HTTPServer *http.Server
Listen WSListen `yaml:"listen"`
}
type WSListen struct {
Address string `yaml:"address"`
Port string `yaml:"port"`
}
func (s *WebServer) Initialize() {
// Initialize default values
s.Listen = WSListen{
Address: "0.0.0.0",
Port: "80",
}
// Attempt to read the config file
configFile, err := os.ReadFile("config.yml")
if err != nil {
if os.IsNotExist(err) {
// File does not exist, log and use default config
fmt.Println("Config file not found, using default settings.")
} else {
// Some other error occurred when trying to read the file, exit
fmt.Println("Error reading config file:", err)
os.Exit(1)
}
} else {
// If the file exists, unmarshal it into the ServiceSettings struct
err = yaml.Unmarshal(configFile, &s)
if err != nil {
fmt.Println("Error parsing config file:", err)
os.Exit(1)
}
}
}
func (s *WebServer) Start() error {
// Create a new MUX router and an HTTP server
r := mux.NewRouter()
s.HTTPServer = &http.Server{
Addr: s.Listen.Address + ":" + s.Listen.Port,
Handler: r,
}
// Associate the various handlers (routes)
s.Routes(r)
// Start the server
fmt.Println("Listening on", s.Listen.Address+":"+s.Listen.Port)
err := s.HTTPServer.ListenAndServe()
// Return error, or nil
return err
}

26
version.go Normal file
View File

@ -0,0 +1,26 @@
package main
import (
_ "embed"
"html/template"
"net/http"
)
//go:embed templates/html/version.html
var versionTemplate string
func handleVersion(w http.ResponseWriter, r *http.Request) {
type SiteInfo struct {
CommitId string
Name string
Version string
}
tmpl, _ := template.New("version.html").Parse(versionTemplate)
// Return (write) the version to the response body
tmpl.Execute(w, SiteInfo{
CommitId: COMMIT_ID,
Name: "YASKM",
Version: APP_VERSION,
})
}

42
version.sh Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env bash
###
# FLOW
###
#
# get version from user
# if version is left balnk, version is "latest"
# get docker push from user
# if docker push is left blank, it's negative
# if version != "latest" create version tag at current commit
# make the app
# if docker push, push docker image
#
# Get version from user
read -p "Version [latest]: " VERSIONINPUT
# If version was not provided, use the latest commit short hash as version
if [ -z ${VERSIONINPUT} ]; then
APP_VERSION="latest"
else
APP_VERSION=${VERSIONINPUT}
fi
# Get docker push option from user
read -p "Docker push? [n]: " DOCKERPUSH
if [ -z ${DOCKERPUSH} ]; then
DOCKERPUSH=n
fi
# Create version tag (if provided)
if [ ! -z ${VERSIONINPUT} ]; then
git tag ${APP_VERSION}
fi
# Build the app
export APP_VERSION
make docker
# If wanted, push the docker image
if [ ${DOCKERPUSH} = "y" ]; then
make dockerpush
fi