mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-08-07 15:26:26 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64f7e7f7fd | |||
| 3a14896555 | |||
| b57bafd310 | |||
| 9e6fb31d90 | |||
| 2b760ec207 | |||
| 2e612a2867 | |||
| f2f57ac413 | |||
| d50a6fcfda | |||
| d323fd3b7e | |||
| 35c2a9e92a | |||
| 5c406743e0 | |||
| b6f116474d | |||
| 3e3e02f132 | |||
| 4b38ac09dd | |||
| 1a322f8ecb | |||
| 8c2caec395 | |||
| de60358c02 | |||
| 997fb3bf48 | |||
| 722b463b6a | |||
| 938dd6cb78 | |||
| e86860b9ea | |||
| e2fb7ea88d | |||
| 6d0100c096 | |||
| 8975e28437 | |||
| 3e2be03047 | |||
| 046b549079 | |||
| 6f42135ec0 | |||
| e5c8243f5f | |||
| 8be6129889 | |||
| f2567830b3 | |||
| 55c19ca6b5 | |||
| 0c77167be1 | |||
| 34c3bbdbd8 | |||
| 55afe4c038 | |||
| 2bb3b5650a | |||
| b4a49fb56c | |||
| c25cfec84c | |||
| cca75fc5cc |
@@ -1,5 +1,3 @@
|
||||
# Docker: Environment variables in Compose
|
||||
|
||||
## Jaeger
|
||||
COCOS_JAEGER_PORT=6831
|
||||
COCOS_JAEGER_FRONTEND=16686
|
||||
@@ -8,9 +6,6 @@ COCOS_JAEGER_CONFIGS=5778
|
||||
COCOS_JAEGER_URL=http://jaeger:14268/api/traces
|
||||
COCOS_JAEGER_TRACE_RATIO=1.0
|
||||
|
||||
## Notification Server
|
||||
COCOS_NOTIFICATION_SERVER_URL="http://localhost:9000"
|
||||
|
||||
## Core Services
|
||||
|
||||
### Manager
|
||||
@@ -0,0 +1,49 @@
|
||||
name: Bug Report
|
||||
description: File a bug/issue report. Make sure to search to see if an issue already exists for the bug you encountered.
|
||||
title: "Bug: <title>"
|
||||
labels: ["bug", "needs-review", "help wanted"]
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What were you trying to achieve?
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What are the expected results?
|
||||
description: A concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What are the received results?
|
||||
description: A concise description of what you received.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
description: What are the steps to reproduce the issue?
|
||||
placeholder: |
|
||||
1. In this environment...
|
||||
2. With this config...
|
||||
3. Run '...'
|
||||
4. See error...
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: In what environment did you encounter the issue?
|
||||
description: A concise description of the environment you encountered the issue in.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information you deem important
|
||||
description: |
|
||||
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,36 @@
|
||||
name: Feature Request
|
||||
description: File a feature request. Make sure to search to see if a request already exists for the feature you are requesting.
|
||||
title: "Feature: <title>"
|
||||
labels: ["enchancement", "needs-review"]
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the feature you are requesting, as well as the possible use case(s) for it.
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Indicate the importance of this feature to you.
|
||||
description: This will help us prioritize the feature request.
|
||||
options:
|
||||
- Must-have
|
||||
- Should-have
|
||||
- Nice-to-have
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Anything that will give us more context about the feature that you are requesting.
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
|
||||
Pull request title should be `COCOS-XXX - description` or `NOISSUE - description` where XXX is ID of the issue that this PR relate to.
|
||||
Please review the [CONTRIBUTING.md](https://github.com/ultravioletrs/cocos/blob/master/CONTRIBUTING.md) file for detailed contributing guidelines.
|
||||
|
||||
For Work In Progress Pull Requests, please use the Draft PR feature, see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.
|
||||
|
||||
For a timely review/response, please avoid force-pushing additional commits if your PR already received reviews or comments.
|
||||
|
||||
- Provide tests for your changes.
|
||||
- Use descriptive commit messages.
|
||||
- Comment your code where appropriate.
|
||||
- Squash your commits
|
||||
- Update any related documentation.
|
||||
-->
|
||||
|
||||
# What type of PR is this?
|
||||
|
||||
<!--This represents the type of PR you are submitting.
|
||||
|
||||
For example:
|
||||
This is a bug fix because it fixes the following issue: #1234
|
||||
This is a feature because it adds the following functionality: ...
|
||||
This is a refactor because it changes the following functionality: ...
|
||||
This is a documentation update because it updates the following documentation: ...
|
||||
This is a dependency update because it updates the following dependencies: ...
|
||||
This is an optimization because it improves the following functionality: ...
|
||||
-->
|
||||
|
||||
## What does this do?
|
||||
|
||||
<!--
|
||||
Please provide a brief description of what this PR is intended to do.
|
||||
Include List any changes that modify/break current functionality.
|
||||
-->
|
||||
|
||||
## Which issue(s) does this PR fix/relate to?
|
||||
|
||||
<!--
|
||||
For pull requests that relate or close an issue, please include them below. We like to follow [Github's guidance on linking issues to pull requests](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
|
||||
|
||||
For example having the text: "Resolves #1234" would connect the current pull request to issue 1234. And when we merge the pull request, Github will automatically close the issue.
|
||||
-->
|
||||
|
||||
- Related Issue #
|
||||
- Resolves #
|
||||
|
||||
## Have you included tests for your changes?
|
||||
|
||||
<!--If you have not included tests, please explain why.
|
||||
For example:
|
||||
Yes, I have included tests for my changes.
|
||||
No, I have not included tests because I do not know how to.
|
||||
-->
|
||||
|
||||
## Did you document any new/modified feature?
|
||||
|
||||
<!--If you have not included documentation, please explain why.
|
||||
For example:
|
||||
Yes, I have updated the documentation for the new feature.
|
||||
No, I have not updated the documentation because I do not know how to.
|
||||
-->
|
||||
|
||||
### Notes
|
||||
|
||||
<!--Please provide any additional information you feel is important.-->
|
||||
@@ -1,41 +0,0 @@
|
||||
# Copyright (c) Ultraviolet
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: Create and publish a Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- 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 Manager and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: true
|
||||
build-args: |
|
||||
SVC=manager
|
||||
tags: ghcr.io/ultravioletrs/cocos/manager:latest
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- main
|
||||
paths:
|
||||
- "manager/manager.proto"
|
||||
- "manager/*.pb.go"
|
||||
- "pkg/manager/*.pb.go"
|
||||
- "agent/agent.proto"
|
||||
- "agent/*.pb.go"
|
||||
pull_request:
|
||||
@@ -14,7 +14,7 @@ on:
|
||||
- main
|
||||
paths:
|
||||
- "manager/manager.proto"
|
||||
- "manager/*.pb.go"
|
||||
- "pkg/manager/*.pb.go"
|
||||
- "agent/agent.proto"
|
||||
- "agent/*.pb.go"
|
||||
|
||||
@@ -24,17 +24,17 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- name: Set up protoc
|
||||
run: |
|
||||
PROTOC_VERSION=25.1
|
||||
PROTOC_GEN_VERSION=v1.31.0
|
||||
PROTOC_VERSION=25.3
|
||||
PROTOC_GEN_VERSION=v1.33.0
|
||||
PROTOC_GRPC_VERSION=v1.3.0
|
||||
|
||||
# Download and install protoc
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
- name: Set up Cocos-AI
|
||||
run: |
|
||||
# Rename .pb.go files to .pb.go.tmp to prevent conflicts
|
||||
for p in $(ls manager/*.pb.go); do
|
||||
for p in $(ls pkg/manager/*.pb.go); do
|
||||
mv $p $p.tmp
|
||||
done
|
||||
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
make protoc
|
||||
|
||||
# Compare generated Go files with the original ones
|
||||
for p in $(ls manager/*.pb.go); do
|
||||
for p in $(ls pkg/manager/*.pb.go); do
|
||||
if ! cmp -s $p $p.tmp; then
|
||||
echo "Proto file and generated Go file $p are out of sync!"
|
||||
exit 1
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Update Ubuntu
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade -y
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Checkout cocos
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'ultravioletrs/cocos'
|
||||
path: cocos
|
||||
|
||||
- name: Checkout buildroot
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'buildroot/buildroot'
|
||||
path: buildroot
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd buildroot
|
||||
make BR2_EXTERNAL=../cocos/hal/linux cocos_defconfig
|
||||
make
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-kernel
|
||||
uses: actions/upload-release-asset@latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./buildroot/output/images/bzImage
|
||||
asset_name: bzImage
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-rootfs
|
||||
uses: actions/upload-release-asset@latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./buildroot/output/images/rootfs.cpio.gz
|
||||
asset_name: rootfs.cpio.gz
|
||||
asset_content_type: application/gzip
|
||||
@@ -14,10 +14,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# Contributing to CoCos
|
||||
|
||||
The following is a set of guidelines to contribute to CoCos and its libraries, which are
|
||||
hosted on the [Ultraviolet Organization](https://github.com/ultravioletrs) on GitHub.
|
||||
|
||||
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to
|
||||
[abuse@ultraviolet.rs](mailto:abuse@ultraviolet.rs).
|
||||
|
||||
## Reporting issues
|
||||
|
||||
Reporting issues are a great way to contribute to the project. We are perpetually grateful about a well-written,
|
||||
thorough bug report.
|
||||
|
||||
Before raising a new issue, check [our issue
|
||||
list](https://github.com/ultravioletrs/cocos/issues) to determine if it already contains the
|
||||
problem that you are facing.
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you for more information. Please be as detailed as possible. The following questions might serve as a template for writing a detailed
|
||||
report:
|
||||
|
||||
- What were you trying to achieve?
|
||||
- What are the expected results?
|
||||
- What are the received results?
|
||||
- What are the steps to reproduce the issue?
|
||||
- In what environment did you encounter the issue?
|
||||
|
||||
## Pull requests
|
||||
|
||||
Good pull requests (e.g. patches, improvements, new features) are a fantastic help. They should
|
||||
remain focused in scope and avoid unrelated commits.
|
||||
|
||||
**Please ask first** before embarking on any significant pull request (e.g. implementing new features,
|
||||
refactoring code etc.), otherwise you risk spending a lot of time working on something that the
|
||||
maintainers might not want to merge into the project.
|
||||
|
||||
Please adhere to the coding conventions used throughout the project. If in doubt, consult the
|
||||
[Effective Go](https://golang.org/doc/effective_go.html) style guide.
|
||||
|
||||
To contribute to the project, [fork](https://help.github.com/articles/fork-a-repo/) it,
|
||||
clone your fork repository, and configure the remotes:
|
||||
|
||||
```
|
||||
git clone https://github.com/<your-username>/cocos.git
|
||||
cd cocos
|
||||
git remote add upstream https://github.com/ultravioletrs/cocos.git
|
||||
```
|
||||
|
||||
If your cloned repository is behind the upstream commits, then get the latest changes from upstream:
|
||||
|
||||
```
|
||||
git checkout master
|
||||
git pull --rebase upstream main
|
||||
```
|
||||
|
||||
Create a new topic branch from `master` using the naming convention `COCOS-[issue-number]`
|
||||
to help us keep track of your contribution scope:
|
||||
|
||||
```
|
||||
git checkout -b COCOS-[issue-number]
|
||||
```
|
||||
|
||||
Commit your changes in logical chunks. When you are ready to commit, make sure
|
||||
to write a Good Commit Message™. Consult the [Erlang's contributing guide](https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
|
||||
if you're unsure of what constitutes a Good Commit Message™. Use [interactive rebase](https://help.github.com/articles/about-git-rebase)
|
||||
to group your commits into logical units of work before making it public.
|
||||
|
||||
Note that every commit you make must be signed. By signing off your work you indicate that you
|
||||
are accepting the [Developer Certificate of Origin](https://developercertificate.org/).
|
||||
|
||||
Use your real name (sorry, no pseudonyms or anonymous contributions). If you set your `user.name`
|
||||
and `user.email` git configs, you can sign your commit automatically with `git commit -s`.
|
||||
|
||||
Locally merge (or rebase) the upstream development branch into your topic branch:
|
||||
|
||||
```
|
||||
git pull --rebase upstream main
|
||||
```
|
||||
|
||||
Push your topic branch up to your fork:
|
||||
|
||||
```
|
||||
git push origin COCOS-[issue-number]
|
||||
```
|
||||
|
||||
[Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title
|
||||
and detailed description.
|
||||
@@ -5,13 +5,6 @@ GOARCH ?= amd64
|
||||
VERSION ?= $(shell git describe --abbrev=0 --tags --always)
|
||||
COMMIT ?= $(shell git rev-parse HEAD)
|
||||
TIME ?= $(shell date +%F_%T)
|
||||
CLI_SOURCE = ./cmd/cli/main.go
|
||||
CLI_BIN = ${BUILD_DIR}/cocos-cli
|
||||
DOCKERS = $(addprefix docker_,$(SERVICES))
|
||||
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
|
||||
COCOS_DOCKER_IMAGE_NAME_PREFIX=ghcr.io/ultravioletrs/cocos/
|
||||
|
||||
USER_REPO ?= $(shell git remote get-url origin | sed -e 's/.*\/\([^/]*\)\/\([^/]*\).*/\1_\2/' )
|
||||
empty:=
|
||||
space:= $(empty) $(empty)
|
||||
|
||||
@@ -24,54 +17,13 @@ define compile_service
|
||||
-o ${BUILD_DIR}/cocos-$(1) cmd/$(1)/main.go
|
||||
endef
|
||||
|
||||
define make_docker
|
||||
$(eval svc=$(subst docker_,,$(1)))
|
||||
|
||||
docker build \
|
||||
--no-cache \
|
||||
--build-arg SVC=$(svc) \
|
||||
--build-arg GOARCH=$(GOARCH) \
|
||||
--build-arg GOARM=$(GOARM) \
|
||||
--build-arg VERSION=$(VERSION) \
|
||||
--build-arg COMMIT=$(COMMIT) \
|
||||
--build-arg TIME=$(TIME) \
|
||||
--tag=$(COCOS_DOCKER_IMAGE_NAME_PREFIX)$(svc) \
|
||||
-f docker/Dockerfile .
|
||||
endef
|
||||
|
||||
define make_docker_dev
|
||||
$(eval svc=$(subst docker_dev_,,$(1)))
|
||||
|
||||
docker build \
|
||||
--no-cache \
|
||||
--build-arg SVC=$(svc) \
|
||||
--tag=$(COCOS_DOCKER_IMAGE_NAME_PREFIX)$(svc) \
|
||||
-f docker/Dockerfile.dev ./build
|
||||
endef
|
||||
|
||||
.PHONY: all $(SERVICES) dockers dockers_dev
|
||||
.PHONY: all $(SERVICES)
|
||||
|
||||
all: $(SERVICES)
|
||||
|
||||
$(DOCKERS):
|
||||
$(call make_docker,$(@),$(GOARCH))
|
||||
|
||||
$(DOCKERS_DEV):
|
||||
$(call make_docker_dev,$(@))
|
||||
|
||||
dockers: $(DOCKERS)
|
||||
dockers_dev: $(DOCKERS_DEV)
|
||||
|
||||
$(SERVICES):
|
||||
$(call compile_service,$(@))
|
||||
|
||||
|
||||
install-cli: cli
|
||||
cp ${CLI_BIN} ~/.local/bin/cocos-cli
|
||||
|
||||
protoc:
|
||||
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative agent/agent.proto
|
||||
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative manager/manager.proto
|
||||
|
||||
run:
|
||||
docker compose -f docker/docker-compose.yml -p cocos up
|
||||
protoc -I. --go_out=./pkg --go_opt=paths=source_relative --go-grpc_out=./pkg --go-grpc_opt=paths=source_relative manager/manager.proto
|
||||
|
||||
@@ -12,54 +12,50 @@ Data is always encrypted, protected by hardware secure enclaves (Trusted Executi
|
||||
attested via secure remote attestation protocols, and invisible to cloud processors or any other
|
||||
3rd party to which computation is offloaded.
|
||||
|
||||
## Install
|
||||
The following prerequisites are needed to run Cocos:
|
||||
## Features
|
||||
|
||||
- [Docker](https://docs.docker.com/install/)
|
||||
- [Docker compose](https://docs.docker.com/compose/install/)
|
||||
Cocos AI is implementing the following features:
|
||||
|
||||
### Build Docker Images
|
||||
Currenty, there is no Docker registry, so Cocos images must be built by hand:
|
||||
```
|
||||
make dockers
|
||||
```
|
||||
|
||||
For this you might be needing to setup DNS servers in your `/etc/resolf.conf` as explained
|
||||
[here](https://github.com/docker/cli/issues/2618) (i.e. add Google's `nameserver 8.8.8.8`).
|
||||
|
||||
### Run Composition
|
||||
|
||||
Once the images are built (`docker images` command should show you `ghcr.io/ultravioletrs/cocos/manager`),
|
||||
composition can be run:
|
||||
|
||||
```bash
|
||||
make run
|
||||
```
|
||||
|
||||
This will bring up the Cocos docker services and interconnect them.
|
||||
- TEE enablement, deployment and monitoring (secure VM manager)
|
||||
- HAL for TEEs based on hardened Linux kernel, secure bootloader and custom-tailored embedded rootfs for minimal TCB
|
||||
- In-enclave agent, netowrking controller and other system software
|
||||
- Encrypted asynchronous data transfer and result delivery
|
||||
- API for programmable platform manipulation
|
||||
- HW and SW supported attestation with verification tools
|
||||
- CLI for system interaction
|
||||
|
||||
## Usage
|
||||
|
||||
The quickest way to start using Cocos is via the CLI. The latest version can be downloaded from the [official releases page][rel].
|
||||
|
||||
It can also be built and used from the project's root directory:
|
||||
Clone the repo and create binaries:
|
||||
|
||||
```bash
|
||||
make cli
|
||||
./build/cocos-cli version
|
||||
git clone git@github.com:ultravioletrs/cocos.git
|
||||
make
|
||||
```
|
||||
|
||||
Additional details on using the CLI can be found in the [CLI documentation](https://docs.cocos.ai/cli).
|
||||
This will create 3 binaries:
|
||||
```bash
|
||||
ls build/
|
||||
# cocos-agent cocos-cli cocos-manager
|
||||
```
|
||||
|
||||
- Manager can be deployed on the AMD SEV-SNP host
|
||||
- Agent can be built into [EOS][eos]-based HAL
|
||||
- CLI can be used to communicate to remote Agent.
|
||||
|
||||
## Documentation
|
||||
|
||||
Official documentation is hosted at [Cocos official docs page][docs]. Documentation is auto-generated, checkout the instructions on [official docs repository](https://github.com/ultravioletrs/docs).
|
||||
Project documentation is hosted at [Cocos AI official docs page][docs].
|
||||
|
||||
Documentation is generated from the [docs repository](https://github.com/ultravioletrs/docs).
|
||||
|
||||
## License
|
||||
Cocos AI is a proprietary product created by Ultraviolet company.
|
||||
Cocos AI is published under permissive open-source [Apache-2.0](LICENSE) license.
|
||||
|
||||
[cc]: https://confidentialcomputing.io/white-papers-reports/
|
||||
[cocos]: https://cocos.ai/
|
||||
[rel]: https://github.com/ultraviolet/cocos/releases
|
||||
[rel]: https://github.com/ultravioletrs/cocos/releases
|
||||
[tee]: https://en.wikipedia.org/wiki/Trusted_execution_environment
|
||||
|
||||
[docs]: https://docs.cocos.ultraviolet.rs
|
||||
[cli]: https://docs.cocos.ultraviolet.rs/cli
|
||||
[eos]: https://github.com/ultravioletrs/eos
|
||||
|
||||
+7
-10
@@ -9,15 +9,12 @@ The service is configured using the environment variables from the following tab
|
||||
| Variable | Description | Default |
|
||||
| ----------------------------- | ------------------------------------------------------ | ------------------------------ |
|
||||
| AGENT_LOG_LEVEL | Log level for agent service (debug, info, warn, error) | info |
|
||||
| AGENT_HTTP_HOST | Agent service HTTP host | "" |
|
||||
| AGENT_HTTP_PORT | Agent service HTTP port | 9031 |
|
||||
| AGENT_HTTP_SERVER_CERT | Path to HTTP server certificate in pem format | "" |
|
||||
| AGENT_HTTP_SERVER_KEY | Path to HTTP server key in pem format | "" |
|
||||
| AGENT_GRPC_HOST | Agent service gRPC host | "" |
|
||||
| AGENT_GRPC_PORT | Agent service gRPC port | 7002 |
|
||||
| AGENT_GRPC_SERVER_CERT | Path to gRPC server certificate in pem format | "" |
|
||||
| AGENT_GRPC_SERVER_KEY | Path to gRPC server key in pem format | "" |
|
||||
| COCOS_NOTIFICATION_SERVER_URL | Server to receive notification events from agent. | http:/localhost:9000 |
|
||||
| AGENT_GRPC_SERVER_CA_CERTS | Path to gRPC server CA certificate | "" |
|
||||
| AGENT_GRPC_CLIENT_CA_CERTS | Path to gRPC client CA certificate | "" |
|
||||
|
||||
|
||||
## Deployment
|
||||
@@ -25,15 +22,15 @@ The service is configured using the environment variables from the following tab
|
||||
To start the service outside of the container, execute the following shell script:
|
||||
|
||||
```bash
|
||||
# download the latest version of the service
|
||||
go get github.com/ultravioletrs/cocos
|
||||
# Download the latest version of the service
|
||||
git clone git@github.com:ultravioletrs/cocos.git
|
||||
|
||||
cd $GOPATH/src/github.com/ultravioletrs/cocos
|
||||
cd cocos
|
||||
|
||||
# compile the agent
|
||||
# Compile the service
|
||||
make agent
|
||||
|
||||
# set the environment variables and run the service
|
||||
# Run the service
|
||||
./build/cocos-agent
|
||||
```
|
||||
|
||||
|
||||
+57
-328
@@ -3,8 +3,8 @@
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v4.25.1
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.25.3
|
||||
// source: agent/agent.proto
|
||||
|
||||
package agent
|
||||
@@ -90,8 +90,6 @@ type AlgoResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AlgorithmID string `protobuf:"bytes,1,opt,name=algorithmID,proto3" json:"algorithmID,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AlgoResponse) Reset() {
|
||||
@@ -126,13 +124,6 @@ func (*AlgoResponse) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *AlgoResponse) GetAlgorithmID() string {
|
||||
if x != nil {
|
||||
return x.AlgorithmID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type DataRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -200,8 +191,6 @@ type DataResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
DatasetID string `protobuf:"bytes,1,opt,name=datasetID,proto3" json:"datasetID,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DataResponse) Reset() {
|
||||
@@ -236,13 +225,6 @@ func (*DataResponse) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *DataResponse) GetDatasetID() string {
|
||||
if x != nil {
|
||||
return x.DatasetID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ResultRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -341,6 +323,8 @@ type AttestationRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ReportData []byte `protobuf:"bytes,1,opt,name=report_data,json=reportData,proto3" json:"report_data,omitempty"` // Should be of length 64.
|
||||
}
|
||||
|
||||
func (x *AttestationRequest) Reset() {
|
||||
@@ -375,6 +359,13 @@ func (*AttestationRequest) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *AttestationRequest) GetReportData() []byte {
|
||||
if x != nil {
|
||||
return x.ReportData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttestationResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -422,203 +413,6 @@ func (x *AttestationResponse) GetFile() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ComputationReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
|
||||
Datasets []*DatasetReq `protobuf:"bytes,4,rep,name=datasets,proto3" json:"datasets,omitempty"`
|
||||
Algorithms []*AlgorithmReq `protobuf:"bytes,5,rep,name=algorithms,proto3" json:"algorithms,omitempty"`
|
||||
ResultConsumers []string `protobuf:"bytes,6,rep,name=result_consumers,json=resultConsumers,proto3" json:"result_consumers,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ComputationReq) Reset() {
|
||||
*x = ComputationReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ComputationReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ComputationReq) ProtoMessage() {}
|
||||
|
||||
func (x *ComputationReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ComputationReq.ProtoReflect.Descriptor instead.
|
||||
func (*ComputationReq) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *ComputationReq) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ComputationReq) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ComputationReq) GetDescription() string {
|
||||
if x != nil {
|
||||
return x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ComputationReq) GetDatasets() []*DatasetReq {
|
||||
if x != nil {
|
||||
return x.Datasets
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ComputationReq) GetAlgorithms() []*AlgorithmReq {
|
||||
if x != nil {
|
||||
return x.Algorithms
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ComputationReq) GetResultConsumers() []string {
|
||||
if x != nil {
|
||||
return x.ResultConsumers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DatasetReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DatasetReq) Reset() {
|
||||
*x = DatasetReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DatasetReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DatasetReq) ProtoMessage() {}
|
||||
|
||||
func (x *DatasetReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DatasetReq.ProtoReflect.Descriptor instead.
|
||||
func (*DatasetReq) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *DatasetReq) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DatasetReq) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AlgorithmReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AlgorithmReq) Reset() {
|
||||
*x = AlgorithmReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AlgorithmReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AlgorithmReq) ProtoMessage() {}
|
||||
|
||||
func (x *AlgorithmReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_proto_msgTypes[10]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AlgorithmReq.ProtoReflect.Descriptor instead.
|
||||
func (*AlgorithmReq) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *AlgorithmReq) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AlgorithmReq) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_agent_agent_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_agent_agent_proto_rawDesc = []byte{
|
||||
@@ -629,66 +423,42 @@ var file_agent_agent_proto_rawDesc = []byte{
|
||||
0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69,
|
||||
0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69,
|
||||
0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x02, 0x69, 0x64, 0x22, 0x30, 0x0a, 0x0c, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d,
|
||||
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69,
|
||||
0x74, 0x68, 0x6d, 0x49, 0x44, 0x22, 0x53, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2c, 0x0a, 0x0c, 0x44, 0x61,
|
||||
0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x61,
|
||||
0x74, 0x61, 0x73, 0x65, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64,
|
||||
0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x49, 0x44, 0x22, 0x2b, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x75,
|
||||
0x02, 0x69, 0x64, 0x22, 0x0e, 0x0a, 0x0c, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x53, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x0e, 0x0a, 0x0c, 0x44, 0x61, 0x74, 0x61,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x75,
|
||||
0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e,
|
||||
0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e,
|
||||
0x73, 0x75, 0x6d, 0x65, 0x72, 0x22, 0x24, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x41,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x35, 0x0a, 0x12, 0x41,
|
||||
0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x22, 0x29, 0x0a, 0x13, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22, 0xe5, 0x01, 0x0a,
|
||||
0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
|
||||
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74,
|
||||
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e,
|
||||
0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61,
|
||||
0x73, 0x65, 0x74, 0x73, 0x12, 0x33, 0x0a, 0x0a, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68,
|
||||
0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74,
|
||||
0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x52, 0x65, 0x71, 0x52, 0x0a, 0x61,
|
||||
0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73,
|
||||
0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x75,
|
||||
0x6d, 0x65, 0x72, 0x73, 0x22, 0x38, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x52,
|
||||
0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e,
|
||||
0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3a,
|
||||
0x0a, 0x0c, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x52, 0x65, 0x71, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0xf5, 0x01, 0x0a, 0x0c, 0x41,
|
||||
0x67, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x41,
|
||||
0x6c, 0x67, 0x6f, 0x12, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6c, 0x67, 0x6f,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e,
|
||||
0x41, 0x6c, 0x67, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31,
|
||||
0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x44,
|
||||
0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65,
|
||||
0x6e, 0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x37, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x67,
|
||||
0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x15, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x41, 0x74,
|
||||
0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x67, 0x65, 0x6e,
|
||||
0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74,
|
||||
0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x61,
|
||||
0x74, 0x61, 0x22, 0x29, 0x0a, 0x13, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c,
|
||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x32, 0xf5, 0x01,
|
||||
0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31,
|
||||
0x0a, 0x04, 0x41, 0x6c, 0x67, 0x6f, 0x12, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41,
|
||||
0x6c, 0x67, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65,
|
||||
0x6e, 0x74, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x31, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e,
|
||||
0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e,
|
||||
0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14,
|
||||
0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73,
|
||||
0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a,
|
||||
0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61,
|
||||
0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e,
|
||||
0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -703,7 +473,7 @@ func file_agent_agent_proto_rawDescGZIP() []byte {
|
||||
return file_agent_agent_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_agent_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
|
||||
var file_agent_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||
var file_agent_agent_proto_goTypes = []interface{}{
|
||||
(*AlgoRequest)(nil), // 0: agent.AlgoRequest
|
||||
(*AlgoResponse)(nil), // 1: agent.AlgoResponse
|
||||
@@ -713,26 +483,21 @@ var file_agent_agent_proto_goTypes = []interface{}{
|
||||
(*ResultResponse)(nil), // 5: agent.ResultResponse
|
||||
(*AttestationRequest)(nil), // 6: agent.AttestationRequest
|
||||
(*AttestationResponse)(nil), // 7: agent.AttestationResponse
|
||||
(*ComputationReq)(nil), // 8: agent.ComputationReq
|
||||
(*DatasetReq)(nil), // 9: agent.DatasetReq
|
||||
(*AlgorithmReq)(nil), // 10: agent.AlgorithmReq
|
||||
}
|
||||
var file_agent_agent_proto_depIdxs = []int32{
|
||||
9, // 0: agent.ComputationReq.datasets:type_name -> agent.DatasetReq
|
||||
10, // 1: agent.ComputationReq.algorithms:type_name -> agent.AlgorithmReq
|
||||
0, // 2: agent.AgentService.Algo:input_type -> agent.AlgoRequest
|
||||
2, // 3: agent.AgentService.Data:input_type -> agent.DataRequest
|
||||
4, // 4: agent.AgentService.Result:input_type -> agent.ResultRequest
|
||||
6, // 5: agent.AgentService.Attestation:input_type -> agent.AttestationRequest
|
||||
1, // 6: agent.AgentService.Algo:output_type -> agent.AlgoResponse
|
||||
3, // 7: agent.AgentService.Data:output_type -> agent.DataResponse
|
||||
5, // 8: agent.AgentService.Result:output_type -> agent.ResultResponse
|
||||
7, // 9: agent.AgentService.Attestation:output_type -> agent.AttestationResponse
|
||||
6, // [6:10] is the sub-list for method output_type
|
||||
2, // [2:6] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
0, // 0: agent.AgentService.Algo:input_type -> agent.AlgoRequest
|
||||
2, // 1: agent.AgentService.Data:input_type -> agent.DataRequest
|
||||
4, // 2: agent.AgentService.Result:input_type -> agent.ResultRequest
|
||||
6, // 3: agent.AgentService.Attestation:input_type -> agent.AttestationRequest
|
||||
1, // 4: agent.AgentService.Algo:output_type -> agent.AlgoResponse
|
||||
3, // 5: agent.AgentService.Data:output_type -> agent.DataResponse
|
||||
5, // 6: agent.AgentService.Result:output_type -> agent.ResultResponse
|
||||
7, // 7: agent.AgentService.Attestation:output_type -> agent.AttestationResponse
|
||||
4, // [4:8] is the sub-list for method output_type
|
||||
0, // [0:4] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_agent_agent_proto_init() }
|
||||
@@ -837,42 +602,6 @@ func file_agent_agent_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ComputationReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DatasetReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AlgorithmReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -880,7 +609,7 @@ func file_agent_agent_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_agent_agent_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 11,
|
||||
NumMessages: 8,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
+8
-21
@@ -20,7 +20,7 @@ message AlgoRequest {
|
||||
string id = 3;
|
||||
}
|
||||
|
||||
message AlgoResponse { string algorithmID = 1; }
|
||||
message AlgoResponse {}
|
||||
|
||||
message DataRequest {
|
||||
bytes dataset = 1;
|
||||
@@ -28,33 +28,20 @@ message DataRequest {
|
||||
string id = 3;
|
||||
}
|
||||
|
||||
message DataResponse { string datasetID = 1; }
|
||||
message DataResponse {}
|
||||
|
||||
message ResultRequest {
|
||||
string consumer = 1;
|
||||
}
|
||||
|
||||
message ResultResponse { bytes file = 1; }
|
||||
|
||||
message AttestationRequest { }
|
||||
|
||||
message AttestationResponse { bytes file = 1; }
|
||||
|
||||
message ComputationReq {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string description = 3;
|
||||
repeated DatasetReq datasets = 4;
|
||||
repeated AlgorithmReq algorithms = 5;
|
||||
repeated string result_consumers = 6;
|
||||
message ResultResponse {
|
||||
bytes file = 1;
|
||||
}
|
||||
|
||||
message DatasetReq {
|
||||
string provider = 1;
|
||||
string id = 2;
|
||||
message AttestationRequest {
|
||||
bytes report_data = 1; // Should be of length 64.
|
||||
}
|
||||
|
||||
message AlgorithmReq {
|
||||
string provider = 1;
|
||||
string id = 2;
|
||||
message AttestationResponse {
|
||||
bytes file = 1;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v4.25.1
|
||||
// - protoc v4.25.3
|
||||
// source: agent/agent.proto
|
||||
|
||||
package agent
|
||||
|
||||
+14
-17
@@ -80,14 +80,12 @@ func encodeAlgoRequest(_ context.Context, request interface{}) (interface{}, err
|
||||
// decodeAlgoResponse is a transport/grpc.DecodeResponseFunc that
|
||||
// converts a gRPC AlgoResponse to a user-domain response.
|
||||
func decodeAlgoResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
|
||||
response, ok := grpcResponse.(*agent.AlgoResponse)
|
||||
_, ok := grpcResponse.(*agent.AlgoResponse)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
|
||||
}
|
||||
|
||||
return algoRes{
|
||||
AlgorithmID: response.AlgorithmID,
|
||||
}, nil
|
||||
return algoRes{}, nil
|
||||
}
|
||||
|
||||
// encodeDataRequest is a transport/grpc.EncodeRequestFunc that
|
||||
@@ -108,14 +106,12 @@ func encodeDataRequest(_ context.Context, request interface{}) (interface{}, err
|
||||
// decodeDataResponse is a transport/grpc.DecodeResponseFunc that
|
||||
// converts a gRPC DataResponse to a user-domain response.
|
||||
func decodeDataResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
|
||||
response, ok := grpcResponse.(*agent.DataResponse)
|
||||
_, ok := grpcResponse.(*agent.DataResponse)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
|
||||
}
|
||||
|
||||
return dataRes{
|
||||
DatasetID: response.DatasetID,
|
||||
}, nil
|
||||
return dataRes{}, nil
|
||||
}
|
||||
|
||||
// encodeResultRequest is a transport/grpc.EncodeRequestFunc that
|
||||
@@ -147,8 +143,11 @@ func decodeResultResponse(_ context.Context, grpcResponse interface{}) (interfac
|
||||
// encodeAttestationRequest is a transport/grpc.EncodeRequestFunc that
|
||||
// converts a user-domain attestationReq to a gRPC request.
|
||||
func encodeAttestationRequest(_ context.Context, request interface{}) (interface{}, error) {
|
||||
// No request parameters needed for retrieving computation result file.
|
||||
return &agent.AttestationRequest{}, nil
|
||||
req, ok := request.(*attestationReq)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid request type: %T", request)
|
||||
}
|
||||
return &agent.AttestationRequest{ReportData: req.ReportData[:]}, nil
|
||||
}
|
||||
|
||||
// decodeAttestationResponse is a transport/grpc.DecodeResponseFunc that
|
||||
@@ -169,13 +168,12 @@ func (c grpcClient) Algo(ctx context.Context, request *agent.AlgoRequest, _ ...g
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := c.algo(ctx, &algoReq{Algorithm: request.Algorithm, Provider: request.Provider, Id: request.Id})
|
||||
_, err := c.algo(ctx, &algoReq{Algorithm: request.Algorithm, Provider: request.Provider, Id: request.Id})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
algoRes := res.(algoRes)
|
||||
return &agent.AlgoResponse{AlgorithmID: algoRes.AlgorithmID}, nil
|
||||
return &agent.AlgoResponse{}, nil
|
||||
}
|
||||
|
||||
// Data implements the Data method of the agent.AgentServiceClient interface.
|
||||
@@ -183,13 +181,12 @@ func (c grpcClient) Data(ctx context.Context, request *agent.DataRequest, _ ...g
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := c.data(ctx, &dataReq{Dataset: request.Dataset, Provider: request.Provider, Id: request.Id})
|
||||
_, err := c.data(ctx, &dataReq{Dataset: request.Dataset, Provider: request.Provider, Id: request.Id})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dataRes := res.(dataRes)
|
||||
return &agent.DataResponse{DatasetID: dataRes.DatasetID}, nil
|
||||
return &agent.DataResponse{}, nil
|
||||
}
|
||||
|
||||
// Result implements the Result method of the agent.AgentServiceClient interface.
|
||||
@@ -211,7 +208,7 @@ func (c grpcClient) Attestation(ctx context.Context, request *agent.AttestationR
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := c.attestation(ctx, &attestationReq{})
|
||||
res, err := c.attestation(ctx, &attestationReq{ReportData: [agent.ReportDataSize]byte(request.ReportData)})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ func algoEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
|
||||
algo := agent.Algorithm{Algorithm: req.Algorithm, Provider: req.Provider, ID: req.Id}
|
||||
|
||||
algorithmID, err := svc.Algo(ctx, algo)
|
||||
err := svc.Algo(ctx, algo)
|
||||
if err != nil {
|
||||
return algoRes{}, err
|
||||
}
|
||||
|
||||
return algoRes{AlgorithmID: algorithmID}, nil
|
||||
return algoRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,12 @@ func dataEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
|
||||
dataset := agent.Dataset{Dataset: req.Dataset, Provider: req.Provider, ID: req.Id}
|
||||
|
||||
datasetID, err := svc.Data(ctx, dataset)
|
||||
err := svc.Data(ctx, dataset)
|
||||
if err != nil {
|
||||
return dataRes{}, err
|
||||
}
|
||||
|
||||
return dataRes{DatasetID: datasetID}, nil
|
||||
return dataRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func attestationEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
if err := req.validate(); err != nil {
|
||||
return attestationRes{}, err
|
||||
}
|
||||
file, err := svc.Attestation(ctx)
|
||||
file, err := svc.Attestation(ctx, req.ReportData)
|
||||
if err != nil {
|
||||
return attestationRes{}, err
|
||||
}
|
||||
|
||||
@@ -54,10 +54,9 @@ func (req resultReq) validate() error {
|
||||
}
|
||||
|
||||
type attestationReq struct {
|
||||
// No request parameters needed for retrieving attestation output
|
||||
ReportData [64]byte
|
||||
}
|
||||
|
||||
func (req attestationReq) validate() error {
|
||||
// No request parameters to validate, so no validation logic needed
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,13 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
type algoRes struct {
|
||||
AlgorithmID string `json:"algorithmId,omitempty"`
|
||||
}
|
||||
type algoRes struct{}
|
||||
|
||||
type dataRes struct {
|
||||
DatasetID string `json:"datasetId,omitempty"`
|
||||
}
|
||||
type dataRes struct{}
|
||||
|
||||
type resultRes struct {
|
||||
File []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
|
||||
@@ -4,6 +4,7 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/go-kit/kit/transport/grpc"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
@@ -54,10 +55,7 @@ func decodeAlgoRequest(_ context.Context, grpcReq interface{}) (interface{}, err
|
||||
}
|
||||
|
||||
func encodeAlgoResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
res := response.(algoRes)
|
||||
return &agent.AlgoResponse{
|
||||
AlgorithmID: res.AlgorithmID,
|
||||
}, nil
|
||||
return &agent.AlgoResponse{}, nil
|
||||
}
|
||||
|
||||
func decodeDataRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
@@ -71,10 +69,7 @@ func decodeDataRequest(_ context.Context, grpcReq interface{}) (interface{}, err
|
||||
}
|
||||
|
||||
func encodeDataResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
res := response.(dataRes)
|
||||
return &agent.DataResponse{
|
||||
DatasetID: res.DatasetID,
|
||||
}, nil
|
||||
return &agent.DataResponse{}, nil
|
||||
}
|
||||
|
||||
func decodeResultRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
@@ -90,8 +85,11 @@ func encodeResultResponse(_ context.Context, response interface{}) (interface{},
|
||||
}
|
||||
|
||||
func decodeAttestationRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
// No fields to extract from gRPC request, so returning an empty struct
|
||||
return attestationReq{}, nil
|
||||
req := grpcReq.(*agent.AttestationRequest)
|
||||
if len(req.ReportData) != agent.ReportDataSize {
|
||||
return nil, errors.New("malformed report data, expect 64 bytes")
|
||||
}
|
||||
return attestationReq{ReportData: [agent.ReportDataSize]byte(req.ReportData)}, nil
|
||||
}
|
||||
|
||||
func encodeAttestationResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
|
||||
+7
-20
@@ -9,38 +9,25 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
var _ agent.Service = (*loggingMiddleware)(nil)
|
||||
|
||||
type loggingMiddleware struct {
|
||||
logger mglog.Logger
|
||||
logger *slog.Logger
|
||||
svc agent.Service
|
||||
}
|
||||
|
||||
// LoggingMiddleware adds logging facilities to the core service.
|
||||
func LoggingMiddleware(svc agent.Service, logger mglog.Logger) agent.Service {
|
||||
func LoggingMiddleware(svc agent.Service, logger *slog.Logger) agent.Service {
|
||||
return &loggingMiddleware{logger, svc}
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Run(ctx context.Context, ac agent.Computation) (response string, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method Run for computation %s took %s to complete", ac.ID, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Run(ctx, ac)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Algo(ctx context.Context, algorithm agent.Algorithm) (response string, err error) {
|
||||
func (lm *loggingMiddleware) Algo(ctx context.Context, algorithm agent.Algorithm) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method Algo took %s to complete", time.Since(begin))
|
||||
if err != nil {
|
||||
@@ -53,7 +40,7 @@ func (lm *loggingMiddleware) Algo(ctx context.Context, algorithm agent.Algorithm
|
||||
return lm.svc.Algo(ctx, algorithm)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Data(ctx context.Context, dataset agent.Dataset) (response string, err error) {
|
||||
func (lm *loggingMiddleware) Data(ctx context.Context, dataset agent.Dataset) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method Data took %s to complete", time.Since(begin))
|
||||
if err != nil {
|
||||
@@ -79,7 +66,7 @@ func (lm *loggingMiddleware) Result(ctx context.Context, consumer string) (respo
|
||||
return lm.svc.Result(ctx, consumer)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Attestation(ctx context.Context) (response []byte, err error) {
|
||||
func (lm *loggingMiddleware) Attestation(ctx context.Context, reportData [agent.ReportDataSize]byte) (response []byte, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method Attestation took %s to complete", time.Since(begin))
|
||||
if err != nil {
|
||||
@@ -89,5 +76,5 @@ func (lm *loggingMiddleware) Attestation(ctx context.Context) (response []byte,
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Attestation(ctx)
|
||||
return lm.svc.Attestation(ctx, reportData)
|
||||
}
|
||||
|
||||
+4
-13
@@ -32,16 +32,7 @@ func MetricsMiddleware(svc agent.Service, counter metrics.Counter, latency metri
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Run(ctx context.Context, ac agent.Computation) (string, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "run").Add(1)
|
||||
ms.latency.With("method", "run").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Run(ctx, ac)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Algo(ctx context.Context, algorithm agent.Algorithm) (string, error) {
|
||||
func (ms *metricsMiddleware) Algo(ctx context.Context, algorithm agent.Algorithm) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "algo").Add(1)
|
||||
ms.latency.With("method", "algo").Observe(time.Since(begin).Seconds())
|
||||
@@ -50,7 +41,7 @@ func (ms *metricsMiddleware) Algo(ctx context.Context, algorithm agent.Algorithm
|
||||
return ms.svc.Algo(ctx, algorithm)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Data(ctx context.Context, dataset agent.Dataset) (string, error) {
|
||||
func (ms *metricsMiddleware) Data(ctx context.Context, dataset agent.Dataset) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "data").Add(1)
|
||||
ms.latency.With("method", "data").Observe(time.Since(begin).Seconds())
|
||||
@@ -68,11 +59,11 @@ func (ms *metricsMiddleware) Result(ctx context.Context, consumer string) ([]byt
|
||||
return ms.svc.Result(ctx, consumer)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Attestation(ctx context.Context) ([]byte, error) {
|
||||
func (ms *metricsMiddleware) Attestation(ctx context.Context, reportData [agent.ReportDataSize]byte) ([]byte, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "attestation").Add(1)
|
||||
ms.latency.With("method", "attestation").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Attestation(ctx)
|
||||
return ms.svc.Attestation(ctx, reportData)
|
||||
}
|
||||
|
||||
+27
-26
@@ -8,18 +8,27 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
_ fmt.Stringer = (*Datasets)(nil)
|
||||
_ fmt.Stringer = (*Algorithms)(nil)
|
||||
)
|
||||
var _ fmt.Stringer = (*Datasets)(nil)
|
||||
|
||||
type AgentConfig struct {
|
||||
LogLevel string `json:"log_level"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
CertFile string `json:"cert_file"`
|
||||
KeyFile string `json:"server_key"`
|
||||
ServerCAFile string `json:"server_ca_file"`
|
||||
ClientCAFile string `json:"client_ca_file"`
|
||||
AttestedTls bool `json:"attested_tls"`
|
||||
}
|
||||
|
||||
type Computation struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Datasets Datasets `json:"datasets,omitempty"`
|
||||
Algorithms Algorithms `json:"algorithms,omitempty"`
|
||||
ResultConsumers []string `json:"result_consumers,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Datasets Datasets `json:"datasets,omitempty"`
|
||||
Algorithm Algorithm `json:"algorithms,omitempty"`
|
||||
ResultConsumers []string `json:"result_consumers,omitempty"`
|
||||
AgentConfig AgentConfig `json:"agent_config,omitempty"`
|
||||
}
|
||||
|
||||
func (d *Datasets) String() string {
|
||||
@@ -30,30 +39,22 @@ func (d *Datasets) String() string {
|
||||
return string(dat)
|
||||
}
|
||||
|
||||
func (a *Algorithms) String() string {
|
||||
dat, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(dat)
|
||||
}
|
||||
|
||||
type Dataset struct {
|
||||
Dataset []byte `json:"-"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Dataset []byte `json:"-"`
|
||||
Hash [32]byte `json:"hash,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type Datasets []Dataset
|
||||
|
||||
type Algorithm struct {
|
||||
Algorithm []byte `json:"-"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Algorithm []byte `json:"-"`
|
||||
Hash [32]byte `json:"hash,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type Algorithms []Algorithm
|
||||
|
||||
func containsID(slice interface{}, id string) int {
|
||||
rangeOnMe := reflect.ValueOf(slice)
|
||||
for i := 0; i < rangeOnMe.Len(); i++ {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package events
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/mdlayher/vsock"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
service string
|
||||
computationID string
|
||||
conn *vsock.Conn
|
||||
}
|
||||
|
||||
type AgentEvent struct {
|
||||
EventType string `json:"event_type"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
ComputationID string `json:"computation_id,omitempty"`
|
||||
Details json.RawMessage `json:"details,omitempty"`
|
||||
Originator string `json:"originator"`
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
SendEvent(event, status string, details json.RawMessage) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
func New(svc, computationID string, sockPort uint32) (Service, error) {
|
||||
conn, err := vsock.Dial(vsock.Host, sockPort, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &service{
|
||||
service: svc,
|
||||
computationID: computationID,
|
||||
conn: conn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) SendEvent(event, status string, details json.RawMessage) error {
|
||||
body := manager.ClientStreamMessage{Message: &manager.ClientStreamMessage_AgentEvent{AgentEvent: &manager.AgentEvent{
|
||||
EventType: event,
|
||||
Timestamp: timestamppb.Now(),
|
||||
ComputationId: s.computationID,
|
||||
Originator: s.service,
|
||||
Status: status,
|
||||
Details: details,
|
||||
}}}
|
||||
protoBody, err := proto.Marshal(&body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := s.conn.Write(protoBody); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Close() error {
|
||||
return s.conn.Close()
|
||||
}
|
||||
+69
-78
@@ -5,21 +5,24 @@ package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"slices"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/ultravioletrs/cocos/internal/events"
|
||||
"github.com/google/go-sev-guest/client"
|
||||
"github.com/ultravioletrs/cocos/agent/events"
|
||||
"github.com/ultravioletrs/cocos/pkg/socket"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
var _ Service = (*agentService)(nil)
|
||||
|
||||
// ReportDataSize is the size of the report data expected by the attestation service.
|
||||
const ReportDataSize = 64
|
||||
|
||||
var (
|
||||
// ErrMalformedEntity indicates malformed entity specification (e.g.
|
||||
// invalid username or password).
|
||||
@@ -41,120 +44,110 @@ var (
|
||||
errResultsNotReady = errors.New("computation results are not yet ready")
|
||||
// errStateNotReady agent received a request in the wrong state.
|
||||
errStateNotReady = errors.New("agent not expecting this operation in the current state")
|
||||
// errHashMismatch provided algorithm/dataset does not match hash in manifest.
|
||||
errHashMismatch = errors.New("malformed data, hash does not match manifest")
|
||||
)
|
||||
|
||||
// Service specifies an API that must be fullfiled by the domain service
|
||||
// implementation, and all of its decorators (e.g. logging & metrics).
|
||||
type Service interface {
|
||||
Run(ctx context.Context, c Computation) (string, error)
|
||||
Algo(ctx context.Context, algorithm Algorithm) (string, error)
|
||||
Data(ctx context.Context, dataset Dataset) (string, error)
|
||||
Algo(ctx context.Context, algorithm Algorithm) error
|
||||
Data(ctx context.Context, dataset Dataset) error
|
||||
Result(ctx context.Context, consumer string) ([]byte, error)
|
||||
Attestation(ctx context.Context) ([]byte, error)
|
||||
Attestation(ctx context.Context, reportData [ReportDataSize]byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type agentService struct {
|
||||
computation Computation
|
||||
algorithms [][]byte
|
||||
datasets [][]byte
|
||||
result []byte
|
||||
attestation []byte
|
||||
sm *StateMachine
|
||||
runError error
|
||||
eventSvc events.Service
|
||||
computation Computation // Holds the current computation request details.
|
||||
algorithm []byte // Stores the algorithm received for the computation.
|
||||
datasets [][]byte // Stores the datasets received for the computation.
|
||||
result []byte // Stores the result of the computation.
|
||||
sm *StateMachine // Manages the state transitions of the agent service.
|
||||
runError error // Stores any error encountered during the computation run.
|
||||
eventSvc events.Service // Service for publishing events related to computation.
|
||||
}
|
||||
|
||||
const (
|
||||
socketPath = "unix_socket"
|
||||
pyRuntime = "python3"
|
||||
notificationTopic = "agent"
|
||||
socketPath = "unix_socket"
|
||||
pyRuntime = "python3"
|
||||
)
|
||||
|
||||
var _ Service = (*agentService)(nil)
|
||||
|
||||
// New instantiates the agent service implementation.
|
||||
func New(ctx context.Context, logger mglog.Logger, eventSvc events.Service) Service {
|
||||
func New(ctx context.Context, logger *slog.Logger, eventSvc events.Service, cmp Computation) Service {
|
||||
svc := &agentService{
|
||||
sm: NewStateMachine(logger),
|
||||
eventSvc: eventSvc,
|
||||
}
|
||||
|
||||
go svc.sm.Start(ctx)
|
||||
svc.sm.SendEvent(start)
|
||||
svc.sm.StateFunctions[idle] = svc.publishEvent("in-progress", json.RawMessage{})
|
||||
svc.sm.StateFunctions[receivingManifests] = svc.publishEvent("in-progress", json.RawMessage{})
|
||||
svc.sm.StateFunctions[receivingAlgorithms] = svc.publishEvent("in-progress", json.RawMessage{})
|
||||
svc.sm.StateFunctions[receivingManifest] = svc.publishEvent("in-progress", json.RawMessage{})
|
||||
svc.sm.StateFunctions[receivingAlgorithm] = svc.publishEvent("in-progress", json.RawMessage{})
|
||||
svc.sm.StateFunctions[receivingData] = svc.publishEvent("in-progress", json.RawMessage{})
|
||||
svc.sm.StateFunctions[resultsReady] = svc.publishEvent("in-progress", json.RawMessage{})
|
||||
svc.sm.StateFunctions[complete] = svc.publishEvent("in-progress", json.RawMessage{})
|
||||
svc.sm.StateFunctions[running] = svc.runComputation
|
||||
|
||||
svc.computation = cmp
|
||||
svc.sm.SendEvent(manifestReceived)
|
||||
return svc
|
||||
}
|
||||
|
||||
func (as *agentService) Run(ctx context.Context, c Computation) (string, error) {
|
||||
if as.sm.GetState() != receivingManifests {
|
||||
return "", errStateNotReady
|
||||
func (as *agentService) Algo(ctx context.Context, algorithm Algorithm) error {
|
||||
if as.sm.GetState() != receivingAlgorithm {
|
||||
return errStateNotReady
|
||||
}
|
||||
cmpJSON, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
if as.algorithm != nil {
|
||||
return errAllManifestItemsReceived
|
||||
}
|
||||
|
||||
as.computation = c
|
||||
as.sm.SendEvent(manifestsReceived)
|
||||
hash := sha3.Sum256(algorithm.Algorithm)
|
||||
|
||||
// Calculate the SHA-256 hash of the algorithm
|
||||
hash := sha256.Sum256(cmpJSON)
|
||||
cmpHash := hex.EncodeToString(hash[:])
|
||||
|
||||
return cmpHash, nil // return computation hash.
|
||||
}
|
||||
|
||||
func (as *agentService) Algo(ctx context.Context, algorithm Algorithm) (string, error) {
|
||||
if as.sm.GetState() != receivingAlgorithms {
|
||||
return "", errStateNotReady
|
||||
}
|
||||
if len(as.computation.Algorithms) == 0 {
|
||||
return "", errAllManifestItemsReceived
|
||||
}
|
||||
index := containsID(as.computation.Algorithms, algorithm.ID)
|
||||
index := containsID(as.computation.Algorithm, algorithm.ID)
|
||||
switch index {
|
||||
case -1:
|
||||
return "", errUndeclaredAlgorithm
|
||||
return errUndeclaredAlgorithm
|
||||
default:
|
||||
if as.computation.Algorithms[index].Provider != algorithm.Provider {
|
||||
return "", errProviderMissmatch
|
||||
if as.computation.Algorithm.Provider != algorithm.Provider {
|
||||
return errProviderMissmatch
|
||||
}
|
||||
if hash != as.computation.Algorithm.Hash {
|
||||
return errHashMismatch
|
||||
}
|
||||
as.computation.Algorithms = slices.Delete(as.computation.Algorithms, index, index+1)
|
||||
}
|
||||
|
||||
as.algorithms = append(as.algorithms, algorithm.Algorithm)
|
||||
as.algorithm = algorithm.Algorithm
|
||||
|
||||
if len(as.computation.Algorithms) == 0 {
|
||||
as.sm.SendEvent(algorithmsReceived)
|
||||
if as.algorithm != nil {
|
||||
as.sm.SendEvent(algorithmReceived)
|
||||
}
|
||||
|
||||
// Calculate the SHA-256 hash of the algorithm.
|
||||
hash := sha256.Sum256(algorithm.Algorithm)
|
||||
algorithmHash := hex.EncodeToString(hash[:])
|
||||
|
||||
// Return the algorithm hash or an error.
|
||||
return algorithmHash, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (as *agentService) Data(ctx context.Context, dataset Dataset) (string, error) {
|
||||
func (as *agentService) Data(ctx context.Context, dataset Dataset) error {
|
||||
if as.sm.GetState() != receivingData {
|
||||
return "", errStateNotReady
|
||||
return errStateNotReady
|
||||
}
|
||||
if len(as.computation.Datasets) == 0 {
|
||||
return "", errAllManifestItemsReceived
|
||||
return errAllManifestItemsReceived
|
||||
}
|
||||
|
||||
hash := sha3.Sum256(dataset.Dataset)
|
||||
|
||||
index := containsID(as.computation.Datasets, dataset.ID)
|
||||
switch index {
|
||||
case -1:
|
||||
return "", errUndeclaredDataset
|
||||
return errUndeclaredDataset
|
||||
default:
|
||||
if as.computation.Datasets[index].Provider != dataset.Provider {
|
||||
return "", errProviderMissmatch
|
||||
return errProviderMissmatch
|
||||
}
|
||||
if hash != as.computation.Datasets[index].Hash {
|
||||
return errHashMismatch
|
||||
}
|
||||
as.computation.Datasets = slices.Delete(as.computation.Datasets, index, index+1)
|
||||
}
|
||||
@@ -165,12 +158,7 @@ func (as *agentService) Data(ctx context.Context, dataset Dataset) (string, erro
|
||||
as.sm.SendEvent(dataReceived)
|
||||
}
|
||||
|
||||
// Calculate the SHA-256 hash of the dataset.
|
||||
hash := sha256.Sum256(dataset.Dataset)
|
||||
datasetHash := hex.EncodeToString(hash[:])
|
||||
|
||||
// Return the dataset hash or an error.
|
||||
return datasetHash, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (as *agentService) Result(ctx context.Context, consumer string) ([]byte, error) {
|
||||
@@ -195,14 +183,17 @@ func (as *agentService) Result(ctx context.Context, consumer string) ([]byte, er
|
||||
return as.result, as.runError
|
||||
}
|
||||
|
||||
func (as *agentService) Attestation(ctx context.Context) ([]byte, error) {
|
||||
// Implement the logic for the Attestation method here
|
||||
// Use the provided ctx parameter as needed
|
||||
var attestation []byte
|
||||
func (as *agentService) Attestation(ctx context.Context, reportData [ReportDataSize]byte) ([]byte, error) {
|
||||
provider, err := client.GetQuoteProvider()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
rawQuote, err := provider.GetRawQuote(reportData)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
as.attestation = attestation
|
||||
|
||||
return as.attestation, nil
|
||||
return rawQuote, nil
|
||||
}
|
||||
|
||||
func (as *agentService) runComputation() {
|
||||
@@ -210,7 +201,7 @@ func (as *agentService) runComputation() {
|
||||
as.sm.logger.Debug("computation run started")
|
||||
defer as.sm.SendEvent(runComplete)
|
||||
as.publishEvent("in-progress", json.RawMessage{})()
|
||||
result, err := run(as.algorithms[0], as.datasets[0])
|
||||
result, err := run(as.algorithm, as.datasets[0])
|
||||
if err != nil {
|
||||
as.runError = err
|
||||
as.publishEvent("failed", json.RawMessage{})()
|
||||
@@ -222,7 +213,7 @@ func (as *agentService) runComputation() {
|
||||
|
||||
func (as *agentService) publishEvent(status string, details json.RawMessage) func() {
|
||||
return func() {
|
||||
if err := as.eventSvc.SendEvent(as.sm.State.String(), as.computation.ID, status, details); err != nil {
|
||||
if err := as.eventSvc.SendEvent(as.sm.State.String(), status, details); err != nil {
|
||||
as.sm.logger.Warn(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
+16
-13
@@ -5,9 +5,8 @@ package agent
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=state
|
||||
@@ -15,8 +14,8 @@ type state int
|
||||
|
||||
const (
|
||||
idle state = iota
|
||||
receivingManifests
|
||||
receivingAlgorithms
|
||||
receivingManifest
|
||||
receivingAlgorithm
|
||||
receivingData
|
||||
running
|
||||
resultsReady
|
||||
@@ -27,8 +26,8 @@ type event int
|
||||
|
||||
const (
|
||||
start event = iota
|
||||
manifestsReceived
|
||||
algorithmsReceived
|
||||
manifestReceived
|
||||
algorithmReceived
|
||||
dataReceived
|
||||
runComplete
|
||||
resultsConsumed
|
||||
@@ -41,27 +40,29 @@ type StateMachine struct {
|
||||
EventChan chan event
|
||||
Transitions map[state]map[event]state
|
||||
StateFunctions map[state]func()
|
||||
logger mglog.Logger
|
||||
logger *slog.Logger
|
||||
wg *sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewStateMachine creates a new StateMachine.
|
||||
func NewStateMachine(logger mglog.Logger) *StateMachine {
|
||||
func NewStateMachine(logger *slog.Logger) *StateMachine {
|
||||
sm := &StateMachine{
|
||||
State: idle,
|
||||
EventChan: make(chan event),
|
||||
Transitions: make(map[state]map[event]state),
|
||||
StateFunctions: make(map[state]func()),
|
||||
logger: logger,
|
||||
wg: &sync.WaitGroup{},
|
||||
}
|
||||
|
||||
sm.Transitions[idle] = make(map[event]state)
|
||||
sm.Transitions[idle][start] = receivingManifests
|
||||
sm.Transitions[idle][start] = receivingManifest
|
||||
|
||||
sm.Transitions[receivingManifests] = make(map[event]state)
|
||||
sm.Transitions[receivingManifests][manifestsReceived] = receivingAlgorithms
|
||||
sm.Transitions[receivingManifest] = make(map[event]state)
|
||||
sm.Transitions[receivingManifest][manifestReceived] = receivingAlgorithm
|
||||
|
||||
sm.Transitions[receivingAlgorithms] = make(map[event]state)
|
||||
sm.Transitions[receivingAlgorithms][algorithmsReceived] = receivingData
|
||||
sm.Transitions[receivingAlgorithm] = make(map[event]state)
|
||||
sm.Transitions[receivingAlgorithm][algorithmReceived] = receivingData
|
||||
|
||||
sm.Transitions[receivingData] = make(map[event]state)
|
||||
sm.Transitions[receivingData][dataReceived] = running
|
||||
@@ -77,6 +78,8 @@ func NewStateMachine(logger mglog.Logger) *StateMachine {
|
||||
|
||||
// Start the state machine.
|
||||
func (sm *StateMachine) Start(ctx context.Context) {
|
||||
sm.wg.Add(1)
|
||||
defer sm.wg.Done()
|
||||
for {
|
||||
select {
|
||||
case event := <-sm.EventChan:
|
||||
|
||||
@@ -9,8 +9,8 @@ func _() {
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[idle-0]
|
||||
_ = x[receivingManifests-1]
|
||||
_ = x[receivingAlgorithms-2]
|
||||
_ = x[receivingManifest-1]
|
||||
_ = x[receivingAlgorithm-2]
|
||||
_ = x[receivingData-3]
|
||||
_ = x[running-4]
|
||||
_ = x[resultsReady-5]
|
||||
|
||||
+4
-6
@@ -16,9 +16,9 @@ func TestStateMachineTransitions(t *testing.T) {
|
||||
event event
|
||||
expected state
|
||||
}{
|
||||
{idle, start, receivingManifests},
|
||||
{receivingManifests, manifestsReceived, receivingAlgorithms},
|
||||
{receivingAlgorithms, algorithmsReceived, receivingData},
|
||||
{idle, start, receivingManifest},
|
||||
{receivingManifest, manifestReceived, receivingAlgorithm},
|
||||
{receivingAlgorithm, algorithmReceived, receivingData},
|
||||
{receivingData, dataReceived, running},
|
||||
{running, runComplete, resultsReady},
|
||||
{resultsReady, resultsConsumed, complete},
|
||||
@@ -27,12 +27,11 @@ func TestStateMachineTransitions(t *testing.T) {
|
||||
for _, testCase := range testCases {
|
||||
t.Run(fmt.Sprintf("Transition from %v to %v", testCase.fromState, testCase.expected), func(t *testing.T) {
|
||||
sm := NewStateMachine(mglog.NewMock())
|
||||
done := make(chan struct{})
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
sm.Start(ctx)
|
||||
close(done)
|
||||
}()
|
||||
sm.wg.Wait()
|
||||
sm.SetState(testCase.fromState)
|
||||
|
||||
sm.SendEvent(testCase.event)
|
||||
@@ -42,7 +41,6 @@ func TestStateMachineTransitions(t *testing.T) {
|
||||
}
|
||||
close(sm.EventChan)
|
||||
cancel()
|
||||
<-done
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
-124
@@ -1,124 +0,0 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: CoCos-AI Manager
|
||||
description: |
|
||||
The manager service creates a VM with CoCos-AI agent:
|
||||
- [The CoCos-AI repository](https://github.com/ultravioletrs/cocos-ai)
|
||||
contact:
|
||||
email: info@ultraviolet.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/ultravioletrs/cocos-ai/blob/main/LICENCE.md
|
||||
version: "1"
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9021
|
||||
- url: https://localhost:9021
|
||||
|
||||
paths:
|
||||
/run:
|
||||
post:
|
||||
summary: Run computation on VM.
|
||||
description: |
|
||||
Send computation to agent. This creates agent virtual machine and sends
|
||||
computation manifest.
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/Run"
|
||||
responses:
|
||||
"200":
|
||||
description: Computation manifest created successfully.
|
||||
"400":
|
||||
description: Request has malformed content.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
HealthRes:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
description: Service status.
|
||||
enum:
|
||||
- pass
|
||||
version:
|
||||
type: string
|
||||
description: Service version.
|
||||
example: 0.0.1
|
||||
commit:
|
||||
type: string
|
||||
description: Service commit hash.
|
||||
example: 7d6f4dc4f7f0c1fa3dc24eddfb18bb5073ff4f62
|
||||
description:
|
||||
type: string
|
||||
description: Service description.
|
||||
example: <service_name> service
|
||||
build_time:
|
||||
type: string
|
||||
description: Service build time.
|
||||
example: 1970-01-01_00:00:00
|
||||
requestBodies:
|
||||
Run:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
computation:
|
||||
description: byte array of computation request as defined in ComputationReq
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
datasets:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
provider:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
algorithms:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
provider:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
results_consumers:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
timeout:
|
||||
type: string
|
||||
example: "2s"
|
||||
|
||||
responses:
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthRes"
|
||||
+51
-18
@@ -1,6 +1,6 @@
|
||||
# Agent CLI
|
||||
|
||||
This repository contains the command-line interface (CLI) tool for interacting with the Agent service. The CLI allows you to perform various tasks such as running computations, uploading algorithms and datasets, and retrieving results.
|
||||
This repository contains the command-line interface (CLI) tool for interacting with the Agent and manager service. The CLI allows you to perform various tasks such as running computations, uploading algorithms and datasets, and retrieving results.
|
||||
|
||||
## Build
|
||||
|
||||
@@ -17,15 +17,60 @@ make cli
|
||||
To run a computation, use the following command:
|
||||
|
||||
```bash
|
||||
./build/cocos-cli run --computation '{"name": "my-computation"}'
|
||||
./build/cocos-cli manager run --computation '{"name": "my-computation"}'
|
||||
```
|
||||
|
||||
#### Get attestation
|
||||
Retrieves attestation information from the SEV guest and saves it to a file.
|
||||
To retrieve attestation from agent, use the following command:
|
||||
```bash
|
||||
./build/cocos-cli agent attestation get '<report_data>'
|
||||
```
|
||||
|
||||
#### Validate attestation
|
||||
Validates the retrieved attestation information against a specified policy and checks its authenticity.
|
||||
To validate and verify attestation from agent, use the following command:
|
||||
```bash
|
||||
./build/cocos-cli agent attestation validate '<attestation>' --report_data '<report_data>'
|
||||
```
|
||||
##### Flags
|
||||
- --config: Path to a JSON file containing the validation configuration. This can be used to override individual flags.
|
||||
- --report_data: Hex-encoded string representing the attestation report data. (Required for the validate command)
|
||||
- --host_data: Hex-encoded string representing the expected HOST_DATA field.
|
||||
- --family_id: Hex-encoded string representing the expected FAMILY_ID field.
|
||||
- --image_id: Hex-encoded string representing the expected IMAGE_ID field.
|
||||
- --report_id: Hex-encoded string representing the expected REPORT_ID field.
|
||||
- --report_id_ma: Hex-encoded string representing the expected REPORT_ID_MA field.
|
||||
- --measurement: Hex-encoded string representing the expected MEASUREMENT field.
|
||||
- --chip_id: Hex-encoded string representing the expected CHIP_ID field.
|
||||
- --minimum_tcb: Minimum acceptable value for CURRENT_TCB, COMMITTED_TCB, and REPORTED_TCB.
|
||||
- --minimum_launch_tcb: Minimum acceptable value for LAUNCH_TCB.
|
||||
- --minimum_guest_svn: Minimum acceptable SnpPolicy.
|
||||
- --minimum_build: Minimum 8-bit build number for AMD-SP firmware.
|
||||
- --check_crl: Download and check the CRL for revoked certificates (default: false).
|
||||
- --disallow_network: If true, disallows network downloads for verification (default: false).
|
||||
- --timeout: Duration to continue retrying failed HTTP requests (default: 2 minutes).
|
||||
- --max_retry_delay: Maximum duration to wait between HTTP request retries (default: 30 seconds).
|
||||
- --require_author_key: Require that AUTHOR_KEY_EN is set to 1 (default: false).
|
||||
- --require_id_block: Require that the VM was launched with an ID_BLOCK signed by a trusted key (default: false).
|
||||
- --permit_provisional_software: Allow provisional firmware (default: false).
|
||||
- --platform_info: Maximum acceptable PLATFORM_INFO field bit-wise (optional).
|
||||
- --minimum_version: Minimum AMD-SP firmware API version (major.minor) (optional).
|
||||
- --trusted_author_keys: Paths to x.509 certificates of trusted author keys (optional).
|
||||
- --trusted_author_key_hashes: Hex-encoded SHA-384 hashes of trusted author keys (optional).
|
||||
- --trusted_id_keys: Paths to x.509 certificates of trusted identity keys (optional).
|
||||
- --trusted_id_key_hashes: Hex-encoded SHA-384 hashes of trusted identity keys (optional).
|
||||
- --product: AMD product name for the chip that generated the attestation report (optional).
|
||||
- --stepping: Machine stepping for the chip that generated the attestation report (optional).
|
||||
- --CA_bundles_paths: Paths to CA bundles for the AMD product (optional).
|
||||
- --CA_bundles: PEM format CA bundles for the AMD product (optional).
|
||||
|
||||
#### Upload Algorithm
|
||||
|
||||
To upload an algorithm, use the following command:
|
||||
|
||||
```bash
|
||||
./build/cocos-cli algo /path/to/algorithm
|
||||
./build/cocos-cli agent algo /path/to/algorithm
|
||||
```
|
||||
|
||||
#### Upload Dataset
|
||||
@@ -33,7 +78,7 @@ To upload an algorithm, use the following command:
|
||||
To upload a dataset, use the following command:
|
||||
|
||||
```bash
|
||||
./build/cocos-cli data /path/to/dataset.csv
|
||||
./build/cocos-cli agent data /path/to/dataset.csv
|
||||
```
|
||||
|
||||
#### Retrieve result
|
||||
@@ -41,17 +86,5 @@ To upload a dataset, use the following command:
|
||||
To retrieve the computation result, use the following command:
|
||||
|
||||
```bash
|
||||
./build/cocos-cli result
|
||||
```
|
||||
|
||||
## Installtion
|
||||
|
||||
To use the CLI, you have the option to install it globally on your system. Here's how:
|
||||
|
||||
### Build the CLI:
|
||||
|
||||
Navigate to the project root and run the following command to build the CLI binary:
|
||||
|
||||
```bash
|
||||
make install-cli
|
||||
```
|
||||
./build/cocos-cli agent result
|
||||
```
|
||||
+3
-4
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
func NewAlgorithmsCmd(sdk agent.Service) *cobra.Command {
|
||||
func (cli *CLI) NewAlgorithmsCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "algo",
|
||||
Short: "Upload an algorithm binary",
|
||||
@@ -32,12 +32,11 @@ func NewAlgorithmsCmd(sdk agent.Service) *cobra.Command {
|
||||
Provider: args[2],
|
||||
}
|
||||
|
||||
response, err := sdk.Algo(cmd.Context(), algoReq)
|
||||
if err != nil {
|
||||
if err := cli.agentSDK.Algo(cmd.Context(), algoReq); err != nil {
|
||||
log.Fatalf("Error uploading algorithm with ID %s and provider %s: %v", algoReq.ID, algoReq.Provider, err)
|
||||
}
|
||||
|
||||
log.Println("Successfully uploaded algorithm:", response)
|
||||
log.Println("Successfully uploaded algorithm")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
+605
-6
@@ -3,23 +3,165 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-sev-guest/abi"
|
||||
"github.com/google/go-sev-guest/proto/check"
|
||||
"github.com/google/go-sev-guest/validate"
|
||||
"github.com/google/go-sev-guest/verify"
|
||||
"github.com/google/go-sev-guest/verify/trust"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
const attestationFilePath = "attestation.txt"
|
||||
const (
|
||||
defaultMinimumTcb = 0
|
||||
defaultMinimumLaunchTcb = 0
|
||||
defaultMinimumGuestSvn = 0
|
||||
defaultGuestPolicy = 0x0000000000030000
|
||||
defaultMinimumBuild = 0
|
||||
defaultCheckCrl = false
|
||||
defaultTimeout = 2 * time.Minute
|
||||
defaultMaxRetryDelay = 30 * time.Second
|
||||
defaultRequireAuthor = false
|
||||
defaultRequireIdBlock = false
|
||||
defaultMinVersion = "0.0"
|
||||
size16 = 16
|
||||
size32 = 32
|
||||
size48 = 48
|
||||
size64 = 64
|
||||
attestationFilePath = "attestation.bin"
|
||||
exampleJSONConfig = `
|
||||
{
|
||||
"rootOfTrust":{
|
||||
"product":"test_product",
|
||||
"cabundlePaths":[
|
||||
"test_cabundlePaths"
|
||||
],
|
||||
"cabundles":[
|
||||
"test_Cabundles"
|
||||
],
|
||||
"checkCrl":true,
|
||||
"disallowNetwork":true
|
||||
},
|
||||
"policy":{
|
||||
"minimumGuestSvn":1,
|
||||
"policy":"1",
|
||||
"familyId":"AQIDBAUGBwgJCgsMDQ4PEA==",
|
||||
"imageId":"AQIDBAUGBwgJCgsMDQ4PEA==",
|
||||
"vmpl":0,
|
||||
"minimumTcb":"1",
|
||||
"minimumLaunchTcb":"1",
|
||||
"platformInfo":"1",
|
||||
"requireAuthorKey":true,
|
||||
"reportData":"J+60aXs8btm8VcGgaJYURGeNCu0FIyWMFXQ7ZUlJDC0FJGJizJsOzDIXgQ75UtPC+Zqe0A3dvnnf5VEeQ61RTg==",
|
||||
"measurement":"8s78ewoX7Xkfy1qsgVnkZwLDotD768Nqt6qTL5wtQOxHsLczipKM6bhDmWiHLdP4",
|
||||
"hostData":"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw=",
|
||||
"reportId":"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw=",
|
||||
"reportIdMa":"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw=",
|
||||
"chipId":"J+60aXs8btm8VcGgaJYURGeNCu0FIyWMFXQ7ZUlJDC0FJGJizJsOzDIXgQ75UtPC+Zqe0A3dvnnf5VEeQ61RTg==",
|
||||
"minimumBuild":1,
|
||||
"minimumVersion":"0.90",
|
||||
"permitProvisionalFirmware":true,
|
||||
"requireIdBlock":true,
|
||||
"trustedAuthorKeys":[
|
||||
"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw="
|
||||
],
|
||||
"trustedAuthorKeyHashes":[
|
||||
"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw="
|
||||
],
|
||||
"trustedIdKeys":[
|
||||
"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw="
|
||||
],
|
||||
"trustedIdKeyHashes":[
|
||||
"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw="
|
||||
],
|
||||
"product":{
|
||||
"name":"SEV_PRODUCT_MILAN",
|
||||
"stepping":1,
|
||||
"machineStepping":1
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
func NewAttestationCmd(sdk agent.Service) *cobra.Command {
|
||||
var (
|
||||
cfg = check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}
|
||||
cfgString string
|
||||
timeout time.Duration
|
||||
maxRetryDelay time.Duration
|
||||
platformInfo string
|
||||
stepping string
|
||||
trustedAuthorKeys []string
|
||||
trustedAuthorHashes []string
|
||||
trustedIdKeys []string
|
||||
trustedIdKeyHashes []string
|
||||
attestationFile string
|
||||
attestation []byte
|
||||
empty16 = [size16]byte{}
|
||||
empty32 = [size32]byte{}
|
||||
empty64 = [size64]byte{}
|
||||
defaultReportIdMa = []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
|
||||
)
|
||||
|
||||
func (cli *CLI) NewAttestationCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "attestation",
|
||||
Short: "Retrieve attestation information",
|
||||
Use: "attestation [command]",
|
||||
Short: "Get and validate attestations",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.Println("Checking attestation")
|
||||
fmt.Printf("Get and validate attestations\n\n")
|
||||
fmt.Printf("Usage:\n %s [command]\n\n", cmd.CommandPath())
|
||||
fmt.Printf("Available Commands:\n")
|
||||
|
||||
result, err := sdk.Attestation(cmd.Context())
|
||||
// Filter out "completion" command
|
||||
availableCommands := make([]*cobra.Command, 0)
|
||||
for _, subCmd := range cmd.Commands() {
|
||||
if subCmd.Name() != "completion" {
|
||||
availableCommands = append(availableCommands, subCmd)
|
||||
}
|
||||
}
|
||||
|
||||
for _, subCmd := range availableCommands {
|
||||
fmt.Printf(" %-15s%s\n", subCmd.Name(), subCmd.Short)
|
||||
}
|
||||
|
||||
fmt.Printf("\nFlags:\n")
|
||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
||||
fmt.Printf(" -%s, --%s %s\n", flag.Shorthand, flag.Name, flag.Usage)
|
||||
})
|
||||
fmt.Printf("\nUse \"%s [command] --help\" for more information about a command.\n", cmd.CommandPath())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Retrieve attestation information from agent. Report data expected in hex enoded string of length 64 bytes.",
|
||||
Example: "report <report_data>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.Println("Getting attestation")
|
||||
|
||||
reportData, err := hex.DecodeString(args[0])
|
||||
if err != nil {
|
||||
log.Fatalf("attestation validation and verification failed with error: %s", err)
|
||||
}
|
||||
if len(reportData) != agent.ReportDataSize {
|
||||
log.Fatalf("report data must be a hex encoded string of length %d bytes", agent.ReportDataSize)
|
||||
}
|
||||
|
||||
result, err := cli.agentSDK.Attestation(cmd.Context(), [agent.ReportDataSize]byte(reportData))
|
||||
if err != nil {
|
||||
log.Fatalf("Error retrieving attestation: %v", err)
|
||||
}
|
||||
@@ -32,3 +174,460 @@ func NewAttestationCmd(sdk agent.Service) *cobra.Command {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "validate",
|
||||
Short: "Validate and verify attestation information. The report is provided as a file path.",
|
||||
Example: "validate <attestation_report_file_path>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.Println("Checking attestation")
|
||||
|
||||
attestationFile = string(args[0])
|
||||
|
||||
if err := parseConfig(); err != nil {
|
||||
log.Fatalf("attestation validation and verification failed with error: %s", err)
|
||||
}
|
||||
if err := parseHashes(); err != nil {
|
||||
log.Fatalf("attestation validation and verification failed with error: %s", err)
|
||||
}
|
||||
if err := parseFiles(); err != nil {
|
||||
log.Fatalf("attestation validation and verification failed with error: %s", err)
|
||||
}
|
||||
// This format is the attestation report in AMD's specified ABI format, immediately
|
||||
// followed by the certificate table bytes.
|
||||
if len(attestation) < abi.ReportSize {
|
||||
log.Fatalf("attestation contents too small (0x%x bytes). Want at least 0x%x bytes", len(attestation), abi.ReportSize)
|
||||
}
|
||||
if err := parseUints(); err != nil {
|
||||
log.Fatalf("attestation validation and verification failed with error: %s", err)
|
||||
}
|
||||
cfg.Policy.Vmpl = wrapperspb.UInt32(0)
|
||||
|
||||
if err := validateInput(); err != nil {
|
||||
log.Fatalf("attestation validation and verification failed with error: %s", err)
|
||||
}
|
||||
|
||||
if err := verifyAndValidateAttestation(attestation); err != nil {
|
||||
log.Fatalf("attestation validation and verification failed with error: %s", err)
|
||||
}
|
||||
log.Println("Attestation validation and verification is successful!")
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVar(
|
||||
&cfgString,
|
||||
"config",
|
||||
"",
|
||||
"Serialized json check.Config protobuf. This will overwrite individual flags. Unmarshalled as json. Example: "+exampleJSONConfig,
|
||||
)
|
||||
cmd.Flags().BytesHexVar(
|
||||
&cfg.Policy.HostData,
|
||||
"host_data",
|
||||
empty32[:],
|
||||
"The expected HOST_DATA field as a hex string. Must encode 32 bytes. Unchecked if unset.",
|
||||
)
|
||||
cmd.Flags().BytesHexVar(
|
||||
&cfg.Policy.ReportData,
|
||||
"report_data",
|
||||
empty64[:],
|
||||
"The expected REPORT_DATA field as a hex string. Must encode 64 bytes. Must be set.",
|
||||
)
|
||||
cmd.Flags().BytesHexVar(
|
||||
&cfg.Policy.FamilyId,
|
||||
"family_id",
|
||||
empty16[:],
|
||||
"The expected FAMILY_ID field as a hex string. Must encode 16 bytes. Unchecked if unset.",
|
||||
)
|
||||
cmd.Flags().BytesHexVar(
|
||||
&cfg.Policy.ImageId,
|
||||
"image_id",
|
||||
empty16[:],
|
||||
"The expected IMAGE_ID field as a hex string. Must encode 16 bytes. Unchecked if unset.",
|
||||
)
|
||||
cmd.Flags().BytesHexVar(
|
||||
&cfg.Policy.ReportId,
|
||||
"report_id",
|
||||
nil,
|
||||
"The expected REPORT_ID field as a hex string. Must encode 32 bytes. Unchecked if unset.",
|
||||
)
|
||||
cmd.Flags().BytesHexVar(
|
||||
&cfg.Policy.ReportIdMa,
|
||||
"report_id_ma",
|
||||
defaultReportIdMa,
|
||||
"The expected REPORT_ID_MA field as a hex string. Must encode 32 bytes. Unchecked if unset.",
|
||||
)
|
||||
cmd.Flags().BytesHexVar(
|
||||
&cfg.Policy.Measurement,
|
||||
"measurement",
|
||||
nil,
|
||||
"The expected MEASUREMENT field as a hex string. Must encode 48 bytes. Unchecked if unset.",
|
||||
)
|
||||
cmd.Flags().BytesHexVar(
|
||||
&cfg.Policy.ChipId,
|
||||
"chip_id",
|
||||
nil,
|
||||
"The expected MEASUREMENT field as a hex string. Must encode 48 bytes. Unchecked if unset.",
|
||||
)
|
||||
cmd.Flags().Uint64Var(
|
||||
&cfg.Policy.MinimumTcb,
|
||||
"minimum_tcb",
|
||||
defaultMinimumTcb,
|
||||
"The minimum acceptable value for CURRENT_TCB, COMMITTED_TCB, and REPORTED_TCB.",
|
||||
)
|
||||
cmd.Flags().Uint64Var(
|
||||
&cfg.Policy.MinimumLaunchTcb,
|
||||
"minimum_lauch_tcb",
|
||||
defaultMinimumLaunchTcb,
|
||||
"The minimum acceptable value for LAUNCH_TCB.",
|
||||
)
|
||||
cmd.Flags().Uint64Var(
|
||||
&cfg.Policy.Policy,
|
||||
"guest_policy",
|
||||
defaultGuestPolicy,
|
||||
"The most acceptable guest SnpPolicy.",
|
||||
)
|
||||
cmd.Flags().Uint32Var(
|
||||
&cfg.Policy.MinimumGuestSvn,
|
||||
"minimum_guest_svn",
|
||||
defaultMinimumGuestSvn,
|
||||
"The most acceptable GUEST_SVN.",
|
||||
)
|
||||
cmd.Flags().Uint32Var(
|
||||
&cfg.Policy.MinimumBuild,
|
||||
"minimum_build",
|
||||
defaultMinimumBuild,
|
||||
"The 8-bit minimum build number for AMD-SP firmware",
|
||||
)
|
||||
cmd.Flags().BoolVar(
|
||||
&cfg.RootOfTrust.CheckCrl,
|
||||
"check_crl",
|
||||
defaultCheckCrl,
|
||||
"Download and check the CRL for revoked certificates.",
|
||||
)
|
||||
cmd.Flags().DurationVar(
|
||||
&timeout,
|
||||
"timeout",
|
||||
defaultTimeout,
|
||||
"Duration to continue to retry failed HTTP requests.",
|
||||
)
|
||||
cmd.Flags().DurationVar(
|
||||
&maxRetryDelay,
|
||||
"max_retry_delay",
|
||||
defaultMaxRetryDelay,
|
||||
"Maximum Duration to wait between HTTP request retries.",
|
||||
)
|
||||
cmd.Flags().BoolVar(
|
||||
&cfg.Policy.RequireAuthorKey,
|
||||
"require_author_key",
|
||||
defaultRequireAuthor,
|
||||
"Require that AUTHOR_KEY_EN is 1.",
|
||||
)
|
||||
cmd.Flags().BoolVar(
|
||||
&cfg.Policy.RequireIdBlock,
|
||||
"require_id_block",
|
||||
defaultRequireIdBlock,
|
||||
"Require that the VM was launch with an ID_BLOCK signed by a trusted id key or author key",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&platformInfo,
|
||||
"platform_info",
|
||||
"",
|
||||
"The maximum acceptable PLATFORM_INFO field bit-wise. May be empty or a 64-bit unsigned integer",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&cfg.Policy.MinimumVersion,
|
||||
"minimum_version",
|
||||
defaultMinVersion,
|
||||
"Minimum AMD-SP firmware API version (major.minor). Each number must be 8-bit non-negative.",
|
||||
)
|
||||
cmd.Flags().StringArrayVar(
|
||||
&trustedAuthorKeys,
|
||||
"trusted_author_keys",
|
||||
[]string{},
|
||||
"Paths to x.509 certificates of trusted author keys",
|
||||
)
|
||||
cmd.Flags().StringArrayVar(
|
||||
&trustedAuthorHashes,
|
||||
"trusted_author_key_hashes",
|
||||
[]string{},
|
||||
"Hex-encoded SHA-384 hash values of trusted author keys in AMD public key format",
|
||||
)
|
||||
cmd.Flags().StringArrayVar(
|
||||
&trustedIdKeys,
|
||||
"trusted_id_keys",
|
||||
[]string{},
|
||||
"Paths to x.509 certificates of trusted author keys",
|
||||
)
|
||||
cmd.Flags().StringArrayVar(
|
||||
&trustedIdKeyHashes,
|
||||
"trusted_id_key_hashes",
|
||||
[]string{},
|
||||
"Hex-encoded SHA-384 hash values of trusted identity keys in AMD public key format",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&cfg.RootOfTrust.Product,
|
||||
"product",
|
||||
"",
|
||||
"The AMD product name for the chip that generated the attestation report.",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&stepping,
|
||||
"stepping",
|
||||
"",
|
||||
"The machine stepping for the chip that generated the attestation report. Default unchecked.",
|
||||
)
|
||||
cmd.Flags().StringArrayVar(
|
||||
&cfg.RootOfTrust.CabundlePaths,
|
||||
"CA_bundles_paths",
|
||||
[]string{},
|
||||
"Paths to CA bundles for the AMD product. Must be in PEM format, ASK, then ARK certificates. If unset, uses embedded root certificates.",
|
||||
)
|
||||
cmd.Flags().StringArrayVar(
|
||||
&cfg.RootOfTrust.Cabundles,
|
||||
"CA_bundles",
|
||||
[]string{},
|
||||
"PEM format CA bundles for the AMD product. Combined with contents of cabundle_paths.",
|
||||
)
|
||||
|
||||
if err := cmd.MarkFlagRequired("report_data"); err != nil {
|
||||
log.Fatalf("Failed to mark flag as required: %s", err)
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func verifyAndValidateAttestation(attestation []byte) error {
|
||||
sopts, err := verify.RootOfTrustToOptions(cfg.RootOfTrust)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sopts.Product = cfg.Policy.Product
|
||||
sopts.Getter = &trust.RetryHTTPSGetter{
|
||||
Timeout: timeout,
|
||||
MaxRetryDelay: maxRetryDelay,
|
||||
Getter: &trust.SimpleHTTPSGetter{},
|
||||
}
|
||||
attestationPB, err := abi.ReportCertsToProto(attestation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = verify.SnpAttestation(attestationPB, sopts); err != nil {
|
||||
return err
|
||||
}
|
||||
opts, err := validate.PolicyToOptions(cfg.Policy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = validate.SnpAttestation(attestationPB, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseConfig decodes config passed as json for check.Config struct.
|
||||
// example
|
||||
/* {
|
||||
"rootOfTrust":{
|
||||
"product":"test_product",
|
||||
"cabundlePaths":[
|
||||
"test_cabundlePaths"
|
||||
],
|
||||
"cabundles":[
|
||||
"test_Cabundles"
|
||||
],
|
||||
"checkCrl":true,
|
||||
"disallowNetwork":true
|
||||
},
|
||||
"policy":{
|
||||
"minimumGuestSvn":1,
|
||||
"policy":"1",
|
||||
"familyId":"AQIDBAUGBwgJCgsMDQ4PEA==",
|
||||
"imageId":"AQIDBAUGBwgJCgsMDQ4PEA==",
|
||||
"vmpl":0,
|
||||
"minimumTcb":"1",
|
||||
"minimumLaunchTcb":"1",
|
||||
"platformInfo":"1",
|
||||
"requireAuthorKey":true,
|
||||
"reportData":"J+60aXs8btm8VcGgaJYURGeNCu0FIyWMFXQ7ZUlJDC0FJGJizJsOzDIXgQ75UtPC+Zqe0A3dvnnf5VEeQ61RTg==",
|
||||
"measurement":"8s78ewoX7Xkfy1qsgVnkZwLDotD768Nqt6qTL5wtQOxHsLczipKM6bhDmWiHLdP4",
|
||||
"hostData":"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw=",
|
||||
"reportId":"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw=",
|
||||
"reportIdMa":"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw=",
|
||||
"chipId":"J+60aXs8btm8VcGgaJYURGeNCu0FIyWMFXQ7ZUlJDC0FJGJizJsOzDIXgQ75UtPC+Zqe0A3dvnnf5VEeQ61RTg==",
|
||||
"minimumBuild":1,
|
||||
"minimumVersion":"0.90",
|
||||
"permitProvisionalFirmware":true,
|
||||
"requireIdBlock":true,
|
||||
"trustedAuthorKeys":[
|
||||
"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw="
|
||||
],
|
||||
"trustedAuthorKeyHashes":[
|
||||
"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw="
|
||||
],
|
||||
"trustedIdKeys":[
|
||||
"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw="
|
||||
],
|
||||
"trustedIdKeyHashes":[
|
||||
"GSvLKpfu59Y9QOF6vhq0vQsOIvb4+5O/UOHLGLBTkdw="
|
||||
],
|
||||
"product":{
|
||||
"name":"SEV_PRODUCT_MILAN",
|
||||
"stepping":1,
|
||||
"machineStepping":1
|
||||
}
|
||||
}
|
||||
}*/
|
||||
func parseConfig() error {
|
||||
if cfgString == "" {
|
||||
return nil
|
||||
}
|
||||
if err := protojson.Unmarshal([]byte(cfgString), &cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
// Populate fields that should not be nil
|
||||
if cfg.RootOfTrust == nil {
|
||||
cfg.RootOfTrust = &check.RootOfTrust{}
|
||||
}
|
||||
if cfg.Policy == nil {
|
||||
cfg.Policy = &check.Policy{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseHashes() error {
|
||||
for _, hash := range trustedAuthorHashes {
|
||||
hashBytes, err := hex.DecodeString(hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Policy.TrustedAuthorKeyHashes = append(cfg.Policy.TrustedAuthorKeyHashes, hashBytes)
|
||||
}
|
||||
for _, hash := range trustedIdKeyHashes {
|
||||
hashBytes, err := hex.DecodeString(hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Policy.TrustedIdKeyHashes = append(cfg.Policy.TrustedIdKeyHashes, hashBytes)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseFiles() error {
|
||||
file, err := os.ReadFile(attestationFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attestation = file
|
||||
for _, path := range trustedAuthorKeys {
|
||||
file, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Policy.TrustedAuthorKeys = append(cfg.Policy.TrustedAuthorKeys, file)
|
||||
}
|
||||
for _, path := range trustedIdKeys {
|
||||
file, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Policy.TrustedIdKeys = append(cfg.Policy.TrustedIdKeys, file)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseUints() error {
|
||||
if stepping != "" {
|
||||
if base := getBase(stepping); base == 10 {
|
||||
num, err := strconv.ParseUint(stepping, getBase(stepping), 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Policy.Product.MachineStepping = wrapperspb.UInt32(uint32(num))
|
||||
} else {
|
||||
num, err := strconv.ParseUint(stepping[2:], base, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Policy.Product.MachineStepping = wrapperspb.UInt32(uint32(num))
|
||||
}
|
||||
}
|
||||
if platformInfo != "" {
|
||||
if base := getBase(platformInfo); base == 10 {
|
||||
num, err := strconv.ParseUint(platformInfo, getBase(platformInfo), 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Policy.PlatformInfo = wrapperspb.UInt64(num)
|
||||
} else {
|
||||
num, err := strconv.ParseUint(platformInfo[2:], base, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Policy.PlatformInfo = wrapperspb.UInt64(num)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBase(val string) int {
|
||||
switch {
|
||||
case strings.HasPrefix(val, "0x"):
|
||||
return 16
|
||||
case strings.HasPrefix(val, "0o"):
|
||||
return 8
|
||||
case strings.HasPrefix(val, "0b"):
|
||||
return 2
|
||||
default:
|
||||
return 10
|
||||
}
|
||||
}
|
||||
|
||||
func validateInput() error {
|
||||
if len(cfg.RootOfTrust.CabundlePaths) != 0 || len(cfg.RootOfTrust.Cabundles) != 0 && cfg.RootOfTrust.Product == "" {
|
||||
return fmt.Errorf("product name must be set if CA bundles are provided")
|
||||
}
|
||||
|
||||
if err := validateFieldLength("report_data", cfg.Policy.ReportData, size64); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateFieldLength("host_data", cfg.Policy.HostData, size32); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateFieldLength("family_id", cfg.Policy.FamilyId, size16); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateFieldLength("image_id", cfg.Policy.ImageId, size16); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateFieldLength("report_id", cfg.Policy.ReportId, size32); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateFieldLength("report_id_ma", cfg.Policy.ReportIdMa, size32); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateFieldLength("measurement", cfg.Policy.Measurement, size48); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateFieldLength("chip_id", cfg.Policy.ChipId, size64); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, hash := range cfg.Policy.TrustedAuthorKeyHashes {
|
||||
if err := validateFieldLength("trusted_author_key_hash", hash, size48); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, hash := range cfg.Policy.TrustedIdKeyHashes {
|
||||
if err := validateFieldLength("trusted_id_key_hash", hash, size48); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateFieldLength(fieldName string, field []byte, expectedLength int) error {
|
||||
if field != nil && len(field) != expectedLength {
|
||||
return fmt.Errorf("%s length should be at least %d bytes long", fieldName, expectedLength)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+3
-4
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
func NewDatasetsCmd(sdk agent.Service) *cobra.Command {
|
||||
func (cli *CLI) NewDatasetsCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "data",
|
||||
Short: "Upload a dataset CSV file",
|
||||
@@ -32,12 +32,11 @@ func NewDatasetsCmd(sdk agent.Service) *cobra.Command {
|
||||
Provider: args[2],
|
||||
}
|
||||
|
||||
response, err := sdk.Data(cmd.Context(), dataReq)
|
||||
if err != nil {
|
||||
if err := cli.agentSDK.Data(cmd.Context(), dataReq); err != nil {
|
||||
log.Fatalf("Error uploading dataset: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Response:", response)
|
||||
log.Println("Successfully uploaded dataset")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Computation Service API
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: http://localhost:7002
|
||||
paths:
|
||||
/run:
|
||||
post:
|
||||
summary: Run a computation
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
description: The computation binary file (Linux executable)
|
||||
responses:
|
||||
"200":
|
||||
description: Computation started
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
computationId:
|
||||
type: string
|
||||
description: Identifier for the computation
|
||||
|
||||
/algo:
|
||||
post:
|
||||
summary: Upload algorithm binary
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
description: The algorithm binary file (Linux executable)
|
||||
responses:
|
||||
"200":
|
||||
description: Algorithm binary uploaded
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
algorithmId:
|
||||
type: string
|
||||
description: Identifier for the uploaded algorithm binary
|
||||
|
||||
/data:
|
||||
post:
|
||||
summary: Upload dataset CSV file
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
description: The dataset CSV file as a binary
|
||||
responses:
|
||||
"200":
|
||||
description: Dataset CSV uploaded
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
datasetId:
|
||||
type: string
|
||||
description: Identifier for the uploaded dataset CSV
|
||||
|
||||
/result:
|
||||
get:
|
||||
summary: Retrieve computation result file
|
||||
responses:
|
||||
"200":
|
||||
description: Computation result file retrieved successfully
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
description: The computation result file
|
||||
|
||||
/attestation:
|
||||
get:
|
||||
summary: Attestation endpoint
|
||||
responses:
|
||||
"200":
|
||||
description: Attestation result file retrieved successfully
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
description: The attestation result file
|
||||
+2
-3
@@ -7,12 +7,11 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
const resultFilePath = "result.bin"
|
||||
|
||||
func NewResultsCmd(sdk agent.Service) *cobra.Command {
|
||||
func (cli *CLI) NewResultsCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "result",
|
||||
Short: "Retrieve computation result file",
|
||||
@@ -20,7 +19,7 @@ func NewResultsCmd(sdk agent.Service) *cobra.Command {
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.Println("Retrieving computation result file")
|
||||
|
||||
result, err := sdk.Result(cmd.Context(), args[0])
|
||||
result, err := cli.agentSDK.Result(cmd.Context(), args[0])
|
||||
if err != nil {
|
||||
log.Fatalf("Error retrieving computation result: %v", err)
|
||||
}
|
||||
|
||||
+8
-1
@@ -6,5 +6,12 @@ import (
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
func SetSDK(s agent.Service) {
|
||||
type CLI struct {
|
||||
agentSDK agent.Service
|
||||
}
|
||||
|
||||
func New(agentSDK agent.Service) *CLI {
|
||||
return &CLI{
|
||||
agentSDK: agentSDK,
|
||||
}
|
||||
}
|
||||
|
||||
+60
-71
@@ -5,22 +5,20 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"log/slog"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/uuid"
|
||||
"github.com/mdlayher/vsock"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"github.com/ultravioletrs/cocos/agent/api"
|
||||
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
||||
"github.com/ultravioletrs/cocos/agent/events"
|
||||
"github.com/ultravioletrs/cocos/internal"
|
||||
"github.com/ultravioletrs/cocos/internal/env"
|
||||
"github.com/ultravioletrs/cocos/internal/events"
|
||||
agentlogger "github.com/ultravioletrs/cocos/internal/logger"
|
||||
"github.com/ultravioletrs/cocos/internal/server"
|
||||
grpcserver "github.com/ultravioletrs/cocos/internal/server/grpc"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
@@ -28,65 +26,54 @@ import (
|
||||
|
||||
const (
|
||||
svcName = "agent"
|
||||
envPrefixHTTP = "AGENT_HTTP_"
|
||||
envPrefixGRPC = "AGENT_GRPC_"
|
||||
defSvcHTTPPort = "9031"
|
||||
defSvcGRPCPort = "7002"
|
||||
)
|
||||
|
||||
var errComputationNotFound = errors.New("computation not found in command line")
|
||||
|
||||
type config struct {
|
||||
LogLevel string `env:"AGENT_LOG_LEVEL" envDefault:"info"`
|
||||
InstanceID string `env:"AGENT_INSTANCE_ID" envDefault:""`
|
||||
NotificationServerURL string `env:"COCOS_NOTIFICATION_SERVER_URL" envDefault:"http://localhost:9000"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
var cfg config
|
||||
if err := env.Parse(&cfg); err != nil {
|
||||
log.Fatalf("failed to load %s configuration : %s", svcName, err)
|
||||
}
|
||||
|
||||
logger, err := mglog.New(os.Stdout, cfg.LogLevel)
|
||||
cfg, err := readConfig()
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
log.Fatalf("failed to read agent configuration from vsock %s", err.Error())
|
||||
}
|
||||
|
||||
if cfg.InstanceID == "" {
|
||||
cfg.InstanceID, err = uuid.New().ID()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to generate instanceID: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
eventSvc := events.New(svcName, cfg.NotificationServerURL)
|
||||
svc := newService(ctx, logger, eventSvc)
|
||||
|
||||
ac, err := extractComputationValue()
|
||||
conn, err := vsock.Dial(vsock.Host, manager.ManagerVsockPort, nil)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("computation not loaded from cmdline : %s", err.Error()))
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := svc.Run(ctx, ac); err != nil {
|
||||
if err := eventSvc.SendEvent("init", ac.ID, "failed", json.RawMessage{}); err != nil {
|
||||
logger.Warn(err.Error())
|
||||
}
|
||||
logger.Fatal(fmt.Sprintf("failed to run computation with err: %s", err))
|
||||
}
|
||||
|
||||
grpcServerConfig := server.Config{Port: defSvcGRPCPort}
|
||||
if err := env.Parse(&grpcServerConfig, env.Options{Prefix: envPrefixGRPC}); err != nil {
|
||||
log.Printf("failed to load %s gRPC server configuration : %s", svcName, err.Error())
|
||||
defer conn.Close()
|
||||
var level slog.Level
|
||||
if err := level.UnmarshalText([]byte(cfg.AgentConfig.LogLevel)); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
handler := agentlogger.NewProtoHandler(conn, &slog.HandlerOptions{Level: level})
|
||||
logger := slog.New(handler)
|
||||
|
||||
eventSvc, err := events.New(svcName, cfg.ID, manager.ManagerVsockPort)
|
||||
if err != nil {
|
||||
log.Printf("failed to create events service %s", err.Error())
|
||||
return
|
||||
}
|
||||
defer eventSvc.Close()
|
||||
svc := newService(ctx, logger, eventSvc, cfg)
|
||||
|
||||
grpcServerConfig := server.Config{
|
||||
Port: cfg.AgentConfig.Port,
|
||||
Host: cfg.AgentConfig.Host,
|
||||
CertFile: cfg.AgentConfig.CertFile,
|
||||
KeyFile: cfg.AgentConfig.KeyFile,
|
||||
ServerCAFile: cfg.AgentConfig.ServerCAFile,
|
||||
ClientCAFile: cfg.AgentConfig.ClientCAFile,
|
||||
AttestedTLS: cfg.AgentConfig.AttestedTls,
|
||||
}
|
||||
|
||||
registerAgentServiceServer := func(srv *grpc.Server) {
|
||||
reflection.Register(srv)
|
||||
agent.RegisterAgentServiceServer(srv, agentgrpc.NewServer(svc))
|
||||
}
|
||||
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger)
|
||||
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger, &svc)
|
||||
|
||||
g.Go(func() error {
|
||||
return gs.Start()
|
||||
@@ -101,8 +88,8 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func newService(ctx context.Context, logger mglog.Logger, eventSvc events.Service) agent.Service {
|
||||
svc := agent.New(ctx, logger, eventSvc)
|
||||
func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Service, cmp agent.Computation) agent.Service {
|
||||
svc := agent.New(ctx, logger, eventSvc, cmp)
|
||||
|
||||
svc = api.LoggingMiddleware(svc, logger)
|
||||
counter, latency := internal.MakeMetrics(svcName, "api")
|
||||
@@ -111,31 +98,33 @@ func newService(ctx context.Context, logger mglog.Logger, eventSvc events.Servic
|
||||
return svc
|
||||
}
|
||||
|
||||
// extractComputationValue to extract computation value from the command line.
|
||||
func extractComputationValue() (agent.Computation, error) {
|
||||
cmdLineBytes, err := os.ReadFile("/proc/cmdline")
|
||||
func readConfig() (agent.Computation, error) {
|
||||
l, err := vsock.Listen(manager.VsockConfigPort, nil)
|
||||
if err != nil {
|
||||
return agent.Computation{}, err
|
||||
}
|
||||
cmdLine := string(cmdLineBytes)
|
||||
paramPrefix := "computation="
|
||||
index := strings.Index(string(cmdLine), paramPrefix)
|
||||
|
||||
if index == -1 {
|
||||
return agent.Computation{}, errComputationNotFound
|
||||
}
|
||||
|
||||
start := index + len(paramPrefix)
|
||||
end := strings.Index(cmdLine[start:], " ")
|
||||
|
||||
cmpUnescaped := cmdLine[start : start+end]
|
||||
var ac agent.Computation
|
||||
if end == -1 {
|
||||
cmpUnescaped = cmdLine[start:]
|
||||
}
|
||||
|
||||
if err := json.Unmarshal([]byte(cmpUnescaped), &ac); err != nil {
|
||||
defer l.Close()
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
return agent.Computation{}, err
|
||||
}
|
||||
defer conn.Close()
|
||||
b := make([]byte, 1024)
|
||||
n, err := conn.Read(b)
|
||||
if err != nil {
|
||||
return agent.Computation{}, err
|
||||
}
|
||||
ac := agent.Computation{
|
||||
AgentConfig: agent.AgentConfig{},
|
||||
}
|
||||
if err := json.Unmarshal(b[:n], &ac); err != nil {
|
||||
return agent.Computation{}, err
|
||||
}
|
||||
if ac.AgentConfig.LogLevel == "" {
|
||||
ac.AgentConfig.LogLevel = "info"
|
||||
}
|
||||
if ac.AgentConfig.Port == "" {
|
||||
ac.AgentConfig.Port = defSvcGRPCPort
|
||||
}
|
||||
return ac, nil
|
||||
}
|
||||
|
||||
+20
-12
@@ -20,10 +20,11 @@ import (
|
||||
const (
|
||||
svcName = "cli"
|
||||
envPrefixAgentGRPC = "AGENT_GRPC_"
|
||||
completion = "completion"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
LogLevel string `env:"AGENT_LOG_LEVEL" envDefault:"info"`
|
||||
LogLevel string `env:"AGENT_LOG_LEVEL" envDefault:"info"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -39,31 +40,33 @@ func main() {
|
||||
|
||||
agentGRPCConfig := grpc.Config{}
|
||||
if err := env.Parse(&agentGRPCConfig, env.Options{Prefix: envPrefixAgentGRPC}); err != nil {
|
||||
logger.Fatal(fmt.Sprintf("failed to load %s gRPC client configuration : %s", svcName, err))
|
||||
logger.Error(fmt.Sprintf("failed to load %s gRPC client configuration : %s", svcName, err))
|
||||
return
|
||||
}
|
||||
|
||||
agentGRPCClient, agentClient, err := agent.NewAgentClient(agentGRPCConfig)
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
defer agentGRPCClient.Close()
|
||||
|
||||
agentSDK := sdk.NewAgentSDK(logger, agentClient)
|
||||
|
||||
cli.SetSDK(agentSDK)
|
||||
cliSVC := cli.New(agentSDK)
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "cocos-cli [command]",
|
||||
Short: "CLI application for Computation Service API",
|
||||
Short: "CLI application for CoCos Service API",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("CLI application for Computation Service API\n\n")
|
||||
fmt.Printf("CLI application for CoCos Service API\n\n")
|
||||
fmt.Printf("Usage:\n %s [command]\n\n", cmd.CommandPath())
|
||||
fmt.Printf("Available Commands:\n")
|
||||
|
||||
// Filter out "completion" command
|
||||
availableCommands := make([]*cobra.Command, 0)
|
||||
for _, subCmd := range cmd.Commands() {
|
||||
if subCmd.Name() != "completion" {
|
||||
if subCmd.Name() != completion {
|
||||
availableCommands = append(availableCommands, subCmd)
|
||||
}
|
||||
}
|
||||
@@ -80,11 +83,16 @@ func main() {
|
||||
},
|
||||
}
|
||||
|
||||
// Root Commands
|
||||
rootCmd.AddCommand(cli.NewAlgorithmsCmd(agentSDK))
|
||||
rootCmd.AddCommand(cli.NewDatasetsCmd(agentSDK))
|
||||
rootCmd.AddCommand(cli.NewResultsCmd(agentSDK))
|
||||
rootCmd.AddCommand(cli.NewAttestationCmd(agentSDK))
|
||||
// Agent Commands
|
||||
rootCmd.AddCommand(cliSVC.NewAlgorithmsCmd())
|
||||
rootCmd.AddCommand(cliSVC.NewDatasetsCmd())
|
||||
rootCmd.AddCommand(cliSVC.NewResultsCmd())
|
||||
attestaionCmd := cliSVC.NewAttestationCmd()
|
||||
rootCmd.AddCommand(attestaionCmd)
|
||||
|
||||
// Attestation commands
|
||||
attestaionCmd.AddCommand(cliSVC.NewGetAttestationCmd())
|
||||
attestaionCmd.AddCommand(cliSVC.NewValidateAttestationValidationCmd())
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
logger.Error(fmt.Sprintf("Command execution failed: %s", err))
|
||||
|
||||
+43
-53
@@ -7,51 +7,41 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/uuid"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"github.com/ultravioletrs/cocos/internal"
|
||||
"github.com/ultravioletrs/cocos/internal/env"
|
||||
"github.com/ultravioletrs/cocos/internal/events"
|
||||
jaegerclient "github.com/ultravioletrs/cocos/internal/jaeger"
|
||||
"github.com/ultravioletrs/cocos/internal/server"
|
||||
grpcserver "github.com/ultravioletrs/cocos/internal/server/grpc"
|
||||
httpserver "github.com/ultravioletrs/cocos/internal/server/http"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
"github.com/ultravioletrs/cocos/manager/api"
|
||||
managergrpc "github.com/ultravioletrs/cocos/manager/api/grpc"
|
||||
httpapi "github.com/ultravioletrs/cocos/manager/api/http"
|
||||
managerapi "github.com/ultravioletrs/cocos/manager/api/grpc"
|
||||
"github.com/ultravioletrs/cocos/manager/qemu"
|
||||
"github.com/ultravioletrs/cocos/manager/tracing"
|
||||
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
||||
managergrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc/manager"
|
||||
pkgmanager "github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
const (
|
||||
svcName = "manager"
|
||||
envPrefixHTTP = "MANAGER_HTTP_"
|
||||
envPrefixGRPC = "MANAGER_GRPC_"
|
||||
envPrefixAgentGRPC = "AGENT_GRPC_"
|
||||
envPrefixQemu = "MANAGER_QEMU_"
|
||||
defSvcGRPCPort = "7001"
|
||||
defSvcHTTPPort = "9021"
|
||||
svcName = "manager"
|
||||
envPrefixGRPC = "MANAGER_GRPC_"
|
||||
envPrefixQemu = "MANAGER_QEMU_"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
LogLevel string `env:"MANAGER_LOG_LEVEL" envDefault:"info"`
|
||||
JaegerURL string `env:"COCOS_JAEGER_URL" envDefault:"http://localhost:14268/api/traces"`
|
||||
InstanceID string `env:"MANAGER_INSTANCE_ID" envDefault:""`
|
||||
NotificationServerURL string `env:"COCOS_NOTIFICATION_SERVER_URL" envDefault:"http://localhost:9000"`
|
||||
HostIP string `env:"MANAGER_HOST_IP" envDefault:"localhost"`
|
||||
LogLevel string `env:"MANAGER_LOG_LEVEL" envDefault:"info"`
|
||||
JaegerURL string `env:"COCOS_JAEGER_URL" envDefault:"http://localhost:14268/api/traces"`
|
||||
InstanceID string `env:"MANAGER_INSTANCE_ID" envDefault:""`
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx := context.Background()
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
var cfg config
|
||||
@@ -67,7 +57,8 @@ func main() {
|
||||
if cfg.InstanceID == "" {
|
||||
cfg.InstanceID, err = uuid.New().ID()
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("Failed to generate instance ID: %s", err))
|
||||
logger.Error(fmt.Sprintf("Failed to generate instance ID: %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,43 +75,42 @@ func main() {
|
||||
|
||||
qemuCfg := qemu.Config{}
|
||||
if err := env.Parse(&qemuCfg, env.Options{Prefix: envPrefixQemu}); err != nil {
|
||||
logger.Fatal(fmt.Sprintf("failed to load QEMU configuration: %s", err))
|
||||
logger.Error(fmt.Sprintf("failed to load QEMU configuration: %s", err))
|
||||
return
|
||||
}
|
||||
exe, args, err := qemu.ExecutableAndArgs(qemuCfg, agent.Computation{})
|
||||
exe, args, err := qemu.ExecutableAndArgs(qemuCfg)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("failed to parse QEMU configuration: %s", err))
|
||||
logger.Error(fmt.Sprintf("failed to parse QEMU configuration: %s", err))
|
||||
return
|
||||
}
|
||||
logger.Info(fmt.Sprintf("%s %s", exe, strings.Join(args, " ")))
|
||||
|
||||
svc := newService(logger, tracer, qemuCfg, events.New(svcName, cfg.NotificationServerURL), cfg)
|
||||
|
||||
httpServerConfig := server.Config{Port: defSvcHTTPPort}
|
||||
if err := env.Parse(&httpServerConfig, env.Options{Prefix: envPrefixHTTP}); err != nil {
|
||||
logger.Fatal(fmt.Sprintf("failed to load %s gRPC server configuration: %s", svcName, err))
|
||||
}
|
||||
hs := httpserver.New(ctx, cancel, svcName, httpServerConfig, httpapi.MakeHandler(svc, cfg.InstanceID), logger)
|
||||
|
||||
grpcServerConfig := server.Config{Port: defSvcGRPCPort}
|
||||
if err := env.Parse(&grpcServerConfig, env.Options{Prefix: envPrefixGRPC}); err != nil {
|
||||
log.Printf("failed to load %s gRPC server configuration: %s", svcName, err.Error())
|
||||
managerGRPCConfig := grpc.Config{}
|
||||
if err := env.Parse(&managerGRPCConfig, env.Options{Prefix: envPrefixGRPC}); err != nil {
|
||||
logger.Error(fmt.Sprintf("failed to load %s gRPC client configuration : %s", svcName, err))
|
||||
return
|
||||
}
|
||||
registerManagerServiceServer := func(srv *grpc.Server) {
|
||||
reflection.Register(srv)
|
||||
manager.RegisterManagerServiceServer(srv, managergrpc.NewServer(svc))
|
||||
|
||||
managerGRPCClient, managerClient, err := managergrpc.NewManagerClient(managerGRPCConfig)
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerManagerServiceServer, logger)
|
||||
defer managerGRPCClient.Close()
|
||||
|
||||
pc, err := managerClient.Process(ctx)
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
eventsChan := make(chan *pkgmanager.ClientStreamMessage)
|
||||
svc := newService(logger, tracer, qemuCfg, eventsChan)
|
||||
|
||||
mc := managerapi.NewClient(pc, svc, eventsChan)
|
||||
|
||||
g.Go(func() error {
|
||||
return hs.Start()
|
||||
})
|
||||
|
||||
g.Go(func() error {
|
||||
return gs.Start()
|
||||
})
|
||||
|
||||
g.Go(func() error {
|
||||
return server.StopHandler(ctx, cancel, logger, svcName, hs, gs)
|
||||
return mc.Process(ctx)
|
||||
})
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
@@ -133,9 +123,9 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func newService(logger mglog.Logger, tracer trace.Tracer, qemuCfg qemu.Config, eventSvc events.Service, cfg config) manager.Service {
|
||||
svc := manager.New(qemuCfg, logger, eventSvc, cfg.HostIP)
|
||||
|
||||
func newService(logger *slog.Logger, tracer trace.Tracer, qemuCfg qemu.Config, eventsChan chan *pkgmanager.ClientStreamMessage) manager.Service {
|
||||
svc := manager.New(qemuCfg, logger, eventsChan)
|
||||
go svc.RetrieveAgentEventsLogs()
|
||||
svc = api.LoggingMiddleware(svc, logger)
|
||||
counter, latency := internal.MakeMetrics(svcName, "api")
|
||||
svc = api.MetricsMiddleware(svc, counter, latency)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
FROM golang:1.21-alpine AS builder
|
||||
ARG SVC
|
||||
ARG GOARCH
|
||||
ARG GOARM
|
||||
ARG VERSION
|
||||
ARG COMMIT
|
||||
ARG TIME
|
||||
|
||||
WORKDIR /go/src/github.com/ultravioletrs/cocos-ai
|
||||
COPY . .
|
||||
RUN apk update \
|
||||
&& apk add make \
|
||||
&& make $SVC \
|
||||
&& mv build/cocos-$SVC /exe
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk add qemu-system-x86_64
|
||||
COPY --from=builder /exe /
|
||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
ENTRYPOINT ["/exe"]
|
||||
@@ -1,7 +0,0 @@
|
||||
FROM alpine:latest
|
||||
ARG SVC
|
||||
RUN apk add --no-cache qemu-system-x86_64
|
||||
COPY cocos-$SVC /exe
|
||||
COPY --from=alpine:latest /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
ENTRYPOINT ["/exe"]
|
||||
@@ -1,36 +0,0 @@
|
||||
version: "3.7"
|
||||
name: "cocos"
|
||||
|
||||
networks:
|
||||
cocos-base-net:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one:1.38.0
|
||||
container_name: cocos-jaeger
|
||||
ports:
|
||||
- ${COCOS_JAEGER_PORT}:${COCOS_JAEGER_PORT}/udp
|
||||
- ${COCOS_JAEGER_FRONTEND}:${COCOS_JAEGER_FRONTEND}
|
||||
- ${COCOS_JAEGER_COLLECTOR}:${COCOS_JAEGER_COLLECTOR}
|
||||
- ${COCOS_JAEGER_CONFIGS}:${COCOS_JAEGER_CONFIGS}
|
||||
networks:
|
||||
- cocos-base-net
|
||||
cocos-manager:
|
||||
image: ghcr.io/ultravioletrs/cocos/manager:latest
|
||||
container_name: cocos-manager
|
||||
env_file:
|
||||
- .env
|
||||
devices:
|
||||
- /dev/kvm
|
||||
volumes:
|
||||
- ../cmd/manager/img:/img
|
||||
- /usr/share/edk2/x64/OVMF_CODE.fd:/usr/share/OVMF/OVMF_CODE.fd
|
||||
- /usr/share/edk2/x64/OVMF_VARS.fd:/usr/share/OVMF/OVMF_VARS.fd
|
||||
depends_on:
|
||||
- jaeger
|
||||
networks:
|
||||
- cocos-base-net
|
||||
ports:
|
||||
- ${MANAGER_HTTP_PORT}:${MANAGER_HTTP_PORT}
|
||||
- ${MANAGER_GRPC_PORT}:${MANAGER_GRPC_PORT}
|
||||
@@ -1,24 +1,26 @@
|
||||
module github.com/ultravioletrs/cocos
|
||||
|
||||
go 1.21.3
|
||||
go 1.21.6
|
||||
|
||||
require (
|
||||
github.com/absmach/magistrala v0.0.0-20240110171157-9f573850fc4b
|
||||
github.com/absmach/magistrala v0.0.0-20240119191055-d95283d31472
|
||||
github.com/caarlos0/env/v7 v7.1.0
|
||||
github.com/cenkalti/backoff/v4 v4.2.1
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519
|
||||
github.com/go-kit/kit v0.13.0
|
||||
github.com/go-zoo/bone v1.3.0
|
||||
github.com/gofrs/uuid v4.4.0+incompatible
|
||||
github.com/google/go-sev-guest v0.10.1
|
||||
github.com/mdlayher/vsock v1.2.1
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1
|
||||
go.opentelemetry.io/otel v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
|
||||
go.opentelemetry.io/otel/sdk v1.21.0
|
||||
go.opentelemetry.io/otel/trace v1.21.0
|
||||
golang.org/x/crypto v0.19.0
|
||||
golang.org/x/sync v0.6.0
|
||||
google.golang.org/grpc v1.60.1
|
||||
google.golang.org/protobuf v1.32.0
|
||||
@@ -27,24 +29,29 @@ require (
|
||||
require (
|
||||
cloud.google.com/go/compute v1.23.3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-configfs-tsm v0.2.2 // indirect
|
||||
github.com/google/logger v1.1.1 // indirect
|
||||
github.com/google/uuid v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/pborman/uuid v1.2.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.45.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
||||
|
||||
@@ -5,8 +5,8 @@ cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGB
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/absmach/magistrala v0.0.0-20240110171157-9f573850fc4b h1:5dwCCLImHebX52aVApF15ruZ/b0MB9Y4zECr3pmF0A4=
|
||||
github.com/absmach/magistrala v0.0.0-20240110171157-9f573850fc4b/go.mod h1:7D+27TxXQwMqTmlerdulb0QtvXpMcSgeGoyvzhxr8MQ=
|
||||
github.com/absmach/magistrala v0.0.0-20240119191055-d95283d31472 h1:MdS3yTTJP/OSFkMJ4+cJ0LnRS9OyPtPxsR0mSFYglXw=
|
||||
github.com/absmach/magistrala v0.0.0-20240119191055-d95283d31472/go.mod h1:02Ip3Ow7JlPT4nb2TdZcOuf7C3ac8tzyEVwB+H1G40g=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/caarlos0/env/v7 v7.1.0 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
|
||||
@@ -26,8 +26,6 @@ github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519 h1:OpkN/n4
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519/go.mod h1:WyJJyfmJ0gWJvjV+ZH4DOgtOYZc1KOvYyBXWCLKxsUU=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
|
||||
github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
|
||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
@@ -39,8 +37,6 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-zoo/bone v1.3.0 h1:PY6sHq37FnQhj+4ZyqFIzJQHvrrGx0GEc3vTZZC/OsI=
|
||||
github.com/go-zoo/bone v1.3.0/go.mod h1:HI3Lhb7G3UQcAwEhOJ2WyNcsFtQX1WYHa0Hl4OBbhW8=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
@@ -49,12 +45,29 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-configfs-tsm v0.2.2 h1:YnJ9rXIOj5BYD7/0DNnzs8AOp7UcvjfTvt215EWcs98=
|
||||
github.com/google/go-configfs-tsm v0.2.2/go.mod h1:EL1GTDFMb5PZQWDviGfZV9n87WeGTR/JUg13RfwkgRo=
|
||||
github.com/google/go-sev-guest v0.10.1 h1:kZIcGD513eqInbezqxchTtOLJlVXALyWlIXu5E0tNJE=
|
||||
github.com/google/go-sev-guest v0.10.1/go.mod h1:/5hrgGWqG7+MPTXKhQz+v9ZE+Eh4MCBdItCNwgshlrk=
|
||||
github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ=
|
||||
github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
|
||||
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
|
||||
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
|
||||
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -82,8 +95,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
|
||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
|
||||
@@ -98,8 +109,12 @@ go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8
|
||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
@@ -114,11 +129,12 @@ golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -9,6 +9,7 @@ git clone git@github.com:ultravioletrs/cocos.git
|
||||
git clone git@github.com:buildroot/buildroot.git
|
||||
cd buildroot
|
||||
make BR2_EXTERNAL=../cocos/hal/linux cocos_defconfig
|
||||
# Execute 'make menuconfig' only if you want to make additional configuration changes to Buildroot.
|
||||
make menuconfig
|
||||
make
|
||||
```
|
||||
|
||||
@@ -38,6 +38,8 @@ CONFIG_AUTOFS4_FS=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_UNWINDER_FRAME_POINTER=y
|
||||
CONFIG_VSOCKETS=y
|
||||
CONFIG_VIRTIO_VSOCKETS=y
|
||||
|
||||
###
|
||||
# AMD SEV-SNP
|
||||
|
||||
@@ -4,7 +4,8 @@ BR2_x86_64=y
|
||||
# System
|
||||
BR2_TARGET_GENERIC_HOSTNAME="cocos"
|
||||
BR2_TARGET_GENERIC_ISSUE="Welcome to Cocos"
|
||||
BR2_SYSTEM_DHCP="eth0"
|
||||
BR2_PACKAGE_DHCP=y
|
||||
BR2_PACKAGE_DHCP_CLIENT=y
|
||||
BR2_INIT_SYSTEMD=y
|
||||
|
||||
# Filesystem
|
||||
@@ -44,3 +45,4 @@ BR2_PACKAGE_HOST_QEMU_SYSTEM_MODE=y
|
||||
|
||||
# Python
|
||||
BR2_PACKAGE_PYTHON3=y
|
||||
BR2_PACKAGE_PYTHON_PIP=y
|
||||
|
||||
@@ -14,12 +14,12 @@ endef
|
||||
define AGENT_INSTALL_TARGET_CMDS
|
||||
$(INSTALL) -D -m 0755 $(@D)/build/cocos-agent $(TARGET_DIR)/bin
|
||||
mkdir -p $(TARGET_DIR)/var/log/cocos
|
||||
mkdir -p $(TARGET_DIR)/cocos/
|
||||
endef
|
||||
|
||||
define AGENT_INSTALL_INIT_SYSTEMD
|
||||
$(INSTALL) -D -m 0644 $(@D)/init/systemd/cocos-agent.service $(TARGET_DIR)/usr/lib/systemd/system/cocos-agent.service
|
||||
$(INSTALL) -D -m 0644 $(@D)/init/systemd/eth0.network $(TARGET_DIR)/etc/systemd/network
|
||||
$(INSTALL) -D -m 0644 $(@D)/init/systemd/00-network.link $(TARGET_DIR)/etc/systemd/network
|
||||
$(INSTALL) -D -m 0755 $(@D)/init/systemd/agent_start_script.sh $(TARGET_DIR)/cocos/agent_start_script.sh
|
||||
endef
|
||||
|
||||
$(eval $(golang-package))
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[Match]
|
||||
OriginalName=*
|
||||
|
||||
[Link]
|
||||
NamePolicy=kernel
|
||||
MACAddressPolicy=persistent
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
# The variable ETH_IFACE contains the name the systemd gave to the network interface.
|
||||
# The systemd configures the name based on the QEMU parameters.
|
||||
# The parts of the name enp0s2 mean:
|
||||
# et - ethernet card. It means this is the ethernet interface.
|
||||
# p - means that the interface is connected to a PCI bus.
|
||||
# 0 - the interface is connected to bus 0.
|
||||
# s2 -the interface is connected to slot 2.
|
||||
|
||||
# The variable ETH_IFACE value must match the name configured through QEMU parameters for the network device.
|
||||
# The bus number and slot number are configured through QEMU device parameters, parameters
|
||||
# addr (for slot number), and bus (for bus number).
|
||||
ETH_IFACE=enp0s2
|
||||
|
||||
ip link set dev $ETH_IFACE up
|
||||
dhclient $ETH_IFACE
|
||||
AGENT_GRPC_HOST=$(ip -4 addr show $ETH_IFACE | grep inet | awk '{print $2}' | cut -d/ -f1)
|
||||
|
||||
export AGENT_GRPC_HOST
|
||||
|
||||
exec /bin/cocos-agent
|
||||
@@ -6,11 +6,10 @@ After=network.target
|
||||
StandardOutput=file:/var/log/cocos/agent.stdout
|
||||
StandardError=file:/var/log/cocos/agent.stderr
|
||||
|
||||
Environment=AGENT_GRPC_HOST=10.0.0.1
|
||||
Environment=AGENT_GRPC_PORT=7002
|
||||
Environment=AGENT_LOG_LEVEL=info
|
||||
|
||||
ExecStart=/bin/cocos-agent
|
||||
ExecStart=/cocos/agent_start_script.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
[Match]
|
||||
Name=eth0
|
||||
|
||||
[Network]
|
||||
Address=10.0.0.1/24
|
||||
+1
-2
@@ -67,8 +67,7 @@ func RunCmdOutput(command string, args ...string) (string, error) {
|
||||
func RunCmdStart(command string, args ...string) (*exec.Cmd, error) {
|
||||
cmd := exec.Command(command, args...)
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("error starting command '%s': %s", cmd.String(), err)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# Events package
|
||||
|
||||
## Overview
|
||||
The events package provides a simple client for sending events to a server. It is designed to be used in conjunction with a server that can handle and process events.
|
||||
|
||||
`service`: A string representing the name of the service. Agent or manager.
|
||||
`serverUrl`: A string representing the URL of the events server.
|
||||
`event`: A string representing the event type of the events.
|
||||
`computationId`: A string representing the computation ID associated with the events. This can be null for idle events.
|
||||
|
||||
The notifications are sent to endpoint `<server_url>/notifications/events` using post method.
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package events
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errFailedToCreateNotification = errors.New("failed to create notification on server")
|
||||
|
||||
type service struct {
|
||||
service string
|
||||
serverUrl string
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
SendEvent(event, computationId, status string, details json.RawMessage) error
|
||||
}
|
||||
|
||||
func New(svc, serverUrl string) Service {
|
||||
return &service{
|
||||
service: svc,
|
||||
serverUrl: serverUrl,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) SendEvent(event, computationId, status string, details json.RawMessage) error {
|
||||
body := struct {
|
||||
EventType string `json:"event_type"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
ComputationID string `json:"computation_id,omitempty"`
|
||||
Details json.RawMessage `json:"details,omitempty"`
|
||||
Originator string `json:"originator"`
|
||||
Status string `json:"status,omitempty"`
|
||||
}{
|
||||
EventType: event,
|
||||
Timestamp: time.Now(),
|
||||
ComputationID: computationId,
|
||||
Originator: s.service,
|
||||
Status: status,
|
||||
Details: details,
|
||||
}
|
||||
jsonBody, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/computations/events", s.serverUrl), bytes.NewReader(jsonBody))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return errFailedToCreateNotification
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -5,14 +5,14 @@ package libvirt
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/digitalocean/go-libvirt"
|
||||
)
|
||||
|
||||
func Connect(logger mglog.Logger) *libvirt.Libvirt {
|
||||
func Connect(logger *slog.Logger) *libvirt.Libvirt {
|
||||
// This dials libvirt on the local machine, but you can substitute the first
|
||||
// two parameters with "tcp", "<ip address>:<port>" to connect to libvirt on
|
||||
// a remote machine.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
var _ slog.Handler = (*handler)(nil)
|
||||
|
||||
type handler struct {
|
||||
opts slog.HandlerOptions
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func NewProtoHandler(w io.Writer, opts *slog.HandlerOptions) slog.Handler {
|
||||
if opts == nil {
|
||||
opts = &slog.HandlerOptions{}
|
||||
}
|
||||
return &handler{
|
||||
opts: *opts,
|
||||
w: w,
|
||||
}
|
||||
}
|
||||
|
||||
// Enabled implements slog.Handler.
|
||||
func (h *handler) Enabled(_ context.Context, l slog.Level) bool {
|
||||
minLevel := slog.LevelInfo
|
||||
if h.opts.Level != nil {
|
||||
minLevel = h.opts.Level.Level()
|
||||
}
|
||||
return l >= minLevel
|
||||
}
|
||||
|
||||
// Handle implements slog.Handler.
|
||||
func (h *handler) Handle(_ context.Context, r slog.Record) error {
|
||||
agentLog := manager.ClientStreamMessage{Message: &manager.ClientStreamMessage_AgentLog{AgentLog: &manager.AgentLog{
|
||||
Timestamp: timestamppb.New(r.Time),
|
||||
Message: r.Message,
|
||||
Level: r.Level.String(),
|
||||
}}}
|
||||
|
||||
b, err := proto.Marshal(&agentLog)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := h.w.Write(b); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithAttrs implements slog.Handler.
|
||||
func (*handler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// WithGroup implements slog.Handler.
|
||||
func (*handler) WithGroup(name string) slog.Handler {
|
||||
panic("unimplemented")
|
||||
}
|
||||
+194
-14
@@ -1,37 +1,60 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"github.com/ultravioletrs/cocos/internal/server"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
const (
|
||||
stopWaitTime = 5 * time.Second
|
||||
stopWaitTime = 5 * time.Second
|
||||
organization = "Ultraviolet"
|
||||
country = "Serbia"
|
||||
province = ""
|
||||
locality = "Belgrade"
|
||||
streetAddress = "Bulevar Arsenija Carnojevica 103"
|
||||
postalCode = "11000"
|
||||
notAfterYear = 1
|
||||
notAfterMonth = 0
|
||||
notAfterDay = 0
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
server.BaseServer
|
||||
server *grpc.Server
|
||||
registerService serviceRegister
|
||||
agent *agent.Service
|
||||
}
|
||||
|
||||
type serviceRegister func(srv *grpc.Server)
|
||||
|
||||
var _ server.Server = (*Server)(nil)
|
||||
|
||||
func New(ctx context.Context, cancel context.CancelFunc, name string, config server.Config, registerService serviceRegister, logger mglog.Logger) server.Server {
|
||||
func New(ctx context.Context, cancel context.CancelFunc, name string, config server.Config, registerService serviceRegister, logger *slog.Logger, agentSvc *agent.Service) server.Server {
|
||||
listenFullAddress := fmt.Sprintf("%s:%s", config.Host, config.Port)
|
||||
|
||||
return &Server{
|
||||
BaseServer: server.BaseServer{
|
||||
Ctx: ctx,
|
||||
@@ -42,35 +65,95 @@ func New(ctx context.Context, cancel context.CancelFunc, name string, config ser
|
||||
Logger: logger,
|
||||
},
|
||||
registerService: registerService,
|
||||
agent: agentSvc,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
errCh := make(chan error)
|
||||
grpcServerOptions := []grpc.ServerOption{
|
||||
grpc.StatsHandler(otelgrpc.NewServerHandler()),
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", s.Address)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to listen on port %s: %w", s.Address, err)
|
||||
}
|
||||
creds := grpc.Creds(insecure.NewCredentials())
|
||||
|
||||
switch {
|
||||
case s.Config.AttestedTLS:
|
||||
certificateBytes, privateKeyBytes, err := generateCertificatesForATLS(s.agent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create certificate: %w", err)
|
||||
}
|
||||
|
||||
certificate, err := tls.X509KeyPair(certificateBytes, privateKeyBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("falied due to invalid key pair: %w", err)
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
ClientAuth: tls.NoClientCert,
|
||||
Certificates: []tls.Certificate{certificate},
|
||||
}
|
||||
|
||||
creds = grpc.Creds(credentials.NewTLS(tlsConfig))
|
||||
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s with Attested TLS", s.Name, s.Address))
|
||||
case s.Config.CertFile != "" || s.Config.KeyFile != "":
|
||||
creds, err := credentials.NewServerTLSFromFile(s.Config.CertFile, s.Config.KeyFile)
|
||||
certificate, err := loadX509KeyPair(s.Config.CertFile, s.Config.KeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load auth certificates: %w", err)
|
||||
}
|
||||
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s with TLS cert %s and key %s", s.Name, s.Address, s.Config.CertFile, s.Config.KeyFile))
|
||||
s.server = grpc.NewServer(
|
||||
grpc.Creds(creds),
|
||||
grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()),
|
||||
)
|
||||
tlsConfig := &tls.Config{
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
Certificates: []tls.Certificate{certificate},
|
||||
}
|
||||
|
||||
var mtlsCA string
|
||||
// Loading Server CA file
|
||||
rootCA, err := loadCertFile(s.Config.ServerCAFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load root ca file: %w", err)
|
||||
}
|
||||
if len(rootCA) > 0 {
|
||||
if tlsConfig.RootCAs == nil {
|
||||
tlsConfig.RootCAs = x509.NewCertPool()
|
||||
}
|
||||
if !tlsConfig.RootCAs.AppendCertsFromPEM(rootCA) {
|
||||
return fmt.Errorf("failed to append root ca to tls.Config")
|
||||
}
|
||||
mtlsCA = fmt.Sprintf("root ca %s", s.Config.ServerCAFile)
|
||||
}
|
||||
|
||||
// Loading Client CA File
|
||||
clientCA, err := loadCertFile(s.Config.ClientCAFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load client ca file: %w", err)
|
||||
}
|
||||
if len(clientCA) > 0 {
|
||||
if tlsConfig.ClientCAs == nil {
|
||||
tlsConfig.ClientCAs = x509.NewCertPool()
|
||||
}
|
||||
if !tlsConfig.ClientCAs.AppendCertsFromPEM(clientCA) {
|
||||
return fmt.Errorf("failed to append client ca to tls.Config")
|
||||
}
|
||||
mtlsCA = fmt.Sprintf("%s client ca %s", mtlsCA, s.Config.ClientCAFile)
|
||||
}
|
||||
creds = grpc.Creds(credentials.NewTLS(tlsConfig))
|
||||
switch {
|
||||
case mtlsCA != "":
|
||||
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s with TLS/mTLS cert %s , key %s and %s", s.Name, s.Address, s.Config.CertFile, s.Config.KeyFile, mtlsCA))
|
||||
default:
|
||||
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s with TLS cert %s and key %s", s.Name, s.Address, s.Config.CertFile, s.Config.KeyFile))
|
||||
}
|
||||
default:
|
||||
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s without TLS", s.Name, s.Address))
|
||||
s.server = grpc.NewServer(
|
||||
grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()),
|
||||
)
|
||||
}
|
||||
|
||||
grpcServerOptions = append(grpcServerOptions, creds)
|
||||
|
||||
s.server = grpc.NewServer(grpcServerOptions...)
|
||||
s.registerService(s.server)
|
||||
|
||||
go func() {
|
||||
@@ -82,7 +165,6 @@ func (s *Server) Start() error {
|
||||
return s.Stop()
|
||||
case err := <-errCh:
|
||||
s.Cancel()
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -102,3 +184,101 @@ func (s *Server) Stop() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadCertFile(certFile string) ([]byte, error) {
|
||||
if certFile != "" {
|
||||
return os.ReadFile(certFile)
|
||||
}
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func loadX509KeyPair(certfile, keyfile string) (tls.Certificate, error) {
|
||||
var cert, key []byte
|
||||
var err error
|
||||
if _, err = os.Stat(certfile); err == nil {
|
||||
cert, err = os.ReadFile(certfile)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
} else if os.IsNotExist(err) {
|
||||
cert = []byte(certfile)
|
||||
} else {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
if _, err := os.Stat(keyfile); err == nil {
|
||||
key, err = os.ReadFile(keyfile)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
} else if os.IsNotExist(err) {
|
||||
key = []byte(keyfile)
|
||||
} else {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
return tls.X509KeyPair(cert, key)
|
||||
}
|
||||
|
||||
func generateCertificatesForATLS(svc *agent.Service) ([]byte, []byte, error) {
|
||||
curve := elliptic.P256()
|
||||
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to generate private/public key: %w", err)
|
||||
}
|
||||
|
||||
publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to marshal the public key: %w", err)
|
||||
}
|
||||
|
||||
// The Attestation Report will be added as an X.509 certificate extension
|
||||
attestationReport, err := (*svc).Attestation(context.Background(), sha3.Sum512(publicKeyBytes))
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to fetch the attestation report: %w", err)
|
||||
}
|
||||
|
||||
certTemplate := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(202403311),
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{organization},
|
||||
Country: []string{country},
|
||||
Province: []string{province},
|
||||
Locality: []string{locality},
|
||||
StreetAddress: []string{streetAddress},
|
||||
PostalCode: []string{postalCode},
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(notAfterYear, notAfterMonth, notAfterDay),
|
||||
KeyUsage: x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6},
|
||||
Critical: false,
|
||||
Value: attestationReport,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
certDERBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create certificate: %w", err)
|
||||
}
|
||||
|
||||
certBytes := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certDERBytes,
|
||||
})
|
||||
|
||||
privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to marshal the private key: %w", err)
|
||||
}
|
||||
|
||||
keyBytes := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: privateKeyBytes,
|
||||
})
|
||||
|
||||
return certBytes, keyBytes, nil
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package http contains the HTTP server implementation.
|
||||
package http
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/ultravioletrs/cocos/internal/server"
|
||||
)
|
||||
|
||||
const (
|
||||
stopWaitTime = 5 * time.Second
|
||||
httpProtocol = "http"
|
||||
httpsProtocol = "https"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
server.BaseServer
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
var _ server.Server = (*Server)(nil)
|
||||
|
||||
func New(ctx context.Context, cancel context.CancelFunc, name string, config server.Config, handler http.Handler, logger mglog.Logger) server.Server {
|
||||
listenFullAddress := fmt.Sprintf("%s:%s", config.Host, config.Port)
|
||||
httpServer := &http.Server{Addr: listenFullAddress, Handler: handler}
|
||||
return &Server{
|
||||
BaseServer: server.BaseServer{
|
||||
Ctx: ctx,
|
||||
Cancel: cancel,
|
||||
Name: name,
|
||||
Address: listenFullAddress,
|
||||
Config: config,
|
||||
Logger: logger,
|
||||
},
|
||||
server: httpServer,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
errCh := make(chan error)
|
||||
s.Protocol = httpProtocol
|
||||
switch {
|
||||
case s.Config.CertFile != "" || s.Config.KeyFile != "":
|
||||
s.Protocol = httpsProtocol
|
||||
s.Logger.Info(fmt.Sprintf("%s service %s server listening at %s with TLS cert %s and key %s", s.Name, s.Protocol, s.Address, s.Config.CertFile, s.Config.KeyFile))
|
||||
go func() {
|
||||
errCh <- s.server.ListenAndServeTLS(s.Config.CertFile, s.Config.KeyFile)
|
||||
}()
|
||||
default:
|
||||
s.Logger.Info(fmt.Sprintf("%s service %s server listening at %s without TLS", s.Name, s.Protocol, s.Address))
|
||||
go func() {
|
||||
errCh <- s.server.ListenAndServe()
|
||||
}()
|
||||
}
|
||||
select {
|
||||
case <-s.Ctx.Done():
|
||||
return s.Stop()
|
||||
case err := <-errCh:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Stop() error {
|
||||
defer s.Cancel()
|
||||
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
|
||||
defer cancelShutdown()
|
||||
if err := s.server.Shutdown(ctxShutdown); err != nil {
|
||||
s.Logger.Error(fmt.Sprintf("%s service %s server error occurred during shutdown at %s: %s", s.Name, s.Protocol, s.Address, err))
|
||||
return fmt.Errorf("%s service %s server error occurred during shutdown at %s: %w", s.Name, s.Protocol, s.Address, err)
|
||||
}
|
||||
s.Logger.Info(fmt.Sprintf("%s %s service shutdown of http at %s", s.Name, s.Protocol, s.Address))
|
||||
return nil
|
||||
}
|
||||
@@ -5,11 +5,10 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
@@ -18,10 +17,13 @@ type Server interface {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Host string `env:"HOST" envDefault:""`
|
||||
Port string `env:"PORT" envDefault:""`
|
||||
CertFile string `env:"SERVER_CERT" envDefault:""`
|
||||
KeyFile string `env:"SERVER_KEY" envDefault:""`
|
||||
Host string `env:"HOST" envDefault:""`
|
||||
Port string `env:"PORT" envDefault:""`
|
||||
CertFile string `env:"SERVER_CERT" envDefault:""`
|
||||
KeyFile string `env:"SERVER_KEY" envDefault:""`
|
||||
ServerCAFile string `env:"SERVER_CA_CERTS" envDefault:""`
|
||||
ClientCAFile string `env:"CLIENT_CA_CERTS" envDefault:""`
|
||||
AttestedTLS bool `env:"ATTESTED_TLS" envDefault:"false"`
|
||||
}
|
||||
|
||||
type BaseServer struct {
|
||||
@@ -30,7 +32,7 @@ type BaseServer struct {
|
||||
Name string
|
||||
Address string
|
||||
Config Config
|
||||
Logger mglog.Logger
|
||||
Logger *slog.Logger
|
||||
Protocol string
|
||||
}
|
||||
|
||||
@@ -49,7 +51,7 @@ func stopAllServer(servers ...Server) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func StopHandler(ctx context.Context, cancel context.CancelFunc, logger mglog.Logger, svcName string, servers ...Server) error {
|
||||
func StopHandler(ctx context.Context, cancel context.CancelFunc, logger *slog.Logger, svcName string, servers ...Server) error {
|
||||
var err error
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGINT, syscall.SIGABRT)
|
||||
|
||||
+67
-80
@@ -1,6 +1,6 @@
|
||||
# Manager
|
||||
|
||||
Manager service provides a barebones HTTP and gRPC API and Service interface implementation for the development of the manager service.
|
||||
Manager service provides a barebones gRPC API and Service interface implementation for the development of the manager service.
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -9,18 +9,14 @@ The service is configured using the environment variables from the following tab
|
||||
| Variable | Description | Default |
|
||||
| ----------------------------- | -------------------------------------------------------- | --------------------------------- |
|
||||
| MANAGER_LOG_LEVEL | Log level for manager service (debug, info, warn, error) | info |
|
||||
| MANAGER_HTTP_HOST | Manager service HTTP host | |
|
||||
| MANAGER_HTTP_PORT | Manager service HTTP port | 9021 |
|
||||
| MANAGER_HTTP_SERVER_CERT | Path to server certificate in pem format | |
|
||||
| MANAGER_HTTP_SERVER_KEY | Path to server key in pem format | |
|
||||
| MANAGER_GRPC_HOST | Manager service gRPC host | |
|
||||
| MANAGER_GRPC_PORT | Manager service gRPC port | 7001 |
|
||||
| MANAGER_GRPC_SERVER_CERT | Path to server certificate in pem format | |
|
||||
| MANAGER_GRPC_SERVER_KEY | Path to server key in pem format | |
|
||||
| MANAGER_GRPC_SERVER_CA_CERTS | Path to gRPC server CA certificate | |
|
||||
| MANAGER_GRPC_CLIENT_CA_CERTS | Path to gRPC client CA certificate | |
|
||||
| COCOS_JAEGER_URL | Jaeger server URL | http://localhost:14268/api/traces |
|
||||
| MANAGER_INSTANCE_ID | Manager service instance ID | |
|
||||
| COCOS_NOTIFICATION_SERVER_URL | Server to receive notification events from agent. | http:/localhost:9000 |
|
||||
| MANAGER_HOST_IP | Mnagaer host IP address | localhost |
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -47,6 +43,22 @@ sudo apt install qemu-kvm
|
||||
|
||||
Create `img` directory in `cmd/manager`. Create `tmp` directory in `cmd/manager`.
|
||||
|
||||
#### Add Vsock
|
||||
The necessary kernel modules must be loaded on the hypervisor. To check if `vhost_vsock` is loaded run:
|
||||
```shell
|
||||
lsmod | grep vhost_vsock
|
||||
```
|
||||
|
||||
If `vhost_vsock` is not loaded run the following commands:
|
||||
|
||||
```shell
|
||||
sudo modprobe vhost_vsock
|
||||
ls -l /dev/vhost-vsock
|
||||
# crw-rw-rw- 1 root kvm 10, 241 Jan 16 12:05 /dev/vhost-vsock
|
||||
ls -l /dev/vsock
|
||||
# crw-rw-rw- 1 root root 10, 121 Jan 16 12:05 /dev/vsock
|
||||
```
|
||||
|
||||
### Prepare Cocos HAL
|
||||
|
||||
Cocos HAL for Linux is framework for building custom in-enclave Linux distribution. Use the instructions in [Readme](https://github.com/ultravioletrs/cocos/blob/main/hal/linux/README.md).
|
||||
@@ -76,10 +88,11 @@ qemu-system-x86_64 \
|
||||
-m 2048M,slots=5,maxmem=10240M \
|
||||
-no-reboot \
|
||||
-drive if=pflash,format=raw,unit=0,file=$OVMF_CODE,readonly=on \
|
||||
-netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 \
|
||||
-netdev user,id=vmnic,hostfwd=tcp::7020-:7002 \
|
||||
-device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= \
|
||||
-device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=3 -vnc :0 \
|
||||
-kernel $KERNEL \
|
||||
-append "earlyprintk=serial console=ttyS0 computation={\"id\":\"c0d15c5e-e37d-4426-b3b7-b432c966fb09\",\"name\":\"Sample_Computation\",\"description\":\"A_sample_computation\",\"datasets\":[{\"provider\":\"Provider1\",\"id\":\"Dataset1\"},{\"provider\":\"Provider2\",\"id\":\"Dataset2\"}],\"algorithms\":[{\"provider\":\"AlgorithmProvider1\",\"id\":\"Algorithm1\"}],\"result_consumers\":[\"Consumer1\"], \"timeout\":\"10m\"}" \
|
||||
-append "earlyprintk=serial console=ttyS0" \
|
||||
-initrd $INITRD \
|
||||
-nographic \
|
||||
-monitor pty \
|
||||
@@ -88,10 +101,9 @@ qemu-system-x86_64 \
|
||||
Once the VM is booted press enter and on the login use username `root`.
|
||||
|
||||
#### Build and run Agent
|
||||
```sh
|
||||
# Start the 'agent' executable in the background using '&' at the end.
|
||||
cocos-agent &
|
||||
|
||||
Agent is started automatically in the VM.
|
||||
```sh
|
||||
# List running processes and use 'grep' to filter for processes containing 'agent' in their names.
|
||||
ps aux | grep cocos-agent
|
||||
# This command helps verify that the 'agent' process is running.
|
||||
@@ -102,12 +114,6 @@ ps aux | grep cocos-agent
|
||||
We can also check if `Agent` is reachable from the host machine:
|
||||
|
||||
```sh
|
||||
# Use netcat (nc) to test the connection to localhost on port 9301.
|
||||
nc -zv localhost 9301
|
||||
# Output:
|
||||
# nc: connect to localhost (::1) port 9301 (tcp) failed: Connection refused
|
||||
# Connection to localhost (127.0.0.1) 9301 port [tcp/*] succeeded!
|
||||
|
||||
# Use netcat (nc) to test the connection to localhost on port 7020.
|
||||
nc -zv localhost 7020
|
||||
# Output:
|
||||
@@ -138,23 +144,19 @@ NB: we set environment variables that we will use in the shell process where we
|
||||
|
||||
## Deployment
|
||||
|
||||
### Standalone
|
||||
|
||||
To start the service outside of the container, execute the following shell script:
|
||||
To start the service, execute the following shell script (note a server needs to be running see [here](../test/computations/README.md)):
|
||||
|
||||
```bash
|
||||
# download the latest version of the service
|
||||
go get github.com/ultravioletrs/cocos
|
||||
# Download the latest version of the service
|
||||
git clone git@github.com:ultravioletrs/cocos.git
|
||||
|
||||
cd $GOPATH/src/github.com/ultravioletrs/cocos
|
||||
cd cocos
|
||||
|
||||
# compile the manager
|
||||
# Compile the manager
|
||||
make manager
|
||||
|
||||
# copy binary to bin
|
||||
make install
|
||||
|
||||
# set the environment variables and run the service
|
||||
# Set the environment variables and run the service
|
||||
MANAGER_GRPC_URL=localhost:7001
|
||||
MANAGER_LOG_LEVEL=debug \
|
||||
MANAGER_QEMU_USE_SUDO=false \
|
||||
MANAGER_QEMU_ENABLE_SEV=false \
|
||||
@@ -164,6 +166,7 @@ MANAGER_QEMU_ENABLE_SEV=false \
|
||||
To enable [AMD SEV](https://www.amd.com/en/developer/sev.html) support, start manager like this
|
||||
|
||||
```sh
|
||||
MANAGER_GRPC_URL=localhost:7001
|
||||
MANAGER_LOG_LEVEL=debug \
|
||||
MANAGER_QEMU_USE_SUDO=true \
|
||||
MANAGER_QEMU_ENABLE_SEV=true \
|
||||
@@ -171,66 +174,50 @@ MANAGER_QEMU_SEV_CBITPOS=51 \
|
||||
./build/cocos-manager
|
||||
```
|
||||
|
||||
The kernel hash feature might not work with the current build of OVMF and QEMU. If so, build the host kernel, QEMU, and OVMF from the [AMD SEV GitHub](https://github.com/AMDESE/AMDSEV/tree/snp-latest) repository.
|
||||
|
||||
### Docker
|
||||
```bash
|
||||
go get github.com/ultravioletrs/cocos
|
||||
To build the OVMF with the kernel hash capability, we must build the AmdSev package of OVMF. The result of the build should be a single `OVMF.fd` file (unlike the regular two OVFM files). The OVMF package is located at `OvmfPkg/AmdSev/AmdSevX64.dsc`.
|
||||
|
||||
cd $GOPATH/src/github.com/ultravioletrs/cocos
|
||||
|
||||
# compile the manager
|
||||
make manager
|
||||
|
||||
# create manager docker image
|
||||
make docker_dev_manager
|
||||
|
||||
# start docker composition
|
||||
make run
|
||||
```
|
||||
|
||||
### Create QEMU virtual machine (VM)
|
||||
|
||||
To create an instance of VM and run a computation, run
|
||||
To enable [AMD SEV-SNP](https://www.amd.com/en/developer/sev.html) support, start manager like this
|
||||
|
||||
```sh
|
||||
curl -sSi -X POST \
|
||||
http://localhost:9021/run \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"computation": {
|
||||
"id":"c0d15c5e-e37d-4426-b3b7-b432c966fb09",
|
||||
"name":"Sample_Computation",
|
||||
"description":"A_sample_computation",
|
||||
"datasets":[
|
||||
{
|
||||
"provider":"Provider1",
|
||||
"id":"Dataset1"
|
||||
},
|
||||
{
|
||||
"provider":"Provider2",
|
||||
"id":"Dataset2"
|
||||
}
|
||||
],
|
||||
"algorithms":[
|
||||
{
|
||||
"provider":"AlgorithmProvider1",
|
||||
"id":"Algorithm1"
|
||||
}
|
||||
],
|
||||
"result_consumers":[
|
||||
"Consumer1"
|
||||
],
|
||||
"timeout":"10m"
|
||||
}
|
||||
}'
|
||||
|
||||
MANAGER_GRPC_URL=localhost:7001 \
|
||||
MANAGER_LOG_LEVEL=debug \
|
||||
MANAGER_QEMU_ENABLE_SEV=false \
|
||||
MANAGER_QEMU_ENABLE_SEV_SNP=true \
|
||||
MANAGER_QEMU_SEV_CBITPOS=51 \
|
||||
MANAGER_QEMU_BIN_PATH=<path to QEMU binary> \
|
||||
MANAGER_QEMU_QEMU_OVMF_CODE_FILE=<path to OVMF.fd Amd Sev built package> \
|
||||
./build/cocos-manager
|
||||
```
|
||||
|
||||
You should be able to create multiple instances by reruning the command.
|
||||
To include the kernel hash into the measurement of the attestation report (SEV or SEV-SNP), start manager like this
|
||||
|
||||
```sh
|
||||
MANAGER_GRPC_URL=localhost:7001 \
|
||||
MANAGER_LOG_LEVEL=debug \
|
||||
MANAGER_QEMU_ENABLE_SEV=false \
|
||||
MANAGER_QEMU_ENABLE_SEV_SNP=true \
|
||||
MANAGER_QEMU_SEV_CBITPOS=51 \
|
||||
MANAGER_QEMU_KERNEL_HASH=true \
|
||||
./build/cocos-manager
|
||||
```
|
||||
|
||||
### Verifying VM launch
|
||||
|
||||
NB: To verify that the manager successfully launched the VM, you need to open two terminals on the same machine. In one terminal, you need to launch `go run main.go` (with the environment variables of choice) and in the other, you can run the verification commands.
|
||||
NB: To verify that the manager successfully launched the VM, you need to open three terminals on the same machine. In one terminal, you need to launch the computations server by executing (with the environment variables of choice):
|
||||
|
||||
```bash
|
||||
go run ./test/computations/main.go <dataset path> <algo path>
|
||||
```
|
||||
|
||||
and in the second the manager by executing (with the environment variables of choice):
|
||||
|
||||
```bash
|
||||
go run ./cmd/manager/main.go
|
||||
```
|
||||
|
||||
Ensure that the Manager can connect to the Manager test server by setting the MANAGER_GRPC_PORT with the port value of the Manager test server. In the last terminal, you can run the verification commands.
|
||||
|
||||
To verify that the manager launched the VM successfully, run the following command:
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/mdlayher/vsock"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
ManagerVsockPort = 9997
|
||||
messageSize int = 1024
|
||||
)
|
||||
|
||||
var errFailedToParseCID = errors.New("failed to parse cid from remote address")
|
||||
|
||||
// RetrieveAgentEventsLogs Retrieve and forward agent logs and events via vsock.
|
||||
func (ms *managerService) RetrieveAgentEventsLogs() {
|
||||
l, err := vsock.Listen(ManagerVsockPort, nil)
|
||||
if err != nil {
|
||||
ms.logger.Warn(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
ms.logger.Warn(err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
go ms.handleConnections(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *managerService) handleConnections(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
b := make([]byte, messageSize)
|
||||
n, err := conn.Read(b)
|
||||
if err != nil {
|
||||
ms.logger.Warn(err.Error())
|
||||
return
|
||||
}
|
||||
cmpID, err := ms.computationIDFromAddress(conn.RemoteAddr().String())
|
||||
if err != nil {
|
||||
ms.logger.Warn(err.Error())
|
||||
continue
|
||||
}
|
||||
var message manager.ClientStreamMessage
|
||||
if err := proto.Unmarshal(b[:n], &message); err != nil {
|
||||
ms.logger.Warn(err.Error())
|
||||
continue
|
||||
}
|
||||
switch mes := message.Message.(type) {
|
||||
case *manager.ClientStreamMessage_AgentEvent:
|
||||
mes.AgentEvent.ComputationId = cmpID
|
||||
ms.eventsChan <- &manager.ClientStreamMessage{Message: mes}
|
||||
case *manager.ClientStreamMessage_AgentLog:
|
||||
mes.AgentLog.ComputationId = cmpID
|
||||
ms.eventsChan <- &manager.ClientStreamMessage{Message: mes}
|
||||
default:
|
||||
ms.logger.Warn("Unexpected agent log or event type")
|
||||
}
|
||||
|
||||
ms.logger.Info(fmt.Sprintf("Agent Log/Event, Computation ID: %s, Message: %s", cmpID, message.String()))
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *managerService) computationIDFromAddress(address string) (string, error) {
|
||||
re := regexp.MustCompile(`vm\((\d+)\)`)
|
||||
matches := re.FindStringSubmatch(address)
|
||||
|
||||
if len(matches) > 1 {
|
||||
cid, err := strconv.Atoi(matches[1])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ms.agents[cid], nil
|
||||
}
|
||||
return "", errFailedToParseCID
|
||||
}
|
||||
+41
-58
@@ -4,72 +4,55 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
"google.golang.org/grpc"
|
||||
pkgmanager "github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
const svcName = "manager.ManagerService"
|
||||
|
||||
type grpcClient struct {
|
||||
run endpoint.Endpoint
|
||||
timeout time.Duration
|
||||
type ManagerClient struct {
|
||||
stream pkgmanager.ManagerService_ProcessClient
|
||||
svc manager.Service
|
||||
responses chan *pkgmanager.ClientStreamMessage
|
||||
}
|
||||
|
||||
// NewClient returns new gRPC client instance.
|
||||
func NewClient(conn *grpc.ClientConn, timeout time.Duration) manager.ManagerServiceClient {
|
||||
return &grpcClient{
|
||||
run: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Run",
|
||||
encodeRunRequest,
|
||||
decodeRunResponse,
|
||||
manager.RunResponse{},
|
||||
).Endpoint(),
|
||||
timeout: timeout,
|
||||
func NewClient(stream pkgmanager.ManagerService_ProcessClient, svc manager.Service, responses chan *pkgmanager.ClientStreamMessage) ManagerClient {
|
||||
return ManagerClient{
|
||||
stream: stream,
|
||||
svc: svc,
|
||||
responses: responses,
|
||||
}
|
||||
}
|
||||
|
||||
// encodeRunRequest is a transport/grpc.EncodeRequestFunc that
|
||||
// converts a user-domain runReq to a gRPC request.
|
||||
func encodeRunRequest(_ context.Context, request interface{}) (interface{}, error) {
|
||||
req, ok := request.(runReq)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid request type: %T", request)
|
||||
}
|
||||
return &manager.RunRequest{
|
||||
Computation: req.Computation,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// decodeRunResponse is a transport/grpc.DecodeResponseFunc that
|
||||
// converts a gRPC RunResponse to a user-domain response.
|
||||
func decodeRunResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
|
||||
res, ok := grpcResponse.(*manager.RunResponse)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
|
||||
}
|
||||
return runRes{AgentAddress: res.AgentAddress}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) Run(ctx context.Context, req *manager.RunRequest, _ ...grpc.CallOption) (*manager.RunResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
runReq := runReq{
|
||||
Computation: req.GetComputation(),
|
||||
}
|
||||
|
||||
res, err := client.run(ctx, runReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
runRes := res.(runRes)
|
||||
return &manager.RunResponse{AgentAddress: runRes.AgentAddress}, nil
|
||||
func (client ManagerClient) Process(ctx context.Context) error {
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
eg.Go(func() error {
|
||||
for {
|
||||
req, err := client.stream.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
port, err := client.svc.Run(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runRes := &pkgmanager.ClientStreamMessage_RunRes{RunRes: &pkgmanager.RunResponse{AgentPort: port, ComputationId: req.Id}}
|
||||
if err := client.stream.Send(&pkgmanager.ClientStreamMessage{Message: runRes}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
eg.Go(func() error {
|
||||
for mes := range client.responses {
|
||||
if err := client.stream.Send(mes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
)
|
||||
|
||||
func runEndpoint(svc manager.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(runReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return runRes{}, err
|
||||
}
|
||||
|
||||
agAddr, err := svc.Run(ctx, req.Computation)
|
||||
if err != nil {
|
||||
return runRes{}, err
|
||||
}
|
||||
|
||||
return runRes{AgentAddress: agAddr}, nil
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
)
|
||||
|
||||
type runReq struct {
|
||||
Computation *manager.Computation `json:"computation"`
|
||||
}
|
||||
|
||||
func (req runReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
type runRes struct {
|
||||
AgentAddress string `json:"agent_address"`
|
||||
}
|
||||
+41
-28
@@ -5,44 +5,57 @@ package grpc
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kit/kit/transport/grpc"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc/peer"
|
||||
)
|
||||
|
||||
type grpcServer struct {
|
||||
run grpc.Handler
|
||||
manager.UnimplementedManagerServiceServer
|
||||
incoming chan *manager.ClientStreamMessage
|
||||
svc Service
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
Run(ipAddress string, runReqChan chan *manager.ComputationRunReq)
|
||||
}
|
||||
|
||||
// NewServer returns new AuthServiceServer instance.
|
||||
func NewServer(svc manager.Service) manager.ManagerServiceServer {
|
||||
func NewServer(ctx context.Context, incoming chan *manager.ClientStreamMessage, svc Service) manager.ManagerServiceServer {
|
||||
return &grpcServer{
|
||||
run: grpc.NewServer(
|
||||
runEndpoint(svc),
|
||||
decodeRunRequest,
|
||||
encodeRunResponse,
|
||||
),
|
||||
incoming: incoming,
|
||||
svc: svc,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
func decodeRunRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*manager.RunRequest)
|
||||
|
||||
return runReq{
|
||||
Computation: req.GetComputation(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeRunResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
res := response.(runRes)
|
||||
return &manager.RunResponse{AgentAddress: res.AgentAddress}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) Run(ctx context.Context, req *manager.RunRequest) (*manager.RunResponse, error) {
|
||||
_, res, err := s.run.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *grpcServer) Process(stream manager.ManagerService_ProcessServer) error {
|
||||
runReqChan := make(chan *manager.ComputationRunReq)
|
||||
client, ok := peer.FromContext(stream.Context())
|
||||
if ok {
|
||||
go s.svc.Run(client.Addr.String(), runReqChan)
|
||||
}
|
||||
rr := res.(*manager.RunResponse)
|
||||
return rr, nil
|
||||
eg, _ := errgroup.WithContext(s.ctx)
|
||||
|
||||
eg.Go(func() error {
|
||||
for {
|
||||
req, err := stream.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.incoming <- req
|
||||
}
|
||||
})
|
||||
|
||||
eg.Go(func() error {
|
||||
for runReq := range runReqChan {
|
||||
if err := stream.Send(runReq); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package http contains implementation of kit service HTTP API.
|
||||
package http
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
)
|
||||
|
||||
func runEndpoint(svc manager.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(runReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mc := manager.Computation{
|
||||
Id: req.Computation.ID,
|
||||
Name: req.Computation.Name,
|
||||
Description: req.Computation.Description,
|
||||
ResultConsumers: req.Computation.ResultConsumers,
|
||||
}
|
||||
for _, algo := range req.Computation.Algorithms {
|
||||
mc.Algorithms = append(mc.Algorithms, &manager.Algorithm{Id: algo.ID, Provider: algo.Provider})
|
||||
}
|
||||
for _, data := range req.Computation.Datasets {
|
||||
mc.Datasets = append(mc.Datasets, &manager.Dataset{Id: data.ID, Provider: data.Provider})
|
||||
}
|
||||
|
||||
// Call the Run method on the service
|
||||
agAddr, err := svc.Run(ctx, &mc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return runRes{AgentAddress: agAddr}, nil
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
var _ apiReq = (*runReq)(nil)
|
||||
|
||||
type apiReq interface {
|
||||
validate() error
|
||||
}
|
||||
|
||||
type runReq struct {
|
||||
Computation agent.Computation `json:"computation"`
|
||||
}
|
||||
|
||||
func (req *runReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
)
|
||||
|
||||
var _ magistrala.Response = (*runRes)(nil)
|
||||
|
||||
type runRes struct {
|
||||
AgentAddress string `json:"agent_address"`
|
||||
}
|
||||
|
||||
func (res runRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res runRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res runRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
"github.com/go-zoo/bone"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
)
|
||||
|
||||
const contentType = "application/json"
|
||||
|
||||
var (
|
||||
errUnsupportedContentType = errors.New("unsupported content type")
|
||||
errInvalidQueryParams = errors.New("invalid query params")
|
||||
)
|
||||
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHandler(svc manager.Service, instanceID string) http.Handler {
|
||||
opts := []kithttp.ServerOption{
|
||||
kithttp.ServerErrorEncoder(encodeError),
|
||||
}
|
||||
|
||||
r := bone.New()
|
||||
|
||||
r.Post("/run", otelhttp.NewHandler(kithttp.NewServer(
|
||||
runEndpoint(svc),
|
||||
decodeRun,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
), "run"))
|
||||
|
||||
r.GetFunc("/health", magistrala.Health("manager", instanceID))
|
||||
r.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func decodeRun(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||
return nil, errUnsupportedContentType
|
||||
}
|
||||
|
||||
var req runReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
|
||||
if ar, ok := response.(magistrala.Response); ok {
|
||||
for k, v := range ar.Headers() {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
|
||||
w.WriteHeader(ar.Code())
|
||||
|
||||
if ar.Empty() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
|
||||
switch err {
|
||||
case manager.ErrMalformedEntity:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case manager.ErrNotFound:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
case manager.ErrUnauthorizedAccess:
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
case errUnsupportedContentType:
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
case errInvalidQueryParams:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case io.ErrUnexpectedEOF:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case io.EOF:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
default:
|
||||
switch err.(type) {
|
||||
case *json.SyntaxError:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case *json.UnmarshalTypeError:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
default:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,25 +9,26 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
pkgmanager "github.com/ultravioletrs/cocos/pkg/manager"
|
||||
)
|
||||
|
||||
var _ manager.Service = (*loggingMiddleware)(nil)
|
||||
|
||||
type loggingMiddleware struct {
|
||||
logger mglog.Logger
|
||||
logger *slog.Logger
|
||||
svc manager.Service
|
||||
}
|
||||
|
||||
// LoggingMiddleware adds logging facilities to the core service.
|
||||
func LoggingMiddleware(svc manager.Service, logger mglog.Logger) manager.Service {
|
||||
func LoggingMiddleware(svc manager.Service, logger *slog.Logger) manager.Service {
|
||||
return &loggingMiddleware{logger, svc}
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Run(ctx context.Context, mc *manager.Computation) (agentAddr string, err error) {
|
||||
func (lm *loggingMiddleware) Run(ctx context.Context, mc *pkgmanager.ComputationRunReq) (agentAddr string, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method Run for computation took %s to complete", time.Since(begin))
|
||||
if err != nil {
|
||||
@@ -39,3 +40,7 @@ func (lm *loggingMiddleware) Run(ctx context.Context, mc *manager.Computation) (
|
||||
|
||||
return lm.svc.Run(ctx, mc)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) RetrieveAgentEventsLogs() {
|
||||
lm.svc.RetrieveAgentEventsLogs()
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
pkgmanager "github.com/ultravioletrs/cocos/pkg/manager"
|
||||
)
|
||||
|
||||
var _ manager.Service = (*metricsMiddleware)(nil)
|
||||
@@ -32,7 +33,7 @@ func MetricsMiddleware(svc manager.Service, counter metrics.Counter, latency met
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Run(ctx context.Context, mc *manager.Computation) (string, error) {
|
||||
func (ms *metricsMiddleware) Run(ctx context.Context, mc *pkgmanager.ComputationRunReq) (string, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "Run").Add(1)
|
||||
ms.latency.With("method", "Run").Observe(time.Since(begin).Seconds())
|
||||
@@ -40,3 +41,7 @@ func (ms *metricsMiddleware) Run(ctx context.Context, mc *manager.Computation) (
|
||||
|
||||
return ms.svc.Run(ctx, mc)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) RetrieveAgentEventsLogs() {
|
||||
ms.svc.RetrieveAgentEventsLogs()
|
||||
}
|
||||
|
||||
@@ -1,477 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v4.25.1
|
||||
// source: manager/manager.proto
|
||||
|
||||
package manager
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type RunRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Computation *Computation `protobuf:"bytes,1,opt,name=computation,proto3" json:"computation,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RunRequest) Reset() {
|
||||
*x = RunRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RunRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RunRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RunRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RunRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RunRequest) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *RunRequest) GetComputation() *Computation {
|
||||
if x != nil {
|
||||
return x.Computation
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Computation struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
|
||||
Datasets []*Dataset `protobuf:"bytes,4,rep,name=datasets,proto3" json:"datasets,omitempty"`
|
||||
Algorithms []*Algorithm `protobuf:"bytes,5,rep,name=algorithms,proto3" json:"algorithms,omitempty"`
|
||||
ResultConsumers []string `protobuf:"bytes,6,rep,name=result_consumers,json=resultConsumers,proto3" json:"result_consumers,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Computation) Reset() {
|
||||
*x = Computation{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Computation) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Computation) ProtoMessage() {}
|
||||
|
||||
func (x *Computation) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Computation.ProtoReflect.Descriptor instead.
|
||||
func (*Computation) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Computation) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Computation) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Computation) GetDescription() string {
|
||||
if x != nil {
|
||||
return x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Computation) GetDatasets() []*Dataset {
|
||||
if x != nil {
|
||||
return x.Datasets
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Computation) GetAlgorithms() []*Algorithm {
|
||||
if x != nil {
|
||||
return x.Algorithms
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Computation) GetResultConsumers() []string {
|
||||
if x != nil {
|
||||
return x.ResultConsumers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Dataset struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Dataset) Reset() {
|
||||
*x = Dataset{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Dataset) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Dataset) ProtoMessage() {}
|
||||
|
||||
func (x *Dataset) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Dataset.ProtoReflect.Descriptor instead.
|
||||
func (*Dataset) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Dataset) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Dataset) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Algorithm struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Algorithm) Reset() {
|
||||
*x = Algorithm{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Algorithm) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Algorithm) ProtoMessage() {}
|
||||
|
||||
func (x *Algorithm) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Algorithm.ProtoReflect.Descriptor instead.
|
||||
func (*Algorithm) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Algorithm) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Algorithm) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RunResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AgentAddress string `protobuf:"bytes,1,opt,name=agent_address,json=agentAddress,proto3" json:"agent_address,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RunResponse) Reset() {
|
||||
*x = RunResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RunResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RunResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RunResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RunResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RunResponse) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *RunResponse) GetAgentAddress() string {
|
||||
if x != nil {
|
||||
return x.AgentAddress
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_manager_manager_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_manager_manager_proto_rawDesc = []byte{
|
||||
0x0a, 0x15, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
|
||||
0x22, 0x44, 0x0a, 0x0a, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36,
|
||||
0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6f,
|
||||
0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x75,
|
||||
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xe0, 0x01, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x75,
|
||||
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x08,
|
||||
0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10,
|
||||
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74,
|
||||
0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x0a, 0x61, 0x6c,
|
||||
0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12,
|
||||
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
|
||||
0x68, 0x6d, 0x52, 0x0a, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, 0x12, 0x29,
|
||||
0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65,
|
||||
0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
|
||||
0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x22, 0x35, 0x0a, 0x07, 0x44, 0x61, 0x74,
|
||||
0x61, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
|
||||
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
|
||||
0x22, 0x37, 0x0a, 0x09, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x32, 0x0a, 0x0b, 0x52, 0x75, 0x6e,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e,
|
||||
0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x32, 0x44, 0x0a,
|
||||
0x0e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x32, 0x0a, 0x03, 0x52, 0x75, 0x6e, 0x12, 0x13, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
|
||||
0x2e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6d, 0x61,
|
||||
0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_manager_manager_proto_rawDescOnce sync.Once
|
||||
file_manager_manager_proto_rawDescData = file_manager_manager_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_manager_manager_proto_rawDescGZIP() []byte {
|
||||
file_manager_manager_proto_rawDescOnce.Do(func() {
|
||||
file_manager_manager_proto_rawDescData = protoimpl.X.CompressGZIP(file_manager_manager_proto_rawDescData)
|
||||
})
|
||||
return file_manager_manager_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_manager_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_manager_manager_proto_goTypes = []interface{}{
|
||||
(*RunRequest)(nil), // 0: manager.RunRequest
|
||||
(*Computation)(nil), // 1: manager.Computation
|
||||
(*Dataset)(nil), // 2: manager.Dataset
|
||||
(*Algorithm)(nil), // 3: manager.Algorithm
|
||||
(*RunResponse)(nil), // 4: manager.RunResponse
|
||||
}
|
||||
var file_manager_manager_proto_depIdxs = []int32{
|
||||
1, // 0: manager.RunRequest.computation:type_name -> manager.Computation
|
||||
2, // 1: manager.Computation.datasets:type_name -> manager.Dataset
|
||||
3, // 2: manager.Computation.algorithms:type_name -> manager.Algorithm
|
||||
0, // 3: manager.ManagerService.Run:input_type -> manager.RunRequest
|
||||
4, // 4: manager.ManagerService.Run:output_type -> manager.RunResponse
|
||||
4, // [4:5] is the sub-list for method output_type
|
||||
3, // [3:4] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_manager_manager_proto_init() }
|
||||
func file_manager_manager_proto_init() {
|
||||
if File_manager_manager_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_manager_manager_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RunRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Computation); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Dataset); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Algorithm); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RunResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_manager_manager_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_manager_manager_proto_goTypes,
|
||||
DependencyIndexes: file_manager_manager_proto_depIdxs,
|
||||
MessageInfos: file_manager_manager_proto_msgTypes,
|
||||
}.Build()
|
||||
File_manager_manager_proto = out.File
|
||||
file_manager_manager_proto_rawDesc = nil
|
||||
file_manager_manager_proto_goTypes = nil
|
||||
file_manager_manager_proto_depIdxs = nil
|
||||
}
|
||||
+44
-7
@@ -3,37 +3,74 @@
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
package manager;
|
||||
|
||||
option go_package = "./manager";
|
||||
|
||||
service ManagerService {
|
||||
rpc Run(RunRequest) returns (RunResponse) {}
|
||||
rpc Process(stream ClientStreamMessage) returns (stream ComputationRunReq) {}
|
||||
}
|
||||
|
||||
message RunRequest {
|
||||
Computation computation = 1;
|
||||
message RunResponse{
|
||||
string agent_port = 1;
|
||||
string computation_id = 2;
|
||||
}
|
||||
|
||||
message Computation {
|
||||
message AgentEvent {
|
||||
string event_type = 1;
|
||||
google.protobuf.Timestamp timestamp = 2;
|
||||
string computation_id = 3;
|
||||
bytes details = 4;
|
||||
string originator = 5;
|
||||
string status = 6;
|
||||
}
|
||||
|
||||
message AgentLog {
|
||||
string message = 1;
|
||||
string computation_id = 2;
|
||||
string level = 3;
|
||||
google.protobuf.Timestamp timestamp = 4;
|
||||
}
|
||||
|
||||
message ClientStreamMessage {
|
||||
oneof message {
|
||||
AgentLog agent_log = 1;
|
||||
AgentEvent agent_event = 2;
|
||||
RunResponse run_res = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message ComputationRunReq {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string description = 3;
|
||||
repeated Dataset datasets = 4;
|
||||
repeated Algorithm algorithms = 5;
|
||||
Algorithm algorithm = 5;
|
||||
repeated string result_consumers = 6;
|
||||
AgentConfig agent_config = 7;
|
||||
}
|
||||
|
||||
message Dataset {
|
||||
string provider = 1;
|
||||
string id = 2;
|
||||
bytes hash = 3; // should be sha3.Sum256, 32 byte length.
|
||||
}
|
||||
|
||||
message Algorithm {
|
||||
string provider = 1;
|
||||
string id = 2;
|
||||
bytes hash = 3; // should be sha3.Sum256, 32 byte length.
|
||||
}
|
||||
|
||||
message RunResponse {
|
||||
string agent_address = 1;
|
||||
message AgentConfig {
|
||||
string port = 1;
|
||||
string host = 2;
|
||||
string cert_file = 3;
|
||||
string key_file = 4;
|
||||
string client_ca_file = 5;
|
||||
string server_ca_file = 6;
|
||||
string log_level = 7;
|
||||
bool attested_tls = 8;
|
||||
}
|
||||
|
||||
+68
-38
@@ -4,6 +4,7 @@ package qemu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type MemoryConfig struct {
|
||||
@@ -36,6 +37,7 @@ type NetDevConfig struct {
|
||||
type VirtioNetPciConfig struct {
|
||||
DisableLegacy string `env:"VIRTIO_NET_PCI_DISABLE_LEGACY" envDefault:"on"`
|
||||
IOMMUPlatform bool `env:"VIRTIO_NET_PCI_IOMMU_PLATFORM" envDefault:"true"`
|
||||
Addr string `env:"VIRTIO_NET_PCI_ADDR" envDefault:"0x2"`
|
||||
ROMFile string `env:"VIRTIO_NET_PCI_ROMFILE"`
|
||||
}
|
||||
|
||||
@@ -44,32 +46,38 @@ type DiskImgConfig struct {
|
||||
RootFsFile string `env:"DISK_IMG_ROOTFS_FILE" envDefault:"img/rootfs.cpio.gz"`
|
||||
}
|
||||
|
||||
type VirtioScsiPciConfig struct {
|
||||
ID string `env:"VIRTIO_SCSI_PCI_ID" envDefault:"scsi"`
|
||||
DisableLegacy string `env:"VIRTIO_SCSI_PCI_DISABLE_LEGACY" envDefault:"on"`
|
||||
IOMMUPlatform bool `env:"VIRTIO_SCSI_PCI_IOMMU_PLATFORM" envDefault:"true"`
|
||||
}
|
||||
|
||||
type SevConfig struct {
|
||||
ID string `env:"SEV_ID" envDefault:"sev0"`
|
||||
CBitPos int `env:"SEV_CBITPOS" envDefault:"51"`
|
||||
ReducedPhysBits int `env:"SEV_REDUCED_PHYS_BITS" envDefault:"1"`
|
||||
}
|
||||
|
||||
type VSockConfig struct {
|
||||
ID string `env:"VSOCK_ID" envDefault:"vhost-vsock-pci0"`
|
||||
GuestCID int `env:"VSOCK_GUEST_CID" envDefault:"3"`
|
||||
vnc int `env:"VSOCK_VNC" envDefault:"0"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
TmpFileLoc string `env:"TMP_FILE_LOC" envDefault:"tmp"`
|
||||
UseSudo bool `env:"USE_SUDO" envDefault:"false"`
|
||||
EnableSEV bool `env:"ENABLE_SEV" envDefault:"true"`
|
||||
QemuBinPath string `env:"BIN_PATH" envDefault:"qemu-system-x86_64"`
|
||||
TmpFileLoc string `env:"TMP_FILE_LOC" envDefault:"tmp"`
|
||||
UseSudo bool `env:"USE_SUDO" envDefault:"false"`
|
||||
EnableSEV bool `env:"ENABLE_SEV" envDefault:"false"`
|
||||
EnableSEVSNP bool `env:"ENABLE_SEV_SNP" envDefault:"true"`
|
||||
|
||||
EnableKVM bool `env:"ENABLE_KVM" envDefault:"true"`
|
||||
|
||||
// machine, CPU, RAM
|
||||
Machine string `env:"MACHINE" envDefault:"q35"`
|
||||
CPU string `env:"CPU" envDefault:"EPYC"`
|
||||
SmpCount int `env:"SMP_COUNT" envDefault:"4"`
|
||||
MaxCpus int `env:"SMP_MAXCPUS" envDefault:"64"`
|
||||
SMPCount int `env:"SMP_COUNT" envDefault:"4"`
|
||||
MaxCPUs int `env:"SMP_MAXCPUS" envDefault:"64"`
|
||||
MemID string `env:"MEM_ID" envDefault:"ram1"`
|
||||
MemoryConfig
|
||||
|
||||
// Kernel hash
|
||||
KernelHash bool `env:"KERNEL_HASH" envDefault:"false"`
|
||||
|
||||
// OVMF
|
||||
OVMFCodeConfig
|
||||
OVMFVarsConfig
|
||||
@@ -78,8 +86,10 @@ type Config struct {
|
||||
NetDevConfig
|
||||
VirtioNetPciConfig
|
||||
|
||||
// Vsock
|
||||
VSockConfig
|
||||
|
||||
// disk
|
||||
VirtioScsiPciConfig
|
||||
DiskImgConfig
|
||||
|
||||
// SEV
|
||||
@@ -90,7 +100,7 @@ type Config struct {
|
||||
Monitor string `env:"MONITOR" envDefault:"pty"`
|
||||
}
|
||||
|
||||
func constructQemuArgs(config Config, computation string) []string {
|
||||
func constructQemuArgs(config Config) []string {
|
||||
args := []string{}
|
||||
|
||||
// virtualization
|
||||
@@ -107,7 +117,7 @@ func constructQemuArgs(config Config, computation string) []string {
|
||||
args = append(args, "-cpu", config.CPU)
|
||||
}
|
||||
|
||||
args = append(args, "-smp", fmt.Sprintf("%d,maxcpus=%d", config.SmpCount, config.MaxCpus))
|
||||
args = append(args, "-smp", fmt.Sprintf("%d,maxcpus=%d", config.SMPCount, config.MaxCPUs))
|
||||
|
||||
args = append(args, "-m", fmt.Sprintf("%s,slots=%d,maxmem=%s",
|
||||
config.MemoryConfig.Size,
|
||||
@@ -123,25 +133,14 @@ func constructQemuArgs(config Config, computation string) []string {
|
||||
config.OVMFCodeConfig.File,
|
||||
config.OVMFCodeConfig.ReadOnly))
|
||||
|
||||
args = append(args, "-drive",
|
||||
fmt.Sprintf("if=%s,format=%s,unit=%d,file=%s",
|
||||
config.OVMFVarsConfig.If,
|
||||
config.OVMFVarsConfig.Format,
|
||||
config.OVMFVarsConfig.Unit,
|
||||
config.OVMFVarsConfig.File))
|
||||
|
||||
// disk
|
||||
args = append(args, "-device",
|
||||
fmt.Sprintf("virtio-scsi-pci,id=%s,disable-legacy=%s,iommu_platform=%t",
|
||||
config.VirtioScsiPciConfig.ID,
|
||||
config.VirtioScsiPciConfig.DisableLegacy,
|
||||
config.VirtioScsiPciConfig.IOMMUPlatform))
|
||||
|
||||
args = append(args, "-kernel", config.DiskImgConfig.KernelFile)
|
||||
|
||||
args = append(args, "-append", fmt.Sprintf("earlyprintk=serial console=ttyS0 computation=%s", computation))
|
||||
|
||||
args = append(args, "-initrd", config.DiskImgConfig.RootFsFile)
|
||||
if !config.KernelHash {
|
||||
args = append(args, "-drive",
|
||||
fmt.Sprintf("if=%s,format=%s,unit=%d,file=%s",
|
||||
config.OVMFVarsConfig.If,
|
||||
config.OVMFVarsConfig.Format,
|
||||
config.OVMFVarsConfig.Unit,
|
||||
config.OVMFVarsConfig.File))
|
||||
}
|
||||
|
||||
// network
|
||||
args = append(args, "-netdev",
|
||||
@@ -150,19 +149,50 @@ func constructQemuArgs(config Config, computation string) []string {
|
||||
config.NetDevConfig.HostFwdAgent, config.NetDevConfig.GuestFwdAgent))
|
||||
|
||||
args = append(args, "-device",
|
||||
fmt.Sprintf("virtio-net-pci,disable-legacy=%s,iommu_platform=%v,netdev=%s,romfile=%s",
|
||||
fmt.Sprintf("virtio-net-pci,disable-legacy=%s,iommu_platform=%v,netdev=%s,addr=%s,romfile=%s",
|
||||
config.VirtioNetPciConfig.DisableLegacy,
|
||||
config.VirtioNetPciConfig.IOMMUPlatform,
|
||||
config.NetDevConfig.ID,
|
||||
config.VirtioNetPciConfig.Addr,
|
||||
config.VirtioNetPciConfig.ROMFile))
|
||||
|
||||
// SEV
|
||||
if config.EnableSEV {
|
||||
args = append(args, "-device", fmt.Sprintf("vhost-vsock-pci,id=%s,guest-cid=%d", config.VSockConfig.ID, config.VSockConfig.GuestCID))
|
||||
args = append(args, "-vnc", fmt.Sprintf(":%d", config.vnc))
|
||||
|
||||
if config.EnableSEVSNP {
|
||||
args = append(args, "-object",
|
||||
fmt.Sprintf("sev-guest,id=%s,cbitpos=%d,reduced-phys-bits=%d",
|
||||
fmt.Sprintf("memory-backend-memfd-private,id=%s,size=%s,share=true",
|
||||
config.MemID,
|
||||
config.MemoryConfig.Size))
|
||||
args = append(args, "-machine",
|
||||
fmt.Sprintf("memory-backend=%s,kvm-type=protected",
|
||||
config.MemID))
|
||||
}
|
||||
|
||||
args = append(args, "-kernel", config.DiskImgConfig.KernelFile)
|
||||
args = append(args, "-append", strconv.Quote("earlyprintk=serial console=ttyS0"))
|
||||
args = append(args, "-initrd", config.DiskImgConfig.RootFsFile)
|
||||
|
||||
// SEV
|
||||
if config.EnableSEV || config.EnableSEVSNP {
|
||||
sevType := "sev-guest"
|
||||
kernelHash := ""
|
||||
|
||||
if config.EnableSEVSNP {
|
||||
sevType = "sev-snp-guest"
|
||||
}
|
||||
|
||||
if config.KernelHash {
|
||||
kernelHash = ",discard=none,kernel-hashes=on"
|
||||
}
|
||||
|
||||
args = append(args, "-object",
|
||||
fmt.Sprintf("%s,id=%s,cbitpos=%d,reduced-phys-bits=%d%s",
|
||||
sevType,
|
||||
config.SevConfig.ID,
|
||||
config.SevConfig.CBitPos,
|
||||
config.SevConfig.ReducedPhysBits))
|
||||
config.SevConfig.ReducedPhysBits,
|
||||
kernelHash))
|
||||
|
||||
args = append(args, "-machine",
|
||||
fmt.Sprintf("memory-encryption=%s", config.SevConfig.ID))
|
||||
|
||||
+18
-26
@@ -4,46 +4,43 @@ package qemu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"github.com/ultravioletrs/cocos/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
qemuRelPath = "qemu-system-x86_64"
|
||||
firmwareVars = "OVMF_VARS"
|
||||
KernelFile = "bzImage"
|
||||
rootfsFile = "rootfs.cpio"
|
||||
)
|
||||
|
||||
func CreateVM(ctx context.Context, cfg Config, ac agent.Computation) (*exec.Cmd, error) {
|
||||
// Create unique emu device identifiers.
|
||||
func CreateVM(ctx context.Context, cfg Config) (*exec.Cmd, error) {
|
||||
// Create unique emu device identifiers
|
||||
id, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
return &exec.Cmd{}, err
|
||||
}
|
||||
qemuCfg := cfg
|
||||
qemuCfg.NetDevConfig.ID = fmt.Sprintf("%s-%s", qemuCfg.NetDevConfig.ID, id)
|
||||
qemuCfg.VirtioScsiPciConfig.ID = fmt.Sprintf("%s-%s", qemuCfg.VirtioScsiPciConfig.ID, id)
|
||||
qemuCfg.SevConfig.ID = fmt.Sprintf("%s-%s", qemuCfg.SevConfig.ID, id)
|
||||
|
||||
// Copy firmware vars file.
|
||||
srcFile := qemuCfg.OVMFVarsConfig.File
|
||||
dstFile := fmt.Sprintf("%s/%s-%s.fd", cfg.TmpFileLoc, firmwareVars, id)
|
||||
err = internal.CopyFile(srcFile, dstFile)
|
||||
if err != nil {
|
||||
return &exec.Cmd{}, err
|
||||
if !cfg.KernelHash {
|
||||
// Copy firmware vars file
|
||||
srcFile := qemuCfg.OVMFVarsConfig.File
|
||||
dstFile := fmt.Sprintf("%s/%s-%s.fd", cfg.TmpFileLoc, firmwareVars, id)
|
||||
err = internal.CopyFile(srcFile, dstFile)
|
||||
if err != nil {
|
||||
return &exec.Cmd{}, err
|
||||
}
|
||||
qemuCfg.OVMFVarsConfig.File = dstFile
|
||||
}
|
||||
qemuCfg.OVMFVarsConfig.File = dstFile
|
||||
|
||||
// Copy img files.
|
||||
srcFile = qemuCfg.DiskImgConfig.KernelFile
|
||||
dstFile = fmt.Sprintf("%s/%s-%s", cfg.TmpFileLoc, KernelFile, id)
|
||||
// Copy img files
|
||||
srcFile := qemuCfg.DiskImgConfig.KernelFile
|
||||
dstFile := fmt.Sprintf("%s/%s-%s", cfg.TmpFileLoc, KernelFile, id)
|
||||
err = internal.CopyFile(srcFile, dstFile)
|
||||
if err != nil {
|
||||
return &exec.Cmd{}, err
|
||||
@@ -58,7 +55,7 @@ func CreateVM(ctx context.Context, cfg Config, ac agent.Computation) (*exec.Cmd,
|
||||
}
|
||||
qemuCfg.DiskImgConfig.RootFsFile = dstFile
|
||||
|
||||
exe, args, err := ExecutableAndArgs(qemuCfg, ac)
|
||||
exe, args, err := ExecutableAndArgs(qemuCfg)
|
||||
if err != nil {
|
||||
return &exec.Cmd{}, err
|
||||
}
|
||||
@@ -70,18 +67,13 @@ func CreateVM(ctx context.Context, cfg Config, ac agent.Computation) (*exec.Cmd,
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func ExecutableAndArgs(cfg Config, ac agent.Computation) (string, []string, error) {
|
||||
exe, err := exec.LookPath(qemuRelPath)
|
||||
func ExecutableAndArgs(cfg Config) (string, []string, error) {
|
||||
exe, err := exec.LookPath(cfg.QemuBinPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
cmpBytes, err := json.Marshal(ac)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
args := constructQemuArgs(cfg, strconv.Quote(string(cmpBytes)))
|
||||
args := constructQemuArgs(cfg)
|
||||
|
||||
if cfg.UseSudo {
|
||||
args = append([]string{exe}, args...)
|
||||
|
||||
+63
-22
@@ -6,16 +6,20 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"github.com/ultravioletrs/cocos/internal/events"
|
||||
"github.com/ultravioletrs/cocos/manager/qemu"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
const hashLength = 32
|
||||
|
||||
var (
|
||||
// ErrMalformedEntity indicates malformed entity specification (e.g.
|
||||
// invalid username or password).
|
||||
@@ -30,46 +34,64 @@ var (
|
||||
|
||||
// ErrFailedToAllocatePort indicates no free port was found on host.
|
||||
ErrFailedToAllocatePort = errors.New("failed to allocate free port on host")
|
||||
|
||||
errInvalidHashLength = errors.New("hash must be of byte length 32")
|
||||
)
|
||||
|
||||
// Service specifies an API that must be fulfilled by the domain service
|
||||
// implementation, and all of its decorators (e.g. logging & metrics).
|
||||
type Service interface {
|
||||
Run(ctx context.Context, c *Computation) (string, error)
|
||||
// Run create a computation.
|
||||
Run(ctx context.Context, c *manager.ComputationRunReq) (string, error)
|
||||
// RetrieveAgentEventsLogs Retrieve and forward agent logs and events via vsock.
|
||||
RetrieveAgentEventsLogs()
|
||||
}
|
||||
|
||||
type managerService struct {
|
||||
qemuCfg qemu.Config
|
||||
logger mglog.Logger
|
||||
eventSvc events.Service
|
||||
hostIP string
|
||||
qemuCfg qemu.Config
|
||||
logger *slog.Logger
|
||||
agents map[int]string // agent map of vsock cid to computationID.
|
||||
eventsChan chan *manager.ClientStreamMessage
|
||||
}
|
||||
|
||||
var _ Service = (*managerService)(nil)
|
||||
|
||||
// New instantiates the manager service implementation.
|
||||
func New(qemuCfg qemu.Config, logger mglog.Logger, eventSvc events.Service, hostIP string) Service {
|
||||
return &managerService{
|
||||
qemuCfg: qemuCfg,
|
||||
eventSvc: eventSvc,
|
||||
hostIP: hostIP,
|
||||
logger: logger,
|
||||
func New(qemuCfg qemu.Config, logger *slog.Logger, eventsChan chan *manager.ClientStreamMessage) Service {
|
||||
ms := &managerService{
|
||||
qemuCfg: qemuCfg,
|
||||
logger: logger,
|
||||
agents: make(map[int]string),
|
||||
eventsChan: eventsChan,
|
||||
}
|
||||
return ms
|
||||
}
|
||||
|
||||
func (ms *managerService) Run(ctx context.Context, c *Computation) (string, error) {
|
||||
func (ms *managerService) Run(ctx context.Context, c *manager.ComputationRunReq) (string, error) {
|
||||
ms.publishEvent("vm-provision", c.Id, "starting", json.RawMessage{})
|
||||
ac := agent.Computation{
|
||||
ID: c.Id,
|
||||
Name: c.Name,
|
||||
Description: c.Description,
|
||||
ResultConsumers: c.ResultConsumers,
|
||||
AgentConfig: agent.AgentConfig{
|
||||
Port: c.AgentConfig.Port,
|
||||
Host: c.AgentConfig.Host,
|
||||
KeyFile: c.AgentConfig.KeyFile,
|
||||
CertFile: c.AgentConfig.CertFile,
|
||||
ServerCAFile: c.AgentConfig.ServerCaFile,
|
||||
ClientCAFile: c.AgentConfig.ClientCaFile,
|
||||
LogLevel: c.AgentConfig.LogLevel,
|
||||
},
|
||||
}
|
||||
for _, algo := range c.Algorithms {
|
||||
ac.Algorithms = append(ac.Algorithms, agent.Algorithm{ID: algo.Id, Provider: algo.Provider})
|
||||
}
|
||||
ac.Algorithm = agent.Algorithm{ID: c.Algorithm.Id, Provider: c.Algorithm.Provider, Hash: [hashLength]byte(c.Algorithm.Hash)}
|
||||
|
||||
for _, data := range c.Datasets {
|
||||
ac.Datasets = append(ac.Datasets, agent.Dataset{ID: data.Id, Provider: data.Provider})
|
||||
if len(data.Hash) != hashLength {
|
||||
ms.publishEvent("vm-provision", c.Id, "failed", json.RawMessage{})
|
||||
return "", errInvalidHashLength
|
||||
}
|
||||
ac.Datasets = append(ac.Datasets, agent.Dataset{ID: data.Id, Provider: data.Provider, Hash: [hashLength]byte(data.Hash)})
|
||||
}
|
||||
|
||||
agentPort, err := getFreePort()
|
||||
@@ -80,13 +102,23 @@ func (ms *managerService) Run(ctx context.Context, c *Computation) (string, erro
|
||||
ms.qemuCfg.HostFwdAgent = agentPort
|
||||
|
||||
ms.publishEvent("vm-provision", c.Id, "in-progress", json.RawMessage{})
|
||||
if _, err = qemu.CreateVM(ctx, ms.qemuCfg, ac); err != nil {
|
||||
if _, err = qemu.CreateVM(ctx, ms.qemuCfg); err != nil {
|
||||
ms.publishEvent("vm-provision", c.Id, "failed", json.RawMessage{})
|
||||
return "", err
|
||||
}
|
||||
|
||||
ms.agents[ms.qemuCfg.VSockConfig.GuestCID] = c.Id
|
||||
|
||||
err = backoff.Retry(func() error {
|
||||
return SendAgentConfig(uint32(ms.qemuCfg.VSockConfig.GuestCID), ac)
|
||||
}, backoff.NewExponentialBackOff())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ms.qemuCfg.VSockConfig.GuestCID++
|
||||
|
||||
ms.publishEvent("vm-provision", c.Id, "complete", json.RawMessage{})
|
||||
return fmt.Sprintf("%s:%d", ms.hostIP, ms.qemuCfg.HostFwdAgent), nil
|
||||
return fmt.Sprint(ms.qemuCfg.HostFwdAgent), nil
|
||||
}
|
||||
|
||||
func getFreePort() (int, error) {
|
||||
@@ -107,7 +139,16 @@ func getFreePort() (int, error) {
|
||||
}
|
||||
|
||||
func (ms *managerService) publishEvent(event, cmpID, status string, details json.RawMessage) {
|
||||
if err := ms.eventSvc.SendEvent(event, cmpID, status, details); err != nil {
|
||||
ms.logger.Warn(err.Error())
|
||||
ms.eventsChan <- &manager.ClientStreamMessage{
|
||||
Message: &manager.ClientStreamMessage_AgentEvent{
|
||||
AgentEvent: &manager.AgentEvent{
|
||||
EventType: event,
|
||||
ComputationId: cmpID,
|
||||
Status: status,
|
||||
Details: details,
|
||||
Timestamp: timestamppb.Now(),
|
||||
Originator: "manager",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
pkgmanager "github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
@@ -21,9 +22,13 @@ func New(svc manager.Service, tracer trace.Tracer) manager.Service {
|
||||
return &tracingMiddleware{tracer, svc}
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) Run(ctx context.Context, mc *manager.Computation) (string, error) {
|
||||
func (tm *tracingMiddleware) Run(ctx context.Context, mc *pkgmanager.ComputationRunReq) (string, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "run")
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.Run(ctx, mc)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) RetrieveAgentEventsLogs() {
|
||||
tm.svc.RetrieveAgentEventsLogs()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package manager
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/mdlayher/vsock"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
const VsockConfigPort uint32 = 9999
|
||||
|
||||
func SendAgentConfig(cid uint32, ac agent.Computation) error {
|
||||
conn, err := vsock.Dial(cid, VsockConfigPort, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
payload, err := json.Marshal(ac)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := conn.Write(payload); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+203
-24
@@ -3,25 +3,67 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/google/go-sev-guest/abi"
|
||||
"github.com/google/go-sev-guest/proto/check"
|
||||
"github.com/google/go-sev-guest/validate"
|
||||
"github.com/google/go-sev-guest/verify"
|
||||
"github.com/google/go-sev-guest/verify/trust"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
gogrpc "google.golang.org/grpc"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
type security int
|
||||
|
||||
const (
|
||||
withoutTLS security = iota
|
||||
withTLS
|
||||
withmTLS
|
||||
)
|
||||
|
||||
var (
|
||||
errGrpcConnect = errors.New("failed to connect to grpc server")
|
||||
errGrpcClose = errors.New("failed to close grpc connection")
|
||||
errGrpcConnect = errors.New("failed to connect to grpc server")
|
||||
errGrpcClose = errors.New("failed to close grpc connection")
|
||||
errManifestOpen = errors.New("failed to open Manifest")
|
||||
errManifestMissing = errors.New("failed due to missing Manifest")
|
||||
errManifestDecode = errors.New("failed to decode Manifest json")
|
||||
errCertificateParse = errors.New("failed to parse x509 certificate")
|
||||
errAttVerification = errors.New("attestation verification failed")
|
||||
errAttValidation = errors.New("attestation validation failed")
|
||||
errCustomExtension = errors.New("failed due to missing custom extension")
|
||||
)
|
||||
|
||||
var (
|
||||
customSEVSNPExtensionOID = asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6}
|
||||
attestationConfiguration = AttestationConfiguration{}
|
||||
timeout = time.Minute * 2
|
||||
maxTryDelay = time.Second * 30
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ClientTLS bool `env:"CLIENT_TLS" envDefault:"false"`
|
||||
CACerts string `env:"CA_CERTS" envDefault:""`
|
||||
URL string `env:"URL" envDefault:"localhost:7001"`
|
||||
Timeout time.Duration `env:"TIMEOUT" envDefault:"60s"`
|
||||
ClientCert string `env:"CLIENT_CERT" envDefault:""`
|
||||
ClientKey string `env:"CLIENT_KEY" envDefault:""`
|
||||
ServerCAFile string `env:"SERVER_CA_CERTS" envDefault:""`
|
||||
URL string `env:"URL" envDefault:"localhost:7001"`
|
||||
Timeout time.Duration `env:"TIMEOUT" envDefault:"60s"`
|
||||
AttestedTLS bool `env:"ATTESTED_TLS" envDefault:"false"`
|
||||
Manifest string `env:"MANIFEST" envDefault:""`
|
||||
}
|
||||
|
||||
type AttestationConfiguration struct {
|
||||
SNPPolicy *check.Policy `json:"snp_policy,omitempty"`
|
||||
RootOFTrust *check.RootOfTrust `json:"root_of_trust,omitempty"`
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
@@ -32,13 +74,13 @@ type Client interface {
|
||||
Secure() string
|
||||
|
||||
// Connection returns the gRPC connection.
|
||||
Connection() *gogrpc.ClientConn
|
||||
Connection() *grpc.ClientConn
|
||||
}
|
||||
|
||||
type client struct {
|
||||
*gogrpc.ClientConn
|
||||
*grpc.ClientConn
|
||||
cfg Config
|
||||
secure bool
|
||||
secure security
|
||||
}
|
||||
|
||||
var _ Client = (*client)(nil)
|
||||
@@ -65,37 +107,174 @@ func (c *client) Close() error {
|
||||
}
|
||||
|
||||
func (c *client) Secure() string {
|
||||
if c.secure {
|
||||
switch c.secure {
|
||||
case withTLS:
|
||||
return "with TLS"
|
||||
case withmTLS:
|
||||
return "with mTLS"
|
||||
case withoutTLS:
|
||||
fallthrough
|
||||
default:
|
||||
return "without TLS"
|
||||
}
|
||||
return "without TLS"
|
||||
}
|
||||
|
||||
func (c *client) Connection() *gogrpc.ClientConn {
|
||||
func (c *client) Connection() *grpc.ClientConn {
|
||||
return c.ClientConn
|
||||
}
|
||||
|
||||
// connect creates new gRPC client and connect to gRPC server.
|
||||
func connect(cfg Config) (*gogrpc.ClientConn, bool, error) {
|
||||
var opts []gogrpc.DialOption
|
||||
secure := false
|
||||
func connect(cfg Config) (*grpc.ClientConn, security, error) {
|
||||
opts := []grpc.DialOption{
|
||||
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
|
||||
}
|
||||
secure := withoutTLS
|
||||
tc := insecure.NewCredentials()
|
||||
|
||||
if cfg.ClientTLS && cfg.CACerts != "" {
|
||||
var err error
|
||||
tc, err = credentials.NewClientTLSFromFile(cfg.CACerts, "")
|
||||
if cfg.AttestedTLS {
|
||||
err := readManifest(cfg)
|
||||
if err != nil {
|
||||
return nil, secure, err
|
||||
return nil, secure, fmt.Errorf("failed to read Manifest %w", err)
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
VerifyPeerCertificate: verifyAttestationReportTLS,
|
||||
}
|
||||
tc = credentials.NewTLS(tlsConfig)
|
||||
} else {
|
||||
if cfg.ServerCAFile != "" {
|
||||
tlsConfig := &tls.Config{}
|
||||
|
||||
// Loading root ca certificates file
|
||||
rootCA, err := os.ReadFile(cfg.ServerCAFile)
|
||||
if err != nil {
|
||||
return nil, secure, fmt.Errorf("failed to load root ca file: %w", err)
|
||||
}
|
||||
if len(rootCA) > 0 {
|
||||
capool := x509.NewCertPool()
|
||||
if !capool.AppendCertsFromPEM(rootCA) {
|
||||
return nil, secure, fmt.Errorf("failed to append root ca to tls.Config")
|
||||
}
|
||||
tlsConfig.RootCAs = capool
|
||||
secure = withTLS
|
||||
}
|
||||
|
||||
// Loading mTLS certificates file
|
||||
if cfg.ClientCert != "" || cfg.ClientKey != "" {
|
||||
certificate, err := tls.LoadX509KeyPair(cfg.ClientCert, cfg.ClientKey)
|
||||
if err != nil {
|
||||
return nil, secure, fmt.Errorf("failed to client certificate and key %w", err)
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{certificate}
|
||||
secure = withmTLS
|
||||
}
|
||||
|
||||
tc = credentials.NewTLS(tlsConfig)
|
||||
}
|
||||
secure = true
|
||||
}
|
||||
|
||||
opts = append(opts, gogrpc.WithTransportCredentials(tc), gogrpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()))
|
||||
opts = append(opts, grpc.WithTransportCredentials(tc))
|
||||
|
||||
conn, err := gogrpc.Dial(cfg.URL, opts...)
|
||||
conn, err := grpc.Dial(cfg.URL, opts...)
|
||||
if err != nil {
|
||||
return nil, secure, errors.Wrap(errGrpcConnect, err)
|
||||
}
|
||||
|
||||
return conn, secure, nil
|
||||
}
|
||||
|
||||
func readManifest(cfg Config) error {
|
||||
if cfg.Manifest != "" {
|
||||
manifest, err := os.Open(cfg.Manifest)
|
||||
if err != nil {
|
||||
return errors.Wrap(errManifestOpen, err)
|
||||
}
|
||||
defer manifest.Close()
|
||||
|
||||
decoder := json.NewDecoder(manifest)
|
||||
err = decoder.Decode(&attestationConfiguration)
|
||||
if err != nil {
|
||||
return errors.Wrap(errManifestDecode, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return errManifestMissing
|
||||
}
|
||||
|
||||
func verifyAttestationReportTLS(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
cert, err := x509.ParseCertificate(rawCerts[0])
|
||||
if err != nil {
|
||||
return errors.Wrap(errCertificateParse, err)
|
||||
}
|
||||
|
||||
for _, ext := range cert.Extensions {
|
||||
if ext.Id.Equal(customSEVSNPExtensionOID) {
|
||||
// Check if the certificate is self-signed
|
||||
err := checkIfCertificateSelfSigned(cert)
|
||||
if err != nil {
|
||||
return errors.Wrap(errAttVerification, err)
|
||||
}
|
||||
|
||||
publicKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey)
|
||||
if err != nil {
|
||||
return errors.Wrap(errAttVerification, err)
|
||||
}
|
||||
|
||||
expectedReportData := sha3.Sum512(publicKeyBytes)
|
||||
attestationConfiguration.SNPPolicy.ReportData = expectedReportData[:]
|
||||
|
||||
// Attestation verification and validation
|
||||
sopts, err := verify.RootOfTrustToOptions(attestationConfiguration.RootOFTrust)
|
||||
if err != nil {
|
||||
return errors.Wrap(errAttVerification, err)
|
||||
}
|
||||
|
||||
sopts.Product = attestationConfiguration.SNPPolicy.Product
|
||||
sopts.Getter = &trust.RetryHTTPSGetter{
|
||||
Timeout: timeout,
|
||||
MaxRetryDelay: maxTryDelay,
|
||||
Getter: &trust.SimpleHTTPSGetter{},
|
||||
}
|
||||
|
||||
attestationPB, err := abi.ReportCertsToProto(ext.Value)
|
||||
if err != nil {
|
||||
return errors.Wrap(errAttVerification, err)
|
||||
}
|
||||
|
||||
if err = verify.SnpAttestation(attestationPB, sopts); err != nil {
|
||||
return errors.Wrap(errAttVerification, err)
|
||||
}
|
||||
|
||||
opts, err := validate.PolicyToOptions(attestationConfiguration.SNPPolicy)
|
||||
if err != nil {
|
||||
return errors.Wrap(errAttVerification, err)
|
||||
}
|
||||
|
||||
if err = validate.SnpAttestation(attestationPB, opts); err != nil {
|
||||
return errors.Wrap(errAttValidation, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return errCustomExtension
|
||||
}
|
||||
|
||||
func checkIfCertificateSelfSigned(cert *x509.Certificate) error {
|
||||
certPool := x509.NewCertPool()
|
||||
certPool.AddCert(cert)
|
||||
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: certPool,
|
||||
CurrentTime: time.Now(),
|
||||
}
|
||||
|
||||
if _, err := cert.Verify(opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
managerapi "github.com/ultravioletrs/cocos/manager/api/grpc"
|
||||
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
)
|
||||
|
||||
// NewManagerClient creates new manager gRPC client instance.
|
||||
@@ -15,5 +14,5 @@ func NewManagerClient(cfg grpc.Config) (grpc.Client, manager.ManagerServiceClien
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return client, managerapi.NewClient(client.Connection(), cfg.Timeout), nil
|
||||
return client, manager.NewManagerServiceClient(client.Connection()), nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,928 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.25.3
|
||||
// source: manager/manager.proto
|
||||
|
||||
package manager
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type RunResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AgentPort string `protobuf:"bytes,1,opt,name=agent_port,json=agentPort,proto3" json:"agent_port,omitempty"`
|
||||
ComputationId string `protobuf:"bytes,2,opt,name=computation_id,json=computationId,proto3" json:"computation_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RunResponse) Reset() {
|
||||
*x = RunResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RunResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RunResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RunResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RunResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RunResponse) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *RunResponse) GetAgentPort() string {
|
||||
if x != nil {
|
||||
return x.AgentPort
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RunResponse) GetComputationId() string {
|
||||
if x != nil {
|
||||
return x.ComputationId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AgentEvent struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
EventType string `protobuf:"bytes,1,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"`
|
||||
Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
ComputationId string `protobuf:"bytes,3,opt,name=computation_id,json=computationId,proto3" json:"computation_id,omitempty"`
|
||||
Details []byte `protobuf:"bytes,4,opt,name=details,proto3" json:"details,omitempty"`
|
||||
Originator string `protobuf:"bytes,5,opt,name=originator,proto3" json:"originator,omitempty"`
|
||||
Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AgentEvent) Reset() {
|
||||
*x = AgentEvent{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AgentEvent) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AgentEvent) ProtoMessage() {}
|
||||
|
||||
func (x *AgentEvent) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AgentEvent.ProtoReflect.Descriptor instead.
|
||||
func (*AgentEvent) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *AgentEvent) GetEventType() string {
|
||||
if x != nil {
|
||||
return x.EventType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentEvent) GetTimestamp() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.Timestamp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *AgentEvent) GetComputationId() string {
|
||||
if x != nil {
|
||||
return x.ComputationId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentEvent) GetDetails() []byte {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *AgentEvent) GetOriginator() string {
|
||||
if x != nil {
|
||||
return x.Originator
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentEvent) GetStatus() string {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AgentLog struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
ComputationId string `protobuf:"bytes,2,opt,name=computation_id,json=computationId,proto3" json:"computation_id,omitempty"`
|
||||
Level string `protobuf:"bytes,3,opt,name=level,proto3" json:"level,omitempty"`
|
||||
Timestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AgentLog) Reset() {
|
||||
*x = AgentLog{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AgentLog) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AgentLog) ProtoMessage() {}
|
||||
|
||||
func (x *AgentLog) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AgentLog.ProtoReflect.Descriptor instead.
|
||||
func (*AgentLog) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *AgentLog) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentLog) GetComputationId() string {
|
||||
if x != nil {
|
||||
return x.ComputationId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentLog) GetLevel() string {
|
||||
if x != nil {
|
||||
return x.Level
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentLog) GetTimestamp() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.Timestamp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ClientStreamMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Types that are assignable to Message:
|
||||
//
|
||||
// *ClientStreamMessage_AgentLog
|
||||
// *ClientStreamMessage_AgentEvent
|
||||
// *ClientStreamMessage_RunRes
|
||||
Message isClientStreamMessage_Message `protobuf_oneof:"message"`
|
||||
}
|
||||
|
||||
func (x *ClientStreamMessage) Reset() {
|
||||
*x = ClientStreamMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ClientStreamMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ClientStreamMessage) ProtoMessage() {}
|
||||
|
||||
func (x *ClientStreamMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ClientStreamMessage.ProtoReflect.Descriptor instead.
|
||||
func (*ClientStreamMessage) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (m *ClientStreamMessage) GetMessage() isClientStreamMessage_Message {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ClientStreamMessage) GetAgentLog() *AgentLog {
|
||||
if x, ok := x.GetMessage().(*ClientStreamMessage_AgentLog); ok {
|
||||
return x.AgentLog
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ClientStreamMessage) GetAgentEvent() *AgentEvent {
|
||||
if x, ok := x.GetMessage().(*ClientStreamMessage_AgentEvent); ok {
|
||||
return x.AgentEvent
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ClientStreamMessage) GetRunRes() *RunResponse {
|
||||
if x, ok := x.GetMessage().(*ClientStreamMessage_RunRes); ok {
|
||||
return x.RunRes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isClientStreamMessage_Message interface {
|
||||
isClientStreamMessage_Message()
|
||||
}
|
||||
|
||||
type ClientStreamMessage_AgentLog struct {
|
||||
AgentLog *AgentLog `protobuf:"bytes,1,opt,name=agent_log,json=agentLog,proto3,oneof"`
|
||||
}
|
||||
|
||||
type ClientStreamMessage_AgentEvent struct {
|
||||
AgentEvent *AgentEvent `protobuf:"bytes,2,opt,name=agent_event,json=agentEvent,proto3,oneof"`
|
||||
}
|
||||
|
||||
type ClientStreamMessage_RunRes struct {
|
||||
RunRes *RunResponse `protobuf:"bytes,3,opt,name=run_res,json=runRes,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*ClientStreamMessage_AgentLog) isClientStreamMessage_Message() {}
|
||||
|
||||
func (*ClientStreamMessage_AgentEvent) isClientStreamMessage_Message() {}
|
||||
|
||||
func (*ClientStreamMessage_RunRes) isClientStreamMessage_Message() {}
|
||||
|
||||
type ComputationRunReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
|
||||
Datasets []*Dataset `protobuf:"bytes,4,rep,name=datasets,proto3" json:"datasets,omitempty"`
|
||||
Algorithm *Algorithm `protobuf:"bytes,5,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
|
||||
ResultConsumers []string `protobuf:"bytes,6,rep,name=result_consumers,json=resultConsumers,proto3" json:"result_consumers,omitempty"`
|
||||
AgentConfig *AgentConfig `protobuf:"bytes,7,opt,name=agent_config,json=agentConfig,proto3" json:"agent_config,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) Reset() {
|
||||
*x = ComputationRunReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ComputationRunReq) ProtoMessage() {}
|
||||
|
||||
func (x *ComputationRunReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ComputationRunReq.ProtoReflect.Descriptor instead.
|
||||
func (*ComputationRunReq) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) GetDescription() string {
|
||||
if x != nil {
|
||||
return x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) GetDatasets() []*Dataset {
|
||||
if x != nil {
|
||||
return x.Datasets
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) GetAlgorithm() *Algorithm {
|
||||
if x != nil {
|
||||
return x.Algorithm
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) GetResultConsumers() []string {
|
||||
if x != nil {
|
||||
return x.ResultConsumers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ComputationRunReq) GetAgentConfig() *AgentConfig {
|
||||
if x != nil {
|
||||
return x.AgentConfig
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Dataset struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Hash []byte `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` // should be sha3.Sum256, 32 byte length.
|
||||
}
|
||||
|
||||
func (x *Dataset) Reset() {
|
||||
*x = Dataset{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Dataset) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Dataset) ProtoMessage() {}
|
||||
|
||||
func (x *Dataset) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Dataset.ProtoReflect.Descriptor instead.
|
||||
func (*Dataset) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *Dataset) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Dataset) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Dataset) GetHash() []byte {
|
||||
if x != nil {
|
||||
return x.Hash
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Algorithm struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Hash []byte `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` // should be sha3.Sum256, 32 byte length.
|
||||
}
|
||||
|
||||
func (x *Algorithm) Reset() {
|
||||
*x = Algorithm{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Algorithm) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Algorithm) ProtoMessage() {}
|
||||
|
||||
func (x *Algorithm) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Algorithm.ProtoReflect.Descriptor instead.
|
||||
func (*Algorithm) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *Algorithm) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Algorithm) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Algorithm) GetHash() []byte {
|
||||
if x != nil {
|
||||
return x.Hash
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AgentConfig struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Port string `protobuf:"bytes,1,opt,name=port,proto3" json:"port,omitempty"`
|
||||
Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"`
|
||||
CertFile string `protobuf:"bytes,3,opt,name=cert_file,json=certFile,proto3" json:"cert_file,omitempty"`
|
||||
KeyFile string `protobuf:"bytes,4,opt,name=key_file,json=keyFile,proto3" json:"key_file,omitempty"`
|
||||
ClientCaFile string `protobuf:"bytes,5,opt,name=client_ca_file,json=clientCaFile,proto3" json:"client_ca_file,omitempty"`
|
||||
ServerCaFile string `protobuf:"bytes,6,opt,name=server_ca_file,json=serverCaFile,proto3" json:"server_ca_file,omitempty"`
|
||||
LogLevel string `protobuf:"bytes,7,opt,name=log_level,json=logLevel,proto3" json:"log_level,omitempty"`
|
||||
AttestedTls bool `protobuf:"varint,8,opt,name=attested_tls,json=attestedTls,proto3" json:"attested_tls,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AgentConfig) Reset() {
|
||||
*x = AgentConfig{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_manager_manager_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AgentConfig) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AgentConfig) ProtoMessage() {}
|
||||
|
||||
func (x *AgentConfig) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_manager_manager_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AgentConfig.ProtoReflect.Descriptor instead.
|
||||
func (*AgentConfig) Descriptor() ([]byte, []int) {
|
||||
return file_manager_manager_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *AgentConfig) GetPort() string {
|
||||
if x != nil {
|
||||
return x.Port
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentConfig) GetHost() string {
|
||||
if x != nil {
|
||||
return x.Host
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentConfig) GetCertFile() string {
|
||||
if x != nil {
|
||||
return x.CertFile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentConfig) GetKeyFile() string {
|
||||
if x != nil {
|
||||
return x.KeyFile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentConfig) GetClientCaFile() string {
|
||||
if x != nil {
|
||||
return x.ClientCaFile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentConfig) GetServerCaFile() string {
|
||||
if x != nil {
|
||||
return x.ServerCaFile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentConfig) GetLogLevel() string {
|
||||
if x != nil {
|
||||
return x.LogLevel
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AgentConfig) GetAttestedTls() bool {
|
||||
if x != nil {
|
||||
return x.AttestedTls
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var File_manager_manager_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_manager_manager_proto_rawDesc = []byte{
|
||||
0x0a, 0x15, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
|
||||
0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x22, 0x53, 0x0a, 0x0b, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12,
|
||||
0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xde, 0x01, 0x0a, 0x0a, 0x41, 0x67, 0x65, 0x6e, 0x74,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74,
|
||||
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x54, 0x79, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
||||
0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||
0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25,
|
||||
0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12,
|
||||
0x1e, 0x0a, 0x0a, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12,
|
||||
0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x9b, 0x01, 0x0a, 0x08, 0x41, 0x67, 0x65, 0x6e,
|
||||
0x74, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x25,
|
||||
0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x38, 0x0a, 0x09, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xbb, 0x01, 0x0a, 0x13, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a,
|
||||
0x09, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74,
|
||||
0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x12,
|
||||
0x36, 0x0a, 0x0b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41,
|
||||
0x67, 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x67, 0x65,
|
||||
0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x72, 0x75, 0x6e, 0x5f, 0x72,
|
||||
0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67,
|
||||
0x65, 0x72, 0x2e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00,
|
||||
0x52, 0x06, 0x72, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x22, 0x9d, 0x02, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a,
|
||||
0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12,
|
||||
0x2c, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x10, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x61, 0x74, 0x61,
|
||||
0x73, 0x65, 0x74, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x30, 0x0a,
|
||||
0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72,
|
||||
0x69, 0x74, 0x68, 0x6d, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12,
|
||||
0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d,
|
||||
0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x75, 0x6c,
|
||||
0x74, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x61, 0x67,
|
||||
0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x14, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x22, 0x49, 0x0a, 0x07, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61,
|
||||
0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x4b,
|
||||
0x0a, 0x09, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70,
|
||||
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
|
||||
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0xf9, 0x01, 0x0a, 0x0b,
|
||||
0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68,
|
||||
0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65,
|
||||
0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x63,
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x61, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x5f, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x43, 0x61, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c,
|
||||
0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c,
|
||||
0x65, 0x76, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64,
|
||||
0x5f, 0x74, 0x6c, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65,
|
||||
0x73, 0x74, 0x65, 0x64, 0x54, 0x6c, 0x73, 0x32, 0x5b, 0x0a, 0x0e, 0x4d, 0x61, 0x6e, 0x61, 0x67,
|
||||
0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x07, 0x50, 0x72, 0x6f,
|
||||
0x63, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43,
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d,
|
||||
0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x22, 0x00,
|
||||
0x28, 0x01, 0x30, 0x01, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_manager_manager_proto_rawDescOnce sync.Once
|
||||
file_manager_manager_proto_rawDescData = file_manager_manager_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_manager_manager_proto_rawDescGZIP() []byte {
|
||||
file_manager_manager_proto_rawDescOnce.Do(func() {
|
||||
file_manager_manager_proto_rawDescData = protoimpl.X.CompressGZIP(file_manager_manager_proto_rawDescData)
|
||||
})
|
||||
return file_manager_manager_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_manager_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||
var file_manager_manager_proto_goTypes = []interface{}{
|
||||
(*RunResponse)(nil), // 0: manager.RunResponse
|
||||
(*AgentEvent)(nil), // 1: manager.AgentEvent
|
||||
(*AgentLog)(nil), // 2: manager.AgentLog
|
||||
(*ClientStreamMessage)(nil), // 3: manager.ClientStreamMessage
|
||||
(*ComputationRunReq)(nil), // 4: manager.ComputationRunReq
|
||||
(*Dataset)(nil), // 5: manager.Dataset
|
||||
(*Algorithm)(nil), // 6: manager.Algorithm
|
||||
(*AgentConfig)(nil), // 7: manager.AgentConfig
|
||||
(*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp
|
||||
}
|
||||
var file_manager_manager_proto_depIdxs = []int32{
|
||||
8, // 0: manager.AgentEvent.timestamp:type_name -> google.protobuf.Timestamp
|
||||
8, // 1: manager.AgentLog.timestamp:type_name -> google.protobuf.Timestamp
|
||||
2, // 2: manager.ClientStreamMessage.agent_log:type_name -> manager.AgentLog
|
||||
1, // 3: manager.ClientStreamMessage.agent_event:type_name -> manager.AgentEvent
|
||||
0, // 4: manager.ClientStreamMessage.run_res:type_name -> manager.RunResponse
|
||||
5, // 5: manager.ComputationRunReq.datasets:type_name -> manager.Dataset
|
||||
6, // 6: manager.ComputationRunReq.algorithm:type_name -> manager.Algorithm
|
||||
7, // 7: manager.ComputationRunReq.agent_config:type_name -> manager.AgentConfig
|
||||
3, // 8: manager.ManagerService.Process:input_type -> manager.ClientStreamMessage
|
||||
4, // 9: manager.ManagerService.Process:output_type -> manager.ComputationRunReq
|
||||
9, // [9:10] is the sub-list for method output_type
|
||||
8, // [8:9] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_manager_manager_proto_init() }
|
||||
func file_manager_manager_proto_init() {
|
||||
if File_manager_manager_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_manager_manager_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RunResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AgentEvent); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AgentLog); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ClientStreamMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ComputationRunReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Dataset); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Algorithm); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AgentConfig); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_manager_manager_proto_msgTypes[3].OneofWrappers = []interface{}{
|
||||
(*ClientStreamMessage_AgentLog)(nil),
|
||||
(*ClientStreamMessage_AgentEvent)(nil),
|
||||
(*ClientStreamMessage_RunRes)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_manager_manager_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 8,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_manager_manager_proto_goTypes,
|
||||
DependencyIndexes: file_manager_manager_proto_depIdxs,
|
||||
MessageInfos: file_manager_manager_proto_msgTypes,
|
||||
}.Build()
|
||||
File_manager_manager_proto = out.File
|
||||
file_manager_manager_proto_rawDesc = nil
|
||||
file_manager_manager_proto_goTypes = nil
|
||||
file_manager_manager_proto_depIdxs = nil
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v4.25.1
|
||||
// - protoc v4.25.3
|
||||
// source: manager/manager.proto
|
||||
|
||||
package manager
|
||||
@@ -22,14 +22,14 @@ import (
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
ManagerService_Run_FullMethodName = "/manager.ManagerService/Run"
|
||||
ManagerService_Process_FullMethodName = "/manager.ManagerService/Process"
|
||||
)
|
||||
|
||||
// ManagerServiceClient is the client API for ManagerService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type ManagerServiceClient interface {
|
||||
Run(ctx context.Context, in *RunRequest, opts ...grpc.CallOption) (*RunResponse, error)
|
||||
Process(ctx context.Context, opts ...grpc.CallOption) (ManagerService_ProcessClient, error)
|
||||
}
|
||||
|
||||
type managerServiceClient struct {
|
||||
@@ -40,20 +40,42 @@ func NewManagerServiceClient(cc grpc.ClientConnInterface) ManagerServiceClient {
|
||||
return &managerServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *managerServiceClient) Run(ctx context.Context, in *RunRequest, opts ...grpc.CallOption) (*RunResponse, error) {
|
||||
out := new(RunResponse)
|
||||
err := c.cc.Invoke(ctx, ManagerService_Run_FullMethodName, in, out, opts...)
|
||||
func (c *managerServiceClient) Process(ctx context.Context, opts ...grpc.CallOption) (ManagerService_ProcessClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &ManagerService_ServiceDesc.Streams[0], ManagerService_Process_FullMethodName, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
x := &managerServiceProcessClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type ManagerService_ProcessClient interface {
|
||||
Send(*ClientStreamMessage) error
|
||||
Recv() (*ComputationRunReq, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type managerServiceProcessClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *managerServiceProcessClient) Send(m *ClientStreamMessage) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *managerServiceProcessClient) Recv() (*ComputationRunReq, error) {
|
||||
m := new(ComputationRunReq)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// ManagerServiceServer is the server API for ManagerService service.
|
||||
// All implementations must embed UnimplementedManagerServiceServer
|
||||
// for forward compatibility
|
||||
type ManagerServiceServer interface {
|
||||
Run(context.Context, *RunRequest) (*RunResponse, error)
|
||||
Process(ManagerService_ProcessServer) error
|
||||
mustEmbedUnimplementedManagerServiceServer()
|
||||
}
|
||||
|
||||
@@ -61,8 +83,8 @@ type ManagerServiceServer interface {
|
||||
type UnimplementedManagerServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedManagerServiceServer) Run(context.Context, *RunRequest) (*RunResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Run not implemented")
|
||||
func (UnimplementedManagerServiceServer) Process(ManagerService_ProcessServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method Process not implemented")
|
||||
}
|
||||
func (UnimplementedManagerServiceServer) mustEmbedUnimplementedManagerServiceServer() {}
|
||||
|
||||
@@ -77,22 +99,30 @@ func RegisterManagerServiceServer(s grpc.ServiceRegistrar, srv ManagerServiceSer
|
||||
s.RegisterService(&ManagerService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ManagerService_Run_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RunRequest)
|
||||
if err := dec(in); err != nil {
|
||||
func _ManagerService_Process_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(ManagerServiceServer).Process(&managerServiceProcessServer{stream})
|
||||
}
|
||||
|
||||
type ManagerService_ProcessServer interface {
|
||||
Send(*ComputationRunReq) error
|
||||
Recv() (*ClientStreamMessage, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type managerServiceProcessServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *managerServiceProcessServer) Send(m *ComputationRunReq) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *managerServiceProcessServer) Recv() (*ClientStreamMessage, error) {
|
||||
m := new(ClientStreamMessage)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ManagerServiceServer).Run(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ManagerService_Run_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ManagerServiceServer).Run(ctx, req.(*RunRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// ManagerService_ServiceDesc is the grpc.ServiceDesc for ManagerService service.
|
||||
@@ -101,12 +131,14 @@ func _ManagerService_Run_Handler(srv interface{}, ctx context.Context, dec func(
|
||||
var ManagerService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "manager.ManagerService",
|
||||
HandlerType: (*ManagerServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
MethodName: "Run",
|
||||
Handler: _ManagerService_Run_Handler,
|
||||
StreamName: "Process",
|
||||
Handler: _ManagerService_Process_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "manager/manager.proto",
|
||||
}
|
||||
+17
-19
@@ -4,59 +4,55 @@ package sdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
var _ agent.Service = (*agentSDK)(nil)
|
||||
|
||||
const size64 = 64
|
||||
|
||||
type agentSDK struct {
|
||||
client agent.AgentServiceClient
|
||||
logger mglog.Logger
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewAgentSDK(log mglog.Logger, agentClient agent.AgentServiceClient) *agentSDK {
|
||||
func NewAgentSDK(log *slog.Logger, agentClient agent.AgentServiceClient) *agentSDK {
|
||||
return &agentSDK{
|
||||
client: agentClient,
|
||||
logger: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (sdk *agentSDK) Run(ctx context.Context, ac agent.Computation) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (sdk *agentSDK) Algo(ctx context.Context, algorithm agent.Algorithm) (string, error) {
|
||||
func (sdk *agentSDK) Algo(ctx context.Context, algorithm agent.Algorithm) error {
|
||||
request := &agent.AlgoRequest{
|
||||
Algorithm: algorithm.Algorithm,
|
||||
Provider: algorithm.Provider,
|
||||
Id: algorithm.ID,
|
||||
}
|
||||
|
||||
response, err := sdk.client.Algo(ctx, request)
|
||||
if err != nil {
|
||||
if _, err := sdk.client.Algo(ctx, request); err != nil {
|
||||
sdk.logger.Error("Failed to call Algo RPC")
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
|
||||
return response.AlgorithmID, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk *agentSDK) Data(ctx context.Context, dataset agent.Dataset) (string, error) {
|
||||
func (sdk *agentSDK) Data(ctx context.Context, dataset agent.Dataset) error {
|
||||
request := &agent.DataRequest{
|
||||
Dataset: dataset.Dataset,
|
||||
Provider: dataset.Provider,
|
||||
Id: dataset.ID,
|
||||
}
|
||||
|
||||
response, err := sdk.client.Data(ctx, request)
|
||||
if err != nil {
|
||||
if _, err := sdk.client.Data(ctx, request); err != nil {
|
||||
sdk.logger.Error("Failed to call Data RPC")
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
|
||||
return response.DatasetID, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk *agentSDK) Result(ctx context.Context, consumer string) ([]byte, error) {
|
||||
@@ -73,8 +69,10 @@ func (sdk *agentSDK) Result(ctx context.Context, consumer string) ([]byte, error
|
||||
return response.File, nil
|
||||
}
|
||||
|
||||
func (sdk *agentSDK) Attestation(ctx context.Context) ([]byte, error) {
|
||||
request := &agent.AttestationRequest{}
|
||||
func (sdk *agentSDK) Attestation(ctx context.Context, reportData [size64]byte) ([]byte, error) {
|
||||
request := &agent.AttestationRequest{
|
||||
ReportData: reportData[:],
|
||||
}
|
||||
|
||||
response, err := sdk.client.Attestation(ctx, request)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Computations Server
|
||||
Manager service is a grpc client. It connects to computations server.
|
||||
The server then responds with a run computation request. Once manager service receives the computation request it will launch an agent service in a virtual machine and pass the computation manifest. Agent will then pass logs and events to manager which are forwarded to the server. `main.go` is a sample of how such a server would be implemented. This is a very simple example for testing purposes.
|
||||
|
||||
## Configuration
|
||||
|
||||
The service is configured using the environment variables from the following table. Note that any unset variables will be replaced with their default values.
|
||||
|
||||
| Variable | Description | Default |
|
||||
| ---------------- | ---------------------------------------- | ------- |
|
||||
| HOST | Computations service gRPC host | |
|
||||
| PORT | Computations service gRPC port | 7001 |
|
||||
| SERVER_CERT | Path to server certificate in pem format | |
|
||||
| SERVER_KEY | Path to server key in pem format | |
|
||||
|
||||
## Running
|
||||
```shell
|
||||
go run main.go <dataset_path> <algo_path>
|
||||
```
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/ultravioletrs/cocos/internal/env"
|
||||
"github.com/ultravioletrs/cocos/internal/server"
|
||||
grpcserver "github.com/ultravioletrs/cocos/internal/server/grpc"
|
||||
managergrpc "github.com/ultravioletrs/cocos/manager/api/grpc"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
var _ managergrpc.Service = (*svc)(nil)
|
||||
|
||||
const (
|
||||
svcName = "manager_test_server"
|
||||
defaultPort = "7001"
|
||||
)
|
||||
|
||||
var (
|
||||
algoPath = "./test/manual/algo/lin_reg.py"
|
||||
dataPath = "./test/manual/data/iris.csv"
|
||||
attestedTLS = false
|
||||
)
|
||||
|
||||
type svc struct {
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (s *svc) Run(ipAdress string, reqChan chan *manager.ComputationRunReq) {
|
||||
s.logger.Debug(fmt.Sprintf("received who am on ip address %s", ipAdress))
|
||||
algo, err := os.ReadFile(algoPath)
|
||||
if err != nil {
|
||||
s.logger.Error(fmt.Sprintf("failed to read algorithm file: %s", err))
|
||||
return
|
||||
}
|
||||
data, err := os.ReadFile(dataPath)
|
||||
if err != nil {
|
||||
s.logger.Error(fmt.Sprintf("failed to read data file: %s", err))
|
||||
return
|
||||
}
|
||||
algoHash := sha3.Sum256(algo)
|
||||
dataHash := sha3.Sum256(data)
|
||||
reqChan <- &manager.ComputationRunReq{
|
||||
Id: "1",
|
||||
Name: "sample computation",
|
||||
Description: "sample descrption",
|
||||
Datasets: []*manager.Dataset{{Id: "1", Provider: "provider1", Hash: dataHash[:]}},
|
||||
Algorithm: &manager.Algorithm{Id: "1", Provider: "provider1", Hash: algoHash[:]},
|
||||
ResultConsumers: []string{"consumer1"},
|
||||
AgentConfig: &manager.AgentConfig{
|
||||
Port: "7002",
|
||||
LogLevel: "debug",
|
||||
AttestedTls: attestedTLS,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 4 {
|
||||
log.Fatalf("usage: %s <data-path> <algo-path> <attested-tls-bool>", os.Args[0])
|
||||
}
|
||||
dataPath = os.Args[1]
|
||||
algoPath = os.Args[2]
|
||||
attestedTLSParam, err := strconv.ParseBool(os.Args[3])
|
||||
if err != nil {
|
||||
log.Fatalf("usage: %s <data-path> <algo-path> <attested-tls-bool>, <attested-tls-bool> must be a bool value", os.Args[0])
|
||||
}
|
||||
attestedTLS = attestedTLSParam
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
incomingChan := make(chan *manager.ClientStreamMessage)
|
||||
|
||||
logger, err := mglog.New(os.Stdout, "debug")
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
go func() {
|
||||
for incoming := range incomingChan {
|
||||
switch incoming.Message.(type) {
|
||||
case *manager.ClientStreamMessage_RunRes:
|
||||
fmt.Println("received runRes")
|
||||
case *manager.ClientStreamMessage_AgentEvent:
|
||||
fmt.Println("received agent event")
|
||||
case *manager.ClientStreamMessage_AgentLog:
|
||||
fmt.Println("received agent log")
|
||||
}
|
||||
fmt.Println(incoming.Message)
|
||||
}
|
||||
}()
|
||||
|
||||
registerAgentServiceServer := func(srv *grpc.Server) {
|
||||
reflection.Register(srv)
|
||||
manager.RegisterManagerServiceServer(srv, managergrpc.NewServer(ctx, incomingChan, &svc{logger: logger}))
|
||||
}
|
||||
grpcServerConfig := server.Config{Port: defaultPort}
|
||||
if err := env.Parse(&grpcServerConfig, env.Options{}); err != nil {
|
||||
logger.Error(fmt.Sprintf("failed to load %s gRPC client configuration : %s", svcName, err))
|
||||
return
|
||||
}
|
||||
|
||||
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger, nil)
|
||||
|
||||
g.Go(func() error {
|
||||
return gs.Start()
|
||||
})
|
||||
|
||||
g.Go(func() error {
|
||||
return server.StopHandler(ctx, cancel, logger, svcName, gs)
|
||||
})
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
logger.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
|
||||
}
|
||||
}
|
||||
+12
-11
@@ -2,33 +2,34 @@
|
||||
|
||||
## CLI
|
||||
|
||||
Throughout the tests, we assume that our current working directory is the root of the `agent` repository, both on the host machine and in the VM.
|
||||
Throughout the tests, we assume that our current working directory is the root of the `cocos` repository, both on the host machine and in the VM.
|
||||
|
||||
### Python requirements
|
||||
|
||||
Do this both on the host machine and in the VM.
|
||||
Do this in the VM.
|
||||
|
||||
```sh
|
||||
apt update
|
||||
apt install python3-pip
|
||||
pip3 install pandas scikit-learn
|
||||
```
|
||||
|
||||
### Agent-CLI interaction
|
||||
|
||||
In the VM, open a console and start `agent`:
|
||||
|
||||
```sh
|
||||
AGENT_LOG_LEVEL=info AGENT_GRPC_URL=10.0.2.15:7002 go run cmd/agent/main.go
|
||||
```
|
||||
Agent is started automatically in the VM when launched but requires configuration and manifest to be passed by manager. Alternatively you can pass configuration using this [simplified script](./agent-config/main.go)
|
||||
|
||||
Open console on the host, and run
|
||||
|
||||
```sh
|
||||
export AGENT_GRPC_URL=localhost:7002
|
||||
|
||||
# Run CLI to provide manifest
|
||||
go run cmd/cli/main.go run --computation '{"id":"123","name":"Sample Computation","description":"A sample computation","status":"Processing","owner":"John Doe","start_time":"2023-11-03T12:03:21.705171284+03:00","end_time":"2023-11-03T13:03:21.705171532+03:00","datasets":[{"provider":"Provider1","id":"Dataset1"},{"provider":"Provider2","id":"Dataset2"}],"algorithms":[{"provider":"AlgorithmProvider1","id":"Algorithm1"}],"result_consumers":["Consumer1","Consumer2"],"ttl":3600,"metadata":{"key1":"value1","key2":42}, "timeout": "2m"}'
|
||||
# For attested TLS, also define the path to the computation.json that contains reference values for the fields of the attestation report
|
||||
export AGENT_GRPC_MANIFEST=./test/manual/computation/computation.json
|
||||
export AGENT_GRPC_ATTESTED_TLS=true
|
||||
|
||||
# Retieve Attestation
|
||||
go run cmd/cli/main.go attestation get '<report_data>'
|
||||
|
||||
# Validate Attestation
|
||||
go run cmd/cli/main.go attestation validate '<attesation>' --report_data '<report_data>'
|
||||
|
||||
# Run the CLI program with algorithm input
|
||||
go run cmd/cli/main.go algo test/manual/algo/lin_reg.py Algorithm1 AlgorithmProvider1
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Simplified script to pass configs to agent without manager and read logs and events for manager.
|
||||
// This tool is meant for testing purposes.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/mdlayher/vsock"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const VsockConfigPort uint32 = 9999
|
||||
|
||||
type AgentConfig struct {
|
||||
LogLevel string `json:"log_level"`
|
||||
InstanceID string `json:"instance_id"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
CertFile string `json:"cert_file"`
|
||||
KeyFile string `json:"server_key"`
|
||||
AttestedTls bool `json:"attested_tls"`
|
||||
}
|
||||
|
||||
type Computation struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Datasets Datasets `json:"datasets,omitempty"`
|
||||
Algorithms Algorithms `json:"algorithms,omitempty"`
|
||||
ResultConsumers []string `json:"result_consumers,omitempty"`
|
||||
AgentConfig AgentConfig `json:"agent_config,omitempty"`
|
||||
}
|
||||
|
||||
func (d *Datasets) String() string {
|
||||
dat, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(dat)
|
||||
}
|
||||
|
||||
func (a *Algorithms) String() string {
|
||||
dat, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(dat)
|
||||
}
|
||||
|
||||
type Dataset struct {
|
||||
Dataset []byte `json:"-"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type Datasets []Dataset
|
||||
|
||||
type Algorithm struct {
|
||||
Algorithm []byte `json:"-"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type Algorithms []Algorithm
|
||||
|
||||
func main() {
|
||||
attestedTLS := false
|
||||
|
||||
if len(os.Args) == 2 {
|
||||
attestedTLSParam, err := strconv.ParseBool(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatalf("usage: %s <attested-tls> - <attested-tls> must be true or false", os.Args[0])
|
||||
}
|
||||
|
||||
attestedTLS = attestedTLSParam
|
||||
} else if len(os.Args) > 2 {
|
||||
log.Fatalf("usage: %s <attested-tls>", os.Args[0])
|
||||
}
|
||||
|
||||
l, err := vsock.Listen(9997, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ac := Computation{
|
||||
ID: "123",
|
||||
Datasets: Datasets{Dataset{ID: "1", Provider: "pr1"}},
|
||||
Algorithms: Algorithms{Algorithm{ID: "1", Provider: "pr1"}},
|
||||
ResultConsumers: []string{"1"},
|
||||
AgentConfig: AgentConfig{
|
||||
LogLevel: "debug",
|
||||
Port: "7002",
|
||||
AttestedTls: attestedTLS,
|
||||
},
|
||||
}
|
||||
fmt.Println(SendAgentConfig(3, ac))
|
||||
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
b := make([]byte, 1024)
|
||||
n, err := conn.Read(b)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
conn.Close()
|
||||
var mes manager.ClientStreamMessage
|
||||
if err := proto.Unmarshal(b[:n], &mes); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
fmt.Println(mes.String())
|
||||
}
|
||||
}
|
||||
|
||||
func SendAgentConfig(cid uint32, ac Computation) error {
|
||||
conn, err := vsock.Dial(cid, VsockConfigPort, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
payload, err := json.Marshal(ac)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := conn.Write(payload); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"snp_policy": {
|
||||
"minimum_guest_svn": 0,
|
||||
"policy": 196608,
|
||||
"minimum_tcb": 1,
|
||||
"minimum_version": "1.0",
|
||||
"minimum_launch_tcb": 1,
|
||||
"measurement": [232, 141, 188, 114, 162, 221, 214, 6, 150, 248, 3, 173, 230, 39, 48, 120, 105, 243, 15, 242, 79, 67, 112, 128, 44, 119, 216, 226, 170, 255, 212, 154, 58, 68, 231, 30, 20, 235, 228, 42, 43, 1, 95, 191, 51, 113, 19, 72],
|
||||
"minimum_build": 1
|
||||
},
|
||||
"root_of_trust": {
|
||||
"product": "Milan",
|
||||
"check_crl": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user