diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c168d4d3..b0c1efa3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,11 +14,9 @@ jobs: uses: actions/checkout@v4 - name: Run plugin run: | - wget https://github.com/interTwin-eu/interlink-docker-plugin/releases/download/0.0.24-no-gpu/docker-plugin_Linux_x86_64 -O docker-plugin \ - && chmod +x docker-plugin \ - && docker ps \ - && export INTERLINKCONFIGPATH=$PWD/ci/manifests/plugin-config.yaml \ - && ./docker-plugin & + git clone https://github.com/interTwin-eu/interlink-slurm-plugin.git \ + && cd interlink-slurm-plugin/docker \ + && docker compose up -d - name: Get Repo Owner id: get_repo_owner run: echo ::set-output name=repo_owner::$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]') @@ -27,7 +25,7 @@ jobs: with: workdir: ci verb: call - args: -s --name my-test build-images new-interlink --plugin-endpoint tcp://localhost:4000 test stdout + args: -s --name slurm-test build-images new-interlink --plugin-endpoint tcp://localhost:4000 test stdout cloud-token: ${{ secrets.DAGGER_CLOUD_TOKEN }} version: "0.13.0" #dagger-flags: -d diff --git a/ci/dagger.json b/ci/dagger.json index 2374e7b1..53fc83d3 100644 --- a/ci/dagger.json +++ b/ci/dagger.json @@ -7,5 +7,6 @@ "source": "github.com/marcosnils/daggerverse/k3s@ce8fe35d309bdb29f9983f7d90ea518e724534fe" } ], + "source": ".", "engineVersion": "v0.13.0" } diff --git a/ci/main.go b/ci/main.go index 19c32429..f89a899b 100644 --- a/ci/main.go +++ b/ci/main.go @@ -48,12 +48,9 @@ type Interlink struct { VirtualKubeletRef string InterlinkRef string PluginRef string - // +private - Kubectl *dagger.Container - // +private - KubeAPIs *dagger.Service - // +private - KubeConfig *dagger.File + Kubectl *dagger.Container + KubeAPIs *dagger.Service + KubeConfig *dagger.File // +private KubeConfigHost *dagger.File InterlinkContainer *dagger.Container @@ -327,16 +324,30 @@ func (m *Interlink) Kube( ctx context.Context, ) (*dagger.Service, error) { - return dag.K3S(m.Name).Server(), nil + return m.KubeAPIs, nil } // Wait for cluster to be ready, then setup the test container func (m *Interlink) Run( ctx context.Context, + // +optional + // +defaultPath="./manifests" + manifests *dagger.Directory, ) (*dagger.Container, error) { - return m.Kubectl. + return dag.Container().From("bitnami/kubectl:1.29.7-debian-12-r3"). + WithUser("root"). + WithExec([]string{"mkdir", "-p", "/opt/user"}). + WithExec([]string{"chown", "-R", "1001:0", "/opt/user"}). + WithExec([]string{"apt", "update"}). + WithExec([]string{"apt", "update"}). + WithExec([]string{"apt", "install", "-y", "curl", "python3", "python3-pip", "python3-venv", "git", "vim"}). + WithMountedFile("/.kube/config", dag.K3S(m.Name).Config(dagger.K3SConfigOpts{Local: false})). + WithExec([]string{"chown", "1001:0", "/.kube/config"}). + WithUser("1001"). + WithDirectory("/manifests", manifests). + WithEntrypoint([]string{"kubectl"}). WithWorkdir("/opt/user"). WithExec([]string{"bash", "-c", "git clone https://github.com/interTwin-eu/vk-test-set.git"}). WithExec([]string{"bash", "-c", "cp /manifests/vktest_config.yaml /opt/user/vk-test-set/vktest_config.yaml"}). @@ -349,19 +360,21 @@ func (m *Interlink) Run( func (m *Interlink) Test( ctx context.Context, // +optional + // +defaultPath="./manifests" + manifests *dagger.Directory, + // +optional localCluster *dagger.Service, // +optional // +default false //cleanup bool, ) (*dagger.Container, error) { - result := m.Kubectl. - WithWorkdir("/opt/user"). - WithExec([]string{"bash", "-c", "git clone https://github.com/interTwin-eu/vk-test-set.git"}). - WithExec([]string{"bash", "-c", "cp /manifests/vktest_config.yaml /opt/user/vk-test-set/vktest_config.yaml"}). - WithWorkdir("/opt/user/vk-test-set"). - WithExec([]string{"bash", "-c", "python3 -m venv .venv && source .venv/bin/activate && pip3 install -e ./ "}). - WithExec([]string{"bash", "-c", "source .venv/bin/activate && export KUBECONFIG=/.kube/config && sleep 0 && pytest -vk 'not rclone'"}) + c, err := m.Run(ctx, manifests) + if err != nil { + return nil, err + } + + result := c.WithExec([]string{"bash", "-c", "source .venv/bin/activate && export KUBECONFIG=/.kube/config && pytest -vk 'not rclone and not limits'"}) return result, nil diff --git a/ci/manifests/vktest_config.yaml b/ci/manifests/vktest_config.yaml index 2b02f2cb..4cca445e 100644 --- a/ci/manifests/vktest_config.yaml +++ b/ci/manifests/vktest_config.yaml @@ -11,7 +11,8 @@ values: namespace: interlink annotations: - slurm-job.vk.io/flags: "--job-name=test-pod-cfg -t 2800 --ntasks=8 --nodes=1 --mem-per-cpu=2000" + slurm-job.vk.io/flags: "--job-name=test-pod-cfg -t 2800" + slurm-job.vk.io/image-root: "docker://" tolerations: - key: virtual-node.interlink/no-schedule diff --git a/example/.DS_Store b/example/.DS_Store deleted file mode 100644 index eb4bb013..00000000 Binary files a/example/.DS_Store and /dev/null differ diff --git a/example/.gitignore b/example/.gitignore deleted file mode 100644 index 1d17dae1..00000000 --- a/example/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.venv diff --git a/example/Dockerfile.mock b/example/Dockerfile.mock deleted file mode 100644 index e69de29b..00000000 diff --git a/example/README.md b/example/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/example/create_openapi.py b/example/create_openapi.py deleted file mode 100644 index 47a81b33..00000000 --- a/example/create_openapi.py +++ /dev/null @@ -1,48 +0,0 @@ -import json -import os.path -from typing import List - -from fastapi import FastAPI -from fastapi.openapi.utils import get_openapi -from fastapi.responses import PlainTextResponse - -import interlink - -app = FastAPI() - - -@app.post("/create") -async def create_pod(pod: List[interlink.Pod]) -> interlink.CreateStruct: - raise NotImplementedError - - -@app.post("/delete") -async def delete_pod(pod: interlink.PodRequest) -> str: - raise NotImplementedError - - -@app.get("/status") -async def status_pod(pods: List[interlink.PodRequest]) -> List[interlink.PodStatus]: - raise NotImplementedError - - -@app.get("/getLogs", response_class=PlainTextResponse) -async def get_logs(req: interlink.LogRequest) -> bytes: - raise NotImplementedError - - -openapi_schema = os.path.join( - os.path.dirname(__file__), *["..", "docs", "openapi", "openapi.json"] -) - -with open(openapi_schema, "w") as f: - json.dump( - get_openapi( - title="interLink sidecar", - version=os.environ.get("VERSION", "v0.0.0"), - openapi_version=app.openapi()["openapi"], - description="openapi spec for interLink apis <-> provider sidecar communication", - routes=app.routes, - ), - f, - ) \ No newline at end of file diff --git a/example/interlink-docker/interlink/InterLinkConfig.yaml b/example/interlink-docker/interlink/InterLinkConfig.yaml deleted file mode 100644 index 6738ee3c..00000000 --- a/example/interlink-docker/interlink/InterLinkConfig.yaml +++ /dev/null @@ -1,9 +0,0 @@ -VKTokenFile: "$HOME/interLink/token" -InterlinkAddress: "http://XXX.XXX.XXX.XXX" -SidecarURL: "http://docker-sidecar" -InterlinkPort: "3000" -SidecarPort: "4000" -ExportPodData: true -DataRootFolder: ".local/interlink/jobs/" -VerboseLogging: true -ErrorsOnlyLogging: false diff --git a/example/interlink-docker/interlink/docker-compose.yaml b/example/interlink-docker/interlink/docker-compose.yaml deleted file mode 100644 index 243c9d5f..00000000 --- a/example/interlink-docker/interlink/docker-compose.yaml +++ /dev/null @@ -1,46 +0,0 @@ -version: '3.7' -services: - interlink: - build: - context: ../../../ - dockerfile: docker/Dockerfile.interlink - restart: always - #network_mode: "host" - ports: - - 3000:3000 - volumes: - - type: bind - source: ./ - target: /etc/interlink - environment: - - INTERLINKCONFIGPATH=/etc/interlink/InterLinkConfig.yaml - # healthcheck: - # test: ["CMD", "/check.sh"] - # interval: 10s - # timeout: 10s - # retries: 3 - # start_period: 5s - docker-sidecar: - image: ghcr.io/intertwin-eu/interlink-sidecar-docker:0.0.2-pre1 - restart: always - privileged: true - cap_add: - - SYS_ADMIN - #network_mode: "host" - ports: - - 4000:4000 - environment: - - INTERLINKCONFIGPATH=/etc/interlink/sidecarConfig.yaml - volumes: - - type: bind - source: ./ - target: /etc/interlink - - type: bind - source: /var/run/docker.sock - target: /var/run/docker.sock - # healthcheck: - # test: ["CMD", "/check.sh"] - # interval: 10s - # timeout: 10s - # retries: 3 - # start_period: 5s diff --git a/example/interlink-docker/interlink/sidecarConfig.yaml b/example/interlink-docker/interlink/sidecarConfig.yaml deleted file mode 100644 index 75b216df..00000000 --- a/example/interlink-docker/interlink/sidecarConfig.yaml +++ /dev/null @@ -1,15 +0,0 @@ -SidecarURL: "http://docker-sidecar" -SidecarPort: "4000" -SbatchPath: "/usr/bin/sbatch" -ScancelPath: "/usr/bin/scancel" -SqueuePath: "/usr/bin/squeue" -CommandPrefix: "" -ExportPodData: true -DataRootFolder: ".local/interlink/jobs/" -Tsocks: false -TsocksPath: "$WORK/tsocks-1.8beta5+ds1/libtsocks.so" -TsocksLoginNode: "login01" -BashPath: /bin/bash -VerboseLogging: true -ErrorsOnlyLogging: false - diff --git a/example/interlink-docker/test_pod.yaml b/example/interlink-docker/test_pod.yaml deleted file mode 100644 index 7dcd1ecf..00000000 --- a/example/interlink-docker/test_pod.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: test-pod-cfg-cowsay-dciangot - namespace: vk - annotations: - slurm-job.vk.io/flags: "--job-name=test-pod-cfg -t 2800 --ntasks=8 --nodes=1 --mem-per-cpu=2000" -spec: - restartPolicy: Never - containers: - - image: ghcr.io/grycap/cowsay - command: ["/bin/sh"] - args: ["-c", "\"touch /tmp/test.txt && sleep 60 && echo \\\"hello muu\\\" | /usr/games/cowsay \" " ] - imagePullPolicy: Always - name: cowsayo - dnsPolicy: ClusterFirst - nodeSelector: - kubernetes.io/hostname: test-vk - tolerations: - - key: virtual-node.interlink/no-schedule - operator: Exists diff --git a/example/interlink-docker/vk/InterLinkConfig.yaml b/example/interlink-docker/vk/InterLinkConfig.yaml deleted file mode 100644 index 02f7f092..00000000 --- a/example/interlink-docker/vk/InterLinkConfig.yaml +++ /dev/null @@ -1,11 +0,0 @@ -VKTokenFile: "$HOME/interLink/token" -InterlinkAddress: "http://XXX.XXX.XXX.XXX" -CommandPrefix: "" -ExportPodData: true -ServiceAccount: "interlink" -Namespace: "vk" -VerboseLogging: true -ErrorsOnlyLogging: false -CPU: 100 -Memory: 128Gi -Pod: 100 diff --git a/example/interlink-docker/vk/deployment.yaml b/example/interlink-docker/vk/deployment.yaml deleted file mode 100644 index 109d1a4a..00000000 --- a/example/interlink-docker/vk/deployment.yaml +++ /dev/null @@ -1,101 +0,0 @@ ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: test-vk - labels: - nodeName: test-vk -spec: - replicas: 1 - selector: - matchLabels: - nodeName: test-vk - template: - metadata: - labels: - nodeName: test-vk - spec: - initContainers: - - name: settoken - image: "docker.io/alpine:3" - command: ["sh", "-c"] - args: ["touch /opt/interlink/token"] - volumeMounts: - - name: token - mountPath: /opt/interlink - containers: - - name: jaeger - image: jaegertracing/all-in-one:1.51 - - name: inttw-vk - image: ghcr.io/intertwin-eu/interlink/virtual-kubelet-inttw:latest - #image: dciangot/vk:latest - imagePullPolicy: Always - #command: ["sleep", "infinity"] - env: - - name: NODENAME - value: test-vk - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - #- name: KUBECONFIG - # value: /etc/interlink/kubeconfig - - name: KUBELET_PORT - value: "10250" - - name: CONFIGPATH - value: "/etc/interlink/InterLinkConfig.yaml" - - name: VKTOKENFILE - value: "/opt/interlink/token" - volumeMounts: - - name: config - mountPath: /etc/interlink/InterLinkConfig.yaml - subPath: InterLinkConfig.yaml - - name: token - mountPath: /opt/interlink - resources: - limits: - cpu: 500m - memory: 600Mi - requests: - cpu: 50m - memory: 100Mi - - name: refresh-token - image: ghcr.io/intertwin-eu/virtual-kubelet-inttw-refresh:latest - imagePullPolicy: Always - env: - - name: IAM_SERVER - value: "https://dodas-iam.cloud.cnaf.infn.it/" - # TODO load env IAM client from secret - - name: IAM_CLIENT_ID - value: "DUMMY" - - name: IAM_CLIENT_SECRET - value: "DUMMY" - - name: IAM_REFRESH_TOKEN - value: "DUMMY" - - name: IAM_VK_AUD - value: intertw-vk - - name: TOKEN_PATH - value: /opt/interlink/token - resources: - limits: - cpu: 500m - memory: 600Mi - requests: - cpu: 50m - memory: 100Mi - volumeMounts: - - name: token - mountPath: /opt/interlink - serviceAccountName: interlink - volumes: - - name: config - configMap: - # Provide the name of the ConfigMap you want to mount. - name: vk-config - - name: kubeconfig - configMap: - # Provide the name of the ConfigMap you want to mount. - name: vk-kubeconfig - - name: token - emptyDir: {} diff --git a/example/interlink-docker/vk/kustomization.yaml b/example/interlink-docker/vk/kustomization.yaml deleted file mode 100644 index 3890ba28..00000000 --- a/example/interlink-docker/vk/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - ./deployment.yaml - - ./service-account.yaml - -configMapGenerator: - - name: vk-config-json - files: - - vk-cfg.json=vk-cfg.json - - name: vk-config - files: - - InterLinkConfig.yaml=InterLinkConfig.yaml \ No newline at end of file diff --git a/example/interlink-docker/vk/otecol_config.yaml b/example/interlink-docker/vk/otecol_config.yaml deleted file mode 100644 index 2f6bb992..00000000 --- a/example/interlink-docker/vk/otecol_config.yaml +++ /dev/null @@ -1,41 +0,0 @@ -extensions: - health_check: - pprof: - endpoint: 0.0.0.0:1777 - zpages: - endpoint: 0.0.0.0:55679 - -receivers: - otlp: - protocols: - grpc: - endpoint: 0.0.0.0:4319 - http: - endpoint: 0.0.0.0:4318 - -processors: - batch: - -exporters: - otlp: - endpoint: "localhost:4317" - tls: - insecure: true - logging: - verbosity: detailed - -service: - - pipelines: - - traces: - receivers: [otlp, opencensus, jaeger, zipkin] - processors: [batch] - exporters: [logging] - - metrics: - receivers: [otlp, opencensus, prometheus] - processors: [batch] - exporters: [logging] - - extensions: [health_check, pprof, zpages] \ No newline at end of file diff --git a/example/interlink-docker/vk/service-account.yaml b/example/interlink-docker/vk/service-account.yaml deleted file mode 100644 index 3dbaa7f2..00000000 --- a/example/interlink-docker/vk/service-account.yaml +++ /dev/null @@ -1,97 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: interlink - namespace: vk ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: interlink-role - namespace: vk -rules: -- apiGroups: - - "coordination.k8s.io" - resources: - - leases - verbs: - - update - - create - - get - - list - - watch - - patch -- apiGroups: - - "" - resources: - - configmaps - - secrets - - services - - serviceaccounts - - namespaces - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - pods - verbs: - - delete - - get - - list - - watch - - patch -- apiGroups: - - "" - resources: - - nodes - verbs: - - create - - get -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - update - - patch -- apiGroups: - - "" - resources: - - pods/status - verbs: - - update - - patch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: interlink-rolebinding -subjects: -- kind: ServiceAccount - name: interlink - namespace: vk -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: interlink-role ---- -apiVersion: v1 -kind: Secret -metadata: - name: interlink-secret - namespace: vk - annotations: - kubernetes.io/service-account.name: interlink - labels: - kubernetes.io/service-account.name: interlink -type: kubernetes.io/service-account-token diff --git a/example/interlink/__init__.py b/example/interlink/__init__.py deleted file mode 100644 index e5559f1a..00000000 --- a/example/interlink/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .provider import * -from .spec import * diff --git a/example/interlink/interlink.egg-info/PKG-INFO b/example/interlink/interlink.egg-info/PKG-INFO deleted file mode 100644 index c028c6da..00000000 --- a/example/interlink/interlink.egg-info/PKG-INFO +++ /dev/null @@ -1,11 +0,0 @@ -Metadata-Version: 2.1 -Name: interlink -Version: 0.0.1 -Summary: interlink provider library -Home-page: package URL -Author: Diego Ciangottini -Author-email: diego.ciangottini@gmail.com -Classifier: Programming Language :: Python :: 3 -Classifier: Operating System :: OS Independent -Requires-Python: >=3.6 -Description-Content-Type: text/markdown diff --git a/example/interlink/interlink.egg-info/SOURCES.txt b/example/interlink/interlink.egg-info/SOURCES.txt deleted file mode 100644 index 64dcb304..00000000 --- a/example/interlink/interlink.egg-info/SOURCES.txt +++ /dev/null @@ -1,7 +0,0 @@ -README.md -setup.py -src/interlink/interlink.egg-info/PKG-INFO -src/interlink/interlink.egg-info/SOURCES.txt -src/interlink/interlink.egg-info/dependency_links.txt -src/interlink/interlink.egg-info/requires.txt -src/interlink/interlink.egg-info/top_level.txt \ No newline at end of file diff --git a/example/interlink/interlink.egg-info/dependency_links.txt b/example/interlink/interlink.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891..00000000 --- a/example/interlink/interlink.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/example/interlink/interlink.egg-info/requires.txt b/example/interlink/interlink.egg-info/requires.txt deleted file mode 100644 index 909e9224..00000000 --- a/example/interlink/interlink.egg-info/requires.txt +++ /dev/null @@ -1,2 +0,0 @@ -fastapi -pydantic diff --git a/example/interlink/interlink.egg-info/top_level.txt b/example/interlink/interlink.egg-info/top_level.txt deleted file mode 100644 index 8b137891..00000000 --- a/example/interlink/interlink.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/example/interlink/provider.py b/example/interlink/provider.py deleted file mode 100644 index 40378a6e..00000000 --- a/example/interlink/provider.py +++ /dev/null @@ -1,53 +0,0 @@ -from fastapi import FastAPI, HTTPException -from .spec import * -from typing import List - - -class Provider(FastAPI): - def __init__( - self, - docker_client, - ): - self.docker = docker_client - self.container_pod_map = {} - - def create(self, pod: Pod) -> CreateStruct: - raise HTTPException(status_code=500, detail="NOT IMPLEMENTED YET") - - def delete(self, pod: PodRequest) -> None: - raise HTTPException(status_code=500, detail="NOT IMPLEMENTED YET") - - def status(self, pod: PodRequest) -> PodStatus: - raise HTTPException(status_code=500, detail="NOT IMPLEMENTED YET") - - def logs(self, req: LogRequest) -> bytes: - raise HTTPException(status_code=500, detail="NOT IMPLEMENTED YET") - - def create_pod(self, pod: Pod) -> CreateStruct: - try: - self.create(pod) - except Exception as ex: - raise ex - - return "Containers created" - - def delete_pod(self, pod: PodRequest) -> str: - try: - self.delete(pod) - except Exception as ex: - raise ex - - return "Containers deleted" - - def get_status(self, pods: List[PodRequest]) -> List[PodStatus]: - pod = pods[0] - - return [self.Status(pod)] - - def get_logs(self, req: LogRequest) -> bytes: - try: - logContent = self.Logs(req) - except Exception as ex: - raise ex - - return logContent \ No newline at end of file diff --git a/example/interlink/spec.py b/example/interlink/spec.py deleted file mode 100644 index 34f9a983..00000000 --- a/example/interlink/spec.py +++ /dev/null @@ -1,196 +0,0 @@ -import datetime -from typing import Dict, List, Optional - -from pydantic import BaseModel, Field - -class Metadata(BaseModel): - name: Optional[str] = None - namespace: Optional[str] = None - uid: Optional[str] = None - annotations: Optional[Dict[str, str]] = Field({}) - labels: Optional[Dict[str, str]] = Field({}) - generate_name: Optional[str] = None - - -class VolumeMount(BaseModel): - name: str - mount_path: str - sub_path: Optional[str] = None - read_only: Optional[bool] = False - mount_propagation: Optional[str] = None - - -class ConfigMapKeySelector(BaseModel): - key: str - name: Optional[str] = None - optional: Optional[bool] = None - - -class SecretKeySelector(BaseModel): - key: str - name: Optional[str] = None - optional: Optional[bool] = None - - -class EnvVarSource(BaseModel): - config_map_key_ref: Optional[ConfigMapKeySelector] = None - secret_key_ref: Optional[SecretKeySelector] = None - - -class EnvVar(BaseModel): - name: str - value: Optional[str] = None - value_from: Optional[EnvVarSource] = None - - -class SecurityContext(BaseModel): - allow_privilege_escalation: Optional[bool] = None - privileged: Optional[bool] = None - proc_mount: Optional[str] = None - read_only_file_system: Optional[bool] = None - run_as_group: Optional[int] = None - run_as_non_root: Optional[bool] = None - run_as_user: Optional[int] = None - - -class Container(BaseModel): - name: str - image: str - tag: str = "latest" - command: List[str] - args: Optional[List[str]] = Field([]) - resources: Optional[dict] = Field({}) - volume_mounts: Optional[List[VolumeMount]] = Field([]) - env: Optional[List[EnvVar]] = None - security_context: Optional[SecurityContext] = None - - -class KeyToPath(BaseModel): - key: Optional[str] - path: str - mode: Optional[int] = None - - -class SecretVolumeSource(BaseModel): - secret_name: str - items: Optional[List[KeyToPath]] = Field([]) - optional: Optional[bool] = None - default_mode: Optional[int] = None - - -class ConfigMapVolumeSource(BaseModel): - name: str - items: Optional[List[KeyToPath]] = Field([]) - optional: Optional[bool] = None - default_mode: Optional[int] = None - - -# class VolumeSource(BaseModel): -# emptyDir: Optional[dict] = None -# secret: Optional[SecretSource] = None -# configMap: Optional[ConfigMapVolumeSource] = None - - -class PodVolume(BaseModel): - name: str - # volumeSource: Optional[VolumeSource] = None - empty_dir: Optional[dict] = None - secret: Optional[SecretVolumeSource] = None - config_map: Optional[ConfigMapVolumeSource] = None - - -class PodSpec(BaseModel): - containers: List[Container] - init_containers: Optional[List[Container]] = None - volumes: Optional[List[PodVolume]] = None - preemption_policy: Optional[str] = None - priority_class_name: Optional[str] = None - priority: Optional[int] = None - restart_policy: Optional[str] = None - termination_grace_period_seconds: Optional[int] = None - - -class PodRequest(BaseModel): - metadata: Metadata - spec: PodSpec - - -class ConfigMap(BaseModel): - metadata: Metadata - data: Optional[dict] - binary_data: Optional[dict] = None - type: Optional[str] = None - immutable: Optional[bool] = None - - -class Secret(BaseModel): - metadata: Metadata - data: Optional[dict] = None - string_data: Optional[dict] = None - type: Optional[str] = None - immutable: Optional[bool] = None - - -class Volume(BaseModel): - name: str - config_maps: Optional[List[ConfigMap]] = None - secrets: Optional[List[Secret]] = None - empty_dirs: Optional[List[str]] = None - - -class Pod(BaseModel): - pod: PodRequest - container: List[Volume] - - -class StateTerminated(BaseModel): - exit_code: int - reason: Optional[str] = None - - -class StateRunning(BaseModel): - started_at: Optional[str] = None - - -class StateWaiting(BaseModel): - message: Optional[str] = None - reason: Optional[str] = None - - -class ContainerStates(BaseModel): - terminated: Optional[StateTerminated] = None - running: Optional[StateRunning] = None - waiting: Optional[StateWaiting] = None - - -class ContainerStatus(BaseModel): - name: str - state: ContainerStates - - -class PodStatus(BaseModel): - name: str - uid: str - namespace: str - containers: List[ContainerStatus] - - -class LogOpts(BaseModel): - tail: Optional[int] = None - limit_bytes: Optional[int] = None - timestamps: Optional[bool] = None - previous: Optional[bool] = None - since_seconds: Optional[int] = None - since_time: Optional[datetime.datetime] = None - - -class LogRequest(BaseModel): - namespace: str - pod_uid: str - pod_name: str - container_name: str - opts: LogOpts - -class CreateStruct(BaseModel): - pod_uid: str - pod_jid: str \ No newline at end of file diff --git a/example/provider_demo.py b/example/provider_demo.py deleted file mode 100644 index c2de9448..00000000 --- a/example/provider_demo.py +++ /dev/null @@ -1,249 +0,0 @@ -import interlink - -from fastapi.responses import PlainTextResponse -from fastapi import FastAPI, HTTPException -from typing import List -import docker -import re -import os -import sqlite3 - -con = sqlite3.connect("plugin.db") -cur = con.cursor() -cur.execute("CREATE TABLE pods(pod_id,j_id,state)") - -app = FastAPI() - - -class MyProvider(interlink.provider.Provider): - def __init__(self, docker): - super().__init__(docker) - - # Recover already running containers refs - self.container_pod_map = {} - statuses = self.docker.api.containers(all=True) - for status in statuses: - name = status["Names"][0] - if len(name.split("-")) > 1: - uid = "-".join(name.split("-")[-5:]) - self.container_pod_map.update({uid: [status["Id"]]}) - print(self.container_pod_map) - - def dump_volumes( - self, pods: List[interlink.PodVolume], volumes: List[interlink.Volume] - ) -> List[str]: - - dataList = [] - - # Match data source information (actual bytes) to the mount ref in pod description - for v in volumes: - if v.config_maps: - for data_source in v.config_maps: - for ref in pods: - pod_mount = ref.volume_source.config_map - if pod_mount: - if ref.name == data_source.metadata.name: - for filename, content in data_source.data.items(): - # write content to file - path = f"{data_source.metadata.namespace}-{data_source.metadata.name}/{filename}" - try: - os.makedirs( - os.path.dirname(path), exist_ok=True - ) - with open(path, "w") as f: - f.write(content) - except Exception as ex: - raise HTTPException(status_code=500, detail=ex) - - # dump list of written files - dataList.append(path) - - if v.secrets: - pass - - if v.empty_dirs: - pass - return dataList - - def create(self, pod: interlink.Pod) -> None: - container = pod.pod.spec.containers[0] - - if pod.pod.spec.volumes: - _ = self.dump_volumes(pod.pod.spec.volumes, pod.container) - - volumes = [] - if container.volume_mounts: - for mount in container.volume_mounts: - if mount.sub_path: - volumes.append( - f"{pod.pod.metadata.namespace}-{mount.name}/{mount.sub_path}:{mount.mount_path}" - ) - else: - volumes.append( - f"{pod.pod.metadata.namespace}-{mount.name}:{mount.mount_path}" - ) - - try: - cmds = " ".join(container.command) - args = " ".join(container.args) - docker_container = self.docker.containers.run( - f"{container.image}:{container.tag}", - f"{cmds} {args}", - name=f"{container.name}-{pod.pod.metadata.uid}", - detach=True, - volumes=volumes, - # runtime="nvidia", - # device_requests=[ - # docker.types.DeviceRequest(device_ids=["0"], capabilities=[['gpu']])] - ) - print(docker_container) - docker_run_id = docker_container.id - except Exception as ex: - raise HTTPException(status_code=500, detail=ex) - - self.container_pod_map.update({pod.pod.metadata.uid: [docker_run_id]}) - print(self.container_pod_map) - - print(pod) - - def delete(self, pod: interlink.PodRequest) -> None: - try: - print(f"docker rm -f {self.container_pod_map[pod.metadata.uid][0]}") - container = self.docker.containers.get( - self.container_pod_map[pod.metadata.uid][0] - ) - container.remove(force=True) - self.container_pod_map.pop(pod.metadata.uid) - except: - raise HTTPException(status_code=404, detail="No containers found for UUID") - print(pod) - return - - def status(self, pod: interlink.PodRequest) -> interlink.PodStatus: - print(self.container_pod_map) - print(pod.metadata.uid) - try: - container = self.docker.containers.get( - self.container_pod_map[pod.metadata.uid][0] - ) - status = container.status - except: - raise HTTPException(status_code=404, detail="No containers found for UUID") - - print(status) - - if status == "running": - try: - statuses = self.docker.api.containers( - filters={"status": "running", "id": container.id} - ) - print(statuses) - started_at = statuses[0]["Created"] - except Exception as ex: - raise HTTPException(status_code=500, detail=ex) - - return interlink.PodStatus( - name=pod.metadata.name, - UID=pod.metadata.uid, - namespace=pod.metadata.namespace, - containers=[ - interlink.ContainerStatus( - name=pod.spec.containers[0].name, - state=interlink.ContainerStates( - running=interlink.StateRunning(started_at=started_at), - waiting=None, - terminated=None, - ), - ) - ], - ) - elif status == "exited": - - try: - statuses = self.docker.api.containers( - filters={"status": "exited", "id": container.id} - ) - print(statuses) - reason = statuses[0]["Status"] - pattern = re.compile(r"Exited \((.*?)\)") - - exitCode = -1 - for match in re.findall(pattern, reason): - exitCode = int(match) - except Exception as ex: - raise HTTPException(status_code=500, detail=ex) - - return interlink.PodStatus( - name=pod.metadata.name, - UID=pod.metadata.uid, - namespace=pod.metadata.namespace, - containers=[ - interlink.ContainerStatus( - name=pod.spec.containers[0].name, - state=interlink.ContainerStates( - running=None, - waiting=None, - terminated=interlink.StateTerminated( - reason=reason, exitCode=exitCode - ), - ), - ) - ], - ) - - return interlink.PodStatus( - name=pod.metadata.name, - UID=pod.metadata.uid, - namespace=pod.metadata.namespace, - containers=[ - interlink.ContainerStatus( - name=pod.spec.containers[0].name, - state=interlink.ContainerStates( - running=None, - waiting=None, - terminated=interlink.StateTerminated( - reason="Completed", exitCode=0 - ), - ), - ) - ], - ) - - def Logs(self, req: interlink.LogRequest) -> bytes: - # TODO: manage more complicated multi container pod - # THIS IS ONLY FOR DEMONSTRATION - print(req.pod_uid) - print(self.container_pod_map[req.pod_uid]) - try: - container = self.docker.containers.get( - self.container_pod_map[req.pod_uid][0] - ) - # log = container.logs(timestamps=req.Opts.Timestamps, tail=req.Opts.Tail) - log = container.logs() - print(log) - except: - raise HTTPException(status_code=404, detail="No containers found for UUID") - return log - - -provider_new = MyProvider(docker_client) - - -@app.post("/create") -async def create_pod(pods: List[interlink.Pod]) -> str: - return provider_new.create_pod(pods) - - -@app.post("/delete") -async def delete_pod(pod: interlink.PodRequest) -> str: - return provider_new.delete_pod(pod) - - -@app.get("/status") -async def status_pod(pods: List[interlink.PodRequest]) -> List[interlink.PodStatus]: - return provider_new.get_status(pods) - - -@app.get("/getLogs", response_class=PlainTextResponse) -async def get_logs(req: interlink.LogRequest) -> bytes: - return provider_new.get_logs(req) diff --git a/example/requirements.txt b/example/requirements.txt deleted file mode 100644 index 909e9224..00000000 --- a/example/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -fastapi -pydantic diff --git a/example/setup.py b/example/setup.py deleted file mode 100644 index 45bfc93e..00000000 --- a/example/setup.py +++ /dev/null @@ -1,34 +0,0 @@ -import setuptools - -with open("README.md", "r", encoding = "utf-8") as fh: - long_description = fh.read() - -install_requires = [] -with open("requirements.txt") as f: - for line in f.readlines(): - req = line.strip() - if not req or req.startswith(("-e", "#")): - continue - install_requires.append(req) - -setuptools.setup( - name = "interlink", - version = "0.0.1", - author = "Diego Ciangottini", - author_email = "diego.ciangottini@gmail.com", - description = "interlink provider library", - long_description = long_description, - long_description_content_type = "text/markdown", - url = "package URL", - project_urls = { - }, - classifiers = [ - "Programming Language :: Python :: 3", - "Operating System :: OS Independent", - ], - packages = ["interlink"], - python_requires = ">=3.6", - install_requires = install_requires -) - - diff --git a/example/test_pod.yaml b/example/test_pod.yaml deleted file mode 100644 index 7cf0809b..00000000 --- a/example/test_pod.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: interlink-quickstart - namespace: default -spec: - nodeSelector: - kubernetes.io/hostname: my-civo-node - automountServiceAccountToken: false - containers: - - args: - - "\"600\"" - command: - - sleep - image: "docker://ubuntu" - imagePullPolicy: Always - name: my-container - resources: - limits: - cpu: "1" - memory: 1Gi - requests: - cpu: "1" - memory: 1Gi - tolerations: - - key: virtual-node.interlink/no-schedule - operator: Exists - - effect: NoExecute - key: node.kubernetes.io/not-ready - operator: Exists - tolerationSeconds: 300 - - effect: NoExecute - key: node.kubernetes.io/unreachable - operator: Exists - tolerationSeconds: 300 -