diff --git a/.gitignore b/.gitignore index f304278..9532c1b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ api/.idea/ api/internal/ .idea/ + +helm/*/charts \ No newline at end of file diff --git a/api/migrations/0_init.sql b/api/migrations/0_init.sql index bb816f5..c66b6b6 100644 --- a/api/migrations/0_init.sql +++ b/api/migrations/0_init.sql @@ -1,5 +1,5 @@ CREATE TABLE IF NOT EXISTS db_state ( - migrations int + migrations int NOT NULL primary key ); CREATE TABLE IF NOT EXISTS games ( diff --git a/frontend/indiestream/src/app/app.config.ts b/frontend/indiestream/src/app/app.config.ts index 9e293ec..71d5611 100644 --- a/frontend/indiestream/src/app/app.config.ts +++ b/frontend/indiestream/src/app/app.config.ts @@ -1,11 +1,27 @@ -import {ApplicationConfig, importProvidersFrom} from '@angular/core'; +import {APP_INITIALIZER, ApplicationConfig, importProvidersFrom} from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { provideHttpClient } from "@angular/common/http"; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import {provideAnimations} from "@angular/platform-browser/animations"; +import { AppConfigService } from './services/app-config.service'; + +export function initConfig(appConfig: AppConfigService) { + return () => appConfig.loadConfig(); +} export const appConfig: ApplicationConfig = { - providers: [provideRouter(routes), provideHttpClient(), provideAnimationsAsync(), provideAnimations()] + providers: [ + provideRouter(routes), + provideHttpClient(), + provideAnimationsAsync(), + provideAnimations(), + { + provide: APP_INITIALIZER, + useFactory: initConfig, + deps: [AppConfigService], + multi: true + } + ] }; diff --git a/frontend/indiestream/src/app/environment.ts b/frontend/indiestream/src/app/environment.ts deleted file mode 100644 index 126cf4c..0000000 --- a/frontend/indiestream/src/app/environment.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const environment = { - production: false, - apiUrl: 'http://localhost:8080', -}; diff --git a/frontend/indiestream/src/app/services/app-config.service.ts b/frontend/indiestream/src/app/services/app-config.service.ts new file mode 100644 index 0000000..5bf5270 --- /dev/null +++ b/frontend/indiestream/src/app/services/app-config.service.ts @@ -0,0 +1,36 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { firstValueFrom, lastValueFrom } from 'rxjs'; + +export interface AppConfig { + production: boolean; + apiUrl: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class AppConfigService { + private config: AppConfig = { + production: false, + apiUrl: "http://localhost:8080" + }; + + constructor(private http: HttpClient) {} + + loadConfig(): Promise { + return firstValueFrom( + this.http.get('/assets/app.config.json') + ).then( data => { + console.log("Config file loaded successfully", data) + this.config = data; + }).catch( err => { + console.error(err); + console.log("Defaulting to development config", this.config) + }); + } + + getConfig(): AppConfig { + return this.config; + } +} diff --git a/frontend/indiestream/src/app/services/games.service.ts b/frontend/indiestream/src/app/services/games.service.ts index ef3f400..447e222 100644 --- a/frontend/indiestream/src/app/services/games.service.ts +++ b/frontend/indiestream/src/app/services/games.service.ts @@ -2,14 +2,16 @@ import { Injectable } from "@angular/core"; import {HttpClient, HttpEvent} from '@angular/common/http'; import { Games, Game } from '../modules/games'; import { Observable } from "rxjs"; -import { environment } from "../environment"; +import { AppConfigService } from "./app-config.service"; @Injectable({ providedIn: 'root' }) export class GamesService { - private apiUrl = environment.apiUrl - constructor(private http: HttpClient) { } + private apiUrl = this.configService.getConfig().apiUrl; + constructor(private http: HttpClient, private configService: AppConfigService) { + console.log(this.configService.getConfig()) + } getGames(): Observable { return this.http.get(this.apiUrl + "/games/"); diff --git a/helm/api/.helmignore b/helm/api/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm/api/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/api/Chart.yaml b/helm/api/Chart.yaml new file mode 100644 index 0000000..cc238c0 --- /dev/null +++ b/helm/api/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: api +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/helm/control-server/.gitkeep b/helm/api/templates/NOTES.txt similarity index 100% rename from helm/control-server/.gitkeep rename to helm/api/templates/NOTES.txt diff --git a/helm/api/templates/api-deployment.yaml b/helm/api/templates/api-deployment.yaml new file mode 100644 index 0000000..2e12126 --- /dev/null +++ b/helm/api/templates/api-deployment.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.appName }} + namespace: {{ .Values.appName }} + labels: + app: {{ .Values.appName }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: {{ .Values.appName }} + template: + metadata: + labels: + app: {{ .Values.appName }} + spec: + containers: + - name: {{ .Values.appName }} + image: {{ .Values.image.name }}:{{ .Values.image.label }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - containerPort: {{ .Values.port }} + env: + - name: PORT + value: {{ .Values.port | quote }} + - name: GIN_MODE + value: {{ .Values.env.ginMode | quote }} + - name: MYSQL_DATABASE + value: {{ .Values.env.mysqlDatabase | quote }} + - name: MYSQL_ROOT_USER + value: {{ .Values.env.mysqlRootUser | quote }} + - name: MYSQL_ROOT_PASSWORD + value: {{ .Values.env.mysqlRootPassword | quote }} + - name: MYSQL_HOST + value: {{ .Values.env.mysqlHost | quote }} + - name: MYSQL_PORT + value: {{ .Values.env.mysqlPort | quote }} \ No newline at end of file diff --git a/helm/api/templates/api-namespace.yaml b/helm/api/templates/api-namespace.yaml new file mode 100644 index 0000000..b073657 --- /dev/null +++ b/helm/api/templates/api-namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.appName }} + labels: + name: {{ .Values.appName }} diff --git a/helm/api/templates/api-service.yaml b/helm/api/templates/api-service.yaml new file mode 100644 index 0000000..cfd960d --- /dev/null +++ b/helm/api/templates/api-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.appName }} + namespace: {{ .Values.appName }} + labels: + app: {{ .Values.appName }} +spec: + type: LoadBalancer + selector: + app: {{ .Values.appName }} + ports: + - protocol: TCP + port: {{ .Values.port }} + targetPort: {{ .Values.port }} \ No newline at end of file diff --git a/helm/api/values-dev.yaml b/helm/api/values-dev.yaml new file mode 100644 index 0000000..955540b --- /dev/null +++ b/helm/api/values-dev.yaml @@ -0,0 +1,8 @@ +image: + name: indiegamestream/api + label: localenv + pullPolicy: Never + +env: + ginMode: debug + mysqlRootPassword: root \ No newline at end of file diff --git a/helm/api/values.yaml b/helm/api/values.yaml new file mode 100644 index 0000000..fe4a44a --- /dev/null +++ b/helm/api/values.yaml @@ -0,0 +1,15 @@ +appName: api +replicas: 1 +port: 8080 + +image: + name: ghcr.io/austriandatalab/indiegamestream/api + label: v1.0.0 # Change to proper version tag + pullPolicy: IfNotPresent + +env: + ginMode: release + mysqlDatabase: api + mysqlRootUser: root + mysqlHost: mysql.mysql.svc.cluster.local + mysqlPort: 3306 \ No newline at end of file diff --git a/helm/frontend/.helmignore b/helm/frontend/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm/frontend/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/frontend/Chart.yaml b/helm/frontend/Chart.yaml new file mode 100644 index 0000000..147b26c --- /dev/null +++ b/helm/frontend/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: frontend +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/helm/pacman/.gitkeep b/helm/frontend/templates/NOTES.txt similarity index 100% rename from helm/pacman/.gitkeep rename to helm/frontend/templates/NOTES.txt diff --git a/helm/frontend/templates/frontend-configmap.yaml b/helm/frontend/templates/frontend-configmap.yaml new file mode 100644 index 0000000..56f95b4 --- /dev/null +++ b/helm/frontend/templates/frontend-configmap.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.appName }}-config + namespace: {{ .Values.appName }} +data: + app.config.json: |- +{{ toJson .Values.appConfig | indent 4 }} \ No newline at end of file diff --git a/helm/frontend/templates/frontend-deployment.yaml b/helm/frontend/templates/frontend-deployment.yaml new file mode 100644 index 0000000..d008ee4 --- /dev/null +++ b/helm/frontend/templates/frontend-deployment.yaml @@ -0,0 +1,34 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.appName }} + namespace: {{ .Values.appName }} + labels: + app: {{ .Values.appName }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: {{ .Values.appName }} + template: + metadata: + labels: + app: {{ .Values.appName }} + spec: + containers: + - name: {{ .Values.appName }} + image: {{ .Values.image.name }}:{{ .Values.image.label }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - containerPort: {{ .Values.port }} + volumeMounts: + - name: "{{ .Values.appName }}-config-volume" + mountPath: "{{ .Values.webRootDirectory }}/assets" + readOnly: true + volumes: + - name: "{{ .Values.appName }}-config-volume" + configMap: + name: "{{ .Values.appName }}-config" + items: + - key: app.config.json + path: app.config.json \ No newline at end of file diff --git a/helm/frontend/templates/frontend-namespace.yaml b/helm/frontend/templates/frontend-namespace.yaml new file mode 100644 index 0000000..b073657 --- /dev/null +++ b/helm/frontend/templates/frontend-namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.appName }} + labels: + name: {{ .Values.appName }} diff --git a/helm/frontend/templates/frontend-service.yaml b/helm/frontend/templates/frontend-service.yaml new file mode 100644 index 0000000..cfd960d --- /dev/null +++ b/helm/frontend/templates/frontend-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.appName }} + namespace: {{ .Values.appName }} + labels: + app: {{ .Values.appName }} +spec: + type: LoadBalancer + selector: + app: {{ .Values.appName }} + ports: + - protocol: TCP + port: {{ .Values.port }} + targetPort: {{ .Values.port }} \ No newline at end of file diff --git a/helm/frontend/values-dev.yaml b/helm/frontend/values-dev.yaml new file mode 100644 index 0000000..0965df8 --- /dev/null +++ b/helm/frontend/values-dev.yaml @@ -0,0 +1,7 @@ +image: + name: indiegamestream/frontend + label: localenv + pullPolicy: Never + +appConfig: + production: false \ No newline at end of file diff --git a/helm/frontend/values.yaml b/helm/frontend/values.yaml new file mode 100644 index 0000000..a6bc86a --- /dev/null +++ b/helm/frontend/values.yaml @@ -0,0 +1,13 @@ +appName: frontend +replicas: 1 +port: 80 + +image: + name: ghcr.io/austriandatalab/indiegamestream/frontend + label: v1.0.0 # Change to proper version tag + pullPolicy: IfNotPresent + +webRootDirectory: /usr/share/nginx/html + +appConfig: + production: true \ No newline at end of file diff --git a/helm/mysql/values-dev.yaml b/helm/mysql/values-dev.yaml new file mode 100644 index 0000000..acd25b2 --- /dev/null +++ b/helm/mysql/values-dev.yaml @@ -0,0 +1,8 @@ +credentials: + root: + password: root + +serverInstances: 1 + +tls: + useSelfSigned: true \ No newline at end of file diff --git a/helm/stunner/.gitkeep b/helm/mysql/values.yaml similarity index 100% rename from helm/stunner/.gitkeep rename to helm/mysql/values.yaml diff --git a/helm/stunner/.helmignore b/helm/stunner/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm/stunner/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/stunner/Chart.lock b/helm/stunner/Chart.lock new file mode 100644 index 0000000..1299847 --- /dev/null +++ b/helm/stunner/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: stunner-gateway-operator + repository: https://l7mp.io/stunner + version: 0.19.0 +digest: sha256:cf52ea4f76441055d528344c69288940ae54166fcf6d0e22143c8820e693b5a3 +generated: "2024-06-02T15:46:17.23111941+02:00" diff --git a/helm/stunner/Chart.yaml b/helm/stunner/Chart.yaml new file mode 100644 index 0000000..da026e0 --- /dev/null +++ b/helm/stunner/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: stunner +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" + +dependencies: +- name: stunner-gateway-operator + version: 0.19.0 + repository: "https://l7mp.io/stunner" \ No newline at end of file diff --git a/helm/stunner/templates/gateway_config.yml b/helm/stunner/templates/gateway_config.yml new file mode 100644 index 0000000..7233f6c --- /dev/null +++ b/helm/stunner/templates/gateway_config.yml @@ -0,0 +1,38 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: stunner-gatewayclass +spec: + controllerName: "stunner.l7mp.io/gateway-operator" + parametersRef: + group: "stunner.l7mp.io" + kind: GatewayConfig + name: stunner-gatewayconfig + namespace: stunner + description: "STUNner is a WebRTC ingress gateway for Kubernetes" +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: udp-gateway + namespace: stunner +spec: + gatewayClassName: stunner-gatewayclass + listeners: + - name: udp-listener + port: 3478 + allowedRoutes: + namespaces: + from: All + protocol: UDP +--- +apiVersion: stunner.l7mp.io/v1 +kind: GatewayConfig +metadata: + name: stunner-gatewayconfig + namespace: stunner +spec: + realm: stunner.l7mp.io + authType: static + userName: "user-1" + password: "pass-1" \ No newline at end of file diff --git a/scripts/control-server/.gitkeep b/helm/stunner/values.yaml similarity index 100% rename from scripts/control-server/.gitkeep rename to helm/stunner/values.yaml diff --git a/scripts/localenv/Makefile b/scripts/localenv/Makefile new file mode 100644 index 0000000..8f02a11 --- /dev/null +++ b/scripts/localenv/Makefile @@ -0,0 +1,194 @@ +define HEADER + ___ _ _ ____ ____ _ +|_ _|_ __ __| (_) ___ / ___| __ _ _ __ ___ ___/ ___|| |_ _ __ ___ __ _ _ __ ___ + | || '_ \ / _` | |/ _ \ | _ / _` | '_ ` _ \ / _ \___ \| __| '__/ _ \/ _` | '_ ` _ \ + | || | | | (_| | | __/ |_| | (_| | | | | | | __/___) | |_| | | __/ (_| | | | | | | +|___|_| |_|\__,_|_|\___|\____|\__,_|_| |_| |_|\___|____/ \__|_| \___|\__,_|_| |_| |_| +endef + +ROOT_DIRECTORY = ../.. +CLUSTER_NAME = indiegamestream +IMAGE_NAMESPACE = indiegamestream +IMAGE_LABEL = localenv + +FRONTEND_NAME=frontend +FRONTEND_IMAGE=$(IMAGE_NAMESPACE)/$(FRONTEND_NAME):$(IMAGE_LABEL) +FRONTEND_DIRECTORY=frontend +FRONTEND_DOCKERFILE=frontend/Dockerfile + +API_NAME=api +API_IMAGE=$(IMAGE_NAMESPACE)/$(API_NAME):$(IMAGE_LABEL) +API_DIRECTORY=api +API_DOCKERFILE=api/Dockerfile + +OPERATOR_NAME=operator +OPERATOR_IMAGE=$(IMAGE_NAMESPACE)/$(OPERATOR_NAME):$(IMAGE_LABEL) +OPERATOR_DIRECTORY=operator +OPERATOR_DOCKERFILE=operator/Dockerfile + +MYSQL_NAME=mysql +STUNNER_NAME=stunner + +HELM_DIRECTORY=helm +HELM_FRONTEND=frontend +HELM_API=api +HELM_OPERATOR=operator +HELM_MYSQL=mysql +HELM_STUNNER=stunner + +.PHONY: * + +# Creates a single-node cluster and installs all components on it +all: build_images create_cluster load_images add_metallb install help + +# Creates a cluster with three nodes and installs all components on it +multi_node: build_images create_multinode_cluster load_images add_metallb install help + +# Removes the cluster and all local images +destroy: teardown_cluster delete_images + +# Builds images +build_images: build_frontend build_api build_operator + +# Loads images into the cluster +load_images: load_frontend load_api load_operator + +# Deletes built images locally +delete_images: delete_frontend delete_api delete_operator + +# Creates all our components +install: install_mysql install_stunner install_operator install_api install_frontend + +# Cleans up the cluster, removing all components +uninstall: uninstall_frontend uninstall_api uninstall_mysql uninstall_stunner uninstall_operator + +create_cluster: + kind create cluster --name $(CLUSTER_NAME) + +create_multinode_cluster: + kind create cluster --name $(CLUSTER_NAME) --config kind-multinode-config.yaml + +add_metallb: + ./add_metallb.sh + +teardown_cluster: + kind delete cluster --name $(CLUSTER_NAME) + +build_frontend: + docker build $(ROOT_DIRECTORY)/$(FRONTEND_DIRECTORY) -t $(FRONTEND_IMAGE) -f $(ROOT_DIRECTORY)/$(FRONTEND_DOCKERFILE) + +build_api: + docker build $(ROOT_DIRECTORY)/$(API_DIRECTORY) -t $(API_IMAGE) -f $(ROOT_DIRECTORY)/$(API_DOCKERFILE) + +build_operator: + docker build $(ROOT_DIRECTORY)/$(OPERATOR_DIRECTORY) -t $(OPERATOR_IMAGE) -f $(ROOT_DIRECTORY)/$(OPERATOR_DOCKERFILE) + +load_frontend: + kind load docker-image $(FRONTEND_IMAGE) --name $(CLUSTER_NAME) + +load_api: + kind load docker-image $(API_IMAGE) --name $(CLUSTER_NAME) + +load_operator: + kind load docker-image $(OPERATOR_IMAGE) --name $(CLUSTER_NAME) + +install_frontend: + helm install -f $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_FRONTEND)/values.yaml \ + -f $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_FRONTEND)/values-dev.yaml \ + --set-string appConfig.apiUrl=http://$$(kubectl get svc api -n api -o jsonpath='{.status.loadBalancer.ingress[0].ip}'):$$(kubectl get svc api -n api -o jsonpath='{.spec.ports[0].port}') \ + $(FRONTEND_NAME) $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_FRONTEND) + +install_mysql: + helm repo add mysql-operator https://mysql.github.io/mysql-operator/ + helm repo update + helm install $(MYSQL_NAME)-operator mysql-operator/mysql-operator --version "2.1.3" --wait \ + --create-namespace --namespace=$(MYSQL_NAME)-operator + helm install $(MYSQL_NAME) mysql-operator/mysql-innodbcluster --version "2.1.3" --wait \ + --create-namespace --namespace=$(MYSQL_NAME) \ + -f $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_MYSQL)/values.yaml \ + -f $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_MYSQL)/values-dev.yaml + +install_api: wait_for_mysql + helm install -f $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_API)/values.yaml \ + -f $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_API)/values-dev.yaml \ + $(API_NAME) $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_API) + +install_operator: + $(MAKE) -C $(ROOT_DIRECTORY)/$(OPERATOR_DIRECTORY) deploy IMG=$(OPERATOR_IMAGE) + +install_stunner: + helm repo add stunner https://l7mp.io/stunner + helm repo update + helm dependency build $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_STUNNER) --skip-refresh + helm install $(STUNNER_NAME) $(ROOT_DIRECTORY)/$(HELM_DIRECTORY)/$(HELM_STUNNER) \ + --create-namespace --namespace=$(STUNNER_NAME) + +uninstall_frontend: + helm uninstall $(FRONTEND_NAME) --wait + +uninstall_api: + helm uninstall $(API_NAME) --wait + +uninstall_operator: + $(MAKE) -C $(ROOT_DIRECTORY)/$(OPERATOR_DIRECTORY) undeploy + +uninstall_mysql: + helm uninstall $(MYSQL_NAME) -n $(MYSQL_NAME) --wait + helm uninstall $(MYSQL_NAME)-operator -n $(MYSQL_NAME)-operator --wait + +uninstall_stunner: + helm uninstall $(STUNNER_NAME) --namespace=$(STUNNER_NAME) + +delete_frontend: + - docker rmi $(FRONTEND_IMAGE) + +delete_api: + - docker rmi $(API_IMAGE) + +delete_operator: + - docker rmi $(OPERATOR_IMAGE) + +redeploy_frontend: uninstall_frontend build_frontend load_frontend install_frontend + +redeploy_api: uninstall_api build_api load_api install_api redeploy_frontend + +redeploy_operator: uninstall_operator build_operator load_operator install_operator + +# waiting for MySQL pod to be created and then wait until router is ready +wait_for_mysql: + @while true; do \ + POD_STATUS=$$(kubectl get pod $(MYSQL_NAME)-0 -n $(MYSQL_NAME) --no-headers -o custom-columns=":status.phase" 2>/dev/null); \ + if [ "$$POD_STATUS" ]; then \ + echo "Pod $(MYSQL_NAME)-0 is created with status: $$POD_STATUS"; \ + break; \ + else \ + echo "Waiting for pod $(MYSQL_NAME)-0 to be created..."; \ + sleep 2; \ + fi \ + done + kubectl wait --for=condition=Ready pod/$(MYSQL_NAME)-0 -n $(MYSQL_NAME) --timeout 600s + + @while true; do \ + POD_STATUS=$$(kubectl get pod -l app.kubernetes.io/component=router -n $(MYSQL_NAME) --no-headers -o custom-columns=":status.phase" 2>/dev/null); \ + if [ "$$POD_STATUS" ]; then \ + echo "MySQL router is created with status: $$POD_STATUS"; \ + break; \ + else \ + echo "Waiting for MySQL router to be created..."; \ + sleep 5; \ + fi \ + done + kubectl wait --for=condition=ready pod -l app.kubernetes.io/component=router -n $(MYSQL_NAME) --timeout=600s + +help: + $(info $(HEADER)) + @echo "----------------------------------------------------------------------" + @echo "Type 'make destroy' to delete the cluster and locally build images" + @echo "Type 'make teardown_cluster' to only delete the cluster" + @echo "Type 'make redeploy_api/frontend/operator' to rebuild and redeploy the given component to the cluster" + @echo "Type 'make help' to get this information" + @echo "Other useful targets can be found in the Makefile" + @echo "----------------------------------------------------------------------" + @echo "The frontend is reachable under http://$$(kubectl get svc frontend -n frontend -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" + @echo "The API is reachable under http://$$(kubectl get svc api -n api -o jsonpath='{.status.loadBalancer.ingress[0].ip}'):$$(kubectl get svc api -n api -o jsonpath='{.spec.ports[0].port}')" + @echo "----------------------------------------------------------------------" \ No newline at end of file diff --git a/scripts/localenv/README.md b/scripts/localenv/README.md new file mode 100644 index 0000000..1615f0d --- /dev/null +++ b/scripts/localenv/README.md @@ -0,0 +1,28 @@ +# Prerequisites +- Debian-based system +- docker +- kubectl +- kind +- helm v3.15.0+ +- go v1.20.0+ + +You need to disable IPV6 in Docker. This can be achieved by adding adding `"ipv6": false` to the Docker daemon config. +If no file exists, this can be achieved by (**overwrites existing config file**): +```bash +echo '{"ipv6": false}' > /etc/docker/daemon.json +``` +Restart the Docker daemon for the configuration to apply: +```bash +sudo systemctl restart docker +``` + +# How to run +## Single-node cluster +```bash +make +``` + +## Multi-node cluster +```bash +make multi_node +``` diff --git a/scripts/localenv/add_metallb.sh b/scripts/localenv/add_metallb.sh new file mode 100755 index 0000000..782c1e2 --- /dev/null +++ b/scripts/localenv/add_metallb.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -e + +kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.4/config/manifests/metallb-native.yaml +{ grep -q "controller"; kill $!; } < <(kubectl get pod -w -n metallb-system) +kubectl wait --namespace metallb-system \ + --for=condition=ready pod \ + --selector=app=metallb \ + --timeout=600s +lb_subnet=$(docker network inspect kind --format '{{json .}}' | jq -r '.IPAM.Config[0].Subnet') + +# Extract the base IP and calculate the range start and end +# This example assumes the subnet is in CIDR notation e.g., 172.20.0.0/16 +IFS='/' read -r base_ip cidr <<< "$lb_subnet" +IFS='.' read -r ip1 ip2 ip3 ip4 <<< "$base_ip" + +# Example calculation: Use the .10.1 for start and .10.50 for the end of the range +# This is a simplistic calculation that might not suit all subnets or requirements +range_start="${ip1}.${ip2}.10.1" +range_end="${ip1}.${ip2}.10.50" + +# Combine them into the range string expected by MetalLB +RANGE="${range_start}-${range_end}" +export RANGE + +# Prepare your YAML file with the ${RANGE} placeholder and use envsubst, apply the YAML file +envsubst < ./metallb-config-template.yaml | kubectl apply -f - diff --git a/scripts/localenv/kind-multinode-config.yaml b/scripts/localenv/kind-multinode-config.yaml new file mode 100644 index 0000000..b67d673 --- /dev/null +++ b/scripts/localenv/kind-multinode-config.yaml @@ -0,0 +1,6 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane +- role: worker +- role: worker \ No newline at end of file diff --git a/scripts/localenv/metallb-config-template.yaml b/scripts/localenv/metallb-config-template.yaml new file mode 100644 index 0000000..97dd9b8 --- /dev/null +++ b/scripts/localenv/metallb-config-template.yaml @@ -0,0 +1,14 @@ +apiVersion: metallb.io/v1beta1 +kind: IPAddressPool +metadata: + name: example + namespace: metallb-system +spec: + addresses: + - ${RANGE} +--- +apiVersion: metallb.io/v1beta1 +kind: L2Advertisement +metadata: + name: empty + namespace: metallb-system \ No newline at end of file diff --git a/scripts/pacman/.gitkeep b/scripts/pacman/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/stunner/.gitkeep b/scripts/stunner/.gitkeep deleted file mode 100644 index e69de29..0000000