-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for external storages on lock, unlock, update, get, and delete #654
Add support for external storages on lock, unlock, update, get, and delete #654
Conversation
7e26750
to
d13ea72
Compare
d13ea72
to
d8e8eab
Compare
a3819e5
to
c845697
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the provided test works, I wasn't able to test it manually, as I run into some problems:
When I wanted to create TI with Backend ID created during tests (I commented cleanup
so I made sure there is such TI), all my mutations failed:
1. Create TI without context
query:
mutation CreateTypeInstances {
createTypeInstances(
in: {
typeInstances: [
{
alias: "helm-release"
typeRef: { path: "cap.type.helm.chart.release", revision: "0.1.0" }
value: {
key: "test" # same as it was
}
backend: {
id: "1cd21f38-49f0-42d9-b2f5-c3e69e00c896" # it's like that already.
}
}
{
alias: "helm-release2"
typeRef: { path: "cap.type.helm.chart.release", revision: "0.1.0" }
value: {
key: "test" # same as it was
}
# backend: {
# id: "123" # it's like that already.
# context: { # new property of type `Any!`
# name: "release-name",
# namespace: "release-namespace",
# }
# }
}
]
usesRelations: [ # All the TIs exist
{from: "helm-release", to: "helm-release2"}
{from: "54f39b4d-280b-406f-afa9-5645328fae70", to: "helm-release2"}
{from: "61d48278-3c5c-4eb5-8b6b-de4ce4582128", to: "helm-release2"}
]
}
) {
id
alias
}
}
logs:
2022-03-09T12:44:58.298+0100 INFO secret-storage-backend secret-storage-backend/server.go:314 getting whole secret {"path": "/tmp/capact/f2863a93-ccc6-46c8-a535-d55836f348e5", "provider": "dotenv"}
output:
{
"errors": [
{
"message": "/storage_backend.StorageBackend/OnDelete NOT_FOUND: path \"/tmp/capact/f2863a93-ccc6-46c8-a535-d55836f348e5\" in provider \"dotenv\" not found",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createTypeInstances"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"path": "/storage_backend.StorageBackend/OnDelete",
"code": 5,
"details": "path \"/tmp/capact/f2863a93-ccc6-46c8-a535-d55836f348e5\" in provider \"dotenv\" not found",
"name": "ClientError",
"stacktrace": [
"ClientError: /storage_backend.StorageBackend/OnDelete NOT_FOUND: path \"/tmp/capact/f2863a93-ccc6-46c8-a535-d55836f348e5\" in provider \"dotenv\" not found",
" at wrapClientError (/Users/pkosiec/repositories/capact/hub-js/node_modules/nice-grpc/lib/client/wrapClientError.js:9:16)",
" at Object.callback (/Users/pkosiec/repositories/capact/hub-js/node_modules/nice-grpc/lib/client/createUnaryMethod.js:31:66)",
" at Object.onReceiveStatus (/Users/pkosiec/repositories/capact/hub-js/node_modules/@grpc/grpc-js/build/src/client.js:180:36)",
" at Object.onReceiveStatus (/Users/pkosiec/repositories/capact/hub-js/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:365:141)",
" at Object.onReceiveStatus (/Users/pkosiec/repositories/capact/hub-js/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:328:181)",
" at /Users/pkosiec/repositories/capact/hub-js/node_modules/@grpc/grpc-js/build/src/call-stream.js:182:78",
" at processTicksAndRejections (node:internal/process/task_queues:78:11)"
]
}
}
}
],
"data": null
}
I believe this is "OnDelete" because the transaction tried to do rollback, but it would be good to know the root cause.
2. Create TI with context
This returns a different error:
mutation CreateTypeInstances {
createTypeInstances(
in: {
typeInstances: [
{
alias: "helm-release"
typeRef: { path: "cap.type.helm.chart.release", revision: "0.1.0" }
value: {
key: "test" # same as it was
}
backend: {
id: "1cd21f38-49f0-42d9-b2f5-c3e69e00c896"
context: {
provider: "mock-me" # same with dotenv
}
}
}
]
usesRelations: []
}
) {
id
alias
}
}
result:
{
"errors": [
{
"message": "Cannot convert object to primitive value",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createTypeInstances"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"TypeError: Cannot convert object to primitive value",
" at TextEncoder.encode (node:internal/encoding:333:32)",
" at DelegatedStorageService.encode (/Users/pkosiec/repositories/capact/hub-js/dist/local/storage/service.js:261:34)",
" at DelegatedStorageService.Delete (/Users/pkosiec/repositories/capact/hub-js/dist/local/storage/service.js:147:31)",
" at processTicksAndRejections (node:internal/process/task_queues:96:5)",
" at async createTypeInstances (/Users/pkosiec/repositories/capact/hub-js/dist/local/mutation/create-type-instances.js:44:9)"
]
}
}
}
],
"data": null
}
The /tmp/capact
is empty in both cases after running the mutation.
Additional data - Get query for backend TI:
query Get($typeInstanceId: ID!) {
typeInstance(id: $typeInstanceId) {
resourceVersions {
spec {
value
}
}
id
backend {
abstract
id
}
usedBy {
id
}
}
}
output:
{
"data": {
"typeInstance": {
"resourceVersions": [
{
"spec": {
"value": {
"acceptValue": true,
"contextSchema": "{\n\t\"$id\": \"#/properties/contextSchema\",\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"provider\": {\n\t\t\t\"$id\": \"#/properties/contextSchema/properties/name\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"const\": \"dotenv\"\n\t\t}\n\t},\n\t\"additionalProperties\": false\n}",
"url": "0.0.0.0:50051"
}
}
}
],
"id": "1cd21f38-49f0-42d9-b2f5-c3e69e00c896",
"backend": {
"abstract": true,
"id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
},
"usedBy": []
}
}
}
@mszostok could you please try by your own and see whether you also encounter such issues? Thanks!
hub-js/src/local/storage/service.ts
Outdated
}); | ||
const cli = await this.getClient(input.backend.id); | ||
if (!cli) { | ||
// TODO(https://github.com/capactio/capact/issues/604): remove after using a real backend in e2e tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is done in #634, let's make sure @mkuziemko is aware of that (that's why I'm mentioning Mati) 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During manual testing I spotted two bugs. Once they are resolved, the PR is ready to be merged 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, great work! 🚀
6a77832
to
ebe69db
Compare
ebe69db
to
048f86f
Compare
Description
Changes proposed in this pull request:
backend.context
fieldNew scope:
Testing
The test that I wrote, proves that it works e2e (Go client -> GraphQL -> Local Hub -> External Storage).
Run neo4j:
Run modified storage server:
Run Local Hub:
Check that no data is stored:
ls /tmp/capact
Run test:
You should output that describe Local Hub state after each operation.
Check that no data is stored:
ls /tmp/capact
as the above test also cleans up all created TypeInstances and gRPC call is also executed against external backends.Related issue(s)
Notes
Sometimes I got unpredictable result from
dotenv
:and in file:
I'm not sure how this can happen, as it's not possible via exposed API. Probably there is some "race" directly in used library with
Put
implementation. However, we decided that backends don't need to be thread safe. To resolve that issue I used the mutex lib to prevent concurrent execution ofvalue
field resolver.