diff --git a/.editorconfig b/.editorconfig index 08b6675d..7d050103 100644 --- a/.editorconfig +++ b/.editorconfig @@ -24,3 +24,7 @@ indent_size = 2 [*.{yml,yaml}] indent_style = space indent_size = 2 + +[Tiltfile] +indent_style = space +indent_size = 2 diff --git a/.github/workflows/check-py.yml b/.github/workflows/check-py.yml new file mode 100644 index 00000000..f91cc647 --- /dev/null +++ b/.github/workflows/check-py.yml @@ -0,0 +1,21 @@ +name: Check Python code + +on: + push: + paths: + - '**/Tiltfile' + - '**.py' + - '.github/workflows/check-py.yml' + +jobs: + check-fmt: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Check format + uses: psf/black@stable + options: '--line-length 100 --include Tiltfile --check' diff --git a/Dockerfile b/Dockerfile index c8b44385..75e72c9c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,62 +2,77 @@ ## common: ## -FROM docker.io/library/golang@sha256:1a5326b07cbab12f4fd7800425f2cf25ff2bd62c404ef41b56cb99669a710a83 as build-common +FROM docker.io/library/golang:1.23.1-bullseye AS build-dependencies +#FROM docker.io/library/golang@sha256:1a5326b07cbab12f4fd7800425f2cf25ff2bd62c404ef41b56cb99669a710a83 AS build-dependencies # 1.23.1-bookworm ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y protobuf-compiler libgpgme-dev && rm -rf /var/lib/apt/lists/* RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.31.0 && go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0 && go install github.com/ethereum/go-ethereum/cmd/abigen@v1.14.9 +FROM build-dependencies AS build-common + WORKDIR /app COPY go.mod go.sum ./ -RUN go mod download && go mod verify +RUN --mount=type=cache,target=/root/.cache/go-build go mod download && go mod verify COPY pkg ./pkg -FROM docker.io/debian@sha256:a629e796d77a7b2ff82186ed15d01a493801c020eed5ce6adaa2704356f15a1c as run-common +#FROM docker.io/debian@sha256:a629e796d77a7b2ff82186ed15d01a493801c020eed5ce6adaa2704356f15a1c AS run-common +FROM docker.io/debian:bullseye-slim AS run-common # bookworm-20240904-slim matching golang:1.23.1-bookworm RUN apt-get update && apt-get install -y libgpgme11 curl jq && rm -rf /var/lib/apt/lists/* ## p2p-helper: ## -FROM build-common as build-p2p-helper +FROM build-common AS build-p2p-helper COPY cmd/ipfs-p2p-helper ./cmd/ipfs-p2p-helper RUN --mount=type=cache,target=/root/.cache/go-build go build -v -o /usr/local/bin/ipfs-p2p-helper ./cmd/ipfs-p2p-helper -FROM run-common as p2p-helper +FROM run-common AS p2p-helper COPY --from=build-p2p-helper /usr/local/bin/ipfs-p2p-helper /usr/local/bin/ipfs-p2p-helper ENTRYPOINT ["ipfs-p2p-helper"] +FROM run-common AS p2p-helper-copy-local + +COPY ./bin/ipfs-p2p-helper /usr/local/bin/ipfs-p2p-helper + +ENTRYPOINT ["ipfs-p2p-helper"] + ## server: ## -FROM build-common as build-server +FROM build-common AS build-server COPY cmd/tpodserver ./cmd/tpodserver RUN --mount=type=cache,target=/root/.cache/go-build go build -v -o /usr/local/bin/tpodserver ./cmd/tpodserver +# RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=bind,source=.,target=/app go build -v -o /usr/local/bin/tpodserver ./cmd/tpodserver -FROM run-common as server +FROM run-common AS server COPY --from=build-server /usr/local/bin/tpodserver /usr/local/bin/tpodserver ENTRYPOINT ["tpodserver"] +FROM run-common AS server-copy-local + +COPY ./bin/tpodserver /usr/local/bin/tpodserver + +ENTRYPOINT ["tpodserver"] + ## autoscaler: ## -FROM build-common as build-autoscaler +FROM build-common AS build-autoscaler COPY autoscaler ./autoscaler RUN --mount=type=cache,target=/root/.cache/go-build go build -v -o /usr/local/bin/autoscaler ./autoscaler -FROM run-common as autoscaler +FROM run-common AS autoscaler COPY --from=build-autoscaler /usr/local/bin/autoscaler /usr/local/bin/autoscaler ENTRYPOINT ["autoscaler"] - - diff --git a/README.md b/README.md index aa98a3a1..b8f0162b 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,12 @@ Before running the various tests, Make sure the following dependencies are insta - **[kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/)**: The Kubernetes command-line tool for managing Kubernetes clusters. - **[docker](https://docs.docker.com/engine/install/)**: platform for developing, shipping, and running applications using containerization. - **[jq](https://jqlang.github.io/jq/)**: lightweight and flexible command-line JSON processor. -- **[minikube](https://minikube.sigs.k8s.io/docs/start/)**: tool that runs a single-node Kubernetes cluster locally. +- **[kind](https://kind.sigs.k8s.io/docs/user/quick-start/)**: tool that runs a single-node Kubernetes cluster locally. +- **[ctlptl](https://github.com/tilt-dev/ctlptl/)**: An utility for declaratively setting up local Kubernetes clusters. +- **[tilt](https://docs.tilt.dev/install.html)**: A toolkit automating the process of setting up a new local development cluster. - **[helm](https://helm.sh/)**: package manager for Kubernetes - **[helmfile](https://github.com/helmfile/helmfile)**: declarative configuration tool for Helm. -- **[forge, cast, anvil](https://github.com/foundry-rs/foundry)**: tools for building Ethereum-based applications. +- **[forge, cast, anvil](https://github.com/foundry-rs/foundry)**: tools for building Ethereum-based applications. - **[ipfs](https://docs.ipfs.tech/install/command-line/#install-official-binary-distributions)**: The InterPlanetary File System - **[constellation](https://docs.edgeless.systems/constellation/getting-started/first-steps-local)**: Constellation is a Kubernetes engine that provides a secure and confidential way to run Kubernetes clusters. (Needed in `test/e2e/constellation`). @@ -55,30 +57,35 @@ npm i && turbo sync ``` > Rerun `turbo sync` whenever you change files under the `proto/` and `contracts/` folders. -To start a local environment for e.g. integration-testing or evaluating the project, you can use the end-to-end tests in the `test/e2e` folder. +To start a local environment for e.g. integration-testing or evaluating the project, you can use `tilt` with Tiltfile in the `test/e2e` folder. -Typical development involves running the minikube end-to-end test, which can be done using the following command: +You can use it, for example, by running the following commands: ```bash -./test/e2e/minikube/run-test.sh +# Create a kind cluster: +ctlptl create cluster kind --registry=ctlptl-registry --kubernetes-version=v1.31.0 +# Start tilt and run the nginx test: +tilt up -- --include ./test/e2e/nginx/Tiltfile ``` -The command, after all dependencies are met, will proceed to start a local docker registry and test ethereum node, build and upload the project to them, then spin up a minikube cluster and deploy all necessary prerequisites into it, and finally deploying a pod from a [manifest file](spec/MANIFEST.md) into the cluster and then querying it over HTTP. It should display the curl command used to query the pod, and you should be able to use it yourself after the script is finished. +The first command will spin up a kind cluster with a local registry. Then, the second command will, after checking that any additional dependencies are met, then deploy all necessary prerequisites into local cluster, and finally deploying a pod from a [manifest file](spec/MANIFEST.md) into the cluster. + -Once you are done playing around with the tests, simply run the following command to delete and stop the minikube cluster: +Once you are done playing around with the test, run the following commands to clean up: ```bash -test/e2e/minikube/run-test.sh teardown +# Clean up the local cluster: +tilt down -- --include ./test/e2e/nginx/Tiltfile +# Delete up the local cluster: +ctlptl create delete kind ``` -(or alternatively, pass `teardown full` to also stop any local docker containers used by the test) - ## Contributing diff --git a/Tiltfile b/Tiltfile new file mode 100644 index 00000000..84740fba --- /dev/null +++ b/Tiltfile @@ -0,0 +1,15 @@ +# -*- mode: Python -*- +# SPDX-License-Identifier: GPL-3.0 + +load( + "./deploy/Tiltfile", "apocryph_resource", "apocryph_build_with_builder", "deploy_apocryph_stack" +) + +config.define_string_list("include") +cfg = config.parse() + +apocryph_build_with_builder() +deploy_apocryph_stack() + +for f in cfg["include"]: + load_dynamic(f) diff --git a/cmd/trustedpods/deploy.go b/cmd/trustedpods/deploy.go index bfd3081d..c0db8e2d 100644 --- a/cmd/trustedpods/deploy.go +++ b/cmd/trustedpods/deploy.go @@ -7,6 +7,7 @@ import ( "crypto/rand" "fmt" "math/big" + "os" "path/filepath" "github.com/comrade-coop/apocryph/pkg/abi" @@ -270,6 +271,27 @@ var deletePodCmd = &cobra.Command{ }, } +var podNamespaceCmd = &cobra.Command{ + Use: fmt.Sprintf("namespace [%s|deployment.yaml]", publisher.DefaultPodFile), + Short: "Get a pod's expected namespace in kubernetes", + Long: "Temporary command, may be removed once/if namespaces are implemented differently.", + GroupID: "lowlevel", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + _, _, _, deployment, err := publisher.ReadPodAndDeployment(args, manifestFormat, deploymentFormat) + if err != nil { + return err + } + configureDeployment(deployment) + + ns := pbcon.NamespaceFromTokenParts(common.BytesToAddress(deployment.Payment.PublisherAddress), common.Hash(deployment.Payment.PodID)) + + _, err = fmt.Fprintln(os.Stdout, ns) + + return err + }, +} + func init() { podCmd.AddCommand(deployPodCmd) podCmd.AddCommand(deletePodCmd) @@ -282,4 +304,7 @@ func init() { deletePodCmd.Flags().AddFlagSet(deploymentFlags) deletePodCmd.Flags().AddFlagSet(syncFlags) + podCmd.AddCommand(podNamespaceCmd) + podNamespaceCmd.Flags().AddFlagSet(deploymentFlags) + podNamespaceCmd.Flags().AddFlagSet(fundFlags) } diff --git a/cmd/trustedpods/flags.go b/cmd/trustedpods/flags.go index c9a7eb78..4591d766 100644 --- a/cmd/trustedpods/flags.go +++ b/cmd/trustedpods/flags.go @@ -75,7 +75,8 @@ var _ = func() error { fundFlags.Int64Var(&unlockTime, "unlock-time", 5*60, "time for unlocking tokens (in seconds)") syncFlags.AddFlag(uploadFlags.Lookup("ipfs")) - syncFlags.StringVar(&publisherKey, "ethereum-key", "", "account string (private key | http[s]://clef#account | /keystore#account | account (in default keystore))") + syncFlags.AddFlag(fundFlags.Lookup("ethereum-key")) + syncFlags.AddFlag(fundFlags.Lookup("pod-id")) registryFlags.StringVar(&ipfsApi, "ipfs", "/ip4/127.0.0.1/tcp/5001", "multiaddr where the ipfs/kubo api can be accessed") registryFlags.StringVar(®istryContractAddress, "registry-contract", "", "registry contract address") @@ -91,6 +92,8 @@ var _ = func() error { registryFlags.StringVar(&tableId, "id", "", "table id") registryFlags.StringVar(®ion, "region", "", "filter providers by region, Ex: us-east-8") registryFlags.AddFlag(fundFlags.Lookup("ethereum-key")) + registryFlags.AddFlag(fundFlags.Lookup("ethereum-rpc")) + return nil }() diff --git a/deploy/Tiltfile b/deploy/Tiltfile new file mode 100644 index 00000000..8f420550 --- /dev/null +++ b/deploy/Tiltfile @@ -0,0 +1,356 @@ +# -*- mode: Python -*- +# SPDX-License-Identifier: GPL-3.0 + +# For more on Extensions, see: https://docs.tilt.dev/extensions.html +load("ext://restart_process", "docker_build_with_restart") +load("ext://namespace", "namespace_create") +load("ext://helm_resource", "helm_resource", "helm_repo") + +local("which jq forge cast helm kubectl docker >/dev/null", echo_off=True) # Check dependencies +cluster_ip = local( + "kubectl get no -o jsonpath --template '{$.items[*].status.addresses[?(.type==\"InternalIP\")].address}'" +) + +# NOTE: Might need to run `chmod o+rw /run/containerd/containerd.sock` for some forms of image upload to work. +def apocryph_resource( + name, + manifest, # TODO: Support Blob manifests! + builder="apocryph-go-builder", + docker_ipfs="ipfs-local", + ethereum_resource="anvil", + ethereum_namespace="eth", + private_key="0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", + pod_id="0x00", + payment_contract="", + registry_contract="", + funds=10000000000000000000000, + upload_images=True, + flags=[], + apply_flags=[], + delete_flags=[], + resource_deps=[], + deploy_script_json="contracts/broadcast/Deploy.s.sol/31337/run-latest.json", +): + if payment_contract == "": + payment_contract = "$(jq .returns.payment.value %s)" % deploy_script_json + if registry_contract == "": + registry_contract = "$(jq .returns.registry.value %s)" % deploy_script_json + + ethereum_port = ( + "$(kubectl get svc -n %s eth-rpc -o jsonpath --template '{$.spec.ports[0].nodePort}')" + % ethereum_namespace + ) + + common_flags = [ + manifest, + "--pod-id", + pod_id, + "--ethereum-key", + private_key, + "--ipfs", + "/ip4/127.0.0.1/tcp/5001", # TODO: use docker's routing! e.g. '/dns4/%s/tcp/5001' % docker_ipfs + "--ethereum-rpc", + "http://%s:%s" % (cluster_ip, ethereum_port), + ] + flags + apply_flags = [ + "--registry-contract", + registry_contract, + "--payment-contract", + payment_contract, + "--upload-images=%s" % ("true" if upload_images else "false"), + "--funds", + str(funds), + ] + apply_flags + + # namespace = local('bash -c "cast keccak (cast concat-hex (cast wallet address %s) (cast to-int256 %s)) | xxd -r -p | base32"' % (private_key, pod_id)) + namespace_cmd = cmdline_in_builder( + " ".join(["./bin/trustedpods", "pod", "namespace"] + common_flags), builder + ) + + deploy_cmd = cmdline_in_builder( + " ".join(["./bin/trustedpods", "pod", "deploy"] + common_flags + apply_flags), builder + ) + kubectl_command = "kubectl get all -o yaml -n $(%s)" % namespace_cmd + apply_cmd = "set -ev; " + deploy_cmd + " 1>&2" + " && " + kubectl_command + # NOTE: if upload_images is False: we might need to also upload images manually + # e.g. with kind image load ... + + delete_cmd = cmdline_in_builder( + " ".join(["./bin/trustedpods", "pod", "delete"] + common_flags + delete_flags), builder + ) + + # TODO: image_deps = [c['image']['url'] for c in read_yaml(manifest)['containers'] if 'url' in c['image']] + k8s_custom_deploy( + name, + apply_cmd=apply_cmd, + delete_cmd=delete_cmd, + deps=manifest, + image_selector="", + live_update=[], + container_selector="", + # image_deps=image_deps, + ) + k8s_resource(name, resource_deps=resource_deps + [builder, docker_ipfs, ethereum_resource]) + + +def docker_ipfs_resource( + name, image, remote_ipfs_namespace="ipfs", resource_deps=[], *args, **kwargs +): + # if config.tilt_subcommand != "down": + services = { + name: { + "image": image, + "container_name": name, + "network_mode": "host", # TODO: Figure out a way to use docker's routing! (host likely only used for ipfs) + "volumes": [ + "ipfs-data:/data/ipfs", + "./configure-ipfs.sh:/container-init.d/050-configure.sh:ro", + ], + }, + } + docker_compose(encode_yaml({"services": services, "volumes": {"ipfs-data": {}}})) + dc_resource(name, *args, **kwargs) + # Ideally there would be a better way to do this (other than hardcoding the ipfs privkey) + remote_peerid = ( + "$(kubectl exec -n ipfs $(kubectl get po -n ipfs -o name) -- ipfs config Identity.PeerID)" + ) + remote_port = ( + "$(kubectl get svc -n ipfs ipfs-swarm -o jsonpath --template '{$.spec.ports[0].nodePort}')" + ) + config_cmd = "ipfs swarm connect /ip4/%s/udp/%s/quic-v1/webtransport/p2p/%s" % ( + cluster_ip, + remote_port, + remote_peerid, + ) + local_resource( + name + "-config", + "docker exec %s %s" % (name, config_cmd), + resource_deps=resource_deps + [name], + ) + + +def builder_resource( + name, + image, + dir=".", + write_dir="", + builder_dir="/app", + volumes=[], + volumes_conf={}, + entrypoint=["sleep", "infinity"], + *args, + **kwargs +): + services = { + name: { + "image": image, + "container_name": name, + "entrypoint": entrypoint, + "working_dir": builder_dir, + "network_mode": "host", # TODO: Figure out a way to use docker's routing! (host likely only used for ipfs) + "volumes": ( + [ + "%s:%s" % (dir, builder_dir), + ] + if write_dir == "" + else [ + "%s:%s:ro" % (dir, builder_dir), + "%s/%s:%s/%s:rw" % (dir, write_dir, builder_dir, write_dir), + ] + ) + + volumes, + }, + } + docker_compose(encode_yaml({"services": services, "volumes": volumes_conf})) + dc_resource(name, *args, **kwargs) + + +def local_resource_in_builder(name, cmd, builder, resource_deps=[], *args, **kwargs): + local_resource( + name, + cmdline_in_builder(cmd, builder), + resource_deps=resource_deps + [builder], + *args, + **kwargs + ) + + +def cmdline_in_builder(cmd, builder): + return "docker exec %s %s" % (builder, cmd) + + +def apocryph_build_with_builder(root_dir="."): + docker_build( + "comradecoop/apocryph/go-builder", + root_dir, + dockerfile=root_dir + "/Dockerfile", + target="build-dependencies", + only=[root_dir + "/Dockerfile"], + ) + builder_resource( + "apocryph-go-builder", + "comradecoop/apocryph/go-builder", + dir=root_dir, + write_dir="bin", + volumes=["go-cache:/root/.cache/go-build", "go-mod-cache:/go/pkg/mod"], + volumes_conf={"go-cache": {}, "go-mod-cache": {}}, + ) + + local_resource_in_builder( + "tpodserver-go-compile", + 'go build -v -buildvcs=false -ldflags="-s -w" -o bin/ ./cmd/tpodserver ./cmd/ipfs-p2p-helper ./cmd/trustedpods', + "apocryph-go-builder", + deps=[root_dir + "/cmd", root_dir + "/pkg"], + ) + + docker_build_with_restart( + "comradecoop/apocryph/server", + root_dir, + dockerfile="./Dockerfile", + target="server-copy-local", + entrypoint=["/usr/local/bin/tpodserver"], + only=[root_dir + "/bin"], + live_update=[ + sync(root_dir + "/bin", "/usr/local/bin/"), + ], + ) + docker_build_with_restart( + "comradecoop/apocryph/p2p-helper", + root_dir, + dockerfile="./Dockerfile", + target="p2p-helper-copy-local", + entrypoint=["/usr/local/bin/ipfs-p2p-helper"], + only=[root_dir + "/bin"], + live_update=[ + sync(root_dir + "/bin", "/usr/local/bin/"), + ], + ) + + +""" # TODO: Need to also build a trustedpods image for use with apocryph_resource... +def apocryph_build_with_dockerfile(): + docker_build( + "comradecoop/apocryph/server", + ".", + dockerfile="./Dockerfile", + target="server", + only=["./go.mod", "./go.sum", "./pkg", "./cmd/tpodserver"], + ) + docker_build( + "comradecoop/apocryph/p2p-helper", + ".", + dockerfile="./Dockerfile", + target="p2p-helper", + only=["./go.mod", "./go.sum", "./pkg", "./cmd/ipfs.p2p-helper"], + ) +""" + + +def deploy_apocryph_stack( + root_dir=".", deployer_key="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +): + # TODO: Run metrics-server!! + + update_settings(k8s_upsert_timeout_secs=160) + + helm_repo("kedacore", "https://kedacore.github.io/charts") + helm_repo("ingress-nginx-chart", "https://kubernetes.github.io/ingress-nginx") + helm_repo("prometheus-community", "https://prometheus-community.github.io/helm-charts") + helm_repo("grafana", "https://grafana.github.io/helm-charts") + helm_resource( + "keda", + "kedacore/keda", + namespace="keda", + resource_deps=["kedacore"], + labels=["apocryph-deps"], + flags=["--create-namespace"], + ) + helm_resource( + "ingress-nginx", + "ingress-nginx-chart/ingress-nginx", + namespace="keda", + resource_deps=["ingress-nginx-chart"], + labels=["apocryph-deps"], + flags=["--create-namespace"], + ) + k8s_yaml(root_dir + "/deploy/keda/ingress.yml") + k8s_resource( + objects=["keda-ingress:ingress"], + new_name="keda-ingress", + resource_deps=["ingress-nginx", "keda-http-addon"], + labels=["apocryph-deps"], + ) + + helm_resource( + "keda-http-addon", + "kedacore/keda-add-ons-http", + namespace="keda", + resource_deps=["kedacore", "keda"], + labels=["apocryph-deps"], + flags=[ + "--set=interceptor.replicas.min=1", + "--set=interceptor.waitTimeout=40s", + "--set=scaler.replicas=1", + "--create-namespace", + ], + ) + helm_resource( + "prometheus", + "prometheus-community/prometheus", + namespace="prometheus", + resource_deps=["prometheus-community"], + labels=["apocryph-deps"], + flags=[ + "--set=alertmanager.enabled=false", + "--set=prometheus-node-exporter.enabled=false", + "--create-namespace", + ], + ) + helm_resource( + "loki", + "grafana/loki-stack", + namespace="loki", + resource_deps=["grafana"], + labels=["apocryph-deps"], + flags=["-f", root_dir + "/deploy/loki/values.yml", "--create-namespace"], + ) + + namespace_create("eth") + # TODO: Recreate anvil when we have new contracts code + k8s_yaml(listdir(root_dir + "/deploy/eth/")) + k8s_resource("anvil", labels=["apocryph-dev"]) + + helm_resource( + "ipfs", + root_dir + "/deploy/ipfs/", + namespace="ipfs", + labels=["apocryph"], + flags=["--set=swarm.announceIp=%s" % cluster_ip, "--create-namespace"], + image_keys=["p2phelper.image"], + image_deps=["comradecoop/apocryph/p2p-helper"], + ) + + docker_ipfs_resource( + "ipfs-local", "docker.io/ipfs/kubo:v0.23.0", "ipfs", labels=["apocryph-dev"] + ) + + helm_resource( + "trustedpods", + root_dir + "/deploy/trustedpods/", + namespace="trustedpods", + resource_deps=["anvil", "ipfs", "loki", "anvil-deploy-contracts"], + labels=["apocryph"], + image_keys=["image"], + image_deps=["comradecoop/apocryph/server"], + ) + # k8s_resource('tpodserver-register', resource_deps=['anvil', 'ipfs', 'anvil-deploy-contracts']) + + local_resource( # TODO: Move to container! + "anvil-deploy-contracts", + labels=["apocryph"], + dir="./contracts/", + cmd="[ -f ./broadcast/Deploy.s.sol/31337/run-latest.json ] || forge script script/Deploy.s.sol --rpc-url http://%s:$(kubectl get svc -n eth eth-rpc -o jsonpath --template '{$.spec.ports[0].nodePort}') --private-key %s --broadcast" + % (cluster_ip, deployer_key), + resource_deps=["anvil"], + deps=["./contracts/src", "./contracts/script", "./contracts/lib"], + ) diff --git a/deploy/configure-ipfs.sh b/deploy/configure-ipfs.sh new file mode 100755 index 00000000..ff1cdca3 --- /dev/null +++ b/deploy/configure-ipfs.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +ipfs config --json Experimental.Libp2pStreamMounting true diff --git a/deploy/eth/anvil-proxy.yml b/deploy/eth/anvil-proxy.yml new file mode 100644 index 00000000..4095ade7 --- /dev/null +++ b/deploy/eth/anvil-proxy.yml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: eth-rpc + namespace: eth + labels: + app: eth +spec: + type: NodePort + selector: + app: anvil + ports: + - name: jsonrpc + port: 8545 + targetPort: 8545 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: anvil + namespace: eth +spec: + replicas: 1 + selector: + matchLabels: + app: anvil + template: + metadata: + labels: + app: anvil + spec: + containers: + - name: anvil + image: ghcr.io/foundry-rs/foundry:nightly-25f24e677a6a32a62512ad4f561995589ac2c7dc # comradecoop/apocryph/test-anvil + ports: + - containerPort: 8545 + command: ["anvil", "--host", "0.0.0.0"] + diff --git a/deploy/ipfs/Chart.yaml b/deploy/ipfs/Chart.yaml new file mode 100644 index 00000000..b0f6f39b --- /dev/null +++ b/deploy/ipfs/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: ipfs +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: "0.30.0" diff --git a/deploy/ipfs/templates/NOTES.txt b/deploy/ipfs/templates/NOTES.txt new file mode 100644 index 00000000..7e4beb7e --- /dev/null +++ b/deploy/ipfs/templates/NOTES.txt @@ -0,0 +1,3 @@ + _ _ ___ _ _ __ _ _ _ +| \|_\ / | |_)|_(_ |\ |/ \| \|_ +|_/|_ \/ _|_| | __) | \|\_/|_/|_ diff --git a/test/e2e/minikube/ipfs/ipfs.yml b/deploy/ipfs/templates/ipfs.yml similarity index 81% rename from test/e2e/minikube/ipfs/ipfs.yml rename to deploy/ipfs/templates/ipfs.yml index b9587671..fa462cb7 100644 --- a/test/e2e/minikube/ipfs/ipfs.yml +++ b/deploy/ipfs/templates/ipfs.yml @@ -2,7 +2,6 @@ apiVersion: v1 kind: Service metadata: name: ipfs-rpc - namespace: ipfs labels: app: ipfs spec: @@ -18,7 +17,6 @@ apiVersion: v1 kind: Service metadata: name: ipfs-swarm - namespace: ipfs labels: app: ipfs spec: @@ -27,10 +25,12 @@ spec: port: 4001 protocol: TCP targetPort: swarm-tcp + nodePort: {{ .Values.swarm.nodePort }} - name: swarm-udp port: 4001 protocol: UDP targetPort: swarm-udp + nodePort: {{ .Values.swarm.nodePort }} type: NodePort selector: app: ipfs @@ -39,18 +39,18 @@ apiVersion: v1 kind: ConfigMap metadata: name: ipfs-config - namespace: ipfs data: configure.sh: | #!/bin/sh set -ex ipfs config --json Experimental.Libp2pStreamMounting true + ipfs config --json Addresses.Announce '["/ip4/{{ .Values.swarm.announceIp }}/tcp/{{ .Values.swarm.nodePort }}", "/ip4/{{ .Values.swarm.announceIp }}/udp/{{ .Values.swarm.nodePort }}/quic", "/ip4/{{ .Values.swarm.announceIp }}/udp/{{ .Values.swarm.nodePort }}/quic-v1", "/ip4/{{ .Values.swarm.announceIp }}/udp/{{ .Values.swarm.nodePort }}/quic-v1/webtransport"]' + --- apiVersion: apps/v1 kind: StatefulSet metadata: name: ipfs - namespace: ipfs spec: replicas: 1 selector: @@ -87,8 +87,8 @@ spec: - name: IPFS_PROFILE value: - name: p2p-helper - image: host.minikube.internal:5000/comradecoop/apocryph/p2p-helper - command: ["ipfs-p2p-helper", "run", "--ipfs", "/ip4/127.0.0.1/tcp/5001"] + image: {{ .Values.p2phelper.image }} + args: ["run", "--ipfs", "/ip4/127.0.0.1/tcp/5001"] volumes: - name: init-scripts configMap: diff --git a/test/e2e/minikube/ipfs/serviceaccount.yml b/deploy/ipfs/templates/serviceaccount.yml similarity index 97% rename from test/e2e/minikube/ipfs/serviceaccount.yml rename to deploy/ipfs/templates/serviceaccount.yml index b0961dbc..b70d0f9e 100644 --- a/test/e2e/minikube/ipfs/serviceaccount.yml +++ b/deploy/ipfs/templates/serviceaccount.yml @@ -4,7 +4,6 @@ metadata: labels: app: ipfs name: ipfs-p2p-serviceaccount - namespace: ipfs # --- # apiVersion: rbac.authorization.k8s.io/v1 # kind: ClusterRole diff --git a/deploy/ipfs/values.yaml b/deploy/ipfs/values.yaml new file mode 100644 index 00000000..e25d35c8 --- /dev/null +++ b/deploy/ipfs/values.yaml @@ -0,0 +1,5 @@ +swarm: + nodePort: 30629 + announceIp: 127.0.0.1 +p2phelper: + image: comradecoop/apocryph/p2p-helper diff --git a/test/e2e/minikube/keda/ingress.yml b/deploy/keda/ingress.yml similarity index 100% rename from test/e2e/minikube/keda/ingress.yml rename to deploy/keda/ingress.yml diff --git a/test/e2e/minikube/loki/values.yml b/deploy/loki/values.yml similarity index 100% rename from test/e2e/minikube/loki/values.yml rename to deploy/loki/values.yml diff --git a/test/e2e/minikube/trustedpods/.helmignore b/deploy/trustedpods/.helmignore similarity index 100% rename from test/e2e/minikube/trustedpods/.helmignore rename to deploy/trustedpods/.helmignore diff --git a/test/e2e/minikube/trustedpods/Chart.yaml b/deploy/trustedpods/Chart.yaml similarity index 100% rename from test/e2e/minikube/trustedpods/Chart.yaml rename to deploy/trustedpods/Chart.yaml diff --git a/test/e2e/minikube/trustedpods/templates/NOTES.txt b/deploy/trustedpods/templates/NOTES.txt similarity index 100% rename from test/e2e/minikube/trustedpods/templates/NOTES.txt rename to deploy/trustedpods/templates/NOTES.txt diff --git a/test/e2e/minikube/trustedpods/templates/serviceaccount.yml b/deploy/trustedpods/templates/serviceaccount.yml similarity index 100% rename from test/e2e/minikube/trustedpods/templates/serviceaccount.yml rename to deploy/trustedpods/templates/serviceaccount.yml diff --git a/test/e2e/minikube/trustedpods/templates/tpodserver.yml b/deploy/trustedpods/templates/tpodserver.yml similarity index 74% rename from test/e2e/minikube/trustedpods/templates/tpodserver.yml rename to deploy/trustedpods/templates/tpodserver.yml index 3d8cc00e..805efb42 100644 --- a/test/e2e/minikube/trustedpods/templates/tpodserver.yml +++ b/deploy/trustedpods/templates/tpodserver.yml @@ -71,9 +71,8 @@ spec: spec: containers: - name: tpodserver - image: host.minikube.internal:5000/comradecoop/apocryph/server - command: [ - "tpodserver", "listen", + image: {{ .Values.image }} + args: ["listen", "--address", "0.0.0.0:8080", "--config", "config.yaml", "--ipfs", "/dns4/ipfs-rpc.ipfs.svc.cluster.local/tcp/5001", @@ -94,9 +93,8 @@ spec: - name: containerd-socket mountPath: /run/containerd/containerd.sock - name: tpodmonitor - image: host.minikube.internal:5000/comradecoop/apocryph/server - command: [ - "tpodserver", "monitor", + image: {{ .Values.image }} + args: ["monitor", "--config", "config.yaml", "--prometheus", "http://prometheus-server.prometheus.svc.cluster.local:80/", "--ethereum-rpc", "http://eth-rpc.eth.svc.cluster.local:8545", @@ -120,3 +118,36 @@ spec: hostPath: path: /run/containerd/containerd.sock serviceAccountName: tpodserver-serviceaccount +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: tpodserver-register + namespace: trustedpods +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: tpodregister + image: {{ .Values.image }} + args: ["registry", "register", + "--config", "config.yaml", + "--ipfs", "/dns4/ipfs-rpc.ipfs.svc.cluster.local/tcp/5001", + "--ethereum-rpc", "http://eth-rpc.eth.svc.cluster.local:8545", + "--ethereum-key", {{ .Values.ethKey }}, # TODO= anvil.accounts[1] prvkey + "--token-contract", {{ .Values.tokenContract }}, + "--registry-contract", {{ .Values.registryContract }}, + ] + volumeMounts: + - name: configs + mountPath: /config.yaml + subPath: config.yaml + readOnly: true + volumes: + - name: configs + configMap: + name: trustedpods-configs + items: + - key: config.yaml + path: config.yaml diff --git a/deploy/trustedpods/values.yaml b/deploy/trustedpods/values.yaml new file mode 100644 index 00000000..77d139de --- /dev/null +++ b/deploy/trustedpods/values.yaml @@ -0,0 +1,6 @@ +image: "comradecoop/apocryph/server" +ethKey: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" +withdraw: + address: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +tokenContract: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +registryContract: 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 diff --git a/pkg/kubernetes/pods.go b/pkg/kubernetes/pods.go index 49ecf03e..cbbfed8a 100644 --- a/pkg/kubernetes/pods.go +++ b/pkg/kubernetes/pods.go @@ -112,6 +112,9 @@ func ApplyPodRequest( Args: container.Command, WorkingDir: container.WorkingDir, } + if container.GetImage().GetCid() == nil { + containerSpec.ImagePullPolicy = corev1.PullIfNotPresent // HACK: Allow URL-only images for easier testing + } if podManifest.KeyPair != nil { // save as hex to parse later as hex diff --git a/pkg/proto/protoconnect/interceptors.go b/pkg/proto/protoconnect/interceptors.go index 6775922e..849bebd8 100644 --- a/pkg/proto/protoconnect/interceptors.go +++ b/pkg/proto/protoconnect/interceptors.go @@ -140,7 +140,7 @@ func (a authInterceptor) authenticate(header http.Header) (common.Address, error // verify publisherAddress in namespace is same one signed in token ns := header.Get(NamespaceHeader) - nsExpected := namespaceFromTokenParts(token.Publisher, token.PodId) + nsExpected := NamespaceFromTokenParts(token.Publisher, token.PodId) if ns == "" { header.Set(NamespaceHeader, nsExpected) } else if ns != nsExpected { @@ -150,7 +150,7 @@ func (a authInterceptor) authenticate(header http.Header) (common.Address, error return token.Publisher, nil } -func namespaceFromTokenParts(publisher common.Address, podId common.Hash) string { +func NamespaceFromTokenParts(publisher common.Address, podId common.Hash) string { namespaceParts := []byte{} namespaceParts = append(namespaceParts, publisher[:]...) namespaceParts = append(namespaceParts, podId[:]...) diff --git a/pkg/provider/download.go b/pkg/provider/download.go index 7618cf77..db8b8465 100644 --- a/pkg/provider/download.go +++ b/pkg/provider/download.go @@ -53,6 +53,9 @@ func DownloadImages(ctx context.Context, client *containerd.Client, ipfsAddress, if err != nil { return nil, err } + if !exists { + log.Printf("Warning: Image %v does not exist locally.\n", c.Image.Url) + } } result[c.Name] = c.Image.Url } diff --git a/test/e2e/common/manifest-nginx.yaml b/test/e2e/common/manifest-nginx.yaml index ce595829..f54524ef 100644 --- a/test/e2e/common/manifest-nginx.yaml +++ b/test/e2e/common/manifest-nginx.yaml @@ -4,7 +4,7 @@ containers: url: docker.io/nginxdemos/nginx-hello:latest ports: - containerPort: '8080' - hostHttpHost: example.local + hostHttpHost: example.localhost name: internal resourceRequests: - amountMillis: '10' diff --git a/test/e2e/minikube/eth/anvil-proxy.yml b/test/e2e/minikube/eth/anvil-proxy.yml deleted file mode 100644 index eefb20d7..00000000 --- a/test/e2e/minikube/eth/anvil-proxy.yml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: eth-rpc - namespace: eth - labels: - app: eth -spec: - type: ExternalName - externalName: host.minikube.internal - ports: - - name: jsonrpc - port: 8545 - targetPort: 8545 diff --git a/test/e2e/minikube/helmfile.yaml b/test/e2e/minikube/helmfile.yaml deleted file mode 100644 index 01c8a13f..00000000 --- a/test/e2e/minikube/helmfile.yaml +++ /dev/null @@ -1,68 +0,0 @@ -repositories: - - name: kedacore - url: https://kedacore.github.io/charts - - name: ingress-nginx - url: https://kubernetes.github.io/ingress-nginx - - name: prometheus-community - url: https://prometheus-community.github.io/helm-charts - - name: grafana - url: https://grafana.github.io/helm-charts - -releases: - - name: keda - namespace: keda - chart: kedacore/keda - - name: ingress-nginx - namespace: keda - chart: ingress-nginx/ingress-nginx - hooks: - - events: ['postsync'] - showlogs: true - command: 'kubectl' - args: - - 'wait' - - '--namespace' - - 'keda' - - '--for=condition=available' - - 'deployment/ingress-nginx-controller' - - '--timeout=500000s' - - name: keda-http-addon - namespace: keda - chart: kedacore/keda-add-ons-http - set: - - name: interceptor.replicas.min - value: 1 - - name: interceptor.waitTimeout - value: 40s - - name: scaler.replicas - value: 1 - needs: - - keda - - name: prometheus - chart: prometheus-community/prometheus - namespace: prometheus - set: - - name: alertmanager.enabled - value: false - - name: prometheus-node-exporter.enabled - value: false - - name: keda-fixes - chart: ./keda - namespace: keda - needs: - - keda-http-addon - - ingress-nginx # NOTE: nginx admission controllers typically fails to wait long enough for nginx to start at this step - - name: ipfs - chart: ./ipfs - namespace: ipfs - - name: loki - chart: grafana/loki-stack - namespace: loki - values: - - ./loki/values.yml - - name: trustedpods - chart: ./trustedpods - namespace: trustedpods - - name: eth - chart: ./eth - namespace: eth diff --git a/test/e2e/minikube/run-test.sh b/test/e2e/minikube/run-test.sh deleted file mode 100755 index daa59a1e..00000000 --- a/test/e2e/minikube/run-test.sh +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: GPL-3.0 - -set -e - -trap 'pkill -f "kubectl port-forward" && kill $(jobs -p) &>/dev/null' EXIT - -if [ "$1" = "teardown" ]; then - minikube delete - - if [ "$2" = "full" ]; then - docker rm --force registry - docker rm --force anvil - rm -r /home/ezio/.apocryph/deployment/ - exit 0 - fi - exit 0 -fi - -cd "$(dirname "$0")" - -which curl >/dev/null; which jq >/dev/null; which xargs >/dev/null; which sed >/dev/null -which go >/dev/null -which ipfs >/dev/null -which forge &>/dev/null || export PATH=$PATH:~/.bin/foundry -which forge >/dev/null; which cast >/dev/null -which minikube >/dev/null; which helmfile >/dev/null; which helm >/dev/null; which kubectl >/dev/null -which docker >/dev/null - -# based on https://stackoverflow.com/a/31269848 / https://bobcopeland.com/blog/2012/10/goto-in-bash/ -if [ -n "$1" ]; then - STEP=${1:-1} - eval "set -v; $(sed -n "/## $STEP: /{:a;n;p;ba};" $0)" - exit -fi - -echo -e "\e[1;32m---" -echo "Note: To skip steps, use '$0 '" -echo " e.g. to skip ahead to configuring IPFS, run '$0 1.2'" -echo -e "---\e[0m" - -set -v - -#sudo chmod o+rw /run/containerd/containerd.sock - -## 0: Set up the external environment - -## 0.1: Build/tag server and p2p-helper images - -docker build -t comradecoop/apocryph/server:latest ../../.. --target server - -docker build -t comradecoop/apocryph/p2p-helper:latest ../../.. --target p2p-helper - -## 0.2: Create local registry and push server and p2p-helper images - -docker run -d -p 5000:5000 --restart=always --name registry registry:2 || echo "Docker registry already running" - -docker tag comradecoop/apocryph/server:latest localhost:5000/comradecoop/apocryph/server:latest -docker push localhost:5000/comradecoop/apocryph/server:latest - -docker tag comradecoop/apocryph/p2p-helper:latest localhost:5000/comradecoop/apocryph/p2p-helper:latest -docker push localhost:5000/comradecoop/apocryph/p2p-helper:latest - -## 0.3: Set up a local ethereum node and deploy contracts to it - -# (NOTE: Unfortunately, we cannot use a port other than 8545, or otherwise the eth-rpc service will break) -docker run -d -p 8545:8545 --restart=always --name=anvil \ - ghcr.io/foundry-rs/foundry:nightly-619f3c56302b5a665164002cb98263cd9812e4d5 \ - -- 'anvil --host 0.0.0.0 --state /anvil-state.json' 2>/dev/null || { - docker exec anvil ash -c 'kill 1 && rm -f /anvil-state.json' # Reset anvil state -} -sleep 5 - -DEPLOYER_KEY=$(docker logs anvil | awk '/Private Keys/ {flag=1; next} flag && /^\(0\)/ {print $2; exit}') # anvil.accounts[0] - -( cd ../../../contracts; forge script script/Deploy.s.sol --private-key "$DEPLOYER_KEY" --rpc-url http://localhost:8545 --broadcast) - -## 1: Set up the Kubernetes environment ## - - -[ "$(minikube status -f'{{.Kubelet}}')" = "Running" ] || minikube start --insecure-registry='host.minikube.internal:5000' --container-runtime=containerd - -minikube addons enable metrics-server - -## 1.1: Apply Helm configurations ## - -kubectl delete namespace trustedpods 2>/dev/null || true - -helmfile sync - -## 1.2: Register the provider in the marketplace - -[ "$PORT_5004" == "" ] && { PORT_5004="yes" ; kubectl port-forward --namespace ipfs svc/ipfs-rpc 5004:5001 & sleep 0.5; } - -go run ../../../cmd/tpodserver registry register \ - --config ../common/config.yaml \ - --ipfs /ip4/127.0.0.1/tcp/5004 \ - --ethereum-rpc http://127.0.0.1:8545 \ - --ethereum-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d \ - --token-contract 0x5FbDB2315678afecb367f032d93F642f64180aa3 \ - --registry-contract 0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0 \ - -## 1.3: Configure provider/in-cluster IPFS and publisher IPFS ## - -{ while ! kubectl get -n ipfs endpoints ipfs-rpc -o json | jq '.subsets[].addresses[].ip' &>/dev/null; do sleep 1; done; } - -O_IPFS_PATH=$IPFS_PATH -export IPFS_PATH=$(mktemp ipfs.XXXX --tmpdir -d) - -[ "$PORT_5004" == "" ] && { PORT_5004="yes" ; kubectl port-forward --namespace ipfs svc/ipfs-rpc 5004:5001 & sleep 0.5; } -echo /ip4/127.0.0.1/tcp/5004 > $IPFS_PATH/api - -SWARM_ADDRESSES=$(minikube service -n ipfs ipfs-swarm --url | head -n 1 | sed -E 's|http://(.+):(.+)|["/ip4/\1/tcp/\2", "/ip4/\1/udp/\2/quic", "/ip4/\1/udp/\2/quic-v1", "/ip4/\1/udp/\2/quic-v1/webtransport"]|') -echo $SWARM_ADDRESSES - -PROVIDER_IPFS=$(curl -X POST "http://127.0.0.1:5004/api/v0/id" | jq '.ID' -r); echo $PROVIDER_IPFS - -CONFIG_BEFORE=$(ipfs config Addresses.AppendAnnounce) -ipfs config Addresses.AppendAnnounce --json "$SWARM_ADDRESSES" -CONFIG_AFTER=$(ipfs config Addresses.AppendAnnounce) - -[ "$CONFIG_BEFORE" = "$CONFIG_AFTER" ] || kubectl delete -n ipfs $(kubectl get po -o name -n ipfs) # Restart ipfs daemon - -export IPFS_PATH=$O_IPFS_PATH - -{ while ! kubectl get -n ipfs endpoints ipfs-rpc -o json | jq '.subsets[].addresses[].ip' &>/dev/null; do sleep 1; done; } - -ipfs id &>/dev/null || ipfs init - -ipfs config --json Experimental.Libp2pStreamMounting true - -[ -n "$IPFS_DAEMON" ] || { IPFS_DAEMON=yes; ipfs daemon & { while ! [ -f ${IPFS_PATH:-~/.ipfs}/api ]; do sleep 0.1; done; } 2>/dev/null; } - -echo "$SWARM_ADDRESSES" | jq -r '.[] + "/p2p/'"$PROVIDER_IPFS"'"' | xargs -n 1 ipfs swarm connect || true - -sleep 1 - -## 2: Deploy example manifest to cluster ## - -PROVIDER_ETH=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 #TODO= anvil.accounts[1] -PUBLISHER_KEY=$(docker logs anvil | awk '/Private Keys/ {flag=1; next} flag && /^\(2\)/ {print $2; exit}') -PAYMENT_CONTRACT=$(cat ../../../contracts/broadcast/Deploy.s.sol/31337/run-latest.json | jq -r '.returns.payment.value') -REGISTRY_CONTRACT=$(cat ../../../contracts/broadcast/Deploy.s.sol/31337/run-latest.json | jq -r '.returns.registry.value') -FUNDS=10000000000000000000000 - -[ "$PORT_5004" == "" ] && { PORT_5004="yes" ; kubectl port-forward --namespace ipfs svc/ipfs-rpc 5004:5001 & sleep 0.5; } -[ -n "$PROVIDER_IPFS" ] || { PROVIDER_IPFS=$(curl -X POST "http://127.0.0.1:5004/api/v0/id" -s | jq '.ID' -r); echo $PROVIDER_IPFS; } -[ -n "$IPFS_DAEMON" ] || { IPFS_DAEMON=yes; ipfs daemon & { while ! [ -f ${IPFS_PATH:-~/.ipfs}/api ]; do sleep 0.1; done; } 2>/dev/null; } - -set +v -set -x - -minikube image load docker.io/nginxdemos/nginx-hello:latest - -go run ../../../cmd/trustedpods/ pod deploy ../common/manifest-nginx.yaml \ - --ethereum-key "$PUBLISHER_KEY" \ - --payment-contract "$PAYMENT_CONTRACT" \ - --registry-contract "$REGISTRY_CONTRACT" \ - --funds "$FUNDS" \ - --mint-funds -# --upload-images=true - -set +x -set -v - -## 3: Connect and measure balances ## - -WITHDRAW_ETH=0x90F79bf6EB2c4f870365E785982E1f101E93b906 #TODO copied from trustedpods/tpodserver.yml -TOKEN_CONTRACT=$(cat ../../../contracts/broadcast/Deploy.s.sol/31337/run-latest.json | jq -r '.returns.token.value') -INGRESS_URL=$(minikube service -n keda ingress-nginx-controller --url=true | head -n 1); echo $INGRESS_URL -MANIFEST_HOST=example.local # From manifest-nginx.yaml - -echo "Provider balance before:" $(cast call "$TOKEN_CONTRACT" "balanceOf(address)" "$WITHDRAW_ETH" | cast to-fixed-point 18) - -set -x - -while ! curl --connect-timeout 40 -H "Host: $MANIFEST_HOST" $INGRESS_URL --fail-with-body; do sleep 10; done -curl -H "Host: $MANIFEST_HOST" $INGRESS_URL --fail-with-body - -set +x - -sleep 45 - -echo "Provider balance after:" $(cast call "$TOKEN_CONTRACT" "balanceOf(address)" "$WITHDRAW_ETH" | cast to-fixed-point 18) - -## 4: In conclusion.. - -set +v - -echo -e "\e[1;32m---" -echo "Note: To interact with the deployed guestbook, run the following" -echo " kubectl port-forward --namespace keda svc/ingress-nginx-controller 1234:80 &" -echo " xdg-open http://guestbook.localhost:1234/" -echo "Note: To stop the minikube cluster/provider, use '$0 teardown'" -echo " and to clean-up everything the script does, use '$0 teardown full'" -echo -e "---\e[0m" - -exit 0; - -## Env: (debug stuff) - -export PROVIDER_ETH=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 #TODO= anvil.accounts[1] -export PUBLISHER_KEY=$(docker logs anvil | awk '/Private Keys/ {flag=1; next} flag && /^\(2\)/ {print $2; exit}') -export TOKEN_CONTRACT=$(cat ../../../contracts/broadcast/Deploy.s.sol/31337/run-latest.json | jq -r '.returns.token.value') -export PAYMENT_CONTRACT=$(cat ../../../contracts/broadcast/Deploy.s.sol/31337/run-latest.json | jq -r '.returns.payment.value') -export REGISTRY_CONTRACT=$(cat ../../../contracts/broadcast/Deploy.s.sol/31337/run-latest.json | jq -r '.returns.registry.value') -export FUNDS=10000000000000000000000 -export INGRESS_URL=$(minikube service -n keda ingress-nginx-controller --url=true | head -n 1); echo $INGRESS_URL -export MANIFEST_HOST=guestbook.localhost # From manifest-guestbook.yaml -[ "$PORT_5004" == "" ] && { PORT_5004="yes" ; kubectl port-forward --namespace ipfs svc/ipfs-rpc 5004:5001 & sleep 0.5; } -[ -n "$PROVIDER_IPFS" ] || { PROVIDER_IPFS=$(curl -X POST "http://127.0.0.1:5004/api/v0/id" -s | jq '.ID' -r); echo $PROVIDER_IPFS; } -[ -n "$IPFS_DAEMON" ] || { IPFS_DAEMON=yes; ipfs daemon & { while ! [ -f ${IPFS_PATH:-~/.ipfs}/api ]; do sleep 0.1; done; } 2>/dev/null; } - -bash diff --git a/test/e2e/minikube/trustedpods/values.yaml b/test/e2e/minikube/trustedpods/values.yaml deleted file mode 100644 index dd612595..00000000 --- a/test/e2e/minikube/trustedpods/values.yaml +++ /dev/null @@ -1,3 +0,0 @@ -ethKey: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" -withdraw: - address: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" diff --git a/test/e2e/nginx/Tiltfile b/test/e2e/nginx/Tiltfile new file mode 100644 index 00000000..a579d55d --- /dev/null +++ b/test/e2e/nginx/Tiltfile @@ -0,0 +1,33 @@ +# -*- mode: Python -*- +# SPDX-License-Identifier: GPL-3.0 + +load("../../../deploy/Tiltfile", "apocryph_resource") + +apocryph_resource( + "nginx-example", + "./test/e2e/common/manifest-nginx.yaml", + upload_images=False, + apply_flags=["--mint-funds"], +) + +"""TODO: +## 3: Connect and measure balances ## + +WITHDRAW_ETH=0x90F79bf6EB2c4f870365E785982E1f101E93b906 #TODO copied from trustedpods/tpodserver.yml +TOKEN_CONTRACT=$(cat ../../../contracts/broadcast/Deploy.s.sol/31337/run-latest.json | jq -r '.returns.token.value') +INGRESS_URL=$(minikube service -n keda ingress-nginx-controller --url=true | head -n 1); echo $INGRESS_URL +MANIFEST_HOST=example.local # From manifest-nginx.yaml + +echo "Provider balance before:" $(cast call "$TOKEN_CONTRACT" "balanceOf(address)" "$WITHDRAW_ETH" | cast to-fixed-point 18) + +set -x + +while ! curl --connect-timeout 40 -H "Host: $MANIFEST_HOST" $INGRESS_URL --fail-with-body; do sleep 10; done +curl -H "Host: $MANIFEST_HOST" $INGRESS_URL --fail-with-body + +set +x + +sleep 45 + +echo "Provider balance after:" $(cast call "$TOKEN_CONTRACT" "balanceOf(address)" "$WITHDRAW_ETH" | cast to-fixed-point 18) +"""