diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b6ce0c1..92051a6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,46 +13,42 @@ env: IMAGE_NAME: sedaprotocol/seda-data-proxy jobs: - build-and-push: - name: 🐳 Build and Push Docker Images + build-and-push-amd64: + name: 🐳 Build and Push Docker Image (amd64) runs-on: ubuntu-latest - strategy: - matrix: - target_arch: - - bun-linux-x64-modern - - bun-linux-arm64 - include: - - target_arch: bun-linux-x64-modern - platform: linux/amd64 - - target_arch: bun-linux-arm64 - platform: linux/arm64 steps: - name: 📥 Checkout code uses: actions/checkout@v4 - - name: 🏷️ Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v5 + - name: 🔐 Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: 🏗️ Build and push Docker image for amd64 + run: | + docker build \ + --build-arg TARGET_ARCH=bun-linux-x64-modern \ + -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-bun-linux-x64-modern \ + -f .build/docker/Dockerfile \ + . + docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-bun-linux-x64-modern + + build-and-push-arm64: + name: 🐳 Build and Push Docker Image (arm64) + runs-on: ubuntu-latest + + steps: + - name: 📥 Checkout code + uses: actions/checkout@v4 + + - name: 🛠️ Set up QEMU for ARM64 + uses: docker/setup-qemu-action@v3 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=tag - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - labels: | - org.opencontainers.image.title=${{ env.IMAGE_NAME }} - org.opencontainers.image.description=Data Proxy Service for Seda Protocol - org.opencontainers.image.version=${{ steps.meta.outputs.version }} - org.opencontainers.image.architecture=${{ matrix.target_arch }} - org.opencontainers.image.source=${{ github.repository }} - org.opencontainers.image.url=https://github.com/${{ github.repository }} - org.opencontainers.image.created=${{ steps.meta.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - - name: 🛠️ Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + platforms: arm64 - name: 🔐 Log in to the Container registry uses: docker/login-action@v3 @@ -61,24 +57,41 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: 🏗️ Build and push Docker image for ${{ matrix.target_arch }} - uses: docker/build-push-action@v5 + - name: 🏗️ Build and push Docker image for arm64 + run: | + docker build \ + --platform linux/arm64 \ + --build-arg TARGET_ARCH=bun-linux-arm64 \ + -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-bun-linux-arm64 \ + -f .build/docker/Dockerfile \ + . + docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-bun-linux-arm64 + + create-manifest: + name: 📝 Create and Push Docker Manifest + needs: + - build-and-push-amd64 + - build-and-push-arm64 + runs-on: ubuntu-latest + + steps: + - name: 🔐 Log in to the Container registry + uses: docker/login-action@v3 with: - context: . - file: .build/docker/Dockerfile - push: true - tags: | - ${{ steps.meta.outputs.tags }}-${{ matrix.target_arch }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - TARGET_ARCH=${{ matrix.target_arch }} - platforms: ${{ matrix.platform }} - cache-from: type=gha - cache-to: type=gha,mode=max + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: 📝 Create and Push Manifest + run: | + docker manifest create ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} \ + --amend ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-bun-linux-x64-modern \ + --amend ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-bun-linux-arm64 + docker manifest push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} create-release: name: 📦 Create GitHub Release - needs: build-and-push + needs: create-manifest runs-on: ubuntu-latest steps: @@ -111,4 +124,5 @@ jobs: - [ghcr.io/sedaprotocol/seda-data-proxy:${{ github.ref_name }}-bun-linux-x64-modern](https://ghcr.io/sedaprotocol/seda-data-proxy:${{ github.ref_name }}-bun-linux-x64-modern) - [ghcr.io/sedaprotocol/seda-data-proxy:${{ github.ref_name }}-bun-linux-arm64](https://ghcr.io/sedaprotocol/seda-data-proxy:${{ github.ref_name }}-bun-linux-arm64) + - [ghcr.io/sedaprotocol/seda-data-proxy:${{ github.ref_name }}](https://ghcr.io/sedaprotocol/seda-data-proxy:${{ github.ref_name }}) token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 0634828..49a3a60 100644 --- a/.gitignore +++ b/.gitignore @@ -175,3 +175,5 @@ dist .DS_Store config.json data-proxy-private-key.json + +ubuntu-dind* diff --git a/helm/.helmignore b/helm/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm/.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/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 0000000..b130cc9 --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: seda-data-proxy +description: A Helm chart for Kubernetes to deploy the SEDA Data Proxy. +version: 0.1.0 +appVersion: "1.0" diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl new file mode 100644 index 0000000..fa4d50f --- /dev/null +++ b/helm/templates/_helpers.tpl @@ -0,0 +1,31 @@ +{{/* +Generate a full name for the resources, optionally including the release name. +*/}} +{{- define "seda-data-proxy.fullname" -}} +{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "seda-data-proxy.labels" -}} +app.kubernetes.io/name: {{ include "seda-data-proxy.name" . }} +helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "seda-data-proxy.selectorLabels" -}} +app.kubernetes.io/name: {{ include "seda-data-proxy.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Template for the name of the application +*/}} +{{- define "seda-data-proxy.name" -}} +{{- .Chart.Name -}} +{{- end }} diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml new file mode 100644 index 0000000..7c232ae --- /dev/null +++ b/helm/templates/configmap.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "seda-data-proxy.fullname" . }}-config +data: + config.json: | + { + "routes": [ + { + "path": "/*", + "upstreamUrl": "https://swapi.dev/api/", + "methods": ["GET"] + } + ] + } diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml new file mode 100644 index 0000000..15d9237 --- /dev/null +++ b/helm/templates/deployment.yaml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "seda-data-proxy.fullname" . }} + labels: + {{- include "seda-data-proxy.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "seda-data-proxy.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "seda-data-proxy.selectorLabels" . | nindent 8 }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - containerPort: {{ .Values.service.port }} + env: + {{- range .Values.envVars }} + - name: {{ .name }} + value: {{ .value }} + {{- end }} + - name: SEDA_DATA_PROXY_PRIVATE_KEY + valueFrom: + secretKeyRef: + name: {{ include "seda-data-proxy.fullname" . }}-secrets + key: SEDA_DATA_PROXY_PRIVATE_KEY + args: ["run", {{ .Values.sedaProxyFlags }} ] + readinessProbe: + httpGet: + path: /status/health + port: {{ .Values.service.port }} + livenessProbe: + httpGet: + path: /status/health + port: {{ .Values.service.port }} + volumeMounts: + - name: config-volume + mountPath: /app/config.json + subPath: config.json + volumes: + - name: config-volume + configMap: + name: {{ include "seda-data-proxy.fullname" . }}-config diff --git a/helm/templates/secret.yaml b/helm/templates/secret.yaml new file mode 100644 index 0000000..d5f2bf8 --- /dev/null +++ b/helm/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "seda-data-proxy.fullname" . }}-secrets + labels: + {{- include "seda-data-proxy.labels" . | nindent 4 }} +type: Opaque +data: + SEDA_DATA_PROXY_PRIVATE_KEY: {{ .Values.secret.sedaDataProxyPrivateKey | b64enc | quote }} diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml new file mode 100644 index 0000000..5501f74 --- /dev/null +++ b/helm/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "seda-data-proxy.fullname" . }} + labels: + {{- include "seda-data-proxy.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + selector: + {{- include "seda-data-proxy.selectorLabels" . | nindent 4 }} diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 0000000..94028d2 --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,23 @@ +imagePullSecrets: [] + +image: + repository: ghcr.io/sedaprotocol/seda-data-proxy + tag: "v0.0.3" + pullPolicy: IfNotPresent + pullSecrets: {} + os: linux + arch: amd64 + +service: + type: ClusterIP + port: 5384 + +replicaCount: 1 + +# export SEDA_PRIVATE_KEY= +# helm install my-release ./chart-name --set secret.sedaDataProxyPrivateKey=$SEDA_PRIVATE_KEY +secret: + sedaDataProxyPrivateKey: "" + +# Uncomment for testing (itdisables request verification) +# sedaProxyFlags: "--disable-proof" diff --git a/workspace/data-proxy/package.json b/workspace/data-proxy/package.json index 84c5187..8d5fa3d 100644 --- a/workspace/data-proxy/package.json +++ b/workspace/data-proxy/package.json @@ -1,7 +1,7 @@ { "name": "@seda-protocol/data-proxy", "main": "./src/index.ts", - "version": "0.0.2", + "version": "0.0.3", "devDependencies": { "@types/big.js": "^6.2.2", "msw": "^2.3.5" diff --git a/workspace/data-proxy/src/cli/init.ts b/workspace/data-proxy/src/cli/init.ts index c14ce3b..fe95f13 100644 --- a/workspace/data-proxy/src/cli/init.ts +++ b/workspace/data-proxy/src/cli/init.ts @@ -7,6 +7,27 @@ import type { Config } from "../config-parser"; import { DEFAULT_PRIVATE_KEY_JSON_FILE_NAME } from "../constants"; import type { FileKeyPair } from "./utils/key-pair"; +async function outputJson( + content: string, + filePath: string, + printOnly = false, +) { + if (printOnly) { + console.log(`Content for ${filePath}:`); + console.log(content); + return; + } + + const writeResult = await tryAsync(async () => writeFile(filePath, content)); + + if (writeResult.isErr) { + console.error(`Writing file to ${filePath} errored: ${writeResult.error}`); + process.exit(1); + } + + console.info(`Written to ${filePath}`); +} + export const initCommand = new Command("init") .description("Initializes a config.json file and generates a private key") .option( @@ -15,6 +36,7 @@ export const initCommand = new Command("init") DEFAULT_PRIVATE_KEY_JSON_FILE_NAME, ) .option("-c, --config ", "Path to config.json", "./config.json") + .option("--print", "Print the content instead of writing it") .action(async (args) => { if (!(await exists(args.privateKeyFile))) { const privateKeyBuff = randomBytes(32); @@ -26,18 +48,11 @@ export const initCommand = new Command("init") privkey: Buffer.from(keyPair.privkey).toString("hex"), }; - const writeResult = await tryAsync(async () => - writeFile(args.privateKeyFile, JSON.stringify(keyPairJson)), + await outputJson( + JSON.stringify(keyPairJson, null, 2), + args.privateKeyFile, + args.print, ); - - if (writeResult.isErr) { - console.error( - `Writing file to ${args.privateKeyFile} errored: ${writeResult.error}`, - ); - process.exit(1); - } - - console.info(`Written private key to ${args.privateKeyFile}`); } else { console.warn( `${args.privateKeyFile} already exists skipping creation of private key`, @@ -62,18 +77,11 @@ export const initCommand = new Command("init") ], }; - const writeResult = await tryAsync(async () => - writeFile(args.config, JSON.stringify(config, null, 4)), + await outputJson( + JSON.stringify(config, null, 2), + args.config, + args.print, ); - - if (writeResult.isErr) { - console.error( - `Writing file to ${args.privateKeyFile} errored: ${writeResult.error}`, - ); - process.exit(1); - } - - console.info(`Written config to ${args.config}`); } else { console.warn(`${args.config} already exists skipping creation of config`); } diff --git a/workspace/data-proxy/src/constants.ts b/workspace/data-proxy/src/constants.ts index 623f074..0459ea7 100644 --- a/workspace/data-proxy/src/constants.ts +++ b/workspace/data-proxy/src/constants.ts @@ -3,7 +3,7 @@ import type { HTTPMethod } from "elysia"; // Server constants export const SERVER_PORT = process.env.SERVER_PORT ?? "5384"; -export const LOG_LEVEL = process.env.LOG_LEVEL ?? "debug"; +export const LOG_LEVEL = process.env.LOG_LEVEL ?? "info"; export const LOG_FILE_DIR = process.env.LOG_FILE_DIR ?? ""; // Environment constants