mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-08-07 15:26:26 +00:00
Compare commits
295 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a322f8ecb | |||
| 8c2caec395 | |||
| de60358c02 | |||
| 997fb3bf48 | |||
| 722b463b6a | |||
| 938dd6cb78 | |||
| e86860b9ea | |||
| e2fb7ea88d | |||
| 6d0100c096 | |||
| 8975e28437 | |||
| 3e2be03047 | |||
| 046b549079 | |||
| 6f42135ec0 | |||
| e5c8243f5f | |||
| 8be6129889 | |||
| f2567830b3 | |||
| 55c19ca6b5 | |||
| 0c77167be1 | |||
| 34c3bbdbd8 | |||
| 55afe4c038 | |||
| 2bb3b5650a | |||
| b4a49fb56c | |||
| c25cfec84c | |||
| cca75fc5cc | |||
| d24ce2b5bd | |||
| 200f207673 | |||
| 004f286900 | |||
| 0a0f757833 | |||
| 1167aeb53f | |||
| a5e6cae92c | |||
| c29ef354fa | |||
| b55b6c9734 | |||
| 4d9f7b1a45 | |||
| 46a91ccbc3 | |||
| 8c5bb52c56 | |||
| ee7159a406 | |||
| ee1f5ebb3d | |||
| 7ea8e48dbb | |||
| a3c5c765b8 | |||
| 34c5472485 | |||
| 1fec5fe3d4 | |||
| 4c53fd26e3 | |||
| 668552256f | |||
| 3e7fc09233 | |||
| 0dac01d752 | |||
| 18508796c1 | |||
| 5adf0349a3 | |||
| 0f831706f9 | |||
| 298878c96d | |||
| 7b31e21818 | |||
| 4ea9ff6531 | |||
| 4958f9468f | |||
| 4eea9c1a4c | |||
| 8c7d4a76ec | |||
| da590bfb63 | |||
| 70785b96e6 | |||
| f1f8f95653 | |||
| 7d47ed7a20 | |||
| 79d1834173 | |||
| a63cafc4d0 | |||
| 63d8035e46 | |||
| 96e3c48fcb | |||
| 91c9274885 | |||
| f9a2fd0b96 | |||
| 7cb04499e8 | |||
| 7657f8bd7a | |||
| dd08b7d0b1 | |||
| e9d143a7d3 | |||
| f690c286f2 | |||
| 194fd29d60 | |||
| 740a631287 | |||
| 514cc18bf8 | |||
| d96b3414c5 | |||
| c8d1ad4793 | |||
| 7302e82173 | |||
| 2d6487790b | |||
| 0ae70d9d75 | |||
| 2e0f3e9240 | |||
| 4f05805600 | |||
| 5171882634 | |||
| b0b22aeed3 | |||
| 16cb51563c | |||
| b78b15efb6 | |||
| 10f9ec8517 | |||
| 7cb1916e7a | |||
| 0ab28aa3cc | |||
| 54e03f3373 | |||
| 91dd8dd7b4 | |||
| e9f4d0c8d4 | |||
| 4d09a9f4c3 | |||
| 115ccc9f7b | |||
| 70840e2a62 | |||
| 83270dc9bc | |||
| 4354f0574c | |||
| db991b529c | |||
| ec865c8d68 | |||
| da7705de61 | |||
| de9feccc51 | |||
| 0049ce2b28 | |||
| c4cc8b48bf | |||
| eb230b5aa6 | |||
| e54d2731cd | |||
| a3c4664497 | |||
| 38558dbe53 | |||
| d70d9fe7e7 | |||
| c3443c5375 | |||
| 2cf6e1ac3e | |||
| 5028946731 | |||
| b3ad784ee0 | |||
| 0b38e94787 | |||
| 1536c6cbf5 | |||
| 6b4a7080e7 | |||
| 4137ad3513 | |||
| 5558a4f72b | |||
| 08f26af910 | |||
| 88e05aea0b | |||
| ce6131e5fd | |||
| 475004cc84 | |||
| 51e69d8ab4 | |||
| d7aca933bd | |||
| 7e21a17317 | |||
| 1012d2cb0e | |||
| 3caaf6a631 | |||
| 9c545d3c7c | |||
| fd68c9712b | |||
| dab603fb5f | |||
| ff47905247 | |||
| 44f742fdb0 | |||
| 6294117de8 | |||
| ada7cb96b7 | |||
| f6d5b616d2 | |||
| a29737b296 | |||
| 5762136b0a | |||
| 95a6957f4e | |||
| 38cdf9405b | |||
| 1a1785e1c7 | |||
| b92806c3b5 | |||
| b92c698800 | |||
| eaef7ddf9a | |||
| 10e2a6d0da | |||
| 6aff8ab0bd | |||
| 4dac375b87 | |||
| 376f204f54 | |||
| 2847a28a0f | |||
| c2240066f9 | |||
| f561f6c4c9 | |||
| a7ce9b1d87 | |||
| c9a7695b64 | |||
| 15d97f64cb | |||
| b82b2c6269 | |||
| f73c829d27 | |||
| 20962362b6 | |||
| ac4d20e07e | |||
| bd884cbcc4 | |||
| f5f645db0a | |||
| d802f65450 | |||
| f6f7152015 | |||
| 9747a0b18d | |||
| 0bf5985f5b | |||
| d1b40f9a06 | |||
| 972e15376f | |||
| d2fff75874 | |||
| 5c3413ff74 | |||
| 897e58faec | |||
| f5d3b7c15b | |||
| 0d3630a31b | |||
| 8ea5dda282 | |||
| c88d77ac6f | |||
| e46a2f137b | |||
| 60070be4d5 | |||
| fb596ab1ee | |||
| f0e7c183e0 | |||
| f379123aa7 | |||
| 54072fc052 | |||
| 2175ae3f1a | |||
| a903ca23cd | |||
| d5ac5fd3a9 | |||
| 7fec10fb56 | |||
| b6809fa5b2 | |||
| 9e2af2c525 | |||
| 9c74a0e7db | |||
| 7c9a5315a7 | |||
| 5bce3a8839 | |||
| 9484a44eb2 | |||
| 150b7ab81c | |||
| a1b4a21cb6 | |||
| b82c62d9b4 | |||
| 94a22d2282 | |||
| 7ac8372720 | |||
| 76b2bed007 | |||
| 885f4c9be1 | |||
| 03d637b5bf | |||
| 0f15d8c731 | |||
| 0d9aa5d88e | |||
| 300cabbaca | |||
| bb88a71eef | |||
| 8505deedc6 | |||
| 6cecedd1a1 | |||
| c09383ac72 | |||
| 8c87ef947b | |||
| 3a57c8d7a4 | |||
| 1829afd123 | |||
| 2c354c3977 | |||
| d59b9293cb | |||
| b5e64528b1 | |||
| f18e82efa7 | |||
| 5b60f079b5 | |||
| 52e681c28d | |||
| a3619098dc | |||
| bd61a3bd9f | |||
| f4ff0feb3c | |||
| cc078a1910 | |||
| 8f0fd5a1fa | |||
| 311dc7e1a7 | |||
| cfb0918c95 | |||
| 74c9c306e6 | |||
| 31b1f397d6 | |||
| 30d6f97976 | |||
| 5b1403edfc | |||
| 2ec9df770c | |||
| 62455e35b2 | |||
| 074186dd55 | |||
| 9a33eb828c | |||
| 5938760f8f | |||
| 2c54aa78d3 | |||
| d32fd050f7 | |||
| f4e71e74b2 | |||
| 45a92ec842 | |||
| 87ea08b08a | |||
| 0b4fbd5efe | |||
| f3cc5848ef | |||
| 71b5617ab3 | |||
| a917c4ba0c | |||
| 93b47a5897 | |||
| 6bd89b08fd | |||
| 6b7a81799c | |||
| 05ce62c158 | |||
| b5c38308f4 | |||
| 1c140ba4ee | |||
| 5277f44e41 | |||
| 4036dd3c85 | |||
| 62234dc7b1 | |||
| ce4726081a | |||
| 5296340326 | |||
| d4e3811640 | |||
| c8d2e96437 | |||
| 53370ba0f6 | |||
| 5a03d2ae4a | |||
| 5496af3af2 | |||
| 01a9f27deb | |||
| d212c77e22 | |||
| 4be83a9888 | |||
| 1e9fa759dd | |||
| 066c8ecfe9 | |||
| f2c58adef6 | |||
| 72b56ee40a | |||
| b7c6eadf4f | |||
| e05aca0b74 | |||
| 49feeb96ee | |||
| 5030a20af6 | |||
| 7b18467800 | |||
| a6d0734212 | |||
| d3acfd1718 | |||
| a150433982 | |||
| cea3e059fe | |||
| 5e2ee315f6 | |||
| 79ce0e34f9 | |||
| 90cea0d143 | |||
| 2e8603208b | |||
| 4191560130 | |||
| e9e9b8d15c | |||
| f02a500c2d | |||
| c1f9fa6328 | |||
| 750bed0d76 | |||
| 306fa302dc | |||
| 780c620b30 | |||
| 7383186143 | |||
| 023d28ea22 | |||
| 16fb3710ac | |||
| fe7c3d9014 | |||
| eb4a0943f6 | |||
| b400210738 | |||
| 7c12be6a24 | |||
| 6f014156b3 | |||
| 122b214299 | |||
| 8831a4f957 | |||
| e25abcf5e0 | |||
| ad60e95736 | |||
| 6ec53d074f | |||
| 35c62cb273 | |||
| 4d3bcf99b4 | |||
| 39c5cc2dd5 | |||
| 278331dc81 | |||
| b7a1fbb2fa | |||
| 22c743c4dd |
@@ -0,0 +1,33 @@
|
||||
## Jaeger
|
||||
COCOS_JAEGER_PORT=6831
|
||||
COCOS_JAEGER_FRONTEND=16686
|
||||
COCOS_JAEGER_COLLECTOR=14268
|
||||
COCOS_JAEGER_CONFIGS=5778
|
||||
COCOS_JAEGER_URL=http://jaeger:14268/api/traces
|
||||
COCOS_JAEGER_TRACE_RATIO=1.0
|
||||
|
||||
## Core Services
|
||||
|
||||
### Manager
|
||||
MANAGER_HTTP_HOST="cocos-manager"
|
||||
MANAGER_HTTP_PORT=9021
|
||||
MANAGER_HTTP_SERVER_CERT=""
|
||||
MANAGER_HTTP_SERVER_KEY=""
|
||||
MANAGER_GRPC_HOST="cocos-manager"
|
||||
MANAGER_GRPC_PORT=7003
|
||||
MANAGER_GRPC_SERVER_CERT=""
|
||||
MANAGER_GRPC_SERVER_KEY=""
|
||||
AGENT_GRPC_URL="192.168.100.4:7002"
|
||||
AGENT_GRPC_TIMEOUT=""
|
||||
AGENT_GRPC_CA_CERTS=""
|
||||
AGENT_GRPC_CLIENT_TLS=""
|
||||
MANAGER_INSTANCE_ID=""
|
||||
MANAGER_LOG_LEVEL=debug
|
||||
MANAGER_QEMU_USE_SUDO=false
|
||||
MANAGER_QEMU_ENABLE_SEV=false
|
||||
MANAGER_QEMU_SEV_CBITPOS=51
|
||||
MANAGER_QEMU_OVMF_CODE_FILE=/usr/share/OVMF/OVMF_CODE.fd
|
||||
MANAGER_QEMU_OVMF_VARS_FILE=/usr/share/OVMF/OVMF_VARS.fd
|
||||
|
||||
# Docker image tag
|
||||
COCOS_RELEASE_TAG=latest
|
||||
@@ -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.-->
|
||||
@@ -0,0 +1,82 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "manager/manager.proto"
|
||||
- "pkg/manager/*.pb.go"
|
||||
- "agent/agent.proto"
|
||||
- "agent/*.pb.go"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "manager/manager.proto"
|
||||
- "pkg/manager/*.pb.go"
|
||||
- "agent/agent.proto"
|
||||
- "agent/*.pb.go"
|
||||
|
||||
jobs:
|
||||
checkproto:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Go
|
||||
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_GRPC_VERSION=v1.3.0
|
||||
|
||||
# Download and install protoc
|
||||
PROTOC_ZIP=protoc-$PROTOC_VERSION-linux-x86_64.zip
|
||||
curl -0L -o $PROTOC_ZIP https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOC_VERSION/$PROTOC_ZIP
|
||||
unzip -o $PROTOC_ZIP -d protoc3
|
||||
sudo mv protoc3/bin/* /usr/local/bin/
|
||||
sudo mv protoc3/include/* /usr/local/include/
|
||||
rm -rf $PROTOC_ZIP protoc3
|
||||
|
||||
# Install protoc-gen-go and protoc-gen-go-grpc
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@$PROTOC_GEN_VERSION
|
||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@$PROTOC_GRPC_VERSION
|
||||
|
||||
# Add protoc to the PATH
|
||||
export PATH=$PATH:/usr/local/bin/protoc
|
||||
|
||||
- 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
|
||||
mv $p $p.tmp
|
||||
done
|
||||
|
||||
for p in $(ls agent/*.pb.go); do
|
||||
mv $p $p.tmp
|
||||
done
|
||||
|
||||
# Generate Go files from protobuf definitions
|
||||
make protoc
|
||||
|
||||
# Compare generated Go files with the original ones
|
||||
for p in $(ls 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
|
||||
fi
|
||||
done
|
||||
|
||||
for p in $(ls agent/*.pb.go); do
|
||||
if ! cmp -s $p $p.tmp; then
|
||||
echo "Proto file and generated Go file $p are out of sync!"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
@@ -1,39 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.19.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Run go vet
|
||||
run: go vet ./...
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: latest
|
||||
args: --no-config --disable-all --enable gosimple --enable govet --enable unused --enable deadcode --timeout 3m
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
- name: Run tests
|
||||
run: go test -mod=vendor -v --race -covermode=atomic -coverprofile cover.out ./...
|
||||
@@ -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
|
||||
@@ -0,0 +1,34 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
make
|
||||
|
||||
- name: Run tests
|
||||
run: go test -v --race -covermode=atomic -coverprofile cover.out ./...
|
||||
@@ -1 +1,8 @@
|
||||
build
|
||||
|
||||
build
|
||||
cmd/manager/img
|
||||
cmd/manager/iso
|
||||
cmd/manager/tmp
|
||||
|
||||
.cov
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
run:
|
||||
timeout: 3m
|
||||
|
||||
issues:
|
||||
max-issues-per-linter: 10
|
||||
max-same-issues: 10
|
||||
|
||||
linters-settings:
|
||||
importas:
|
||||
no-unaliased: true
|
||||
no-extra-aliases: false
|
||||
alias:
|
||||
- pkg: github.com/absmach/magistrala/logger
|
||||
alias: mglog
|
||||
|
||||
gocritic:
|
||||
enabled-checks:
|
||||
- captLocal
|
||||
- dupImport
|
||||
- singleCaseSwitch
|
||||
- switchTrue
|
||||
- importShadow
|
||||
- httpNoBody
|
||||
- paramTypeCombine
|
||||
- emptyStringTest
|
||||
- builtinShadow
|
||||
- exposedSyncMutex
|
||||
disabled-checks:
|
||||
- appendAssign
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
disabled-tags:
|
||||
- performance
|
||||
- style
|
||||
- experimental
|
||||
- opinionated
|
||||
misspell:
|
||||
ignore-words:
|
||||
- "mosquitto"
|
||||
stylecheck:
|
||||
checks: ["-ST1000", "-ST1003", "-ST1020", "-ST1021", "-ST1022"]
|
||||
goheader:
|
||||
template: |-
|
||||
Copyright (c) Ultraviolet
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- importas
|
||||
- gocritic
|
||||
- gosimple
|
||||
- errcheck
|
||||
- govet
|
||||
- unused
|
||||
- goconst
|
||||
- godot
|
||||
- godox
|
||||
- ineffassign
|
||||
- misspell
|
||||
- stylecheck
|
||||
- whitespace
|
||||
- gci
|
||||
- gofmt
|
||||
- goimports
|
||||
- loggercheck
|
||||
- goheader
|
||||
- asasalint
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- contextcheck
|
||||
- decorder
|
||||
- dogsled
|
||||
- errchkjson
|
||||
- errname
|
||||
- execinquery
|
||||
- exportloopref
|
||||
- ginkgolinter
|
||||
- gocheckcompilerdirectives
|
||||
- gofumpt
|
||||
- goprintffuncname
|
||||
- importas
|
||||
- makezero
|
||||
- mirror
|
||||
- nakedret
|
||||
- dupword
|
||||
@@ -1,11 +1,11 @@
|
||||
# Contributing to Mainflux
|
||||
# Contributing to CoCos
|
||||
|
||||
The following is a set of guidelines to contribute to Mainflux and its libraries, which are
|
||||
hosted on the [Mainflux Organization](https://github.com/mainflux) on GitHub.
|
||||
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@mainflux.com](mailto:abuse@mainflux.com).
|
||||
[abuse@ultraviolet.rs](mailto:abuse@ultraviolet.rs).
|
||||
|
||||
## Reporting issues
|
||||
|
||||
@@ -13,7 +13,7 @@ Reporting issues are a great way to contribute to the project. We are perpetuall
|
||||
thorough bug report.
|
||||
|
||||
Before raising a new issue, check [our issue
|
||||
list](https://github.com/mainflux/mainflux/issues) to determine if it already contains the
|
||||
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
|
||||
@@ -41,23 +41,23 @@ To contribute to the project, [fork](https://help.github.com/articles/fork-a-rep
|
||||
clone your fork repository, and configure the remotes:
|
||||
|
||||
```
|
||||
git clone https://github.com/<your-username>/mainflux.git
|
||||
cd mainflux
|
||||
git remote add upstream https://github.com/mainflux/mainflux.git
|
||||
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 master
|
||||
git pull --rebase upstream main
|
||||
```
|
||||
|
||||
Create a new topic branch from `master` using the naming convention `MF-[issue-number]`
|
||||
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 MF-[issue-number]
|
||||
git checkout -b COCOS-[issue-number]
|
||||
```
|
||||
|
||||
Commit your changes in logical chunks. When you are ready to commit, make sure
|
||||
@@ -74,13 +74,13 @@ and `user.email` git configs, you can sign your commit automatically with `git c
|
||||
Locally merge (or rebase) the upstream development branch into your topic branch:
|
||||
|
||||
```
|
||||
git pull --rebase upstream master
|
||||
git pull --rebase upstream main
|
||||
```
|
||||
|
||||
Push your topic branch up to your fork:
|
||||
|
||||
```
|
||||
git push origin MF-[issue-number]
|
||||
git push origin COCOS-[issue-number]
|
||||
```
|
||||
|
||||
[Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title
|
||||
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,81 +1,35 @@
|
||||
COCOS_DOCKER_IMAGE_NAME_PREFIX ?= cocos
|
||||
BUILD_DIR = build
|
||||
SERVICES = computations datasets
|
||||
DOCKERS = $(addprefix docker_,$(SERVICES))
|
||||
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
|
||||
SERVICES = manager agent cli
|
||||
CGO_ENABLED ?= 0
|
||||
GOARCH ?= amd64
|
||||
VERSION ?= $(shell git describe --abbrev=0 --tags)
|
||||
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
|
||||
empty:=
|
||||
space:= $(empty) $(empty)
|
||||
|
||||
define compile_service
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
|
||||
go build -mod=vendor -ldflags "-s -w \
|
||||
-X 'github.com/ultravioletrs/cocos/internal/http.BuildTime=$(TIME)' \
|
||||
-X 'github.com/ultravioletrs/cocos/internal/http.Version=$(VERSION)' \
|
||||
-X 'github.com/ultravioletrs/cocos/internal/http.Commit=$(COMMIT)'" \
|
||||
go build -ldflags "-s -w \
|
||||
-X 'github.com/absmach/magistrala.BuildTime=$(TIME)' \
|
||||
-X 'github.com/absmach/magistrala.Version=$(VERSION)' \
|
||||
-X 'github.com/absmach/magistrala.Commit=$(COMMIT)'" \
|
||||
-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)
|
||||
|
||||
all: $(SERVICES)
|
||||
|
||||
.PHONY: all $(SERVICES) dockers dockers_dev latest release
|
||||
|
||||
clean:
|
||||
rm -rf ${BUILD_DIR}
|
||||
|
||||
cleandocker:
|
||||
# Stops containers and removes containers, networks, volumes, and images created by up
|
||||
docker-compose -f docker/docker-compose.yml down --rmi all -v --remove-orphans
|
||||
|
||||
ifdef pv
|
||||
# Remove unused volumes
|
||||
docker volume ls -f name=$(MF_DOCKER_IMAGE_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
|
||||
endif
|
||||
|
||||
install:
|
||||
cp ${BUILD_DIR}/* $(GOBIN)
|
||||
|
||||
test:
|
||||
go test -mod=vendor -v -race -count 1 -tags test $(shell go list ./... | grep -v 'vendor\|cmd')
|
||||
|
||||
$(SERVICES):
|
||||
$(call compile_service,$(@))
|
||||
|
||||
$(DOCKERS):
|
||||
$(call make_docker,$(@),$(GOARCH))
|
||||
|
||||
$(DOCKERS_DEV):
|
||||
$(call make_docker_dev,$(@))
|
||||
install-cli: cli
|
||||
cp ${CLI_BIN} ~/.local/bin/cocos-cli
|
||||
|
||||
dockers: $(DOCKERS)
|
||||
dockers_dev: $(DOCKERS_DEV)
|
||||
|
||||
run:
|
||||
docker-compose -f docker/docker-compose.yml up
|
||||
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=./pkg --go_opt=paths=source_relative --go-grpc_out=./pkg --go-grpc_opt=paths=source_relative manager/manager.proto
|
||||
|
||||
@@ -12,36 +12,6 @@ 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:
|
||||
|
||||
- [Docker](https://docs.docker.com/install/)
|
||||
- [Docker compose](https://docs.docker.com/compose/install/)
|
||||
|
||||
### 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 `cocos/computations` and `cocos/datasets`),
|
||||
composition can be run:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker/docker-compose.yml up
|
||||
```
|
||||
|
||||
This will bring up the Cocos docker services and interconnect them. This command can also be executed using the project's included Makefile:
|
||||
|
||||
```bash
|
||||
make run
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The quickest way to start using Cocos is via the CLI. The latest version can be downloaded from the [official releases page][rel].
|
||||
@@ -53,11 +23,11 @@ make cli
|
||||
./build/cocos-cli version
|
||||
```
|
||||
|
||||
Additional details on using the CLI can be found in the [CLI documentation](https://docs.mainflux.io/cli).
|
||||
Additional details on using the CLI can be found in the [CLI documentation](https://docs.cocos.ai/cli).
|
||||
|
||||
## 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/cocos/docs).
|
||||
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).
|
||||
|
||||
## License
|
||||
Cocos AI is a proprietary product created by Ultraviolet company.
|
||||
@@ -66,3 +36,4 @@ Cocos AI is a proprietary product created by Ultraviolet company.
|
||||
[cocos]: https://cocos.ai/
|
||||
[rel]: https://github.com/ultraviolet/cocos/releases
|
||||
[tee]: https://en.wikipedia.org/wiki/Trusted_execution_environment
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Agent
|
||||
|
||||
Agent service provides a barebones HTTP and gRPC API and Service interface implementation for the development of the agent service.
|
||||
|
||||
## 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 |
|
||||
| ----------------------------- | ------------------------------------------------------ | ------------------------------ |
|
||||
| AGENT_LOG_LEVEL | Log level for agent service (debug, info, warn, error) | info |
|
||||
| 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 | "" |
|
||||
| AGENT_GRPC_SERVER_CA_CERTS | Path to gRPC server CA certificate | "" |
|
||||
| AGENT_GRPC_CLIENT_CA_CERTS | Path to gRPC client CA certificate | "" |
|
||||
| COCOS_NOTIFICATION_SERVER_URL | Server to receive notification events from agent. | http:/localhost:9000 |
|
||||
|
||||
|
||||
## Deployment
|
||||
|
||||
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
|
||||
|
||||
cd $GOPATH/src/github.com/ultravioletrs/cocos
|
||||
|
||||
# compile the agent
|
||||
make agent
|
||||
|
||||
# set the environment variables and run the service
|
||||
./build/cocos-agent
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
For more information about service capabilities and its usage, please check out the [README documentation](../README.md).
|
||||
@@ -0,0 +1,624 @@
|
||||
// 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: agent/agent.proto
|
||||
|
||||
package agent
|
||||
|
||||
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 AlgoRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Algorithm []byte `protobuf:"bytes,1,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
|
||||
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AlgoRequest) Reset() {
|
||||
*x = AlgoRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AlgoRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AlgoRequest) ProtoMessage() {}
|
||||
|
||||
func (x *AlgoRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_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 AlgoRequest.ProtoReflect.Descriptor instead.
|
||||
func (*AlgoRequest) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *AlgoRequest) GetAlgorithm() []byte {
|
||||
if x != nil {
|
||||
return x.Algorithm
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *AlgoRequest) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AlgoRequest) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AlgoResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *AlgoResponse) Reset() {
|
||||
*x = AlgoResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AlgoResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AlgoResponse) ProtoMessage() {}
|
||||
|
||||
func (x *AlgoResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_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 AlgoResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AlgoResponse) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type DataRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Dataset []byte `protobuf:"bytes,1,opt,name=dataset,proto3" json:"dataset,omitempty"`
|
||||
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DataRequest) Reset() {
|
||||
*x = DataRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DataRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DataRequest) ProtoMessage() {}
|
||||
|
||||
func (x *DataRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_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 DataRequest.ProtoReflect.Descriptor instead.
|
||||
func (*DataRequest) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *DataRequest) GetDataset() []byte {
|
||||
if x != nil {
|
||||
return x.Dataset
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DataRequest) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DataRequest) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type DataResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *DataResponse) Reset() {
|
||||
*x = DataResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DataResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DataResponse) ProtoMessage() {}
|
||||
|
||||
func (x *DataResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_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 DataResponse.ProtoReflect.Descriptor instead.
|
||||
func (*DataResponse) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
type ResultRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Consumer string `protobuf:"bytes,1,opt,name=consumer,proto3" json:"consumer,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ResultRequest) Reset() {
|
||||
*x = ResultRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ResultRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ResultRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ResultRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_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 ResultRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ResultRequest) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ResultRequest) GetConsumer() string {
|
||||
if x != nil {
|
||||
return x.Consumer
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ResultResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
File []byte `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ResultResponse) Reset() {
|
||||
*x = ResultResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ResultResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ResultResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ResultResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_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 ResultResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ResultResponse) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *ResultResponse) GetFile() []byte {
|
||||
if x != nil {
|
||||
return x.File
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
func (x *AttestationRequest) Reset() {
|
||||
*x = AttestationRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AttestationRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AttestationRequest) ProtoMessage() {}
|
||||
|
||||
func (x *AttestationRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_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 AttestationRequest.ProtoReflect.Descriptor instead.
|
||||
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
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
File []byte `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AttestationResponse) Reset() {
|
||||
*x = AttestationResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_agent_agent_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AttestationResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AttestationResponse) ProtoMessage() {}
|
||||
|
||||
func (x *AttestationResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_agent_agent_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 AttestationResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AttestationResponse) Descriptor() ([]byte, []int) {
|
||||
return file_agent_agent_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *AttestationResponse) GetFile() []byte {
|
||||
if x != nil {
|
||||
return x.File
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_agent_agent_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_agent_agent_proto_rawDesc = []byte{
|
||||
0x0a, 0x11, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x12, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x22, 0x57, 0x0a, 0x0b, 0x41, 0x6c,
|
||||
0x67, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67,
|
||||
0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, 0x6c,
|
||||
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, 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, 0x35, 0x0a, 0x12, 0x41,
|
||||
0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
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 (
|
||||
file_agent_agent_proto_rawDescOnce sync.Once
|
||||
file_agent_agent_proto_rawDescData = file_agent_agent_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_agent_agent_proto_rawDescGZIP() []byte {
|
||||
file_agent_agent_proto_rawDescOnce.Do(func() {
|
||||
file_agent_agent_proto_rawDescData = protoimpl.X.CompressGZIP(file_agent_agent_proto_rawDescData)
|
||||
})
|
||||
return file_agent_agent_proto_rawDescData
|
||||
}
|
||||
|
||||
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
|
||||
(*DataRequest)(nil), // 2: agent.DataRequest
|
||||
(*DataResponse)(nil), // 3: agent.DataResponse
|
||||
(*ResultRequest)(nil), // 4: agent.ResultRequest
|
||||
(*ResultResponse)(nil), // 5: agent.ResultResponse
|
||||
(*AttestationRequest)(nil), // 6: agent.AttestationRequest
|
||||
(*AttestationResponse)(nil), // 7: agent.AttestationResponse
|
||||
}
|
||||
var file_agent_agent_proto_depIdxs = []int32{
|
||||
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() }
|
||||
func file_agent_agent_proto_init() {
|
||||
if File_agent_agent_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_agent_agent_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AlgoRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AlgoResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DataRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DataResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ResultRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ResultResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AttestationRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_agent_agent_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AttestationResponse); 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_agent_agent_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 8,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_agent_agent_proto_goTypes,
|
||||
DependencyIndexes: file_agent_agent_proto_depIdxs,
|
||||
MessageInfos: file_agent_agent_proto_msgTypes,
|
||||
}.Build()
|
||||
File_agent_agent_proto = out.File
|
||||
file_agent_agent_proto_rawDesc = nil
|
||||
file_agent_agent_proto_goTypes = nil
|
||||
file_agent_agent_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package agent;
|
||||
|
||||
option go_package = "./agent";
|
||||
|
||||
service AgentService {
|
||||
rpc Algo(AlgoRequest) returns (AlgoResponse) {}
|
||||
rpc Data(DataRequest) returns (DataResponse) {}
|
||||
rpc Result(ResultRequest) returns (ResultResponse) {}
|
||||
rpc Attestation(AttestationRequest) returns (AttestationResponse) {}
|
||||
}
|
||||
|
||||
message AlgoRequest {
|
||||
bytes algorithm = 1;
|
||||
string provider = 2;
|
||||
string id = 3;
|
||||
}
|
||||
|
||||
message AlgoResponse {}
|
||||
|
||||
message DataRequest {
|
||||
bytes dataset = 1;
|
||||
string provider = 2;
|
||||
string id = 3;
|
||||
}
|
||||
|
||||
message DataResponse {}
|
||||
|
||||
message ResultRequest {
|
||||
string consumer = 1;
|
||||
}
|
||||
|
||||
message ResultResponse {
|
||||
bytes file = 1;
|
||||
}
|
||||
|
||||
message AttestationRequest {
|
||||
bytes report_data = 1;
|
||||
}
|
||||
|
||||
message AttestationResponse {
|
||||
bytes file = 1;
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v4.25.1
|
||||
// source: agent/agent.proto
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
AgentService_Algo_FullMethodName = "/agent.AgentService/Algo"
|
||||
AgentService_Data_FullMethodName = "/agent.AgentService/Data"
|
||||
AgentService_Result_FullMethodName = "/agent.AgentService/Result"
|
||||
AgentService_Attestation_FullMethodName = "/agent.AgentService/Attestation"
|
||||
)
|
||||
|
||||
// AgentServiceClient is the client API for AgentService 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 AgentServiceClient interface {
|
||||
Algo(ctx context.Context, in *AlgoRequest, opts ...grpc.CallOption) (*AlgoResponse, error)
|
||||
Data(ctx context.Context, in *DataRequest, opts ...grpc.CallOption) (*DataResponse, error)
|
||||
Result(ctx context.Context, in *ResultRequest, opts ...grpc.CallOption) (*ResultResponse, error)
|
||||
Attestation(ctx context.Context, in *AttestationRequest, opts ...grpc.CallOption) (*AttestationResponse, error)
|
||||
}
|
||||
|
||||
type agentServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewAgentServiceClient(cc grpc.ClientConnInterface) AgentServiceClient {
|
||||
return &agentServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) Algo(ctx context.Context, in *AlgoRequest, opts ...grpc.CallOption) (*AlgoResponse, error) {
|
||||
out := new(AlgoResponse)
|
||||
err := c.cc.Invoke(ctx, AgentService_Algo_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) Data(ctx context.Context, in *DataRequest, opts ...grpc.CallOption) (*DataResponse, error) {
|
||||
out := new(DataResponse)
|
||||
err := c.cc.Invoke(ctx, AgentService_Data_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) Result(ctx context.Context, in *ResultRequest, opts ...grpc.CallOption) (*ResultResponse, error) {
|
||||
out := new(ResultResponse)
|
||||
err := c.cc.Invoke(ctx, AgentService_Result_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) Attestation(ctx context.Context, in *AttestationRequest, opts ...grpc.CallOption) (*AttestationResponse, error) {
|
||||
out := new(AttestationResponse)
|
||||
err := c.cc.Invoke(ctx, AgentService_Attestation_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AgentServiceServer is the server API for AgentService service.
|
||||
// All implementations must embed UnimplementedAgentServiceServer
|
||||
// for forward compatibility
|
||||
type AgentServiceServer interface {
|
||||
Algo(context.Context, *AlgoRequest) (*AlgoResponse, error)
|
||||
Data(context.Context, *DataRequest) (*DataResponse, error)
|
||||
Result(context.Context, *ResultRequest) (*ResultResponse, error)
|
||||
Attestation(context.Context, *AttestationRequest) (*AttestationResponse, error)
|
||||
mustEmbedUnimplementedAgentServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedAgentServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedAgentServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedAgentServiceServer) Algo(context.Context, *AlgoRequest) (*AlgoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Algo not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) Data(context.Context, *DataRequest) (*DataResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Data not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) Result(context.Context, *ResultRequest) (*ResultResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Result not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) Attestation(context.Context, *AttestationRequest) (*AttestationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Attestation not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) mustEmbedUnimplementedAgentServiceServer() {}
|
||||
|
||||
// UnsafeAgentServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to AgentServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeAgentServiceServer interface {
|
||||
mustEmbedUnimplementedAgentServiceServer()
|
||||
}
|
||||
|
||||
func RegisterAgentServiceServer(s grpc.ServiceRegistrar, srv AgentServiceServer) {
|
||||
s.RegisterService(&AgentService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _AgentService_Algo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AlgoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AgentServiceServer).Algo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AgentService_Algo_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AgentServiceServer).Algo(ctx, req.(*AlgoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AgentService_Data_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DataRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AgentServiceServer).Data(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AgentService_Data_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AgentServiceServer).Data(ctx, req.(*DataRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AgentService_Result_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ResultRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AgentServiceServer).Result(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AgentService_Result_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AgentServiceServer).Result(ctx, req.(*ResultRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AgentService_Attestation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AttestationRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AgentServiceServer).Attestation(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AgentService_Attestation_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AgentServiceServer).Attestation(ctx, req.(*AttestationRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// AgentService_ServiceDesc is the grpc.ServiceDesc for AgentService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var AgentService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "agent.AgentService",
|
||||
HandlerType: (*AgentServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Algo",
|
||||
Handler: _AgentService_Algo_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Data",
|
||||
Handler: _AgentService_Data_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Result",
|
||||
Handler: _AgentService_Result_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Attestation",
|
||||
Handler: _AgentService_Attestation_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "agent/agent.proto",
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package api contains API-related concerns: endpoint definitions, middlewares
|
||||
// and all resource representations.
|
||||
package api
|
||||
@@ -0,0 +1,218 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const svcName = "agent.AgentService"
|
||||
|
||||
type grpcClient struct {
|
||||
algo endpoint.Endpoint
|
||||
data endpoint.Endpoint
|
||||
result endpoint.Endpoint
|
||||
attestation endpoint.Endpoint
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// NewClient returns new gRPC client instance.
|
||||
func NewClient(conn *grpc.ClientConn, timeout time.Duration) agent.AgentServiceClient {
|
||||
return &grpcClient{
|
||||
algo: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Algo",
|
||||
encodeAlgoRequest,
|
||||
decodeAlgoResponse,
|
||||
agent.AlgoResponse{},
|
||||
).Endpoint(),
|
||||
data: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Data",
|
||||
encodeDataRequest,
|
||||
decodeDataResponse,
|
||||
agent.DataResponse{},
|
||||
).Endpoint(),
|
||||
result: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Result",
|
||||
encodeResultRequest,
|
||||
decodeResultResponse,
|
||||
agent.ResultResponse{},
|
||||
).Endpoint(),
|
||||
attestation: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Attestation",
|
||||
encodeAttestationRequest,
|
||||
decodeAttestationResponse,
|
||||
agent.AttestationResponse{},
|
||||
).Endpoint(),
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// encodeAlgoRequest is a transport/grpc.EncodeRequestFunc that
|
||||
// converts a user-domain algoReq to a gRPC request.
|
||||
func encodeAlgoRequest(_ context.Context, request interface{}) (interface{}, error) {
|
||||
req, ok := request.(*algoReq)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid request type: %T", request)
|
||||
}
|
||||
|
||||
return &agent.AlgoRequest{
|
||||
Algorithm: req.Algorithm,
|
||||
Provider: req.Provider,
|
||||
Id: req.Id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// decodeAlgoResponse is a transport/grpc.DecodeResponseFunc that
|
||||
// converts a gRPC AlgoResponse to a user-domain response.
|
||||
func decodeAlgoResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
|
||||
_, ok := grpcResponse.(*agent.AlgoResponse)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
|
||||
}
|
||||
|
||||
return algoRes{}, nil
|
||||
}
|
||||
|
||||
// encodeDataRequest is a transport/grpc.EncodeRequestFunc that
|
||||
// converts a user-domain dataReq to a gRPC request.
|
||||
func encodeDataRequest(_ context.Context, request interface{}) (interface{}, error) {
|
||||
req, ok := request.(*dataReq)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid request type: %T", request)
|
||||
}
|
||||
|
||||
return &agent.DataRequest{
|
||||
Dataset: req.Dataset,
|
||||
Provider: req.Provider,
|
||||
Id: req.Id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// decodeDataResponse is a transport/grpc.DecodeResponseFunc that
|
||||
// converts a gRPC DataResponse to a user-domain response.
|
||||
func decodeDataResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
|
||||
_, ok := grpcResponse.(*agent.DataResponse)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
|
||||
}
|
||||
|
||||
return dataRes{}, nil
|
||||
}
|
||||
|
||||
// encodeResultRequest is a transport/grpc.EncodeRequestFunc that
|
||||
// converts a user-domain resultReq to a gRPC request.
|
||||
func encodeResultRequest(_ context.Context, request interface{}) (interface{}, error) {
|
||||
req, ok := request.(*resultReq)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid request type: %T", request)
|
||||
}
|
||||
|
||||
return &agent.ResultRequest{
|
||||
Consumer: req.Consumer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// decodeResultResponse is a transport/grpc.DecodeResponseFunc that
|
||||
// converts a gRPC ResultResponse to a user-domain response.
|
||||
func decodeResultResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
|
||||
response, ok := grpcResponse.(*agent.ResultResponse)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
|
||||
}
|
||||
|
||||
return resultRes{
|
||||
File: response.File,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// encodeAttestationRequest is a transport/grpc.EncodeRequestFunc that
|
||||
// converts a user-domain attestationReq to a gRPC request.
|
||||
func encodeAttestationRequest(_ context.Context, request interface{}) (interface{}, error) {
|
||||
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
|
||||
// converts a gRPC AttestationResponse to a user-domain response.
|
||||
func decodeAttestationResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
|
||||
response, ok := grpcResponse.(*agent.AttestationResponse)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
|
||||
}
|
||||
|
||||
return attestationRes{
|
||||
File: response.File,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Algo implements the Algo method of the agent.AgentServiceClient interface.
|
||||
func (c grpcClient) Algo(ctx context.Context, request *agent.AlgoRequest, _ ...grpc.CallOption) (*agent.AlgoResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
|
||||
_, err := c.algo(ctx, &algoReq{Algorithm: request.Algorithm, Provider: request.Provider, Id: request.Id})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &agent.AlgoResponse{}, nil
|
||||
}
|
||||
|
||||
// Data implements the Data method of the agent.AgentServiceClient interface.
|
||||
func (c grpcClient) Data(ctx context.Context, request *agent.DataRequest, _ ...grpc.CallOption) (*agent.DataResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
|
||||
_, err := c.data(ctx, &dataReq{Dataset: request.Dataset, Provider: request.Provider, Id: request.Id})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &agent.DataResponse{}, nil
|
||||
}
|
||||
|
||||
// Result implements the Result method of the agent.AgentServiceClient interface.
|
||||
func (c grpcClient) Result(ctx context.Context, request *agent.ResultRequest, _ ...grpc.CallOption) (*agent.ResultResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := c.result(ctx, &resultReq{Consumer: request.Consumer})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultRes := res.(resultRes)
|
||||
return &agent.ResultResponse{File: resultRes.File}, nil
|
||||
}
|
||||
|
||||
// Result implements the Result method of the agent.AgentServiceClient interface.
|
||||
func (c grpcClient) Attestation(ctx context.Context, request *agent.AttestationRequest, _ ...grpc.CallOption) (*agent.AttestationResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := c.attestation(ctx, &attestationReq{ReportData: request.ReportData})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attestationRes := res.(attestationRes)
|
||||
return &agent.AttestationResponse{File: attestationRes.File}, nil
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package grpc contains implementation of kit service gRPC API.
|
||||
package grpc
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
func algoEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(algoReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return algoRes{}, err
|
||||
}
|
||||
|
||||
algo := agent.Algorithm{Algorithm: req.Algorithm, Provider: req.Provider, ID: req.Id}
|
||||
|
||||
err := svc.Algo(ctx, algo)
|
||||
if err != nil {
|
||||
return algoRes{}, err
|
||||
}
|
||||
|
||||
return algoRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func dataEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(dataReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return dataRes{}, err
|
||||
}
|
||||
|
||||
dataset := agent.Dataset{Dataset: req.Dataset, Provider: req.Provider, ID: req.Id}
|
||||
|
||||
err := svc.Data(ctx, dataset)
|
||||
if err != nil {
|
||||
return dataRes{}, err
|
||||
}
|
||||
|
||||
return dataRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func resultEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(resultReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return resultRes{}, err
|
||||
}
|
||||
file, err := svc.Result(ctx, req.Consumer)
|
||||
if err != nil {
|
||||
return resultRes{}, err
|
||||
}
|
||||
|
||||
return resultRes{File: file}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func attestationEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(attestationReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return attestationRes{}, err
|
||||
}
|
||||
file, err := svc.Attestation(ctx, req.ReportData)
|
||||
if err != nil {
|
||||
return attestationRes{}, err
|
||||
}
|
||||
|
||||
return attestationRes{File: file}, nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type algoReq struct {
|
||||
Algorithm []byte `protobuf:"bytes,1,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
|
||||
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (req algoReq) validate() error {
|
||||
if len(req.Algorithm) == 0 {
|
||||
return errors.New("algorithm binary is required")
|
||||
}
|
||||
if req.Id == "" {
|
||||
return errors.New("malformed entity")
|
||||
}
|
||||
if req.Provider == "" {
|
||||
return errors.New("malformed entity")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type dataReq struct {
|
||||
Dataset []byte `protobuf:"bytes,1,opt,name=dataset,proto3" json:"dataset,omitempty"`
|
||||
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (req dataReq) validate() error {
|
||||
if len(req.Dataset) == 0 {
|
||||
return errors.New("dataset CSV file is required")
|
||||
}
|
||||
if req.Id == "" {
|
||||
return errors.New("malformed entity")
|
||||
}
|
||||
if req.Provider == "" {
|
||||
return errors.New("malformed entity")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type resultReq struct {
|
||||
Consumer string `protobuf:"bytes,1,opt,name=consumer,proto3" json:"consumer,omitempty"`
|
||||
}
|
||||
|
||||
func (req resultReq) validate() error {
|
||||
// No request parameters to validate, so no validation logic needed
|
||||
return nil
|
||||
}
|
||||
|
||||
type attestationReq struct {
|
||||
ReportData []byte
|
||||
}
|
||||
|
||||
func (req attestationReq) validate() error {
|
||||
if req.ReportData == nil {
|
||||
return errors.New("malformed entity")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
type algoRes struct{}
|
||||
|
||||
type dataRes struct{}
|
||||
|
||||
type resultRes struct {
|
||||
File []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type attestationRes struct {
|
||||
File []byte
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kit/kit/transport/grpc"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
type grpcServer struct {
|
||||
algo grpc.Handler
|
||||
data grpc.Handler
|
||||
result grpc.Handler
|
||||
attestation grpc.Handler
|
||||
agent.UnimplementedAgentServiceServer
|
||||
}
|
||||
|
||||
// NewServer returns new AgentServiceServer instance.
|
||||
func NewServer(svc agent.Service) agent.AgentServiceServer {
|
||||
return &grpcServer{
|
||||
algo: grpc.NewServer(
|
||||
algoEndpoint(svc),
|
||||
decodeAlgoRequest,
|
||||
encodeAlgoResponse,
|
||||
),
|
||||
data: grpc.NewServer(
|
||||
dataEndpoint(svc),
|
||||
decodeDataRequest,
|
||||
encodeDataResponse,
|
||||
),
|
||||
result: grpc.NewServer(
|
||||
resultEndpoint(svc),
|
||||
decodeResultRequest,
|
||||
encodeResultResponse,
|
||||
),
|
||||
attestation: grpc.NewServer(
|
||||
attestationEndpoint(svc),
|
||||
decodeAttestationRequest,
|
||||
encodeAttestationResponse,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func decodeAlgoRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*agent.AlgoRequest)
|
||||
|
||||
return algoReq{
|
||||
Algorithm: req.Algorithm,
|
||||
Provider: req.Provider,
|
||||
Id: req.Id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeAlgoResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
return &agent.AlgoResponse{}, nil
|
||||
}
|
||||
|
||||
func decodeDataRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*agent.DataRequest)
|
||||
|
||||
return dataReq{
|
||||
Dataset: req.Dataset,
|
||||
Provider: req.Provider,
|
||||
Id: req.Id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeDataResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
return &agent.DataResponse{}, nil
|
||||
}
|
||||
|
||||
func decodeResultRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*agent.ResultRequest)
|
||||
return resultReq{Consumer: req.Consumer}, nil
|
||||
}
|
||||
|
||||
func encodeResultResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
res := response.(resultRes)
|
||||
return &agent.ResultResponse{
|
||||
File: res.File,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeAttestationRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*agent.AttestationRequest)
|
||||
return attestationReq{ReportData: req.ReportData}, nil
|
||||
}
|
||||
|
||||
func encodeAttestationResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
res := response.(attestationRes)
|
||||
return &agent.AttestationResponse{
|
||||
File: res.File,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) Algo(ctx context.Context, req *agent.AlgoRequest) (*agent.AlgoResponse, error) {
|
||||
_, res, err := s.algo.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ar := res.(*agent.AlgoResponse)
|
||||
return ar, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) Data(ctx context.Context, req *agent.DataRequest) (*agent.DataResponse, error) {
|
||||
_, res, err := s.data.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dr := res.(*agent.DataResponse)
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) Result(ctx context.Context, req *agent.ResultRequest) (*agent.ResultResponse, error) {
|
||||
_, res, err := s.result.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rr := res.(*agent.ResultResponse)
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) Attestation(ctx context.Context, req *agent.AttestationRequest) (*agent.AttestationResponse, error) {
|
||||
_, res, err := s.attestation.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rr := res.(*agent.AttestationResponse)
|
||||
return rr, nil
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
var _ agent.Service = (*loggingMiddleware)(nil)
|
||||
|
||||
type loggingMiddleware struct {
|
||||
logger *slog.Logger
|
||||
svc agent.Service
|
||||
}
|
||||
|
||||
// LoggingMiddleware adds logging facilities to the core service.
|
||||
func LoggingMiddleware(svc agent.Service, logger *slog.Logger) agent.Service {
|
||||
return &loggingMiddleware{logger, svc}
|
||||
}
|
||||
|
||||
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 {
|
||||
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.Algo(ctx, algorithm)
|
||||
}
|
||||
|
||||
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 {
|
||||
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.Data(ctx, dataset)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Result(ctx context.Context, consumer string) (response []byte, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method Result took %s to complete", 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.Result(ctx, consumer)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Attestation(ctx context.Context, reportData []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 {
|
||||
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.Attestation(ctx, reportData)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !test
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
var _ agent.Service = (*metricsMiddleware)(nil)
|
||||
|
||||
type metricsMiddleware struct {
|
||||
counter metrics.Counter
|
||||
latency metrics.Histogram
|
||||
svc agent.Service
|
||||
}
|
||||
|
||||
// MetricsMiddleware instruments core service by tracking request count and
|
||||
// latency.
|
||||
func MetricsMiddleware(svc agent.Service, counter metrics.Counter, latency metrics.Histogram) agent.Service {
|
||||
return &metricsMiddleware{
|
||||
counter: counter,
|
||||
latency: latency,
|
||||
svc: svc,
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Algo(ctx, algorithm)
|
||||
}
|
||||
|
||||
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())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Data(ctx, dataset)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Result(ctx context.Context, consumer string) ([]byte, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "result").Add(1)
|
||||
ms.latency.With("method", "result").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Result(ctx, consumer)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Attestation(ctx context.Context, reportData []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, reportData)
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package agent
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
_ fmt.Stringer = (*Datasets)(nil)
|
||||
_ fmt.Stringer = (*Algorithms)(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"`
|
||||
}
|
||||
|
||||
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:"-"`
|
||||
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:"-"`
|
||||
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++ {
|
||||
s := rangeOnMe.Index(i)
|
||||
f := s.FieldByName("ID")
|
||||
if f.IsValid() {
|
||||
if f.Interface() == id {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package agent
|
||||
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha512"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"slices"
|
||||
|
||||
"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)
|
||||
|
||||
var (
|
||||
// ErrMalformedEntity indicates malformed entity specification (e.g.
|
||||
// invalid username or password).
|
||||
ErrMalformedEntity = errors.New("malformed entity specification")
|
||||
// ErrUnauthorizedAccess indicates missing or invalid credentials provided
|
||||
// when accessing a protected resource.
|
||||
ErrUnauthorizedAccess = errors.New("missing or invalid credentials provided")
|
||||
// errUndeclaredAlgorithm indicates algorithm was not declared in computation manifest.
|
||||
errUndeclaredAlgorithm = errors.New("algorithm not declared in computation manifest")
|
||||
// errUndeclaredAlgorithm indicates algorithm was not declared in computation manifest.
|
||||
errUndeclaredDataset = errors.New("dataset not declared in computation manifest")
|
||||
// errProviderMissmatch algorithm/dataset provider does not match computation manifest.
|
||||
errProviderMissmatch = errors.New("provider does not match declaration on manifest")
|
||||
// errAllManifestItemsReceived indicates no new computation manifest items expected.
|
||||
errAllManifestItemsReceived = errors.New("all expected manifest Items have been received")
|
||||
// errUndeclaredConsumer indicates the consumer requesting results in not declared in computation manifest.
|
||||
errUndeclaredConsumer = errors.New("result consumer is undeclared in computation manifest")
|
||||
// errResultsNotReady indicates the computation results are not ready.
|
||||
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 {
|
||||
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, reportData []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type agentService struct {
|
||||
computation Computation // Holds the current computation request details.
|
||||
algorithms [][]byte // Stores the algorithms 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"
|
||||
)
|
||||
|
||||
var _ Service = (*agentService)(nil)
|
||||
|
||||
// New instantiates the agent service implementation.
|
||||
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[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(manifestsReceived)
|
||||
return svc
|
||||
}
|
||||
|
||||
func (as *agentService) Algo(ctx context.Context, algorithm Algorithm) error {
|
||||
if as.sm.GetState() != receivingAlgorithms {
|
||||
return errStateNotReady
|
||||
}
|
||||
if len(as.computation.Algorithms) == 0 {
|
||||
return errAllManifestItemsReceived
|
||||
}
|
||||
|
||||
hash := sha3.Sum256(algorithm.Algorithm)
|
||||
|
||||
index := containsID(as.computation.Algorithms, algorithm.ID)
|
||||
switch index {
|
||||
case -1:
|
||||
return errUndeclaredAlgorithm
|
||||
default:
|
||||
if as.computation.Algorithms[index].Provider != algorithm.Provider {
|
||||
return errProviderMissmatch
|
||||
}
|
||||
if hash != as.computation.Algorithms[index].Hash {
|
||||
return errHashMismatch
|
||||
}
|
||||
as.computation.Algorithms = slices.Delete(as.computation.Algorithms, index, index+1)
|
||||
}
|
||||
|
||||
as.algorithms = append(as.algorithms, algorithm.Algorithm)
|
||||
|
||||
if len(as.computation.Algorithms) == 0 {
|
||||
as.sm.SendEvent(algorithmsReceived)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (as *agentService) Data(ctx context.Context, dataset Dataset) error {
|
||||
if as.sm.GetState() != receivingData {
|
||||
return errStateNotReady
|
||||
}
|
||||
if len(as.computation.Datasets) == 0 {
|
||||
return errAllManifestItemsReceived
|
||||
}
|
||||
|
||||
hash := sha3.Sum256(dataset.Dataset)
|
||||
|
||||
index := containsID(as.computation.Datasets, dataset.ID)
|
||||
switch index {
|
||||
case -1:
|
||||
return errUndeclaredDataset
|
||||
default:
|
||||
if as.computation.Datasets[index].Provider != dataset.Provider {
|
||||
return errProviderMissmatch
|
||||
}
|
||||
if hash != as.computation.Datasets[index].Hash {
|
||||
return errHashMismatch
|
||||
}
|
||||
as.computation.Datasets = slices.Delete(as.computation.Datasets, index, index+1)
|
||||
}
|
||||
|
||||
as.datasets = append(as.datasets, dataset.Dataset)
|
||||
|
||||
if len(as.computation.Datasets) == 0 {
|
||||
as.sm.SendEvent(dataReceived)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (as *agentService) Result(ctx context.Context, consumer string) ([]byte, error) {
|
||||
if as.sm.GetState() != resultsReady {
|
||||
return []byte{}, errResultsNotReady
|
||||
}
|
||||
if len(as.computation.ResultConsumers) == 0 {
|
||||
return []byte{}, errAllManifestItemsReceived
|
||||
}
|
||||
index := slices.Index(as.computation.ResultConsumers, consumer)
|
||||
switch index {
|
||||
case -1:
|
||||
return []byte{}, errUndeclaredConsumer
|
||||
default:
|
||||
as.computation.ResultConsumers = slices.Delete(as.computation.ResultConsumers, index, index+1)
|
||||
}
|
||||
|
||||
if len(as.computation.ResultConsumers) == 0 {
|
||||
as.sm.SendEvent(resultsConsumed)
|
||||
}
|
||||
// Return the result file or an error
|
||||
return as.result, as.runError
|
||||
}
|
||||
|
||||
func (as *agentService) Attestation(ctx context.Context, reportData []byte) ([]byte, error) {
|
||||
provider, err := client.GetQuoteProvider()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
rawQuote, err := provider.GetRawQuote(sha512.Sum512(reportData))
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return rawQuote, nil
|
||||
}
|
||||
|
||||
func (as *agentService) runComputation() {
|
||||
as.publishEvent("starting", json.RawMessage{})()
|
||||
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])
|
||||
if err != nil {
|
||||
as.runError = err
|
||||
as.publishEvent("failed", json.RawMessage{})()
|
||||
return
|
||||
}
|
||||
as.publishEvent("complete", json.RawMessage{})()
|
||||
as.result = result
|
||||
}
|
||||
|
||||
func (as *agentService) publishEvent(status string, details json.RawMessage) func() {
|
||||
return func() {
|
||||
if err := as.eventSvc.SendEvent(as.sm.State.String(), status, details); err != nil {
|
||||
as.sm.logger.Warn(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func run(algoContent, dataContent []byte) ([]byte, error) {
|
||||
listener, err := socket.StartUnixSocketServer(socketPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating stdout pipe: %v", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
// Create channels for received data and errors
|
||||
dataChannel := make(chan []byte)
|
||||
errorChannel := make(chan error)
|
||||
|
||||
var result []byte
|
||||
|
||||
go socket.AcceptConnection(listener, dataChannel, errorChannel)
|
||||
|
||||
// Construct the Python script content with CSV data as a command-line argument
|
||||
script := string(algoContent)
|
||||
data := string(dataContent)
|
||||
cmd := exec.Command(pyRuntime, "-c", script, data, socketPath)
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("error starting Python script: %v", err)
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return nil, fmt.Errorf("python script execution error: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case result = <-dataChannel:
|
||||
return result, nil
|
||||
case err = <-errorChannel:
|
||||
return nil, fmt.Errorf("error receiving data: %v", err)
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=state
|
||||
type state int
|
||||
|
||||
const (
|
||||
idle state = iota
|
||||
receivingManifests
|
||||
receivingAlgorithms
|
||||
receivingData
|
||||
running
|
||||
resultsReady
|
||||
complete
|
||||
)
|
||||
|
||||
type event int
|
||||
|
||||
const (
|
||||
start event = iota
|
||||
manifestsReceived
|
||||
algorithmsReceived
|
||||
dataReceived
|
||||
runComplete
|
||||
resultsConsumed
|
||||
)
|
||||
|
||||
// StateMachine represents the state machine.
|
||||
type StateMachine struct {
|
||||
mu sync.Mutex
|
||||
State state
|
||||
EventChan chan event
|
||||
Transitions map[state]map[event]state
|
||||
StateFunctions map[state]func()
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// NewStateMachine creates a new 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,
|
||||
}
|
||||
|
||||
sm.Transitions[idle] = make(map[event]state)
|
||||
sm.Transitions[idle][start] = receivingManifests
|
||||
|
||||
sm.Transitions[receivingManifests] = make(map[event]state)
|
||||
sm.Transitions[receivingManifests][manifestsReceived] = receivingAlgorithms
|
||||
|
||||
sm.Transitions[receivingAlgorithms] = make(map[event]state)
|
||||
sm.Transitions[receivingAlgorithms][algorithmsReceived] = receivingData
|
||||
|
||||
sm.Transitions[receivingData] = make(map[event]state)
|
||||
sm.Transitions[receivingData][dataReceived] = running
|
||||
|
||||
sm.Transitions[running] = make(map[event]state)
|
||||
sm.Transitions[running][runComplete] = resultsReady
|
||||
|
||||
sm.Transitions[resultsReady] = make(map[event]state)
|
||||
sm.Transitions[resultsReady][resultsConsumed] = complete
|
||||
|
||||
return sm
|
||||
}
|
||||
|
||||
// Start the state machine.
|
||||
func (sm *StateMachine) Start(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case event := <-sm.EventChan:
|
||||
nextState, valid := sm.Transitions[sm.GetState()][event]
|
||||
if valid {
|
||||
sm.mu.Lock()
|
||||
sm.State = nextState
|
||||
sm.mu.Unlock()
|
||||
sm.logger.Debug(fmt.Sprintf("Transition: %v -> %v\n", sm.GetState(), nextState))
|
||||
} else {
|
||||
sm.logger.Error(fmt.Sprintf("Invalid transition: %v -> ???\n", sm.GetState()))
|
||||
}
|
||||
stateFunc, exists := sm.StateFunctions[sm.GetState()]
|
||||
if exists {
|
||||
go stateFunc()
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SendEvent sends an event to the state machine.
|
||||
func (sm *StateMachine) SendEvent(event event) {
|
||||
sm.EventChan <- event
|
||||
}
|
||||
|
||||
func (sm *StateMachine) GetState() state {
|
||||
sm.mu.Lock()
|
||||
state := sm.State
|
||||
sm.mu.Unlock()
|
||||
return state
|
||||
}
|
||||
|
||||
func (sm *StateMachine) SetState(state state) {
|
||||
sm.mu.Lock()
|
||||
sm.State = state
|
||||
sm.mu.Unlock()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Code generated by "stringer -type=state"; DO NOT EDIT.
|
||||
|
||||
package agent
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[idle-0]
|
||||
_ = x[receivingManifests-1]
|
||||
_ = x[receivingAlgorithms-2]
|
||||
_ = x[receivingData-3]
|
||||
_ = x[running-4]
|
||||
_ = x[resultsReady-5]
|
||||
_ = x[complete-6]
|
||||
}
|
||||
|
||||
const _state_name = "idlereceivingManifestsreceivingAlgorithmsreceivingDatarunningresultsReadycomplete"
|
||||
|
||||
var _state_index = [...]uint8{0, 4, 22, 41, 54, 61, 73, 81}
|
||||
|
||||
func (i state) String() string {
|
||||
if i < 0 || i >= state(len(_state_index)-1) {
|
||||
return "state(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _state_name[_state_index[i]:_state_index[i+1]]
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
)
|
||||
|
||||
func TestStateMachineTransitions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
fromState state
|
||||
event event
|
||||
expected state
|
||||
}{
|
||||
{idle, start, receivingManifests},
|
||||
{receivingManifests, manifestsReceived, receivingAlgorithms},
|
||||
{receivingAlgorithms, algorithmsReceived, receivingData},
|
||||
{receivingData, dataReceived, running},
|
||||
{running, runComplete, resultsReady},
|
||||
{resultsReady, resultsConsumed, complete},
|
||||
}
|
||||
|
||||
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.SetState(testCase.fromState)
|
||||
|
||||
sm.SendEvent(testCase.event)
|
||||
|
||||
if sm.GetState() != testCase.expected {
|
||||
t.Errorf("Expected state %v after the event, but got %v", testCase.expected, sm.GetState())
|
||||
}
|
||||
close(sm.EventChan)
|
||||
cancel()
|
||||
<-done
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateMachineInvalidTransition(t *testing.T) {
|
||||
sm := NewStateMachine(mglog.NewMock())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go sm.Start(ctx)
|
||||
|
||||
sm.SetState(idle)
|
||||
|
||||
sm.SendEvent(dataReceived)
|
||||
|
||||
if sm.State != idle {
|
||||
t.Errorf("State should not change on an invalid event, but got %v", sm.State)
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
@@ -1,471 +0,0 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Computations service
|
||||
description: HTTP API for managing computations
|
||||
version: "1.0.0"
|
||||
|
||||
paths:
|
||||
/computations:
|
||||
post:
|
||||
summary: Add new computation
|
||||
description: |
|
||||
Adds new computation to the list of computations owned by user identified using
|
||||
the provided access token.
|
||||
tags:
|
||||
- computations
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ComputationCreateReq"
|
||||
responses:
|
||||
'201':
|
||||
$ref: "#/components/responses/ComputationRes"
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'409':
|
||||
description: Entity already exist.
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'422':
|
||||
description: Database can't process request.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
get:
|
||||
summary: Retrieves computations
|
||||
description: |
|
||||
Retrieves a list of computations. Due to performance concerns, data
|
||||
is retrieved in subsets. The API user must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
tags:
|
||||
- computations
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
- $ref: "#/components/parameters/Name"
|
||||
- $ref: "#/components/parameters/Order"
|
||||
- $ref: "#/components/parameters/Direction"
|
||||
- $ref: "#/components/parameters/Metadata"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/ComputationsPageRes"
|
||||
'400':
|
||||
description: Failed due to malformed query parameters.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: A non-existent entity request.
|
||||
'422':
|
||||
description: Database can't process request.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/computations/search:
|
||||
post:
|
||||
summary: Search and retrieves computations
|
||||
description: |
|
||||
Retrieves a list of computations with name and metadata filtering.
|
||||
Due to performance concerns, data is retrieved in subsets.
|
||||
The API user must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
tags:
|
||||
- computations
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ComputationsSearchReq"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/ComputationsPageRes"
|
||||
'400':
|
||||
description: Failed due to malformed query parameters.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: A non-existent entity request.
|
||||
'422':
|
||||
description: Unprocessable Entity
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/computations/{Id}:
|
||||
get:
|
||||
summary: Retrieves computation info
|
||||
tags:
|
||||
- computation
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Id"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/ComputationRes"
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: Computation does not exist.
|
||||
'422':
|
||||
description: Database can't process request.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
put:
|
||||
summary: Updates computation info
|
||||
description: |
|
||||
Update is performed by replacing the current resource data with values
|
||||
provided in a request payload.
|
||||
tags:
|
||||
- computations
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Id"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ComputationUpdateReq"
|
||||
responses:
|
||||
'200':
|
||||
description: Computation updated.
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: Computation does not exist.
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
summary: Removes a computation
|
||||
description: |
|
||||
Removes a computation.
|
||||
tags:
|
||||
- computation
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Id"
|
||||
responses:
|
||||
'204':
|
||||
description: Computation removed.
|
||||
'400':
|
||||
description: Failed due to malformed ID.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: |
|
||||
Computation key that is used for computation auth. If there is
|
||||
not one provided service will generate one in UUID
|
||||
format.
|
||||
Identity:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Computation unique identifier. This can be either
|
||||
provided by the user or left blank. If the user provides a UUID,
|
||||
it would be validated. If there is not one provided then
|
||||
the service will generate one in UUID format.
|
||||
ComputationReqSchema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Free-form name.
|
||||
description:
|
||||
type: string
|
||||
description: Free-form description
|
||||
datasets:
|
||||
type: array
|
||||
description: An array of datasets.
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
algorithms:
|
||||
type: array
|
||||
description: An array of algorithms.
|
||||
minItems: 1
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
startTime:
|
||||
type: number
|
||||
description: Start timestamp of the computations
|
||||
endTime:
|
||||
type: number
|
||||
description: End of the computation
|
||||
status:
|
||||
type: string
|
||||
description: Current status of the computation
|
||||
owner:
|
||||
type: string
|
||||
description: ID of the user who started computation
|
||||
datasetProviders:
|
||||
type: array
|
||||
description: List of IDs of users who provided datasets
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
algorithmProviders:
|
||||
type: array
|
||||
description: List of IDs of users who provided algorithms
|
||||
minItems: 1
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
ttl:
|
||||
type: number
|
||||
description: Period for computation to live in an inactive state
|
||||
metadata:
|
||||
type: object
|
||||
description: Arbitrary, object-encoded data.
|
||||
ComputationsReqSchema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Name filter. Filtering is performed as a case-insensitive partial match.
|
||||
metadata:
|
||||
type: object
|
||||
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
|
||||
total:
|
||||
type: integer
|
||||
description: Total number of items.
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval.
|
||||
default: 0
|
||||
minimum: 0
|
||||
limit:
|
||||
type: integer
|
||||
description: Size of the subset to retrieve.
|
||||
default: 10
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
order:
|
||||
type: string
|
||||
description: Order type.
|
||||
default: id
|
||||
enum:
|
||||
- name
|
||||
- id
|
||||
dir:
|
||||
type: string
|
||||
description: Order direction.
|
||||
default: desc
|
||||
enum:
|
||||
- asc
|
||||
- desc
|
||||
ComputationResSchema:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier generated by the service.
|
||||
name:
|
||||
type: string
|
||||
description: Free-form name.
|
||||
key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Auto-generated access key.
|
||||
metadata:
|
||||
type: object
|
||||
description: Arbitrary, object-encoded data.
|
||||
required:
|
||||
- id
|
||||
- type
|
||||
- key
|
||||
ComputationsPage:
|
||||
type: object
|
||||
properties:
|
||||
computations:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/ComputationResSchema"
|
||||
total:
|
||||
type: integer
|
||||
description: Total number of items.
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval.
|
||||
limit:
|
||||
type: integer
|
||||
description: Maximum number of items to return in one page.
|
||||
required:
|
||||
- computations
|
||||
parameters:
|
||||
Id:
|
||||
name: Id
|
||||
description: Unique identifier.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
Limit:
|
||||
name: limit
|
||||
description: Size of the subset to retrieve.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
required: false
|
||||
Offset:
|
||||
name: offset
|
||||
description: Number of items to skip during retrieval.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
required: false
|
||||
Name:
|
||||
name: name
|
||||
description: Name filter. Filtering is performed as a case-insensitive partial match.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
Order:
|
||||
name: order
|
||||
description: Order type.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
default: id
|
||||
enum:
|
||||
- name
|
||||
- id
|
||||
required: false
|
||||
Direction:
|
||||
name: dir
|
||||
description: Order direction.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
default: desc
|
||||
enum:
|
||||
- asc
|
||||
- desc
|
||||
required: false
|
||||
Metadata:
|
||||
name: metadata
|
||||
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
|
||||
requestBodies:
|
||||
ComputationCreateReq:
|
||||
description: JSON-formatted document describing the new computaton.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ComputationReqSchema"
|
||||
ComputationsCreateReq:
|
||||
description: JSON-formatted document describing the new computation.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
$ref: "#/components/schemas/Key"
|
||||
computations:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ComputationsReqSchema"
|
||||
ComputationUpdateReq:
|
||||
description: Arbitrary, object-encoded data.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Free-form name.
|
||||
metadata:
|
||||
type: object
|
||||
ComputationsSearchReq:
|
||||
description: JSON-formatted document describing search parameters.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ComputationReqSchema"
|
||||
KeyUpdateReq:
|
||||
required: true
|
||||
description: JSON containing computations.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Computation key that is used for computation auth.
|
||||
responses:
|
||||
CreateComputationRes:
|
||||
description: Computation registered.
|
||||
headers:
|
||||
Location:
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Created computation's relative URL.
|
||||
example: /computations/{id}
|
||||
ComputationRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ComputationResSchema"
|
||||
ComputationsPageRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ComputationsPage"
|
||||
IdentityRes:
|
||||
description: ID returned.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Identity"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
format: byte
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -1,446 +0,0 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Datasets service
|
||||
description: HTTP API for managing datasets
|
||||
version: "1.0.0"
|
||||
|
||||
paths:
|
||||
/datasets:
|
||||
post:
|
||||
summary: Add new dataset
|
||||
description: |
|
||||
Adds new dataset to the list of datasets owned by user identified using
|
||||
the provided access token.
|
||||
tags:
|
||||
- datasets
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/DatasetCreateReq"
|
||||
responses:
|
||||
'201':
|
||||
$ref: "#/components/responses/DatasetRes"
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'409':
|
||||
description: Entity already exist.
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'422':
|
||||
description: Database can't process request.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
get:
|
||||
summary: Retrieves datasets
|
||||
description: |
|
||||
Retrieves a list of datasets. Due to performance concerns, data
|
||||
is retrieved in subsets. The API user must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
tags:
|
||||
- datasets
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
- $ref: "#/components/parameters/Name"
|
||||
- $ref: "#/components/parameters/Order"
|
||||
- $ref: "#/components/parameters/Direction"
|
||||
- $ref: "#/components/parameters/Metadata"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/DatasetsPageRes"
|
||||
'400':
|
||||
description: Failed due to malformed query parameters.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: A non-existent entity request.
|
||||
'422':
|
||||
description: Database can't process request.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/datasets/search:
|
||||
post:
|
||||
summary: Search and retrieves datasets
|
||||
description: |
|
||||
Retrieves a list of datasets with name and metadata filtering.
|
||||
Due to performance concerns, data is retrieved in subsets.
|
||||
The API user must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
tags:
|
||||
- datasets
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/DatasetsSearchReq"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/DatasetsPageRes"
|
||||
'400':
|
||||
description: Failed due to malformed query parameters.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: A non-existent entity request.
|
||||
'422':
|
||||
description: Unprocessable Entity
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/datasets/{Id}:
|
||||
get:
|
||||
summary: Retrieves dataset info
|
||||
tags:
|
||||
- dataset
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Id"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/DatasetRes"
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: Dataset does not exist.
|
||||
'422':
|
||||
description: Database can't process request.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
put:
|
||||
summary: Updates dataset info
|
||||
description: |
|
||||
Update is performed by replacing the current resource data with values
|
||||
provided in a request payload.
|
||||
tags:
|
||||
- datasets
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Id"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/DatasetUpdateReq"
|
||||
responses:
|
||||
'200':
|
||||
description: dataset updated.
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: Dataset does not exist.
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
summary: Removes a dataset
|
||||
description: |
|
||||
Removes a dataset.
|
||||
tags:
|
||||
- dataset
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Id"
|
||||
responses:
|
||||
'204':
|
||||
description: Dataset removed.
|
||||
'400':
|
||||
description: Failed due to malformed ID.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
DatasetReqSchema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Free-form name.
|
||||
description:
|
||||
type: string
|
||||
description: Free-form description
|
||||
datasets:
|
||||
type: array
|
||||
description: An array of datasets.
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
algorithms:
|
||||
type: array
|
||||
description: An array of algorithms.
|
||||
minItems: 1
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
startTime:
|
||||
type: number
|
||||
description: Start timestamp of the datasets
|
||||
endTime:
|
||||
type: number
|
||||
description: End of the dataset
|
||||
status:
|
||||
type: string
|
||||
description: Current status of the dataset
|
||||
owner:
|
||||
type: string
|
||||
description: ID of the user who started dataset
|
||||
datasetProviders:
|
||||
type: array
|
||||
description: List of IDs of users who provided datasets
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
algorithmProviders:
|
||||
type: array
|
||||
description: List of IDs of users who provided algorithms
|
||||
minItems: 1
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
ttl:
|
||||
type: number
|
||||
description: Period for dataset to live in an inactive state
|
||||
metadata:
|
||||
type: object
|
||||
description: Arbitrary, object-encoded data.
|
||||
DatasetsReqSchema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Name filter. Filtering is performed as a case-insensitive partial match.
|
||||
metadata:
|
||||
type: object
|
||||
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
|
||||
total:
|
||||
type: integer
|
||||
description: Total number of items.
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval.
|
||||
default: 0
|
||||
minimum: 0
|
||||
limit:
|
||||
type: integer
|
||||
description: Size of the subset to retrieve.
|
||||
default: 10
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
order:
|
||||
type: string
|
||||
description: Order type.
|
||||
default: id
|
||||
enum:
|
||||
- name
|
||||
- id
|
||||
dir:
|
||||
type: string
|
||||
description: Order direction.
|
||||
default: desc
|
||||
enum:
|
||||
- asc
|
||||
- desc
|
||||
DatasetResSchema:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier generated by the service.
|
||||
name:
|
||||
type: string
|
||||
description: Free-form name.
|
||||
key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Auto-generated access key.
|
||||
metadata:
|
||||
type: object
|
||||
description: Arbitrary, object-encoded data.
|
||||
required:
|
||||
- id
|
||||
- type
|
||||
- key
|
||||
DatasetsPage:
|
||||
type: object
|
||||
properties:
|
||||
datasets:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/DatasetResSchema"
|
||||
total:
|
||||
type: integer
|
||||
description: Total number of items.
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval.
|
||||
limit:
|
||||
type: integer
|
||||
description: Maximum number of items to return in one page.
|
||||
required:
|
||||
- datasets
|
||||
parameters:
|
||||
Id:
|
||||
name: Id
|
||||
description: Unique identifier.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
Limit:
|
||||
name: limit
|
||||
description: Size of the subset to retrieve.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
required: false
|
||||
Offset:
|
||||
name: offset
|
||||
description: Number of items to skip during retrieval.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
required: false
|
||||
Name:
|
||||
name: name
|
||||
description: Name filter. Filtering is performed as a case-insensitive partial match.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
Order:
|
||||
name: order
|
||||
description: Order type.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
default: id
|
||||
enum:
|
||||
- name
|
||||
- id
|
||||
required: false
|
||||
Direction:
|
||||
name: dir
|
||||
description: Order direction.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
default: desc
|
||||
enum:
|
||||
- asc
|
||||
- desc
|
||||
required: false
|
||||
Metadata:
|
||||
name: metadata
|
||||
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
|
||||
requestBodies:
|
||||
DatasetCreateReq:
|
||||
description: JSON-formatted document describing the new dataset.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DatasetReqSchema"
|
||||
DatasetsCreateReq:
|
||||
description: JSON-formatted document describing the new dataset.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
datasets:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/DatasetsReqSchema"
|
||||
DatasetUpdateReq:
|
||||
description: Arbitrary, object-encoded data.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Free-form name.
|
||||
metadata:
|
||||
type: object
|
||||
DatasetsSearchReq:
|
||||
description: JSON-formatted document describing search parameters.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DatasetReqSchema"
|
||||
KeyUpdateReq:
|
||||
required: true
|
||||
description: JSON containing datasets.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Thing key that is used for thing auth.
|
||||
responses:
|
||||
CreateDatasetRes:
|
||||
description: Dataset registered.
|
||||
headers:
|
||||
Location:
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Created dataset's relative URL.
|
||||
example: /datasets/{id}
|
||||
DatasetRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DatasetResSchema"
|
||||
DatasetsPageRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DatasetsPage"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
format: byte
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -1,84 +0,0 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "5ed31077-ca87-496e-9b98-b8793ce7c5d2",
|
||||
"name": "CoCoS",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Create Computation",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"Calculate salary\",\n \"description\": \"my test computation\",\n \"ttl\": 1243\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:9000/computations",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "9000",
|
||||
"path": [
|
||||
"computations"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "View Computation",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:9000/computations/c89b53d3-c088-4b5a-addd-51a90ea94325",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "9000",
|
||||
"path": [
|
||||
"computations",
|
||||
"c89b53d3-c088-4b5a-addd-51a90ea94325"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
],
|
||||
"event": [
|
||||
{
|
||||
"listen": "prerequest",
|
||||
"script": {
|
||||
"type": "text/javascript",
|
||||
"exec": [
|
||||
""
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"type": "text/javascript",
|
||||
"exec": [
|
||||
""
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "jwt",
|
||||
"value": "",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# Agent CLI
|
||||
|
||||
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
|
||||
|
||||
From the project root:
|
||||
|
||||
```bash
|
||||
make cli
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
#### Run Computation
|
||||
|
||||
To run a computation, use the following command:
|
||||
|
||||
```bash
|
||||
./build/cocos-cli manager run --computation '{"name": "my-computation"}'
|
||||
```
|
||||
|
||||
#### Get attestation
|
||||
To retrieve attestation from agent, use the following command:
|
||||
```bash
|
||||
./build/cocos-cli agent attestation get '<report_data>'
|
||||
```
|
||||
|
||||
#### Validate attestation
|
||||
To validate and verify attestation from agent, use the following command:
|
||||
```bash
|
||||
./build/cocos-cli agent attestation validate '<attestation>' '<report_data>'
|
||||
```
|
||||
|
||||
#### Upload Algorithm
|
||||
|
||||
To upload an algorithm, use the following command:
|
||||
|
||||
```bash
|
||||
./build/cocos-cli agent algo /path/to/algorithm
|
||||
```
|
||||
|
||||
#### Upload Dataset
|
||||
|
||||
To upload a dataset, use the following command:
|
||||
|
||||
```bash
|
||||
./build/cocos-cli agent data /path/to/dataset.csv
|
||||
```
|
||||
|
||||
#### Retrieve result
|
||||
|
||||
To retrieve the computation result, use the following command:
|
||||
|
||||
```bash
|
||||
./build/cocos-cli agent 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
|
||||
```
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package cli
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
func (cli *CLI) NewAlgorithmsCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "algo",
|
||||
Short: "Upload an algorithm binary",
|
||||
Example: "algo <algo_file> <id> <provider>",
|
||||
Args: cobra.ExactArgs(3),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
algorithmFile := args[0]
|
||||
|
||||
log.Println("Uploading algorithm binary:", algorithmFile)
|
||||
|
||||
algorithm, err := os.ReadFile(algorithmFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading algorithm file: %v", err)
|
||||
}
|
||||
|
||||
algoReq := agent.Algorithm{
|
||||
Algorithm: algorithm,
|
||||
ID: args[1],
|
||||
Provider: args[2],
|
||||
}
|
||||
|
||||
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")
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/google/go-sev-guest/abi"
|
||||
"github.com/google/go-sev-guest/validate"
|
||||
"github.com/google/go-sev-guest/verify"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const attestationFilePath = "attestation.txt"
|
||||
|
||||
func (cli *CLI) NewAttestationCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "attestation [command]",
|
||||
Short: "Get and validate attestations",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("Get and validate attestations\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" {
|
||||
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",
|
||||
Example: "report <report_data>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.Println("Getting attestation")
|
||||
|
||||
result, err := cli.agentSDK.Attestation(cmd.Context(), []byte(args[0]))
|
||||
if err != nil {
|
||||
log.Fatalf("Error retrieving attestation: %v", err)
|
||||
}
|
||||
|
||||
if err = os.WriteFile(attestationFilePath, result, 0o644); err != nil {
|
||||
log.Fatalf("Error saving attestation result: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Attestation result retrieved and saved successfully!")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "validate",
|
||||
Short: "Validate and verify attestation information",
|
||||
Example: "validate <attestation> <report_data>",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.Println("Checking attestation")
|
||||
|
||||
if err := verifyAndValidateAttestation([]byte(args[0]), []byte(args[1])); err != nil {
|
||||
log.Fatalf("attestation validation and veification failed with error: %s", err)
|
||||
}
|
||||
log.Println("Attestation validation and verification is successful!")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func verifyAndValidateAttestation(attestation, reportData []byte) error {
|
||||
attestationPB, err := abi.ReportCertsToProto(attestation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = verify.SnpAttestation(attestationPB, verify.DefaultOptions()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = validate.SnpAttestation(attestationPB, &validate.Options{ReportData: reportData}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package cli
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
func (cli *CLI) NewDatasetsCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "data",
|
||||
Short: "Upload a dataset CSV file",
|
||||
Example: "data <dataset.csv> <id> <provider>",
|
||||
Args: cobra.ExactArgs(3),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
datasetFile := args[0]
|
||||
|
||||
log.Println("Uploading dataset CSV:", datasetFile)
|
||||
|
||||
dataset, err := os.ReadFile(datasetFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading dataset file: %v", err)
|
||||
}
|
||||
|
||||
dataReq := agent.Dataset{
|
||||
Dataset: dataset,
|
||||
ID: args[1],
|
||||
Provider: args[2],
|
||||
}
|
||||
|
||||
if err := cli.agentSDK.Data(cmd.Context(), dataReq); err != nil {
|
||||
log.Fatalf("Error uploading dataset: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Successfully uploaded dataset")
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package cli
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const resultFilePath = "result.bin"
|
||||
|
||||
func (cli *CLI) NewResultsCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "result",
|
||||
Short: "Retrieve computation result file",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.Println("Retrieving computation result file")
|
||||
|
||||
result, err := cli.agentSDK.Result(cmd.Context(), args[0])
|
||||
if err != nil {
|
||||
log.Fatalf("Error retrieving computation result: %v", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(resultFilePath, result, 0o644); err != nil {
|
||||
log.Fatalf("Error saving computation result to %s: %v", resultFilePath, err)
|
||||
}
|
||||
|
||||
log.Println("Computation result retrieved and saved successfully!")
|
||||
},
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
type CLI struct {
|
||||
agentSDK agent.Service
|
||||
}
|
||||
|
||||
func New(agentSDK agent.Service) *CLI {
|
||||
return &CLI{
|
||||
agentSDK: agentSDK,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
|
||||
"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"
|
||||
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"
|
||||
)
|
||||
|
||||
const (
|
||||
svcName = "agent"
|
||||
defSvcGRPCPort = "7002"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
cfg, err := readConfig()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read agent configuration from vsock %s", err.Error())
|
||||
}
|
||||
|
||||
conn, err := vsock.Dial(vsock.Host, manager.ManagerVsockPort, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
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,
|
||||
}
|
||||
|
||||
registerAgentServiceServer := func(srv *grpc.Server) {
|
||||
reflection.Register(srv)
|
||||
agent.RegisterAgentServiceServer(srv, agentgrpc.NewServer(svc))
|
||||
}
|
||||
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger)
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
svc = api.MetricsMiddleware(svc, counter, latency)
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
func readConfig() (agent.Computation, error) {
|
||||
l, err := vsock.Listen(manager.VsockConfigPort, nil)
|
||||
if err != nil {
|
||||
return agent.Computation{}, err
|
||||
}
|
||||
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
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/ultravioletrs/cocos/cli"
|
||||
"github.com/ultravioletrs/cocos/internal/env"
|
||||
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
||||
"github.com/ultravioletrs/cocos/pkg/clients/grpc/agent"
|
||||
"github.com/ultravioletrs/cocos/pkg/sdk"
|
||||
)
|
||||
|
||||
const (
|
||||
svcName = "cli"
|
||||
envPrefixAgentGRPC = "AGENT_GRPC_"
|
||||
completion = "completion"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
LogLevel string `env:"AGENT_LOG_LEVEL" envDefault:"info"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
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)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating logger: %s", err)
|
||||
}
|
||||
|
||||
agentGRPCConfig := grpc.Config{}
|
||||
if err := env.Parse(&agentGRPCConfig, env.Options{Prefix: envPrefixAgentGRPC}); err != nil {
|
||||
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.Error(err.Error())
|
||||
return
|
||||
}
|
||||
defer agentGRPCClient.Close()
|
||||
|
||||
agentSDK := sdk.NewAgentSDK(logger, agentClient)
|
||||
|
||||
cliSVC := cli.New(agentSDK)
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "cocos-cli [command]",
|
||||
Short: "CLI application for CoCos Service API",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
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 {
|
||||
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())
|
||||
},
|
||||
}
|
||||
|
||||
// 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))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/pkg/uuid"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
jconfig "github.com/uber/jaeger-client-go/config"
|
||||
"github.com/ultravioletrs/clients"
|
||||
authapi "github.com/ultravioletrs/clients/api/grpc"
|
||||
"github.com/ultravioletrs/cocos/computations"
|
||||
"github.com/ultravioletrs/cocos/computations/api/api"
|
||||
"github.com/ultravioletrs/cocos/computations/postgres"
|
||||
"github.com/ultravioletrs/cocos/internal/db"
|
||||
"github.com/ultravioletrs/cocos/internal/env"
|
||||
"github.com/ultravioletrs/cocos/internal/errors"
|
||||
"github.com/ultravioletrs/cocos/internal/http"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
const (
|
||||
defLogLevel = "debug"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "5432"
|
||||
defDBUser = "cocos"
|
||||
defDBPass = "cocos"
|
||||
defDB = "computations"
|
||||
defDBSSLMode = "disable"
|
||||
defDBSSLCert = ""
|
||||
defDBSSLKey = ""
|
||||
defDBSSLRootCert = ""
|
||||
defHTTPPort = "9000"
|
||||
defServerCert = ""
|
||||
defServerKey = ""
|
||||
|
||||
defJaegerURL = ""
|
||||
defAuthTLS = "false"
|
||||
defAuthCACerts = ""
|
||||
defAuthURL = "localhost:8181"
|
||||
defAuthTimeout = "1s"
|
||||
|
||||
envLogLevel = "COCOS_COMPUTATIONS_LOG_LEVEL"
|
||||
envDBHost = "COCOS_COMPUTATIONS_DB_HOST"
|
||||
envDBPort = "COCOS_COMPUTATIONS_DB_PORT"
|
||||
envDBUser = "COCOS_COMPUTATIONS_DB_USER"
|
||||
envDBPass = "COCOS_COMPUTATIONS_DB_PASS"
|
||||
envDB = "COCOS_COMPUTATIONS_DB"
|
||||
envDBSSLMode = "COCOS_COMPUTATIONS_DB_SSL_MODE"
|
||||
envDBSSLCert = "COCOS_COMPUTATIONS_DB_SSL_CERT"
|
||||
envDBSSLKey = "COCOS_COMPUTATIONS_DB_SSL_KEY"
|
||||
envDBSSLRootCert = "COCOS_COMPUTATIONS_DB_SSL_ROOT_CERT"
|
||||
envHTTPPort = "COCOS_COMPUTATIONS_HTTP_PORT"
|
||||
envServerCert = "COCOS_COMPUTATIONS_SERVER_CERT"
|
||||
envServerKey = "COCOS_COMPUTATIONS_SERVER_KEY"
|
||||
|
||||
envJaegerURL = "MF_JAEGER_URL"
|
||||
envAuthTLS = "COCOS_COMPUTATIONS_AUTH_CLIENT_TLS"
|
||||
envAuthCACerts = "COCOS_COMPUTATIONS_AUTH_CA_CERTS"
|
||||
envAuthURL = "COCOS_COMPUTATIONS_AUTH_GRPC_URL"
|
||||
envAuthTimeout = "COCOS_COMPUTATIONS_AUTH_GRPC_TIMEOUT"
|
||||
)
|
||||
|
||||
const svcName = "Computations"
|
||||
|
||||
type config struct {
|
||||
logLevel string
|
||||
dbConfig db.Config
|
||||
httpPort string
|
||||
serverCert string
|
||||
serverKey string
|
||||
jaegerURL string
|
||||
authTLS bool
|
||||
authCACerts string
|
||||
authURL string
|
||||
authTimeout time.Duration
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
authTimeout, err := time.ParseDuration(mainflux.Env(envAuthTimeout, defAuthTimeout))
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid %s value: %s", envAuthTimeout, err.Error())
|
||||
}
|
||||
|
||||
tls, err := strconv.ParseBool(mainflux.Env(envAuthTLS, defAuthTLS))
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid value passed for %s\n", envAuthTLS)
|
||||
}
|
||||
|
||||
dbConfig := db.Config{
|
||||
Host: env.Load(envDBHost, defDBHost),
|
||||
Port: env.Load(envDBPort, defDBPort),
|
||||
User: env.Load(envDBUser, defDBUser),
|
||||
Pass: env.Load(envDBPass, defDBPass),
|
||||
Name: env.Load(envDB, defDB),
|
||||
SSLMode: env.Load(envDBSSLMode, defDBSSLMode),
|
||||
SSLCert: env.Load(envDBSSLCert, defDBSSLCert),
|
||||
SSLKey: env.Load(envDBSSLKey, defDBSSLKey),
|
||||
SSLRootCert: env.Load(envDBSSLRootCert, defDBSSLRootCert),
|
||||
Migrations: postgres.Migrations,
|
||||
}
|
||||
return config{
|
||||
dbConfig: dbConfig,
|
||||
authTLS: tls,
|
||||
authTimeout: authTimeout,
|
||||
logLevel: env.Load(envLogLevel, defLogLevel),
|
||||
httpPort: env.Load(envHTTPPort, defHTTPPort),
|
||||
serverCert: env.Load(envServerCert, defServerCert),
|
||||
serverKey: env.Load(envServerKey, defServerKey),
|
||||
authCACerts: env.Load(envAuthCACerts, defAuthCACerts),
|
||||
jaegerURL: env.Load(envJaegerURL, defJaegerURL),
|
||||
authURL: env.Load(envAuthURL, defAuthURL),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfig()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
l, err := logger.New(os.Stdout, cfg.logLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
db, err := db.Connect(cfg.dbConfig)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
authTracer, closer := initJaeger("auth", cfg.jaegerURL, l)
|
||||
defer closer.Close()
|
||||
|
||||
auth, close := connectToAuth(cfg, authTracer, l)
|
||||
if close != nil {
|
||||
defer close()
|
||||
}
|
||||
|
||||
repo := postgres.NewRepository(db)
|
||||
idp := uuid.New()
|
||||
svc := computations.NewService(repo, idp, auth)
|
||||
svc = api.LoggingMiddleware(svc, l)
|
||||
h := api.MakeHandler(svc, nil, l)
|
||||
|
||||
g.Go(func() error {
|
||||
return http.StartServer(ctx, svcName, cfg.httpPort, cfg.serverCert, cfg.serverKey, h, l)
|
||||
})
|
||||
g.Go(errors.Handle(svcName, l, ctx, cancel))
|
||||
if err := g.Wait(); err != nil {
|
||||
l.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
|
||||
}
|
||||
}
|
||||
|
||||
func initJaeger(svcName, url string, logger logger.Logger) (opentracing.Tracer, io.Closer) {
|
||||
if url == "" {
|
||||
return opentracing.NoopTracer{}, ioutil.NopCloser(nil)
|
||||
}
|
||||
|
||||
tracer, closer, err := jconfig.Configuration{
|
||||
ServiceName: svcName,
|
||||
Sampler: &jconfig.SamplerConfig{
|
||||
Type: "const",
|
||||
Param: 1,
|
||||
},
|
||||
Reporter: &jconfig.ReporterConfig{
|
||||
LocalAgentHostPort: url,
|
||||
LogSpans: true,
|
||||
},
|
||||
}.NewTracer()
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to init Jaeger: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return tracer, closer
|
||||
}
|
||||
|
||||
func connectToAuth(cfg config, tracer opentracing.Tracer, logger logger.Logger) (clients.AuthServiceClient, func() error) {
|
||||
var opts []grpc.DialOption
|
||||
if cfg.authTLS {
|
||||
if cfg.authCACerts != "" {
|
||||
tpc, err := credentials.NewClientTLSFromFile(cfg.authCACerts, "")
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create tls credentials: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
opts = append(opts, grpc.WithTransportCredentials(tpc))
|
||||
}
|
||||
} else {
|
||||
opts = append(opts, grpc.WithInsecure())
|
||||
logger.Info("gRPC communication is not encrypted")
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(cfg.authURL, opts...)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to auth service: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
return authapi.NewClient(tracer, conn, cfg.authTimeout), conn.Close
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/pkg/uuid"
|
||||
"github.com/ultravioletrs/cocos/datasets"
|
||||
"github.com/ultravioletrs/cocos/datasets/api"
|
||||
"github.com/ultravioletrs/cocos/datasets/postgres"
|
||||
"github.com/ultravioletrs/cocos/internal/db"
|
||||
"github.com/ultravioletrs/cocos/internal/env"
|
||||
"github.com/ultravioletrs/cocos/internal/errors"
|
||||
"github.com/ultravioletrs/cocos/internal/http"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
defLogLevel = "debug"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "5432"
|
||||
defDBUser = "cocos"
|
||||
defDBPass = "cocos"
|
||||
defDB = "datasets"
|
||||
defDBSSLMode = "disable"
|
||||
defDBSSLCert = ""
|
||||
defDBSSLKey = ""
|
||||
defDBSSLRootCert = ""
|
||||
defHTTPPort = "9001"
|
||||
defServerCert = ""
|
||||
defServerKey = ""
|
||||
|
||||
defAuthTLS = "false"
|
||||
defAuthCACerts = ""
|
||||
defAuthURL = "localhost:8181"
|
||||
defAuthTimeout = "1s"
|
||||
|
||||
envLogLevel = "COCOS_DATASETS_LOG_LEVEL"
|
||||
envDBHost = "COCOS_DATASETS_DB_HOST"
|
||||
envDBPort = "COCOS_DATASETS_DB_PORT"
|
||||
envDBUser = "COCOS_DATASETS_DB_USER"
|
||||
envDBPass = "COCOS_DATASETS_DB_PASS"
|
||||
envDB = "COCOS_DATASETS_DB"
|
||||
envDBSSLMode = "COCOS_DATASETS_DB_SSL_MODE"
|
||||
envDBSSLCert = "COCOS_DATASETS_DB_SSL_CERT"
|
||||
envDBSSLKey = "COCOS_DATASETS_DB_SSL_KEY"
|
||||
envDBSSLRootCert = "COCOS_DATASETS_DB_SSL_ROOT_CERT"
|
||||
envHTTPPort = "COCOS_DATASETS_HTTP_PORT"
|
||||
envServerCert = "COCOS_DATASETS_SERVER_CERT"
|
||||
envServerKey = "COCOS_DATASETS_SERVER_KEY"
|
||||
|
||||
envAuthTLS = "COCOS_DATASETS_AUTH_CLIENT_TLS"
|
||||
envAuthCACerts = "COCOS_DATASETS_AUTH_CA_CERTS"
|
||||
envAuthURL = "COCOS_DATASETS_AUTH_GRPC_URL"
|
||||
envAuthTimeout = "COCOS_DATASETS_AUTH_GRPC_TIMEOUT"
|
||||
)
|
||||
|
||||
const svcName = "Datasets"
|
||||
|
||||
type config struct {
|
||||
logLevel string
|
||||
dbConfig db.Config
|
||||
httpPort string
|
||||
serverCert string
|
||||
serverKey string
|
||||
authTLS bool
|
||||
authCACerts string
|
||||
authURL string
|
||||
authTimeout time.Duration
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
authTimeout, err := time.ParseDuration(mainflux.Env(envAuthTimeout, defAuthTimeout))
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid %s value: %s", envAuthTimeout, err.Error())
|
||||
}
|
||||
|
||||
tls, err := strconv.ParseBool(mainflux.Env(envAuthTLS, defAuthTLS))
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid value passed for %s\n", envAuthTLS)
|
||||
}
|
||||
|
||||
dbConfig := db.Config{
|
||||
Host: env.Load(envDBHost, defDBHost),
|
||||
Port: env.Load(envDBPort, defDBPort),
|
||||
User: env.Load(envDBUser, defDBUser),
|
||||
Pass: env.Load(envDBPass, defDBPass),
|
||||
Name: env.Load(envDB, defDB),
|
||||
SSLMode: env.Load(envDBSSLMode, defDBSSLMode),
|
||||
SSLCert: env.Load(envDBSSLCert, defDBSSLCert),
|
||||
SSLKey: env.Load(envDBSSLKey, defDBSSLKey),
|
||||
SSLRootCert: env.Load(envDBSSLRootCert, defDBSSLRootCert),
|
||||
Migrations: postgres.Migrations,
|
||||
}
|
||||
return config{
|
||||
dbConfig: dbConfig,
|
||||
authTLS: tls,
|
||||
authTimeout: authTimeout,
|
||||
logLevel: env.Load(envLogLevel, defLogLevel),
|
||||
httpPort: env.Load(envHTTPPort, defHTTPPort),
|
||||
serverCert: env.Load(envServerCert, defServerCert),
|
||||
serverKey: env.Load(envServerKey, defServerKey),
|
||||
authCACerts: env.Load(envAuthCACerts, defAuthCACerts),
|
||||
authURL: env.Load(envAuthURL, defAuthURL),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfig()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
l, err := logger.New(os.Stdout, cfg.logLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
db, err := db.Connect(cfg.dbConfig)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
repo := postgres.NewRepository(db)
|
||||
idp := uuid.New()
|
||||
svc := datasets.NewService(repo, idp)
|
||||
svc = api.LoggingMiddleware(svc, l)
|
||||
h := api.MakeHandler(svc, nil, l)
|
||||
|
||||
g.Go(func() error {
|
||||
return http.StartServer(ctx, svcName, cfg.httpPort, cfg.serverCert, cfg.serverKey, h, l)
|
||||
})
|
||||
g.Go(errors.Handle(svcName, l, ctx, cancel))
|
||||
if err := g.Wait(); err != nil {
|
||||
l.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/uuid"
|
||||
"github.com/ultravioletrs/cocos/internal"
|
||||
"github.com/ultravioletrs/cocos/internal/env"
|
||||
jaegerclient "github.com/ultravioletrs/cocos/internal/jaeger"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
"github.com/ultravioletrs/cocos/manager/api"
|
||||
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"
|
||||
)
|
||||
|
||||
const (
|
||||
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:""`
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := 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)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
if cfg.InstanceID == "" {
|
||||
cfg.InstanceID, err = uuid.New().ID()
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to generate instance ID: %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
tp, err := jaegerclient.NewProvider(ctx, svcName, cfg.JaegerURL, cfg.InstanceID)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to init Jaeger: %s", err))
|
||||
}
|
||||
defer func() {
|
||||
if err := tp.Shutdown(ctx); err != nil {
|
||||
logger.Error(fmt.Sprintf("Error shutting down tracer provider: %v", err))
|
||||
}
|
||||
}()
|
||||
tracer := tp.Tracer(svcName)
|
||||
|
||||
qemuCfg := qemu.Config{}
|
||||
if err := env.Parse(&qemuCfg, env.Options{Prefix: envPrefixQemu}); err != nil {
|
||||
logger.Error(fmt.Sprintf("failed to load QEMU configuration: %s", err))
|
||||
return
|
||||
}
|
||||
exe, args, err := qemu.ExecutableAndArgs(qemuCfg)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("failed to parse QEMU configuration: %s", err))
|
||||
return
|
||||
}
|
||||
logger.Info(fmt.Sprintf("%s %s", exe, strings.Join(args, " ")))
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
managerGRPCClient, managerClient, err := managergrpc.NewManagerClient(managerGRPCConfig)
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
defer managerGRPCClient.Close()
|
||||
|
||||
pc, err := managerClient.Process(ctx)
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
if err := pc.Send(&pkgmanager.ClientStreamMessage{Message: &pkgmanager.ClientStreamMessage_Whoami{}}); 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 mc.Process(ctx)
|
||||
})
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
logger.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
|
||||
}
|
||||
|
||||
err = internal.DeleteFilesInDir(qemuCfg.TmpFileLoc)
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
svc = tracing.New(svc, tracer)
|
||||
|
||||
return svc
|
||||
}
|
||||
Executable
+270
@@ -0,0 +1,270 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# user changeable parameters
|
||||
#
|
||||
|
||||
HDA_FILE="cmd/manager/img/focal-server-cloudimg-amd64.qcow2"
|
||||
GUEST_SIZE_IN_MB="4096"
|
||||
SEV_GUEST="1"
|
||||
SMP_NCPUS="4"
|
||||
CONSOLE="serial"
|
||||
VNC_PORT=""
|
||||
USE_VIRTIO="1"
|
||||
|
||||
UEFI_BIOS_CODE="/usr/share/OVMF/OVMF_CODE.fd"
|
||||
UEFI_BIOS_VARS_ORIG="/usr/share/OVMF/OVMF_VARS.fd"
|
||||
UEFI_BIOS_VARS_COPY="cmd/manager/img/OVMF_VARS.fd"
|
||||
|
||||
CBITPOS=51
|
||||
HOST_HTTP_PORT=9301
|
||||
GUEST_HTTP_PORT=9031
|
||||
HOST_GRPC_PORT=7020
|
||||
GUEST_GRPC_PORT=7002
|
||||
|
||||
ENABLE_FILE_LOG="0"
|
||||
EXEC_QEMU_CMDLINE="0"
|
||||
|
||||
usage() {
|
||||
echo "$0 [options]"
|
||||
echo "Available <commands>:"
|
||||
echo " -hda hard disk ($HDA_FILE)"
|
||||
echo " -nosev disable sev support"
|
||||
echo " -mem guest memory"
|
||||
echo " -smp number of cpus"
|
||||
echo " -console display console to use (serial or gxl)"
|
||||
echo " -vnc VNC port to use"
|
||||
echo " -bios bios to use (default $UEFI_BIOS_CODE)"
|
||||
echo " -kernel kernel to use"
|
||||
echo " -initrd initrd to use"
|
||||
echo " -cdrom CDROM image"
|
||||
echo " -virtio use virtio devices"
|
||||
echo " -cbitpos location of the C-bit"
|
||||
echo " -hosthttp host http port"
|
||||
echo " -guesthttp guest http port"
|
||||
echo " -hostgrpc host grpc port"
|
||||
echo " -guestgrpc guest grpc port"
|
||||
echo " -origuefivars UEFI BIOS vars original file (default $UEFI_BIOS_VARS_ORIG)"
|
||||
echo " -copyuefivars UEFI BIOS vars copy file (default $UEFI_BIOS_VARS_COPY)"
|
||||
echo " -exec execute the QEMU command (default $EXEC_QEMU_CMDLINE)"
|
||||
echo " -filelog enable/disable QEMU cmd line file log (default: $ENABLE_FILE_LOG)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
while [[ $1 != "" ]]; do
|
||||
case "$1" in
|
||||
-hda)
|
||||
HDA_FILE=${2}
|
||||
shift
|
||||
;;
|
||||
-nosev)
|
||||
SEV_GUEST="0"
|
||||
;;
|
||||
-mem)
|
||||
GUEST_SIZE_IN_MB=${2}
|
||||
shift
|
||||
;;
|
||||
-console)
|
||||
CONSOLE=${2}
|
||||
shift
|
||||
;;
|
||||
-smp)
|
||||
SMP_NCPUS=$2
|
||||
shift
|
||||
;;
|
||||
-vnc)
|
||||
VNC_PORT=$2
|
||||
shift
|
||||
;;
|
||||
-bios)
|
||||
UEFI_BIOS_CODE=$2
|
||||
shift
|
||||
;;
|
||||
-initrd)
|
||||
INITRD_FILE=$2
|
||||
shift
|
||||
;;
|
||||
-kernel)
|
||||
KERNEL_FILE=$2
|
||||
shift
|
||||
;;
|
||||
-cdrom)
|
||||
CDROM_FILE=$2
|
||||
shift
|
||||
;;
|
||||
-virtio)
|
||||
USE_VIRTIO="1"
|
||||
;;
|
||||
-cbitpos)
|
||||
CBITPOS=$2
|
||||
shift
|
||||
;;
|
||||
-hosthttp)
|
||||
HOST_HTTP_PORT=$2
|
||||
shift
|
||||
;;
|
||||
-guesthttp)
|
||||
GUEST_HTTP_PORT=$2
|
||||
shift
|
||||
;;
|
||||
-guestgrpc)
|
||||
GUEST_GRPC_PORT=$2
|
||||
shift
|
||||
;;
|
||||
-hostgrpc)
|
||||
HOST_GRPC_PORT=$2
|
||||
shift
|
||||
;;
|
||||
-origuefivars)
|
||||
UEFI_BIOS_VARS_ORIG=$2
|
||||
shift
|
||||
;;
|
||||
-copyuefivars)
|
||||
UEFI_BIOS_VARS_COPY=$2
|
||||
shift
|
||||
;;
|
||||
-exec)
|
||||
EXEC_QEMU_CMDLINE="1"
|
||||
;;
|
||||
-filelog)
|
||||
ENABLE_FILE_LOG="1"
|
||||
;;
|
||||
*)
|
||||
usage;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
#
|
||||
# func definitions
|
||||
#
|
||||
|
||||
add_opts() {
|
||||
echo -n "$* " >> ${QEMU_CMDLINE}
|
||||
}
|
||||
|
||||
run_cmd() {
|
||||
if ! "$@"; then
|
||||
echo "Command '$*' failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# copy BIOS variables to new dest for VM use without modifying the original ones
|
||||
cp "$UEFI_BIOS_VARS_ORIG" "$UEFI_BIOS_VARS_COPY"
|
||||
|
||||
#
|
||||
# Qemu cmd line construction
|
||||
#
|
||||
|
||||
# we add all the qemu command line options into a file
|
||||
QEMU_CMDLINE=/tmp/cmdline.$$
|
||||
rm -rf ${QEMU_CMDLINE}
|
||||
|
||||
add_opts "$(which qemu-system-x86_64)"
|
||||
|
||||
# Basic virtual machine property
|
||||
add_opts "-enable-kvm -cpu EPYC -machine q35"
|
||||
|
||||
# add number of VCPUs
|
||||
[ -n "$SMP_NCPUS" ] && add_opts "-smp ${SMP_NCPUS},maxcpus=64"
|
||||
|
||||
# define guest memory
|
||||
add_opts "-m ${GUEST_SIZE_IN_MB}M,slots=5,maxmem=30G"
|
||||
|
||||
# The OVMF binary, including the non-volatile variable store, appears as a
|
||||
# "normal" qemu drive on the host side, and it is exposed to the guest as a
|
||||
# persistent flash device.
|
||||
add_opts "-drive if=pflash,format=raw,unit=0,file=${UEFI_BIOS_CODE},readonly=on"
|
||||
add_opts "-drive if=pflash,format=raw,unit=1,file=${UEFI_BIOS_VARS_COPY}"
|
||||
|
||||
# add CDROM if specified
|
||||
[ -n "$CDROM_FILE" ] && add_opts "-drive file=${CDROM_FILE},media=cdrom -boot d"
|
||||
|
||||
add_opts "-netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::$HOST_HTTP_PORT-:$GUEST_HTTP_PORT,hostfwd=tcp::$HOST_GRPC_PORT-:$GUEST_GRPC_PORT"
|
||||
add_opts "-device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile="
|
||||
|
||||
# If harddisk file is specified then add the HDD drive
|
||||
if [ -n "$HDA_FILE" ]; then
|
||||
if [ "$USE_VIRTIO" = "1" ]; then
|
||||
if [[ ${HDA_FILE} = *"qcow2" ]]; then
|
||||
add_opts "-drive file=${HDA_FILE},if=none,id=disk0,format=qcow2"
|
||||
else
|
||||
add_opts "-drive file=${HDA_FILE},if=none,id=disk0,format=raw"
|
||||
fi
|
||||
add_opts "-device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true"
|
||||
add_opts "-device scsi-hd,drive=disk0"
|
||||
else
|
||||
if [[ ${HDA_FILE} = *"qcow2" ]]; then
|
||||
add_opts "-drive file=${HDA_FILE},format=qcow2"
|
||||
else
|
||||
add_opts "-drive file=${HDA_FILE},format=raw"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# If this is SEV guest then add the encryption device objects to enable support
|
||||
if [ ${SEV_GUEST} = "1" ]; then
|
||||
add_opts "-object sev-guest,id=sev0,cbitpos=${CBITPOS},reduced-phys-bits=1"
|
||||
add_opts "-machine memory-encryption=sev0"
|
||||
fi
|
||||
|
||||
# if console is serial then disable graphical interface
|
||||
if [ "${CONSOLE}" = "serial" ]; then
|
||||
add_opts "-nographic"
|
||||
else
|
||||
add_opts "-vga ${CONSOLE}"
|
||||
fi
|
||||
|
||||
# if -kernel arg is specified then use the kernel provided in command line for boot
|
||||
if [ "${KERNEL_FILE}" != "" ]; then
|
||||
add_opts "-kernel $KERNEL_FILE"
|
||||
add_opts "-append \"console=ttyS0 earlyprintk=serial root=/dev/sda2\""
|
||||
[ -n "$INITRD_FILE" ] && add_opts "-initrd ${INITRD_FILE}"
|
||||
fi
|
||||
|
||||
# start vnc server
|
||||
[ -n "$VNC_PORT" ] && add_opts "-vnc :${VNC_PORT}" && echo "Starting VNC on port ${VNC_PORT}"
|
||||
|
||||
# start monitor on pty
|
||||
add_opts "-monitor pty"
|
||||
|
||||
#
|
||||
# Qemu cmd line log
|
||||
#
|
||||
|
||||
# Set the log file path if ENABLE_FILE_LOG is 1
|
||||
if [ "$ENABLE_FILE_LOG" = "1" ]; then
|
||||
LOG_FILE=$(pwd)/stdout.log
|
||||
|
||||
# Save the command line args into log file
|
||||
cat "$QEMU_CMDLINE" > "$LOG_FILE"
|
||||
echo >> "$LOG_FILE"
|
||||
fi
|
||||
|
||||
# Log the command line to the console
|
||||
cat "$QEMU_CMDLINE"
|
||||
|
||||
#
|
||||
# Qemu cmd line execution
|
||||
#
|
||||
|
||||
if [[ "${EXEC_QEMU_CMDLINE}" = "0" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# map CTRL-C to CTRL ]
|
||||
echo "Mapping CTRL-C to CTRL-]"
|
||||
stty intr ^]
|
||||
|
||||
echo "Launching VM ..."
|
||||
if [ "$ENABLE_FILE_LOG" = "1" ]; then
|
||||
bash ${QEMU_CMDLINE} 2>&1 | tee -a "${LOG_FILE}"
|
||||
else
|
||||
bash ${QEMU_CMDLINE} 2>&1
|
||||
fi
|
||||
|
||||
# restore the mapping
|
||||
stty intr ^c
|
||||
|
||||
rm -rf ${QEMU_CMDLINE}
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set your default values for sudo and sev
|
||||
sudo_option=false
|
||||
sev_option=false
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
key="$1"
|
||||
|
||||
case $key in
|
||||
--sudo)
|
||||
sudo_option=true
|
||||
shift
|
||||
;;
|
||||
--sev)
|
||||
sev_option=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $key"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
build_qemu_command() {
|
||||
local qemu_command="/usr/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 2048M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=$MANAGER_QEMU_OVMF_CODE_FILE,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -nographic -monitor pty"
|
||||
|
||||
if [ "$sev_option" = true ]; then
|
||||
qemu_command="$qemu_command -object sev-guest,id=sev0,cbitpos=51,reduced-phys-bits=1 -machine memory-encryption=sev0"
|
||||
fi
|
||||
|
||||
echo "$qemu_command"
|
||||
}
|
||||
|
||||
if [ ! -f "img/OVMF_VARS.fd" ]; then
|
||||
cp "$MANAGER_QEMU_OVMF_VARS_FILE" "img/OVMF_VARS.fd"
|
||||
echo "Copied $MANAGER_QEMU_OVMF_VARS_FILE to img/OVMF_VARS.fd"
|
||||
else
|
||||
echo "img/OVMF_VARS.fd already exists. No need to copy."
|
||||
fi
|
||||
|
||||
echo "Launching VM ..."
|
||||
|
||||
qemu_command=$(build_qemu_command)
|
||||
echo "$qemu_command"
|
||||
|
||||
echo "Mapping CTRL-C to CTRL-]"
|
||||
stty intr ^]
|
||||
|
||||
if [ "$sudo_option" = true ]; then
|
||||
# Split the command and arguments into an array; << operator is known as a "here string"
|
||||
IFS=" " read -r -a qemu_command_array <<< "$qemu_command"
|
||||
# Treat each element in the array as a separate word, preserving spaces within each element
|
||||
sudo "${qemu_command_array[@]}"
|
||||
else
|
||||
$qemu_command
|
||||
fi
|
||||
|
||||
# Restore the mapping
|
||||
stty intr ^c
|
||||
@@ -0,0 +1,62 @@
|
||||
<domain type="kvm">
|
||||
<name>QEmu-alpine-standard-x86_64</name>
|
||||
<uuid>c7a5fdbd-cdaf-9455-926a-d65c16db1809</uuid>
|
||||
<metadata>
|
||||
<libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
|
||||
<libosinfo:os id="http://alpinelinux.org/alpinelinux/3.15"/>
|
||||
</libosinfo:libosinfo>
|
||||
</metadata>
|
||||
<memory unit="KiB">4194304</memory>
|
||||
<currentMemory unit="KiB">4194304</currentMemory>
|
||||
<vcpu placement="static">1</vcpu>
|
||||
<os>
|
||||
<type arch="x86_64" machine="q35">hvm</type>
|
||||
<bootmenu enable="yes"/>
|
||||
<loader readonly="yes" type="pflash">/usr/share/OVMF/OVMF_CODE.fd</loader>
|
||||
<nvram template='/usr/share/OVMF/OVMF_VARS.fd'>./img/OVMF_VARS.fd</nvram>
|
||||
<!-- <boot dev='hd'/> -->
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
<vmport state="off"/>
|
||||
</features>
|
||||
<cpu mode="host-passthrough" check="none" migratable="on"/>
|
||||
<clock offset="utc">
|
||||
<timer name="rtc" tickpolicy="catchup"/>
|
||||
<timer name="pit" tickpolicy="delay"/>
|
||||
<timer name="hpet" present="no"/>
|
||||
</clock>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<pm>
|
||||
<suspend-to-mem enabled="no"/>
|
||||
<suspend-to-disk enabled="no"/>
|
||||
</pm>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||
<disk type="file" device="disk">
|
||||
<driver name="qemu" type="qcow2" discard="unmap"/>
|
||||
<source file="./img/focal-server-cloudimg-amd64.qcow2"/>
|
||||
<target dev="vda" bus="virtio"/>
|
||||
<address type="pci" domain="0x0000" bus="0x04" slot="0x00" function="0x0"/>
|
||||
<boot order="1"/>
|
||||
</disk>
|
||||
<graphics type="spice" autoport="yes">
|
||||
<listen type="address"/>
|
||||
<image compression="off"/>
|
||||
</graphics>
|
||||
<video>
|
||||
<model type="qxl" ram="65536" vram="65536" vgamem="16384" heads="1" primary="yes"/>
|
||||
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0"/>
|
||||
</video>
|
||||
<interface type="network">
|
||||
<mac address="52:54:00:03:7b:5f"/>
|
||||
<source network="default"/>
|
||||
<model type="virtio"/>
|
||||
<address type="pci" domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
|
||||
</interface>
|
||||
</devices>
|
||||
|
||||
</domain>
|
||||
@@ -0,0 +1,6 @@
|
||||
<pool type="dir">
|
||||
<name>virtimages</name>
|
||||
<target>
|
||||
<path>./img</path>
|
||||
</target>
|
||||
</pool>
|
||||
@@ -0,0 +1,15 @@
|
||||
<volume>
|
||||
<name>boot.img</name>
|
||||
<allocation>0</allocation>
|
||||
<capacity unit="G">1</capacity>
|
||||
<target>
|
||||
<format type="qcow2"/>
|
||||
<path>./img/boot.img</path>
|
||||
<permissions>
|
||||
<owner>107</owner>
|
||||
<group>107</group>
|
||||
<mode>0744</mode>
|
||||
<label>virt_image_t</label>
|
||||
</permissions>
|
||||
</target>
|
||||
</volume>
|
||||
@@ -1,4 +0,0 @@
|
||||
// Package api contains API-related concerns: endpoint
|
||||
// definitions, middlewares, and all resource representations.
|
||||
|
||||
package api
|
||||
@@ -1,106 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
"github.com/ultravioletrs/cocos/computations"
|
||||
)
|
||||
|
||||
func create(svc computations.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(createReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return createRes{}, err
|
||||
}
|
||||
cid, err := svc.CreateComputation(ctx, req.token, req.computation)
|
||||
if err != nil {
|
||||
return createRes{}, err
|
||||
}
|
||||
ret := createRes{
|
||||
ID: cid,
|
||||
created: true,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
func view(svc computations.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(viewReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return viewRes{}, err
|
||||
}
|
||||
computation, err := svc.ViewComputation(ctx, req.token, req.id)
|
||||
if err != nil {
|
||||
return createRes{}, err
|
||||
}
|
||||
ret := viewRes{
|
||||
Computation: computation,
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
func list(svc computations.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return listRes{}, err
|
||||
}
|
||||
res, err := svc.ListComputations(ctx, req.token, req.meta)
|
||||
if err != nil {
|
||||
return listRes{}, err
|
||||
}
|
||||
ret := listRes{
|
||||
Page: res,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
func update(svc computations.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(updateReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
computation := computations.Computation{
|
||||
ID: req.id,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
|
||||
if err := svc.UpdateComputation(ctx, req.token, computation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := createRes{ID: req.id, created: false}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func remove(svc computations.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(viewReq)
|
||||
|
||||
err := req.validate()
|
||||
if err == errors.ErrNotFound {
|
||||
return removeRes{}, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := svc.RemoveComputation(ctx, req.token, req.id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return removeRes{}, nil
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/ultravioletrs/cocos/computations"
|
||||
)
|
||||
|
||||
var _ computations.Service = (*loggingMiddleware)(nil)
|
||||
|
||||
type loggingMiddleware struct {
|
||||
logger log.Logger
|
||||
svc computations.Service
|
||||
}
|
||||
|
||||
// LoggingMiddleware adds logging facilities to the core service.
|
||||
func LoggingMiddleware(svc computations.Service, logger log.Logger) computations.Service {
|
||||
return &loggingMiddleware{logger, svc}
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) CreateComputation(ctx context.Context, token string, computation computations.Computation) (id string, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method create_computation for user %s took %s to complete", token, 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.CreateComputation(ctx, token, computation)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ViewComputation(ctx context.Context, token, id string) (c computations.Computation, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method view_computation for user %s took %s to complete", token, 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.ViewComputation(ctx, token, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ListComputations(ctx context.Context, token string, meta computations.PageMetadata) (page computations.Page, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method list_computations for user %s took %s to complete", token, 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.ListComputations(ctx, token, meta)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UpdateComputation(ctx context.Context, token string, computation computations.Computation) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method update_computation for user %s took %s to complete", token, 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.UpdateComputation(ctx, token, computation)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) RemoveComputation(ctx context.Context, token, id string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method remove_computation for user %s took %s to complete", token, 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.RemoveComputation(ctx, token, id)
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
//go:build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/ultravioletrs/cocos/computations"
|
||||
)
|
||||
|
||||
var _ computations.Service = (*metricsMiddleware)(nil)
|
||||
|
||||
type metricsMiddleware struct {
|
||||
counter metrics.Counter
|
||||
latency metrics.Histogram
|
||||
svc computations.Service
|
||||
}
|
||||
|
||||
// MetricsMiddleware instruments core service by tracking request count and latency.
|
||||
func MetricsMiddleware(svc computations.Service, counter metrics.Counter, latency metrics.Histogram) computations.Service {
|
||||
return &metricsMiddleware{
|
||||
counter: counter,
|
||||
latency: latency,
|
||||
svc: svc,
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) CreateComputation(ctx context.Context, token string, computation computations.Computation) (string, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "create_computation").Add(1)
|
||||
ms.latency.With("method", "create_computation").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.CreateComputation(ctx, token, computation)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ViewComputation(ctx context.Context, token, id string) (computations.Computation, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "view_computation").Add(1)
|
||||
ms.latency.With("method", "view_computation").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ViewComputation(ctx, token, id)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ListComputations(ctx context.Context, token string, meta computations.PageMetadata) (page computations.Page, err error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_computations").Add(1)
|
||||
ms.latency.With("method", "list_computations").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ListComputations(ctx, token, meta)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) UpdateComputation(ctx context.Context, token string, computation computations.Computation) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "update_computations").Add(1)
|
||||
ms.latency.With("method", "update_computations").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.UpdateComputation(ctx, token, computation)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) RemoveComputation(ctx context.Context, token, id string) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "remove_computation").Add(1)
|
||||
ms.latency.With("method", "remove_computation").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.RemoveComputation(ctx, token, id)
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package api
|
||||
|
||||
import "github.com/ultravioletrs/cocos/computations"
|
||||
|
||||
type createReq struct {
|
||||
computation computations.Computation
|
||||
token string
|
||||
}
|
||||
|
||||
func (req createReq) validate() error {
|
||||
return req.computation.Validate()
|
||||
}
|
||||
|
||||
type viewReq struct {
|
||||
token string
|
||||
id string
|
||||
}
|
||||
|
||||
func (req viewReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type listReq struct {
|
||||
token string
|
||||
meta computations.PageMetadata
|
||||
}
|
||||
|
||||
func (req listReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type updateReq struct {
|
||||
token string
|
||||
id string
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
func (req updateReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/ultravioletrs/cocos/computations"
|
||||
)
|
||||
|
||||
type createRes struct {
|
||||
ID string
|
||||
created bool
|
||||
}
|
||||
|
||||
func (res createRes) Code() int {
|
||||
if res.created {
|
||||
return http.StatusCreated
|
||||
}
|
||||
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res createRes) Headers() map[string]string {
|
||||
if res.created {
|
||||
return map[string]string{
|
||||
"Location": fmt.Sprintf("/computations/%s", res.ID),
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res createRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type viewRes struct {
|
||||
computations.Computation
|
||||
}
|
||||
|
||||
func (res viewRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res viewRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res viewRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type errorRes struct {
|
||||
Err string `json:"error"`
|
||||
}
|
||||
|
||||
type listRes struct {
|
||||
computations.Page
|
||||
}
|
||||
|
||||
func (res listRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res listRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res listRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type removeRes struct{}
|
||||
|
||||
func (res removeRes) Code() int {
|
||||
return http.StatusNoContent
|
||||
}
|
||||
|
||||
func (res removeRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res removeRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
"github.com/go-zoo/bone"
|
||||
"github.com/mainflux/mainflux"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/ultravioletrs/cocos/computations"
|
||||
"github.com/ultravioletrs/cocos/internal/apiutil"
|
||||
httputil "github.com/ultravioletrs/cocos/internal/http"
|
||||
)
|
||||
|
||||
const (
|
||||
contentType = "application/json"
|
||||
offsetKey = "offset"
|
||||
limitKey = "limit"
|
||||
orderKey = "order"
|
||||
dirKey = "dir"
|
||||
metadataKey = "metadata"
|
||||
defOffset = 0
|
||||
defLimit = 10
|
||||
bearerPrefix = "Bearer "
|
||||
)
|
||||
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHandler(svc computations.Service, tracer opentracing.Tracer, logger log.Logger) http.Handler {
|
||||
opts := []kithttp.ServerOption{
|
||||
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
|
||||
}
|
||||
mux := bone.New()
|
||||
|
||||
mux.Post("/computations", kithttp.NewServer(
|
||||
// kitot.TraceServer(tracer, "register")(createComputation(svc)),
|
||||
create(svc),
|
||||
decodeCreate,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Get("/computations", kithttp.NewServer(
|
||||
// kitot.TraceServer(tracer, "register")(createComputation(svc)),
|
||||
list(svc),
|
||||
decodeList,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Get("/computations/:id", kithttp.NewServer(
|
||||
view(svc),
|
||||
decodeView,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Put("/computations/:id", kithttp.NewServer(
|
||||
update(svc),
|
||||
decodeUpdate,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Delete("/computations/:id", kithttp.NewServer(
|
||||
remove(svc),
|
||||
decodeView,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.GetFunc("/health", httputil.Health("computations", "Computation management service"))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return mux
|
||||
}
|
||||
|
||||
func decodeCreate(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := createReq{
|
||||
token: extractBearerToken(r),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req.computation); err != nil {
|
||||
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
or, err := apiutil.ReadStringQuery(r, orderKey, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d, err := apiutil.ReadStringQuery(r, dirKey, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req := listReq{
|
||||
|
||||
token: extractBearerToken(r),
|
||||
meta: computations.PageMetadata{
|
||||
Offset: o,
|
||||
Limit: l,
|
||||
Order: or,
|
||||
Dir: d,
|
||||
Metadata: m,
|
||||
},
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := viewReq{
|
||||
token: extractBearerToken(r),
|
||||
id: bone.GetValue(r, "id"),
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeUpdate(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||
return nil, errors.ErrUnsupportedContentType
|
||||
}
|
||||
|
||||
req := updateReq{
|
||||
token: extractBearerToken(r),
|
||||
id: bone.GetValue(r, "id"),
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
|
||||
if ar, ok := response.(mainflux.Response); ok {
|
||||
for k, v := range ar.Headers() {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
w.WriteHeader(ar.Code())
|
||||
|
||||
if ar.Empty() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
switch {
|
||||
case errors.Contains(err, errors.ErrInvalidQueryParams),
|
||||
errors.Contains(err, errors.ErrMalformedEntity):
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case errors.Contains(err, errors.ErrCreateEntity),
|
||||
errors.Contains(err, errors.ErrUpdateEntity),
|
||||
errors.Contains(err, errors.ErrViewEntity),
|
||||
errors.Contains(err, errors.ErrRemoveEntity):
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
default:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
if errorVal, ok := err.(errors.Error); ok {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
if err := json.NewEncoder(w).Encode(errorRes{Err: errorVal.Msg()}); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extractBearerToken(r *http.Request) string {
|
||||
token := r.Header.Get("Authorization")
|
||||
if !strings.HasPrefix(token, bearerPrefix) {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimPrefix(token, bearerPrefix)
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package computations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Computation struct {
|
||||
ID string `json:"id,omitempty" db:"id"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
Description string `json:"description,omitempty" db:"description"`
|
||||
Status string `json:"status,omitempty" db:"status"`
|
||||
Owner string `json:"owner,omitempty" db:"owner"`
|
||||
StartTime time.Time `json:"start_time,omitempty" db:"start_time"`
|
||||
EndTime time.Time `json:"end_time,omitempty" db:"end_time"`
|
||||
Datasets []string `json:"datasets,omitempty" db:"datasets"`
|
||||
Algorithms []string `json:"algorithms,omitempty" db:"algorithms"`
|
||||
DatasetProviders []string `json:"dataset_providers,omitempty" db:"dataset_providers"`
|
||||
AlgorithmProviders []string `json:"algorithm_providers,omitempty" db:"algorithm_providers"`
|
||||
Ttl int `json:"ttl,omitempty" db:"ttl"`
|
||||
Metadata Metadata `json:"metadata,omitempty" db:"metadata"`
|
||||
}
|
||||
|
||||
type Metadata map[string]interface{}
|
||||
|
||||
type PageMetadata struct {
|
||||
Total uint64 `json:"total,omitempty"`
|
||||
Offset uint64 `json:"offset,omitempty"`
|
||||
Limit uint64 `json:"limit,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Order string `json:"order,omitempty"`
|
||||
Dir string `json:"dir,omitempty"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type Page struct {
|
||||
PageMetadata
|
||||
Computations []Computation `json:"computations,omitempty"`
|
||||
}
|
||||
|
||||
func (c Computation) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Repository interface {
|
||||
Save(ctx context.Context, c Computation) (string, error)
|
||||
View(ctx context.Context, id string) (Computation, error)
|
||||
RetrieveAll(ctx context.Context, owner string, pm PageMetadata) (Page, error)
|
||||
Update(ctx context.Context, c Computation) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Package computations contains domain concept definitions
|
||||
// needed to support Computations service functionality.
|
||||
|
||||
package computations
|
||||
@@ -1,355 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
"github.com/ultravioletrs/cocos/computations"
|
||||
db "github.com/ultravioletrs/cocos/internal/db"
|
||||
)
|
||||
|
||||
const (
|
||||
errInvalid = "invalid_text_representation"
|
||||
errTruncation = "string_data_right_truncation"
|
||||
errDuplicate = "unique_violation"
|
||||
)
|
||||
|
||||
var _ computations.Repository = (*computationRepo)(nil)
|
||||
|
||||
type computationRepo struct {
|
||||
db db.Database
|
||||
}
|
||||
|
||||
func NewRepository(db db.Database) computations.Repository {
|
||||
return computationRepo{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (repo computationRepo) Save(ctx context.Context, c computations.Computation) (string, error) {
|
||||
q := `INSERT INTO computations (id, name, description, status, owner, start_time, end_time, datasets, algorithms, dataset_providers, algorithm_providers, ttl, metadata)
|
||||
VALUES (:id, :name, :description, :status, :owner, :start_time, :end_time, :datasets, :algorithms, :dataset_providers, :algorithm_providers, :ttl, :metadata) RETURNING id`
|
||||
comp, err := fromComputation(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
row, err := repo.db.NamedQueryContext(ctx, q, comp)
|
||||
if err != nil {
|
||||
pqErr, ok := err.(*pq.Error)
|
||||
if ok {
|
||||
switch pqErr.Code.Name() {
|
||||
case errInvalid, errTruncation:
|
||||
return "", errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
case errDuplicate:
|
||||
return "", errors.Wrap(errors.ErrConflict, err)
|
||||
}
|
||||
}
|
||||
return "", errors.Wrap(errors.ErrCreateEntity, err)
|
||||
}
|
||||
|
||||
defer row.Close()
|
||||
row.Next()
|
||||
var id string
|
||||
if err := row.Scan(&id); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (repo computationRepo) View(ctx context.Context, id string) (computations.Computation, error) {
|
||||
q := `SELECT id, name, description, status, owner, start_time, end_time, datasets,
|
||||
algorithms, dataset_providers, algorithm_providers, ttl, metadata
|
||||
FROM computations
|
||||
WHERE id = $1`
|
||||
|
||||
c := dbComputation{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
if err := repo.db.QueryRowxContext(ctx, q, id).StructScan(&c); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return computations.Computation{}, errors.Wrap(errors.ErrNotFound, err)
|
||||
|
||||
}
|
||||
return computations.Computation{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
return toComputation(c)
|
||||
}
|
||||
|
||||
func (repo computationRepo) RetrieveAll(ctx context.Context, owner string, pm computations.PageMetadata) (computations.Page, error) {
|
||||
nq, name := getNameQuery(pm.Name)
|
||||
oq := getOrderQuery(pm.Order)
|
||||
dq := getDirQuery(pm.Dir)
|
||||
m, mq, err := getMetadataQuery(pm.Metadata)
|
||||
if err != nil {
|
||||
return computations.Page{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
var query []string
|
||||
if mq != "" {
|
||||
query = append(query, mq)
|
||||
}
|
||||
if nq != "" {
|
||||
query = append(query, nq)
|
||||
}
|
||||
|
||||
var whereClause string
|
||||
if len(query) > 0 {
|
||||
whereClause = fmt.Sprintf(" WHERE %s", strings.Join(query, " AND "))
|
||||
}
|
||||
|
||||
q := `SELECT id, name, description, status, owner, start_time, end_time, datasets,
|
||||
algorithms, dataset_providers, algorithm_providers, ttl, metadata
|
||||
FROM computations %s
|
||||
ORDER BY %s %s LIMIT :limit OFFSET :offset`
|
||||
|
||||
q = fmt.Sprintf(q, whereClause, oq, dq)
|
||||
params := map[string]interface{}{
|
||||
"owner": owner,
|
||||
"limit": pm.Limit,
|
||||
"offset": pm.Offset,
|
||||
"name": name,
|
||||
"metadata": m,
|
||||
}
|
||||
|
||||
rows, err := repo.db.NamedQueryContext(ctx, q, params)
|
||||
if err != nil {
|
||||
return computations.Page{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var items []computations.Computation
|
||||
for rows.Next() {
|
||||
dbc := dbComputation{Owner: owner}
|
||||
if err := rows.StructScan(&dbc); err != nil {
|
||||
return computations.Page{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
c, err := toComputation(dbc)
|
||||
if err != nil {
|
||||
return computations.Page{}, err
|
||||
}
|
||||
|
||||
items = append(items, c)
|
||||
}
|
||||
|
||||
cq := fmt.Sprintf(`SELECT COUNT(*) FROM computations %s;`, whereClause)
|
||||
|
||||
total, err := repo.total(ctx, cq, params)
|
||||
if err != nil {
|
||||
return computations.Page{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
page := computations.Page{
|
||||
Computations: items,
|
||||
PageMetadata: computations.PageMetadata{
|
||||
Total: total,
|
||||
Offset: pm.Offset,
|
||||
Limit: pm.Limit,
|
||||
Order: pm.Order,
|
||||
Dir: pm.Dir,
|
||||
},
|
||||
}
|
||||
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (repo computationRepo) Update(ctx context.Context, c computations.Computation) error {
|
||||
q := `UPDATE computations SET name = :name, metadata = :metadata, description = :description WHERE id = :id;`
|
||||
dbcpt, err := toDBComputation(c)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.ErrUpdateEntity, err)
|
||||
}
|
||||
res, errdb := repo.db.NamedExecContext(ctx, q, dbcpt)
|
||||
if errdb != nil {
|
||||
pqErr, ok := errdb.(*pq.Error)
|
||||
if ok {
|
||||
switch pqErr.Code.Name() {
|
||||
case errInvalid, errTruncation:
|
||||
return errors.Wrap(errors.ErrMalformedEntity, errdb)
|
||||
}
|
||||
}
|
||||
return errors.Wrap(errors.ErrUpdateEntity, errdb)
|
||||
|
||||
}
|
||||
|
||||
cnt, errdb := res.RowsAffected()
|
||||
if errdb != nil {
|
||||
return errors.Wrap(errors.ErrUpdateEntity, errdb)
|
||||
}
|
||||
|
||||
if cnt == 0 {
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo computationRepo) Delete(ctx context.Context, id string) error {
|
||||
q := `DELETE FROM computations WHERE id = :id`
|
||||
|
||||
c := dbComputation{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
if _, err := repo.db.NamedExecContext(ctx, q, c); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return errors.Wrap(errors.ErrNotFound, err)
|
||||
|
||||
}
|
||||
return errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo computationRepo) total(ctx context.Context, query string, params interface{}) (uint64, error) {
|
||||
rows, err := repo.db.NamedQueryContext(ctx, query, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
total := uint64(0)
|
||||
if rows.Next() {
|
||||
if err := rows.Scan(&total); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
type dbComputation struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Description string `db:"description"`
|
||||
Status string `db:"status"`
|
||||
Owner string `db:"owner"`
|
||||
StartTime time.Time `db:"start_time"`
|
||||
EndTime time.Time `db:"end_time"`
|
||||
Datasets pq.StringArray `db:"datasets"`
|
||||
Algorithms pq.StringArray `db:"algorithms"`
|
||||
DatasetProviders pq.StringArray `db:"dataset_providers"`
|
||||
AlgorithmProviders pq.StringArray `db:"algorithm_providers"`
|
||||
Ttl int `db:"ttl"`
|
||||
Metadata []byte `db:"metadata"`
|
||||
}
|
||||
|
||||
func toComputation(c dbComputation) (computations.Computation, error) {
|
||||
var metadata map[string]interface{}
|
||||
if c.Metadata != nil {
|
||||
if err := json.Unmarshal([]byte(c.Metadata), &metadata); err != nil {
|
||||
return computations.Computation{}, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
}
|
||||
ret := computations.Computation{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Description: c.Description,
|
||||
Status: c.Status,
|
||||
Owner: c.Owner,
|
||||
StartTime: c.StartTime,
|
||||
EndTime: c.EndTime,
|
||||
Datasets: c.Datasets,
|
||||
Algorithms: c.Algorithms,
|
||||
DatasetProviders: c.DatasetProviders,
|
||||
AlgorithmProviders: c.AlgorithmProviders,
|
||||
Ttl: c.Ttl,
|
||||
Metadata: metadata,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func fromComputation(c computations.Computation) (dbComputation, error) {
|
||||
metadata := []byte("{}")
|
||||
if len(c.Metadata) > 0 {
|
||||
b, err := json.Marshal(c.Metadata)
|
||||
if err != nil {
|
||||
return dbComputation{}, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
metadata = b
|
||||
}
|
||||
ret := dbComputation{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Description: c.Description,
|
||||
Status: c.Status,
|
||||
Owner: c.Owner,
|
||||
StartTime: c.StartTime,
|
||||
EndTime: c.EndTime,
|
||||
Datasets: c.Datasets,
|
||||
Algorithms: c.Algorithms,
|
||||
DatasetProviders: c.DatasetProviders,
|
||||
AlgorithmProviders: c.AlgorithmProviders,
|
||||
Ttl: c.Ttl,
|
||||
Metadata: metadata,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func getNameQuery(name string) (string, string) {
|
||||
if name == "" {
|
||||
return "", ""
|
||||
}
|
||||
name = fmt.Sprintf(`%%%s%%`, strings.ToLower(name))
|
||||
nq := `LOWER(name) LIKE :name`
|
||||
return nq, name
|
||||
}
|
||||
|
||||
func getOrderQuery(order string) string {
|
||||
switch order {
|
||||
case "name":
|
||||
return "name"
|
||||
default:
|
||||
return "id"
|
||||
}
|
||||
}
|
||||
|
||||
func getDirQuery(dir string) string {
|
||||
switch dir {
|
||||
case "asc":
|
||||
return "ASC"
|
||||
default:
|
||||
return "DESC"
|
||||
}
|
||||
}
|
||||
|
||||
func getMetadataQuery(m computations.Metadata) ([]byte, string, error) {
|
||||
mq := ""
|
||||
mb := []byte("{}")
|
||||
if len(m) > 0 {
|
||||
mq = `metadata @> :metadata`
|
||||
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
mb = b
|
||||
}
|
||||
return mb, mq, nil
|
||||
}
|
||||
|
||||
func toDBComputation(cpt computations.Computation) (dbComputation, error) {
|
||||
data := []byte("{}")
|
||||
if len(cpt.Metadata) > 0 {
|
||||
b, err := json.Marshal(cpt.Metadata)
|
||||
if err != nil {
|
||||
return dbComputation{}, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
data = b
|
||||
}
|
||||
|
||||
return dbComputation{
|
||||
ID: cpt.ID,
|
||||
Owner: cpt.Owner,
|
||||
Name: cpt.Name,
|
||||
Description: cpt.Description,
|
||||
Metadata: data,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Package postgres contains repository implementations using
|
||||
// PostgreSQL as the underlying database.
|
||||
|
||||
package postgres
|
||||
@@ -1,32 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import migrate "github.com/rubenv/sql-migrate"
|
||||
|
||||
var Migrations = &migrate.MemoryMigrationSource{
|
||||
Migrations: []*migrate.Migration{
|
||||
{
|
||||
Id: "computations_1",
|
||||
Up: []string{
|
||||
`CREATE TABLE IF NOT EXISTS computations (
|
||||
id UUID,
|
||||
owner VARCHAR(255),
|
||||
name VARCHAR(1025),
|
||||
description text,
|
||||
status VARCHAR(255),
|
||||
start_time timestamp NOT NULL,
|
||||
end_time timestamp,
|
||||
datasets text[],
|
||||
algorithms text[],
|
||||
dataset_providers text[],
|
||||
algorithm_providers text[],
|
||||
ttl integer,
|
||||
metadata JSON,
|
||||
PRIMARY KEY (id, owner)
|
||||
)`,
|
||||
},
|
||||
Down: []string{
|
||||
"DROP TABLE computations",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package computations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
"github.com/ultravioletrs/clients"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
CreateComputation(ctx context.Context, token string, computation Computation) (string, error)
|
||||
ViewComputation(ctx context.Context, token, id string) (Computation, error)
|
||||
ListComputations(ctx context.Context, token string, meta PageMetadata) (Page, error)
|
||||
UpdateComputation(ctx context.Context, token string, computation Computation) error
|
||||
RemoveComputation(ctx context.Context, token, id string) error
|
||||
}
|
||||
|
||||
type service struct {
|
||||
repo Repository
|
||||
idp mainflux.IDProvider
|
||||
auth clients.AuthServiceClient
|
||||
}
|
||||
|
||||
func NewService(repo Repository, idp mainflux.IDProvider, auth clients.AuthServiceClient) Service {
|
||||
return service{
|
||||
repo: repo,
|
||||
idp: idp,
|
||||
auth: auth,
|
||||
}
|
||||
}
|
||||
|
||||
func (svc service) CreateComputation(ctx context.Context, token string, computation Computation) (string, error) {
|
||||
id, err := svc.idp.ID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
computation.ID = id
|
||||
computation.StartTime = time.Now()
|
||||
return svc.repo.Save(ctx, computation)
|
||||
}
|
||||
|
||||
func (svc service) ViewComputation(ctx context.Context, token string, id string) (Computation, error) {
|
||||
// Use id as both subject and object as token is currently empty
|
||||
// c_add policy is an example of acceptable policy from clients service.
|
||||
if err := svc.authorize(ctx, id, id, "c_add"); err != nil {
|
||||
return Computation{}, errors.Wrap(errors.ErrAuthentication, err)
|
||||
}
|
||||
return svc.repo.View(ctx, id)
|
||||
}
|
||||
|
||||
func (svc service) ListComputations(ctx context.Context, token string, meta PageMetadata) (Page, error) {
|
||||
return svc.repo.RetrieveAll(ctx, token, meta)
|
||||
}
|
||||
|
||||
func (svc service) UpdateComputation(ctx context.Context, token string, computation Computation) error {
|
||||
return svc.repo.Update(ctx, computation)
|
||||
}
|
||||
|
||||
func (svc service) RemoveComputation(ctx context.Context, token string, id string) error {
|
||||
// Use id as both subject and object as token is currently empty
|
||||
// c_delete policy is an example of acceptable policy from clients service.
|
||||
if err := svc.authorize(ctx, id, id, "c_delete"); err != nil {
|
||||
return errors.Wrap(errors.ErrAuthentication, err)
|
||||
}
|
||||
return svc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (svc service) authorize(ctx context.Context, subject, object, action string) error {
|
||||
req := &clients.AuthorizeReq{
|
||||
Sub: subject,
|
||||
Obj: object,
|
||||
Act: action,
|
||||
}
|
||||
res, err := svc.auth.Authorize(ctx, req)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.ErrAuthorization, err)
|
||||
}
|
||||
if !res.GetAuthorized() {
|
||||
return errors.ErrAuthorization
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Package api contains API-related concerns: endpoint
|
||||
// definitions, middlewares, and all resource representations.
|
||||
|
||||
package api
|
||||
@@ -1,115 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/ultravioletrs/cocos/datasets"
|
||||
)
|
||||
|
||||
func createDatasetsEndpoint(svc datasets.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(createReq)
|
||||
|
||||
id, err := svc.CreateDataset(ctx, req.dataset)
|
||||
if err != nil {
|
||||
return createRes{}, err
|
||||
}
|
||||
|
||||
res := createRes{
|
||||
ID: id,
|
||||
created: true,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func viewDatasetsEndpoint(svc datasets.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(viewRequest)
|
||||
|
||||
ds, err := svc.ViewDataset(ctx, req.owner, req.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := viewRes{
|
||||
Dataset: ds,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listDatasetsEndpoint(svc datasets.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listResourcesReq)
|
||||
|
||||
page, err := svc.ListDatasets(ctx, req.owner, req.pageMetadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := datasetsPageRes{
|
||||
pageRes: pageRes{
|
||||
Total: page.Total,
|
||||
Offset: page.Offset,
|
||||
Limit: page.Limit,
|
||||
Order: page.Order,
|
||||
Dir: page.Dir,
|
||||
},
|
||||
Datasets: []datasets.Dataset{},
|
||||
}
|
||||
res.Datasets = append(res.Datasets, page.Datasets...)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func updateDatasetEndpoint(svc datasets.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(updateReq)
|
||||
|
||||
dataset := datasets.Dataset{
|
||||
ID: req.id,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
|
||||
if err := svc.UpdateDataset(ctx, dataset); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := createRes{ID: req.id, created: false}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func uploadDatasetEndpoint(svc datasets.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(uploadReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := svc.UploadDataset(ctx, req.id, req.owner, req.Payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := createRes{ID: req.id, created: false}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func removeDatasetEndpoint(svc datasets.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(viewRequest)
|
||||
|
||||
if err := svc.RemoveDataset(ctx, req.id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return removeRes{}, nil
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
|
||||
"github.com/ultravioletrs/cocos/datasets"
|
||||
)
|
||||
|
||||
var _ datasets.Service = (*loggingMiddleware)(nil)
|
||||
|
||||
type loggingMiddleware struct {
|
||||
logger log.Logger
|
||||
svc datasets.Service
|
||||
}
|
||||
|
||||
// LoggingMiddleware adds logging facilities to the core service.
|
||||
func LoggingMiddleware(svc datasets.Service, logger log.Logger) datasets.Service {
|
||||
return &loggingMiddleware{logger, svc}
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) CreateDataset(ctx context.Context, dts datasets.Dataset) (id string, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method create_dataset took %s to complete", 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.CreateDataset(ctx, dts)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ViewDataset(ctx context.Context, owner, id string) (d datasets.Dataset, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method view_dataset took %s to complete", 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.ViewDataset(ctx, owner, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ListDatasets(ctx context.Context, owner string, meta datasets.PageMetadata) (page datasets.Page, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method list_datasets took %s to complete", 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.ListDatasets(ctx, owner, meta)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UpdateDataset(ctx context.Context, dataset datasets.Dataset) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method update_dataset took %s to complete", 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.UpdateDataset(ctx, dataset)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UploadDataset(ctx context.Context, id, owner string, payload []byte) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method upload_dataset took %s to complete", 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.UploadDataset(ctx, id, owner, payload)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) RemoveDataset(ctx context.Context, id string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method remove_dataset took %s to complete", 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.RemoveDataset(ctx, id)
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/ultravioletrs/cocos/datasets"
|
||||
)
|
||||
|
||||
var _ datasets.Service = (*metricsMiddleware)(nil)
|
||||
|
||||
type metricsMiddleware struct {
|
||||
counter metrics.Counter
|
||||
latency metrics.Histogram
|
||||
svc datasets.Service
|
||||
}
|
||||
|
||||
// MetricsMiddleware instruments core service by tracking request count and latency.
|
||||
func MetricsMiddleware(svc datasets.Service, counter metrics.Counter, latency metrics.Histogram) datasets.Service {
|
||||
return &metricsMiddleware{
|
||||
counter: counter,
|
||||
latency: latency,
|
||||
svc: svc,
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) CreateDataset(ctx context.Context, dts datasets.Dataset) (id string, err error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "create_dataset").Add(1)
|
||||
ms.latency.With("method", "create_dataset").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.CreateDataset(ctx, dts)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ViewDataset(ctx context.Context, owner, id string) (datasets.Dataset, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "view_dataset").Add(1)
|
||||
ms.latency.With("method", "view_dataset").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ViewDataset(ctx, owner, id)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ListDatasets(ctx context.Context, owner string, meta datasets.PageMetadata) (page datasets.Page, err error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_datasets").Add(1)
|
||||
ms.latency.With("method", "list_datasets").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ListDatasets(ctx, owner, meta)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) UpdateDataset(ctx context.Context, dataset datasets.Dataset) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "update_datasets").Add(1)
|
||||
ms.latency.With("method", "update_datasets").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.UpdateDataset(ctx, dataset)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) UploadDataset(ctx context.Context, id, owner string, payload []byte) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "update_datasets").Add(1)
|
||||
ms.latency.With("method", "update_datasets").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.UploadDataset(ctx, id, owner, payload)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) RemoveDataset(ctx context.Context, id string) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "remove_dataset").Add(1)
|
||||
ms.latency.With("method", "remove_dataset").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.RemoveDataset(ctx, id)
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/ultravioletrs/cocos/datasets"
|
||||
)
|
||||
|
||||
type createReq struct {
|
||||
dataset datasets.Dataset
|
||||
token string
|
||||
}
|
||||
|
||||
type listResourcesReq struct {
|
||||
owner string
|
||||
pageMetadata datasets.PageMetadata
|
||||
}
|
||||
|
||||
type updateReq struct {
|
||||
id string
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type uploadReq struct {
|
||||
owner string
|
||||
token string
|
||||
id string
|
||||
Payload []byte
|
||||
}
|
||||
|
||||
func (req uploadReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type viewRequest struct {
|
||||
id string
|
||||
owner string
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/ultravioletrs/cocos/datasets"
|
||||
)
|
||||
|
||||
type createRes struct {
|
||||
ID string
|
||||
created bool
|
||||
}
|
||||
|
||||
func (res createRes) Code() int {
|
||||
if res.created {
|
||||
return http.StatusCreated
|
||||
}
|
||||
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res createRes) Headers() map[string]string {
|
||||
if res.created {
|
||||
return map[string]string{
|
||||
"Location": fmt.Sprintf("/datasets/%s", res.ID),
|
||||
}
|
||||
}
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res createRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type errorRes struct {
|
||||
Err string `json:"error"`
|
||||
}
|
||||
|
||||
type removeRes struct{}
|
||||
|
||||
func (res removeRes) Code() int {
|
||||
return http.StatusNoContent
|
||||
}
|
||||
|
||||
func (res removeRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res removeRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type viewRes struct {
|
||||
datasets.Dataset
|
||||
}
|
||||
|
||||
func (res viewRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res viewRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res viewRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type datasetsPageRes struct {
|
||||
pageRes
|
||||
Datasets []datasets.Dataset `json:"datasets"`
|
||||
}
|
||||
|
||||
func (res datasetsPageRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res datasetsPageRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res datasetsPageRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type pageRes struct {
|
||||
Total uint64 `json:"total"`
|
||||
Offset uint64 `json:"offset"`
|
||||
Limit uint64 `json:"limit"`
|
||||
Order string `json:"order"`
|
||||
Dir string `json:"direction"`
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
"github.com/go-zoo/bone"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/ultravioletrs/cocos/datasets"
|
||||
"github.com/ultravioletrs/cocos/internal/apiutil"
|
||||
httputil "github.com/ultravioletrs/cocos/internal/http"
|
||||
)
|
||||
|
||||
const (
|
||||
contentType = "application/json"
|
||||
offsetKey = "offset"
|
||||
nameKey = "name"
|
||||
limitKey = "limit"
|
||||
orderKey = "order"
|
||||
dirKey = "dir"
|
||||
metadataKey = "metadata"
|
||||
sharedKey = "shared"
|
||||
defOffset = 0
|
||||
defLimit = 10
|
||||
bearerPrefix = "Bearer "
|
||||
)
|
||||
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHandler(svc datasets.Service, tracer opentracing.Tracer, logger logger.Logger) http.Handler {
|
||||
opts := []kithttp.ServerOption{
|
||||
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
|
||||
}
|
||||
|
||||
mux := bone.New()
|
||||
|
||||
mux.Post("/datasets", kithttp.NewServer(
|
||||
createDatasetsEndpoint(svc),
|
||||
decodeCreateDatasets,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Get("/datasets", kithttp.NewServer(
|
||||
listDatasetsEndpoint(svc),
|
||||
decodeList,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Get("/datasets/:id", kithttp.NewServer(
|
||||
viewDatasetsEndpoint(svc),
|
||||
decodeView,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Put("/datasets/:id", kithttp.NewServer(
|
||||
updateDatasetEndpoint(svc),
|
||||
decodeUpdateDataset,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Patch("/datasets/payload/:id", kithttp.NewServer(
|
||||
uploadDatasetEndpoint(svc),
|
||||
decodeUploadDataset,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Delete("/datasets/:id", kithttp.NewServer(
|
||||
removeDatasetEndpoint(svc),
|
||||
decodeView,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.GetFunc("/health", httputil.Health("datasets", "Datasets management service"))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return mux
|
||||
}
|
||||
|
||||
func decodeCreateDatasets(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := createReq{
|
||||
token: extractBearerToken(r),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req.dataset); err != nil {
|
||||
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err := apiutil.ReadStringQuery(r, nameKey, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
or, err := apiutil.ReadStringQuery(r, orderKey, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d, err := apiutil.ReadStringQuery(r, dirKey, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
shared, err := apiutil.ReadBoolQuery(r, sharedKey, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := listResourcesReq{
|
||||
pageMetadata: datasets.PageMetadata{
|
||||
Offset: o,
|
||||
Limit: l,
|
||||
Name: n,
|
||||
Order: or,
|
||||
Dir: d,
|
||||
Metadata: m,
|
||||
FetchSharedDatasets: shared,
|
||||
},
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := viewRequest{
|
||||
id: bone.GetValue(r, "id"),
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeUpdateDataset(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||
return nil, errors.ErrUnsupportedContentType
|
||||
}
|
||||
|
||||
req := updateReq{
|
||||
id: bone.GetValue(r, "id"),
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeUploadDataset(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||
return nil, errors.ErrUnsupportedContentType
|
||||
}
|
||||
|
||||
payload, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, errors.ErrMalformedEntity
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
req := uploadReq{
|
||||
token: extractBearerToken(r),
|
||||
id: bone.GetValue(r, "id"),
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
|
||||
if ar, ok := response.(mainflux.Response); ok {
|
||||
for k, v := range ar.Headers() {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
w.WriteHeader(ar.Code())
|
||||
|
||||
if ar.Empty() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
switch {
|
||||
case errors.Contains(err, errors.ErrInvalidQueryParams),
|
||||
errors.Contains(err, errors.ErrMalformedEntity):
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case errors.Contains(err, errors.ErrCreateEntity),
|
||||
errors.Contains(err, errors.ErrUpdateEntity),
|
||||
errors.Contains(err, errors.ErrViewEntity),
|
||||
errors.Contains(err, errors.ErrRemoveEntity):
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
default:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
if errorVal, ok := err.(errors.Error); ok {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
if err := json.NewEncoder(w).Encode(errorRes{Err: errorVal.Msg()}); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extractBearerToken(r *http.Request) string {
|
||||
token := r.Header.Get("Authorization")
|
||||
if !strings.HasPrefix(token, bearerPrefix) {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimPrefix(token, bearerPrefix)
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package datasets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Dataset struct {
|
||||
ID string `json:"id,omitempty" db:"id"`
|
||||
Token string `json:"token,omitempty" db:"token"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
Description string `json:"description,omitempty" db:"description"`
|
||||
Owner string `json:"owner,omitempty" db:"owner"`
|
||||
Size uint64 `json:"size,omitempty" db:"size"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty" db:"updated_at"`
|
||||
Location string `json:"location,omitempty" db:"location"`
|
||||
Format string `json:"format,omitempty" db:"format"`
|
||||
Metadata Metadata `json:"metadata,omitempty" db:"metadata"`
|
||||
Path string `json:"Path,omitempty" db:"path"`
|
||||
}
|
||||
|
||||
type Metadata map[string]interface{}
|
||||
|
||||
type PageMetadata struct {
|
||||
Total uint64 `json:"total,omitempty"`
|
||||
Offset uint64 `json:"offset,omitempty"`
|
||||
Limit uint64 `json:"limit,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Order string `json:"order,omitempty"`
|
||||
Dir string `json:"dir,omitempty"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
FetchSharedDatasets bool
|
||||
}
|
||||
|
||||
type Page struct {
|
||||
PageMetadata
|
||||
Datasets []Dataset `json:"datasets,omitempty"`
|
||||
}
|
||||
|
||||
func (d Dataset) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DatasetRepository specifies a dataset persistence API.
|
||||
type DatasetRepository interface {
|
||||
// Save persists multiple datasets. Datasets are saved using a transaction. If one dataset
|
||||
// fails then none will be saved. Successful operation is indicated by non-nil
|
||||
// error response.
|
||||
Save(ctx context.Context, dts Dataset) (string, error)
|
||||
|
||||
// RetrieveAll retrieves the subset of datasets owned by the specified user
|
||||
RetrieveByID(ctx context.Context, owner, id string) (Dataset, error)
|
||||
|
||||
// RetrieveAll retrieves the subset of datasets owned by the specified user
|
||||
RetrieveAll(ctx context.Context, owner string, pm PageMetadata) (Page, error)
|
||||
|
||||
// Update performs an update to the existing dataset. A non-nil error is
|
||||
// returned to indicate operation failure.
|
||||
Update(ctx context.Context, d Dataset) error
|
||||
|
||||
// Remove removes the dataset having the provided identifier, that is owned
|
||||
// by the specified user.
|
||||
Delete(ctx context.Context, id string) error
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Package dataset contains domain concept definitions
|
||||
// needed to support dataset service functionality.
|
||||
|
||||
package datasets
|
||||
@@ -1,360 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
"github.com/ultravioletrs/cocos/datasets"
|
||||
db "github.com/ultravioletrs/cocos/internal/db"
|
||||
)
|
||||
|
||||
const (
|
||||
errDuplicate = "unique_violation"
|
||||
errInvalid = "invalid_text_representation"
|
||||
errTruncation = "string_data_right_truncation"
|
||||
)
|
||||
|
||||
var _ datasets.DatasetRepository = (*datasetRepo)(nil)
|
||||
|
||||
type datasetRepo struct {
|
||||
db db.Database
|
||||
}
|
||||
|
||||
// NewRepository returns a new Datasets repository implementation.
|
||||
func NewRepository(db db.Database) datasets.DatasetRepository {
|
||||
return datasetRepo{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (repo datasetRepo) Save(ctx context.Context, dataset datasets.Dataset) (string, error) {
|
||||
q := `INSERT INTO datasets (id, owner, name, metadata, description, format, location, created_at, updated_at)
|
||||
VALUES (:id, :owner, :name, :metadata, :description, :format, :location, :created_at, :updated_at) RETURNING id;`
|
||||
|
||||
ds, err := fromDataset(dataset)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(errors.ErrCreateEntity, err)
|
||||
}
|
||||
|
||||
row, err := repo.db.NamedQueryContext(ctx, q, ds)
|
||||
if err != nil {
|
||||
pqErr, ok := err.(*pq.Error)
|
||||
if ok {
|
||||
switch pqErr.Code.Name() {
|
||||
case errInvalid, errTruncation:
|
||||
return "", errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
case errDuplicate:
|
||||
return "", errors.Wrap(errors.ErrConflict, err)
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.Wrap(errors.ErrCreateEntity, err)
|
||||
}
|
||||
defer row.Close()
|
||||
row.Next()
|
||||
var id string
|
||||
if err := row.Scan(&id); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (repo datasetRepo) RetrieveByID(ctx context.Context, owner, id string) (datasets.Dataset, error) {
|
||||
q := `SELECT id, name, owner, metadata, description, location, format, created_at, updated_at FROM datasets WHERE id = $1;`
|
||||
|
||||
dbds := dbDataset{ID: id}
|
||||
|
||||
if err := repo.db.QueryRowxContext(ctx, q, id).StructScan(&dbds); err != nil {
|
||||
pqErr, ok := err.(*pq.Error)
|
||||
if err == sql.ErrNoRows || ok && errInvalid == pqErr.Code.Name() {
|
||||
return datasets.Dataset{}, errors.Wrap(errors.ErrNotFound, err)
|
||||
}
|
||||
return datasets.Dataset{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
return toDataset(dbds)
|
||||
}
|
||||
|
||||
func (repo datasetRepo) RetrieveAll(ctx context.Context, owner string, pm datasets.PageMetadata) (datasets.Page, error) {
|
||||
nq, name := NameQuery(pm.Name)
|
||||
oq := OrderQuery(pm.Order)
|
||||
dq := DirQuery(pm.Dir)
|
||||
m, mq, err := MetadataQuery(pm.Metadata)
|
||||
if err != nil {
|
||||
return datasets.Page{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
var query []string
|
||||
if mq != "" {
|
||||
query = append(query, mq)
|
||||
}
|
||||
if nq != "" {
|
||||
query = append(query, nq)
|
||||
}
|
||||
|
||||
var whereClause string
|
||||
if len(query) > 0 {
|
||||
whereClause = fmt.Sprintf(" WHERE %s", strings.Join(query, " AND "))
|
||||
}
|
||||
|
||||
q := `SELECT id, name, COALESCE(description, '') AS description, owner, created_at,
|
||||
updated_at, location, format, metadata
|
||||
FROM datasets %s
|
||||
ORDER BY %s %s LIMIT :limit OFFSET :offset`
|
||||
|
||||
q = fmt.Sprintf(q, whereClause, oq, dq)
|
||||
params := map[string]interface{}{
|
||||
"owner": owner,
|
||||
"limit": pm.Limit,
|
||||
"offset": pm.Offset,
|
||||
"name": name,
|
||||
"metadata": m,
|
||||
}
|
||||
|
||||
rows, err := repo.db.NamedQueryContext(ctx, q, params)
|
||||
if err != nil {
|
||||
return datasets.Page{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var items []datasets.Dataset
|
||||
for rows.Next() {
|
||||
dbd := dbDataset{Owner: owner}
|
||||
if err := rows.StructScan(&dbd); err != nil {
|
||||
return datasets.Page{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
ds, err := toDataset(dbd)
|
||||
if err != nil {
|
||||
return datasets.Page{}, err
|
||||
}
|
||||
items = append(items, ds)
|
||||
}
|
||||
cq := fmt.Sprintf(`SELECT COUNT(*) FROM datasets %s;`, whereClause)
|
||||
|
||||
total, err := repo.total(ctx, cq, params)
|
||||
if err != nil {
|
||||
return datasets.Page{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
page := datasets.Page{
|
||||
Datasets: items,
|
||||
PageMetadata: datasets.PageMetadata{
|
||||
Total: total,
|
||||
Offset: pm.Offset,
|
||||
Limit: pm.Limit,
|
||||
Order: pm.Order,
|
||||
Dir: pm.Dir,
|
||||
},
|
||||
}
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (repo datasetRepo) Update(ctx context.Context, d datasets.Dataset) error {
|
||||
q := `UPDATE datasets SET name = :name, metadata = :metadata, description = :description WHERE id = :id;`
|
||||
|
||||
dbdts, err := toDBDataset(d)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.ErrUpdateEntity, err)
|
||||
}
|
||||
res, errdb := repo.db.NamedExecContext(ctx, q, dbdts)
|
||||
if errdb != nil {
|
||||
pqErr, ok := errdb.(*pq.Error)
|
||||
if ok {
|
||||
switch pqErr.Code.Name() {
|
||||
case errInvalid, errTruncation:
|
||||
return errors.Wrap(errors.ErrMalformedEntity, errdb)
|
||||
}
|
||||
}
|
||||
|
||||
return errors.Wrap(errors.ErrUpdateEntity, errdb)
|
||||
}
|
||||
|
||||
cnt, errdb := res.RowsAffected()
|
||||
if errdb != nil {
|
||||
return errors.Wrap(errors.ErrUpdateEntity, errdb)
|
||||
}
|
||||
|
||||
if cnt == 0 {
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo datasetRepo) Delete(ctx context.Context, id string) error {
|
||||
q := `DELETE FROM datasets WHERE id = :id`
|
||||
|
||||
ds := dbDataset{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
if _, err := repo.db.NamedExecContext(ctx, q, ds); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return errors.Wrap(errors.ErrNotFound, err)
|
||||
|
||||
}
|
||||
return errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo datasetRepo) total(ctx context.Context, query string, params interface{}) (uint64, error) {
|
||||
rows, err := repo.db.NamedQueryContext(ctx, query, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
total := uint64(0)
|
||||
if rows.Next() {
|
||||
if err := rows.Scan(&total); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
type dbDataset struct {
|
||||
ID string `db:"id"`
|
||||
Token string `db:"token"`
|
||||
Name string `db:"name"`
|
||||
Description string `db:"description"`
|
||||
Owner string `db:"owner"`
|
||||
Size uint64 `db:"size"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Location string `db:"location"`
|
||||
Format string `db:"format"`
|
||||
Metadata []byte `db:"metadata"`
|
||||
Path string `db:"path"`
|
||||
}
|
||||
|
||||
func toDataset(d dbDataset) (datasets.Dataset, error) {
|
||||
var metadata map[string]interface{}
|
||||
if d.Metadata != nil {
|
||||
if err := json.Unmarshal([]byte(d.Metadata), &metadata); err != nil {
|
||||
return datasets.Dataset{}, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
}
|
||||
ret := datasets.Dataset{
|
||||
ID: d.ID,
|
||||
Token: d.Token,
|
||||
Name: d.Name,
|
||||
Description: d.Description,
|
||||
Owner: d.Owner,
|
||||
Size: d.Size,
|
||||
CreatedAt: d.CreatedAt,
|
||||
UpdatedAt: d.UpdatedAt,
|
||||
Location: d.Location,
|
||||
Format: d.Format,
|
||||
Metadata: metadata,
|
||||
Path: d.Path,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func fromDataset(d datasets.Dataset) (dbDataset, error) {
|
||||
metadata := []byte("{}")
|
||||
if len(d.Metadata) > 0 {
|
||||
b, err := json.Marshal(d.Metadata)
|
||||
if err != nil {
|
||||
return dbDataset{}, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
metadata = b
|
||||
}
|
||||
ret := dbDataset{
|
||||
ID: d.ID,
|
||||
Token: d.Token,
|
||||
Name: d.Name,
|
||||
Description: d.Description,
|
||||
Owner: d.Owner,
|
||||
Size: d.Size,
|
||||
CreatedAt: d.CreatedAt,
|
||||
UpdatedAt: d.UpdatedAt,
|
||||
Location: d.Location,
|
||||
Format: d.Format,
|
||||
Metadata: metadata,
|
||||
Path: d.Path,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func NameQuery(name string) (string, string) {
|
||||
if name == "" {
|
||||
return "", ""
|
||||
}
|
||||
name = fmt.Sprintf(`%%%s%%`, strings.ToLower(name))
|
||||
nq := `LOWER(name) LIKE :name`
|
||||
return nq, name
|
||||
}
|
||||
|
||||
func OrderQuery(order string) string {
|
||||
switch order {
|
||||
case "name":
|
||||
return "name"
|
||||
default:
|
||||
return "id"
|
||||
}
|
||||
}
|
||||
|
||||
func DirQuery(dir string) string {
|
||||
switch dir {
|
||||
case "asc":
|
||||
return "ASC"
|
||||
default:
|
||||
return "DESC"
|
||||
}
|
||||
}
|
||||
|
||||
func MetadataQuery(m datasets.Metadata) ([]byte, string, error) {
|
||||
mq := ""
|
||||
mb := []byte("{}")
|
||||
if len(m) > 0 {
|
||||
mq = `metadata @> :metadata`
|
||||
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
mb = b
|
||||
}
|
||||
return mb, mq, nil
|
||||
}
|
||||
|
||||
func (repo datasetRepo) Remove(ctx context.Context, id string) error {
|
||||
dbth := dbDataset{
|
||||
ID: id,
|
||||
}
|
||||
q := `DELETE FROM datasets WHERE id = :id`
|
||||
if _, err := repo.db.NamedExecContext(ctx, q, dbth); err != nil {
|
||||
return errors.Wrap(errors.ErrRemoveEntity, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toDBDataset(ds datasets.Dataset) (dbDataset, error) {
|
||||
data := []byte("{}")
|
||||
if len(ds.Metadata) > 0 {
|
||||
b, err := json.Marshal(ds.Metadata)
|
||||
if err != nil {
|
||||
return dbDataset{}, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
data = b
|
||||
}
|
||||
|
||||
return dbDataset{
|
||||
ID: ds.ID,
|
||||
Owner: ds.Owner,
|
||||
Name: ds.Name,
|
||||
Description: ds.Description,
|
||||
Metadata: data,
|
||||
Size: ds.Size,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Package dataset contains domain concept definitions
|
||||
// needed to support dataset service functionality.
|
||||
|
||||
package postgres
|
||||
@@ -1,33 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
// used to register Postgres driver
|
||||
_ "github.com/lib/pq"
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
)
|
||||
|
||||
var Migrations = &migrate.MemoryMigrationSource{
|
||||
Migrations: []*migrate.Migration{
|
||||
{
|
||||
Id: "datasets_01",
|
||||
Up: []string{
|
||||
`CREATE TABLE IF NOT EXISTS datasets (
|
||||
id UUID,
|
||||
name VARCHAR(1025),
|
||||
owner VARCHAR(255),
|
||||
description text,
|
||||
created_at timestamp NOT NULL,
|
||||
updated_at timestamp NOT NULL,
|
||||
size INT,
|
||||
location TEXT,
|
||||
format VARCHAR(255),
|
||||
metadata JSON,
|
||||
PRIMARY KEY (id, owner)
|
||||
)`,
|
||||
},
|
||||
Down: []string{
|
||||
"DROP TABLE datasets",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package datasets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
)
|
||||
|
||||
type datasetsService struct {
|
||||
repo DatasetRepository
|
||||
idp mainflux.IDProvider
|
||||
}
|
||||
|
||||
func NewService(repo DatasetRepository, idp mainflux.IDProvider) Service {
|
||||
return &datasetsService{
|
||||
repo: repo,
|
||||
idp: idp,
|
||||
}
|
||||
}
|
||||
|
||||
// Service specifies an API that must be fulfiled by the domain service
|
||||
// implementation, and all of its decorators (e.g. logging & metrics).
|
||||
type Service interface {
|
||||
// CreateDatasets adds datasets to the user.
|
||||
CreateDataset(ctx context.Context, dataset Dataset) (string, error)
|
||||
|
||||
// ViewDataset retrieves data about the dataset identified with the provided
|
||||
// ID, that belongs to the user identified by the provided token.
|
||||
ViewDataset(ctx context.Context, owner, id string) (Dataset, error)
|
||||
|
||||
// ListDatasets retrieves data about subset of datasets that belongs to the
|
||||
// user identified by the provided token.
|
||||
ListDatasets(ctx context.Context, owner string, meta PageMetadata) (Page, error)
|
||||
|
||||
// UpdateDataset updates the dataset identified by the provided ID, that
|
||||
// belongs to the user identified by the provided token.
|
||||
UpdateDataset(ctx context.Context, dataset Dataset) error
|
||||
|
||||
// UploadDataset uploads the actual dataset content to the dataset path.
|
||||
UploadDataset(ctx context.Context, id, owner string, payload []byte) error
|
||||
|
||||
// RemoveDataset removes the dataset identified with the provided ID, that
|
||||
// belongs to the user identified by the provided token.
|
||||
RemoveDataset(ctx context.Context, id string) error
|
||||
}
|
||||
|
||||
func (ds *datasetsService) CreateDataset(ctx context.Context, dataset Dataset) (string, error) {
|
||||
id, err := ds.idp.ID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dataset.ID = id
|
||||
dataset.CreatedAt = time.Now()
|
||||
return ds.repo.Save(ctx, dataset)
|
||||
}
|
||||
|
||||
func (ds *datasetsService) ViewDataset(ctx context.Context, owner, id string) (Dataset, error) {
|
||||
return ds.repo.RetrieveByID(ctx, owner, id)
|
||||
}
|
||||
|
||||
func (ds *datasetsService) ListDatasets(ctx context.Context, owner string, pm PageMetadata) (Page, error) {
|
||||
page, err := ds.repo.RetrieveAll(ctx, owner, pm)
|
||||
if err != nil {
|
||||
return Page{}, err
|
||||
}
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (ds *datasetsService) UpdateDataset(ctx context.Context, dataset Dataset) error {
|
||||
return ds.repo.Update(ctx, dataset)
|
||||
}
|
||||
|
||||
func (ds *datasetsService) UploadDataset(ctx context.Context, id, owner string, payload []byte) error {
|
||||
dataset, err := ds.repo.RetrieveByID(ctx, owner, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := filepath.Join(dataset.Path, dataset.ID)
|
||||
file, err := os.Create(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
filename := path
|
||||
err = os.WriteFile(filename, payload, fs.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(filename, payload, fs.ModePerm)
|
||||
}
|
||||
|
||||
func (ds *datasetsService) RemoveDataset(ctx context.Context, id string) error {
|
||||
if err := ds.repo.Delete(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
return ds.repo.Delete(ctx, id)
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Package cocos acts as an umbrella package containing
|
||||
// multiple microservices and defines shared domain concepts.
|
||||
|
||||
package cocos
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
# Docker: Environment variables in Compose
|
||||
|
||||
## COCOS services
|
||||
|
||||
### Computations service
|
||||
COCOS_COMPUTATIONS_LOG_LEVEL=debug
|
||||
COCOS_COMPUTATIONS_DB_PORT=5432
|
||||
COCOS_COMPUTATIONS_DB_USER=cocos
|
||||
COCOS_COMPUTATIONS_DB_PASS=cocos
|
||||
COCOS_COMPUTATIONS_DB=computations
|
||||
COCOS_COMPUTATIONS_HTTP_PORT=9000
|
||||
|
||||
### Datasets service
|
||||
COCOS_DATASETS_LOG_LEVEL=debug
|
||||
COCOS_DATASETS_DB_PORT=5432
|
||||
COCOS_DATASETS_DB_USER=cocos
|
||||
COCOS_DATASETS_DB_PASS=cocos
|
||||
COCOS_DATASETS_DB=datasets
|
||||
COCOS_DATASETS_HTTP_PORT=9001
|
||||
|
||||
### Clients service
|
||||
UV_CLIENTS_LOG_LEVEL=debug
|
||||
UV_CLIENTS_DB_HOST=clients-db
|
||||
UV_CLIENTS_DB_PORT=5439
|
||||
UV_CLIENTS_DB_USER=uv
|
||||
UV_CLIENTS_DB_PASS=uv
|
||||
UV_CLIENTS_DB=clients
|
||||
UV_CLIENTS_DB_SSL_MODE=
|
||||
UV_CLIENTS_DB_SSL_CERT=
|
||||
UV_CLIENTS_DB_SSL_KEY=
|
||||
UV_CLIENTS_DB_SSL_ROOT_CERT=
|
||||
UV_CLIENTS_HTTP_PORT=9191
|
||||
UV_CLIENTS_GRPC_PORT=9192
|
||||
UV_CLIENTS_GRPC_TIMEOUT=1s
|
||||
UV_CLIENTS_SERVER_CERT=
|
||||
UV_CLIENTS_SERVER_KEY=
|
||||
|
||||
# Docker image tag
|
||||
MF_RELEASE_TAG=latest
|
||||
|
||||
# Docker image tag
|
||||
COCOS_RELEASE_TAG=latest
|
||||
@@ -1,19 +0,0 @@
|
||||
FROM golang:1.18-alpine AS builder
|
||||
ARG SVC
|
||||
ARG GOARCH
|
||||
ARG GOARM
|
||||
ARG VERSION
|
||||
ARG COMMIT
|
||||
ARG TIME
|
||||
|
||||
WORKDIR /go/src/github.com/ultravioletrs/cocos
|
||||
COPY . .
|
||||
RUN apk update \
|
||||
&& apk add make\
|
||||
&& make $SVC \
|
||||
&& mv build/cocos-$SVC /exe
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=builder /exe /
|
||||
ENTRYPOINT ["/exe"]
|
||||
@@ -1,4 +0,0 @@
|
||||
FROM scratch
|
||||
ARG SVC
|
||||
COPY cocos-$SVC /exe
|
||||
ENTRYPOINT ["/exe"]
|
||||
@@ -1,128 +0,0 @@
|
||||
version: "3.7"
|
||||
|
||||
networks:
|
||||
cocos-base-net:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
cocos-computations-db-volume:
|
||||
cocos-datasets-db-volume:
|
||||
cocos-clients-db-volume:
|
||||
|
||||
services:
|
||||
|
||||
# CoCoS services
|
||||
computations-db:
|
||||
image: postgres:13.3-alpine
|
||||
container_name: cocos-computations-db
|
||||
restart: on-failure
|
||||
environment:
|
||||
POSTGRES_USER: ${COCOS_COMPUTATIONS_DB_USER}
|
||||
POSTGRES_PASSWORD: ${COCOS_COMPUTATIONS_DB_PASS}
|
||||
POSTGRES_DB: ${COCOS_COMPUTATIONS_DB}
|
||||
networks:
|
||||
- cocos-base-net
|
||||
volumes:
|
||||
- cocos-computations-db-volume:/var/lib/postgresql/data
|
||||
|
||||
computations:
|
||||
image: cocos/computations:${COCOS_RELEASE_TAG}
|
||||
container_name: cocos-computations
|
||||
depends_on:
|
||||
- computations-db
|
||||
- clients
|
||||
restart: on-failure
|
||||
environment:
|
||||
COCOS_COMPUTATIONS_LOG_LEVEL: ${COCOS_COMPUTATIONS_LOG_LEVEL}
|
||||
COCOS_COMPUTATIONS_DB_HOST: computations-db
|
||||
COCOS_COMPUTATIONS_DB_PORT: ${COCOS_COMPUTATIONS_DB_PORT}
|
||||
COCOS_COMPUTATIONS_DB_USER: ${COCOS_COMPUTATIONS_DB_USER}
|
||||
COCOS_COMPUTATIONS_DB_PASS: ${COCOS_COMPUTATIONS_DB_PASS}
|
||||
COCOS_COMPUTATIONS_DB: ${COCOS_COMPUTATIONS_DB}
|
||||
COCOS_COMPUTATIONS_HTTP_PORT: ${COCOS_COMPUTATIONS_HTTP_PORT}
|
||||
COCOS_COMPUTATIONS_AUTH_GRPC_URL: clients:${UV_CLIENTS_GRPC_PORT}
|
||||
COCO_COMPUTATIONS_AUTH_GRPC_TIMEOUT: ${UV_CLIENTS_GRPC_TIMEOUT}
|
||||
ports:
|
||||
- ${COCOS_COMPUTATIONS_HTTP_PORT}:${COCOS_COMPUTATIONS_HTTP_PORT}
|
||||
networks:
|
||||
- cocos-base-net
|
||||
|
||||
datasets-db:
|
||||
image: postgres:13.3-alpine
|
||||
container_name: cocos-datasets-db
|
||||
restart: on-failure
|
||||
environment:
|
||||
POSTGRES_USER: ${COCOS_DATASETS_DB_USER}
|
||||
POSTGRES_PASSWORD: ${COCOS_DATASETS_DB_PASS}
|
||||
POSTGRES_DB: ${COCOS_DATASETS_DB}
|
||||
networks:
|
||||
- cocos-base-net
|
||||
volumes:
|
||||
- cocos-datasets-db-volume:/var/lib/postgresql/data
|
||||
|
||||
datasets:
|
||||
image: cocos/datasets:${COCOS_RELEASE_TAG}
|
||||
container_name: cocos-datasets
|
||||
depends_on:
|
||||
- datasets-db
|
||||
- clients
|
||||
restart: on-failure
|
||||
environment:
|
||||
COCOS_DATASETS_LOG_LEVEL: ${COCOS_DATASETS_LOG_LEVEL}
|
||||
COCOS_DATASETS_DB_HOST: datasets-db
|
||||
COCOS_DATASETS_DB_PORT: ${COCOS_DATASETS_DB_PORT}
|
||||
COCOS_DATASETS_DB_USER: ${COCOS_DATASETS_DB_USER}
|
||||
COCOS_DATASETS_DB_PASS: ${COCOS_DATASETS_DB_PASS}
|
||||
COCOS_DATASETS_DB: ${COCOS_DATASETS_DB}
|
||||
COCOS_DATASETS_HTTP_PORT: ${COCOS_DATASETS_HTTP_PORT}
|
||||
COCOS_DATASETS_AUTH_GRPC_URL: clients:${UV_CLIENTS_GRPC_PORT}
|
||||
COCOS_DATASETS_AUTH_GRPC_TIMEOUT: ${UV_CLIENTS_GRPC_TIMEOUT}
|
||||
ports:
|
||||
- ${COCOS_DATASETS_HTTP_PORT}:${COCOS_DATASETS_HTTP_PORT}
|
||||
networks:
|
||||
- cocos-base-net
|
||||
clients-db:
|
||||
image: postgres:13.3-alpine
|
||||
container_name: cocos-clients-db
|
||||
restart: on-failure
|
||||
expose:
|
||||
- ${UV_CLIENTS_DB_PORT}
|
||||
environment:
|
||||
POSTGRES_USER: ${UV_CLIENTS_DB_USER}
|
||||
POSTGRES_PASSWORD: ${UV_CLIENTS_DB_PASS}
|
||||
POSTGRES_DB: ${UV_CLIENTS_DB}
|
||||
networks:
|
||||
- cocos-base-net
|
||||
command: -p ${UV_CLIENTS_DB_PORT}
|
||||
volumes:
|
||||
- cocos-clients-db-volume:/var/lib/postgresql/data
|
||||
|
||||
clients:
|
||||
image: ultraviolet/clients:${MF_RELEASE_TAG}
|
||||
container_name: cocos-clients
|
||||
depends_on:
|
||||
- clients-db
|
||||
restart: on-failure
|
||||
expose:
|
||||
- ${UV_CLIENTS_GRPC_PORT}
|
||||
environment:
|
||||
UV_CLIENTS_LOG_LEVEL: ${UV_CLIENTS_LOG_LEVEL}
|
||||
UV_CLIENTS_DB_HOST: ${UV_CLIENTS_DB_HOST}
|
||||
UV_CLIENTS_DB_PORT: ${UV_CLIENTS_DB_PORT}
|
||||
UV_CLIENTS_DB_USER: ${UV_CLIENTS_DB_USER}
|
||||
UV_CLIENTS_DB_PASS: ${UV_CLIENTS_DB_PASS}
|
||||
UV_CLIENTS_DB: ${UV_CLIENTS_DB}
|
||||
UV_CLIENTS_DB_SSL_MODE: ${UV_CLIENTS_DB_SSL_MODE}
|
||||
UV_CLIENTS_DB_SSL_CERT: ${UV_CLIENTS_DB_SSL_CERT}
|
||||
UV_CLIENTS_DB_SSL_KEY: ${UV_CLIENTS_DB_SSL_KEY}
|
||||
UV_CLIENTS_DB_SSL_ROOT_CERT: ${UV_CLIENTS_DB_SSL_ROOT_CERT}
|
||||
UV_CLIENTS_HTTP_PORT: ${UV_CLIENTS_HTTP_PORT}
|
||||
UV_CLIENTS_GRPC_PORT: ${UV_CLIENTS_GRPC_PORT}
|
||||
UV_CLIENTS_GRPC_TIMEOUT: ${UV_CLIENTS_GRPC_TIMEOUT}
|
||||
UV_CLIENTS_SERVER_CERT: ${UV_CLIENTS_SERVER_CERT}
|
||||
UV_CLIENTS_SERVER_KEY: ${UV_CLIENTS_SERVER_KEY}
|
||||
ports:
|
||||
- ${UV_CLIENTS_HTTP_PORT}:${UV_CLIENTS_HTTP_PORT}
|
||||
- ${UV_CLIENTS_GRPC_PORT}:${UV_CLIENTS_GRPC_PORT}
|
||||
networks:
|
||||
- cocos-base-net
|
||||
@@ -1,16 +0,0 @@
|
||||
version: v0.6.0-alpha.3
|
||||
|
||||
log:
|
||||
level: debug
|
||||
|
||||
namespaces:
|
||||
- id: 0
|
||||
name: members
|
||||
|
||||
serve:
|
||||
read:
|
||||
host: 0.0.0.0
|
||||
port: 4466
|
||||
write:
|
||||
host: 0.0.0.0
|
||||
port: 4467
|
||||
@@ -1,8 +0,0 @@
|
||||
To: {{range $index, $v := .To}}{{if $index}},{{end}}{{$v}}{{end}}
|
||||
From: {{.From}}
|
||||
Subject: {{.Subject}}
|
||||
{{.Header}}
|
||||
You have a new message:
|
||||
{{.Content}}
|
||||
{{.Footer}}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
To: {{range $index, $v := .To}}{{if $index}},{{end}}{{$v}}{{end}}
|
||||
From: {{.From}}
|
||||
Subject: {{.Subject}}
|
||||
{{.Header}}
|
||||
You have initiated password reset.
|
||||
Follow the link below to reset password.
|
||||
{{.Content}}
|
||||
{{.Footer}}
|
||||
|
||||
@@ -1,41 +1,58 @@
|
||||
module github.com/ultravioletrs/cocos
|
||||
|
||||
go 1.18
|
||||
go 1.21.6
|
||||
|
||||
require (
|
||||
github.com/go-kit/kit v0.12.0
|
||||
github.com/go-zoo/bone v1.3.0
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/lib/pq v1.10.6
|
||||
github.com/mainflux/mainflux v0.0.0-20220624143112-931b48f3a7d6
|
||||
github.com/opentracing/opentracing-go v1.2.0
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/rubenv/sql-migrate v1.1.2
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible
|
||||
github.com/ultravioletrs/clients v0.0.0-20220812211530-116a1800cd38
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
|
||||
google.golang.org/grpc v1.47.0
|
||||
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/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/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
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.23.3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
||||
github.com/go-kit/log v0.2.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // 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.2.0 // indirect
|
||||
github.com/prometheus/common v0.33.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect
|
||||
google.golang.org/protobuf v1.28.0 // 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.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
|
||||
)
|
||||
|
||||
@@ -1,781 +1,167 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME=
|
||||
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
|
||||
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
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/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/caarlos0/env/v7 v7.1.0 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
|
||||
github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4=
|
||||
github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4=
|
||||
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
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/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
|
||||
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
|
||||
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
|
||||
github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY=
|
||||
github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY=
|
||||
github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519 h1:OpkN/n40cmKenDQS+IOAeW9DLhYy4DADSeZnouCEV/E=
|
||||
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/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=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
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/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=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
||||
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kortschak/utter v1.0.1/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
|
||||
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mainflux/mainflux v0.0.0-20220624143112-931b48f3a7d6 h1:um7t06LRWOhg7xkXDiqjE9nza0xYbCvpjMIJ4LpgX1U=
|
||||
github.com/mainflux/mainflux v0.0.0-20220624143112-931b48f3a7d6/go.mod h1:jWkCsO75NjakH18Qmz6TPq7cKzSMtAfe0K+ZalpI8To=
|
||||
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
|
||||
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
|
||||
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
|
||||
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
|
||||
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1 h1:oL4IBbcqwhhNWh31bjOX8C/OCy0zs9906d/VUru+bqg=
|
||||
github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
|
||||
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.33.0 h1:rHgav/0a6+uYgGdNt3jwz8FNSesO/Hsang3O0T9A5SE=
|
||||
github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rubenv/sql-migrate v1.1.2 h1:9M6oj4e//owVVHYrFISmY9LBRw6gzkCNmD9MV36tZeQ=
|
||||
github.com/rubenv/sql-migrate v1.1.2/go.mod h1:/7TZymwxN8VWumcIxw1jjHEcR1djpdkMHQPT4FWdnbQ=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
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=
|
||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
|
||||
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ultravioletrs/clients v0.0.0-20220812211530-116a1800cd38 h1:WrMG/LEFrJTGjodTVHxtWZMbxoyWUdFeWEFNkSHFc2M=
|
||||
github.com/ultravioletrs/clients v0.0.0-20220812211530-116a1800cd38/go.mod h1:6GNy758K7HXn9dTLB6Ig/8APix0dW1a4kR/m7EuyopQ=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
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/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=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
|
||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
||||
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
|
||||
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
|
||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
||||
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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
|
||||
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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.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 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac h1:qSNTkEN+L2mvWcLgJOR+8bdHX9rN/IdU3A1Ghpfb1Rg=
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg=
|
||||
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
|
||||
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
|
||||
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
source "$BR2_EXTERNAL_COCOS_PATH/package/agent/Config.in"
|
||||
@@ -0,0 +1,14 @@
|
||||
# Hardware Abstraction Layer (HAL) for Confidential Computing
|
||||
Cocos HAL for Linux is framework for building custom in-enclave Linux distribution.
|
||||
|
||||
## Usage
|
||||
HAL uses [Buildroot](https://buildroot.org/)'s [_External Tree_ mechanism](https://buildroot.org/downloads/manual/manual.html#outside-br-custom) for building custom distro:
|
||||
|
||||
```bash
|
||||
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
|
||||
make menuconfig
|
||||
make
|
||||
```
|
||||
@@ -0,0 +1,64 @@
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_HYPERVISOR_GUEST=y
|
||||
CONFIG_PARAVIRT=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_INET=y
|
||||
# CONFIG_WIRELESS is not set
|
||||
CONFIG_PCI=y
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_SCSI_VIRTIO=y
|
||||
CONFIG_ATA=y
|
||||
CONFIG_ATA_PIIX=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
CONFIG_NE2K_PCI=y
|
||||
CONFIG_8139CP=y
|
||||
# CONFIG_WLAN is not set
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_VIRTIO_CONSOLE=y
|
||||
CONFIG_HW_RANDOM_VIRTIO=m
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO_BALLOON=y
|
||||
CONFIG_VIRTIO_INPUT=y
|
||||
CONFIG_VIRTIO_MMIO=y
|
||||
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
|
||||
CONFIG_EXT4_FS=y
|
||||
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
|
||||
###
|
||||
CONFIG_EFI=y
|
||||
CONFIG_EFI_STUB=y
|
||||
CONFIG_VIRT_DRIVERS=y
|
||||
CONFIG_LOCALVERSION_AUTO=n
|
||||
CONFIG_AMD_MEM_ENCRYPT=y
|
||||
CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=n
|
||||
CONFIG_CRYPTO_AES=y
|
||||
CONFIG_SYSTEM_TRUSTED_KEYS=n
|
||||
CONFIG_SYSTEM_REVOCATION_KEYS=n
|
||||
CONFIG_MODULE_SIG_KEY=n
|
||||
CONFIG_SEV_GUEST=y
|
||||
CONFIG_IOMMU_DEFAULT_PASSTHROUGH=n
|
||||
CONFIG_PREEMPT_COUNT=n
|
||||
CONFIG_PREEMPT=n
|
||||
CONFIG_PREEMPT_DYNAMIC=n
|
||||
CONFIG_DEBUG_PREEMPT=n
|
||||
CONFIG_CGROUP_MISC=y
|
||||
CONFIG_X86_CPUID=y
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -u
|
||||
set -e
|
||||
|
||||
# Add a console on tty1
|
||||
if [ -e ${TARGET_DIR}/etc/inittab ]; then
|
||||
grep -qE '^tty1::' ${TARGET_DIR}/etc/inittab || \
|
||||
sed -i '/GENERIC_SERIAL/a\
|
||||
tty1::respawn:/sbin/getty -L tty1 0 vt100 # QEMU graphical window' ${TARGET_DIR}/etc/inittab
|
||||
fi
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
COCOS_BOARD_DIR="$(dirname "$0")"
|
||||
DEFCONFIG_NAME="$(basename "$2")"
|
||||
README_FILES="${COCOS_BOARD_DIR}/readme.txt"
|
||||
START_QEMU_SCRIPT="${BINARIES_DIR}/start-qemu.sh"
|
||||
|
||||
if [[ "${DEFCONFIG_NAME}" =~ ^"cocos_*" ]]; then
|
||||
# Not a Qemu defconfig, can't test.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Search for "# qemu_*_defconfig" tag in all readme.txt files.
|
||||
# Qemu command line on multilines using back slash are accepted.
|
||||
# shellcheck disable=SC2086 # glob over each readme file
|
||||
QEMU_CMD_LINE="$(sed -r ':a; /\\$/N; s/\\\n//; s/\t/ /; ta; /# '"${DEFCONFIG_NAME}"'$/!d; s/#.*//' ${README_FILES})"
|
||||
|
||||
if [ -z "${QEMU_CMD_LINE}" ]; then
|
||||
# No Qemu cmd line found, can't test.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Remove output/images path since the script will be in
|
||||
# the same directory as the kernel and the rootfs images.
|
||||
QEMU_CMD_LINE="${QEMU_CMD_LINE//output\/images\//}"
|
||||
|
||||
# Remove -serial stdio if present, keep it as default args
|
||||
DEFAULT_ARGS="$(sed -r -e '/-serial stdio/!d; s/.*(-serial stdio).*/\1/' <<<"${QEMU_CMD_LINE}")"
|
||||
QEMU_CMD_LINE="${QEMU_CMD_LINE//-serial stdio/}"
|
||||
|
||||
# Remove any string before qemu-system-*
|
||||
QEMU_CMD_LINE="$(sed -r -e 's/^.*(qemu-system-)/\1/' <<<"${QEMU_CMD_LINE}")"
|
||||
|
||||
# Disable graphical output and redirect serial I/Os to console
|
||||
case ${DEFCONFIG_NAME} in
|
||||
(qemu_sh4eb_r2d_defconfig|qemu_sh4_r2d_defconfig)
|
||||
# Special case for SH4
|
||||
SERIAL_ARGS="-serial stdio -display none"
|
||||
;;
|
||||
(*)
|
||||
SERIAL_ARGS="-nographic"
|
||||
;;
|
||||
esac
|
||||
|
||||
sed -e "s|@SERIAL_ARGS@|${SERIAL_ARGS}|g" \
|
||||
-e "s|@DEFAULT_ARGS@|${DEFAULT_ARGS}|g" \
|
||||
-e "s|@QEMU_CMD_LINE@|${QEMU_CMD_LINE}|g" \
|
||||
-e "s|@HOST_DIR@|${HOST_DIR}|g" \
|
||||
<"${COCOS_BOARD_DIR}/start-qemu.sh.in" \
|
||||
>"${START_QEMU_SCRIPT}"
|
||||
chmod +x "${START_QEMU_SCRIPT}"
|
||||
@@ -0,0 +1,7 @@
|
||||
Run the emulation with:
|
||||
|
||||
qemu-system-x86_64 -M pc -kernel output/images/bzImage -drive file=output/images/rootfs.ext2,if=virtio,format=raw -append "rootwait root=/dev/vda console=tty1 console=ttyS0" -serial stdio -net nic,model=virtio -net user # cocos_defconfig
|
||||
|
||||
Optionally add -smp N to emulate a SMP system with N CPUs.
|
||||
|
||||
The login prompt will appear in the graphical window.
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
BINARIES_DIR="${0%/*}/"
|
||||
# shellcheck disable=SC2164
|
||||
cd "${BINARIES_DIR}"
|
||||
|
||||
mode_serial=false
|
||||
mode_sys_qemu=false
|
||||
while [ "$1" ]; do
|
||||
case "$1" in
|
||||
--serial-only|serial-only) mode_serial=true; shift;;
|
||||
--use-system-qemu) mode_sys_qemu=true; shift;;
|
||||
--) shift; break;;
|
||||
*) echo "unknown option: $1" >&2; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ${mode_serial}; then
|
||||
EXTRA_ARGS='@SERIAL_ARGS@'
|
||||
else
|
||||
EXTRA_ARGS='@DEFAULT_ARGS@'
|
||||
fi
|
||||
|
||||
if ! ${mode_sys_qemu}; then
|
||||
export PATH="@HOST_DIR@/bin:${PATH}"
|
||||
fi
|
||||
|
||||
exec @QEMU_CMD_LINE@ ${EXTRA_ARGS} "$@"
|
||||
@@ -0,0 +1,48 @@
|
||||
# Architecture
|
||||
BR2_x86_64=y
|
||||
|
||||
# System
|
||||
BR2_TARGET_GENERIC_HOSTNAME="cocos"
|
||||
BR2_TARGET_GENERIC_ISSUE="Welcome to Cocos"
|
||||
BR2_PACKAGE_DHCP=y
|
||||
BR2_PACKAGE_DHCP_CLIENT=y
|
||||
BR2_INIT_SYSTEMD=y
|
||||
|
||||
# Filesystem
|
||||
# BR2_TARGET_ROOTFS_TAR is not set
|
||||
BR2_TARGET_ROOTFS_CPIO=y
|
||||
BR2_TARGET_ROOTFS_CPIO_FULL=y
|
||||
BR2_TARGET_ROOTFS_CPIO_GZIP=y
|
||||
|
||||
# Image
|
||||
BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_COCOS_PATH)/board/cocos/post-build.sh"
|
||||
|
||||
# Image
|
||||
BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_COCOS_PATH)/board/cocos/post-image.sh"
|
||||
BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_DEFCONFIG)"
|
||||
|
||||
# Linux headers same as kernel
|
||||
BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_6_6=y
|
||||
BR2_TOOLCHAIN_HEADERS_AT_LEAST_6_5=y
|
||||
BR2_TOOLCHAIN_HEADERS_AT_LEAST_6_6=y
|
||||
BR2_TOOLCHAIN_HEADERS_LATEST=y
|
||||
BR2_TOOLCHAIN_HEADERS_AT_LEAST="6.6"
|
||||
|
||||
# Kernel
|
||||
BR2_LINUX_KERNEL=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_GIT=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_REPO_URL="https://github.com/torvalds/linux.git"
|
||||
BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION="v6.6"
|
||||
BR2_LINUX_KERNEL_VERSION="v6.6"
|
||||
BR2_LINUX_KERNEL_PATCH=""
|
||||
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_COCOS_PATH)/board/cocos/linux.config"
|
||||
BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
|
||||
|
||||
# host-qemu for gitlab testing
|
||||
BR2_PACKAGE_HOST_QEMU=y
|
||||
BR2_PACKAGE_HOST_QEMU_SYSTEM_MODE=y
|
||||
|
||||
# Python
|
||||
BR2_PACKAGE_PYTHON3=y
|
||||
BR2_PACKAGE_PYTHON_PIP=y
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user