mirror of
https://github.com/onepanelio/onepanel.git
synced 2025-11-03 01:53:38 +08:00
Compare commits
127 Commits
v0.11.0
...
v0.12.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb4a229984 | ||
|
|
c3f76f971c | ||
|
|
dc27fd3319 | ||
|
|
0a8744656c | ||
|
|
1910a47a21 | ||
|
|
e3fd781cd3 | ||
|
|
5eff42fb2c | ||
|
|
3067c62a7f | ||
|
|
adb7f0b74a | ||
|
|
bdc3d99fed | ||
|
|
aa6725fbc9 | ||
|
|
8da35695de | ||
|
|
fc7cdb5681 | ||
|
|
7bbeba544d | ||
|
|
5b7f5c9724 | ||
|
|
1effb919d6 | ||
|
|
7f6f58884a | ||
|
|
16274dd946 | ||
|
|
cebb412175 | ||
|
|
5dbb2104ce | ||
|
|
2232d4e946 | ||
|
|
e66c095500 | ||
|
|
7af3c9dd7c | ||
|
|
b01c0c41a8 | ||
|
|
59d0c95307 | ||
|
|
d319d41929 | ||
|
|
9435404701 | ||
|
|
b6b8652829 | ||
|
|
5073cbdff1 | ||
|
|
0b77438d57 | ||
|
|
59e7d58503 | ||
|
|
fa96d6ef66 | ||
|
|
6c0d3fe598 | ||
|
|
b0361cdc6c | ||
|
|
e526505365 | ||
|
|
993ce397aa | ||
|
|
7a8df485ad | ||
|
|
7936eac98d | ||
|
|
94ae9071aa | ||
|
|
8b6d10d112 | ||
|
|
a94ae526ca | ||
|
|
8e2b1ab106 | ||
|
|
e83e5d495e | ||
|
|
0f5cf7be4d | ||
|
|
7295ba36b3 | ||
|
|
a8958b0136 | ||
|
|
69a6a72303 | ||
|
|
92f2be7cac | ||
|
|
46f4465103 | ||
|
|
ca45e29dd5 | ||
|
|
dfd892d6f1 | ||
|
|
c1d123ec2c | ||
|
|
7c2001f5ac | ||
|
|
aff166fb40 | ||
|
|
40759738ae | ||
|
|
a0454cdfc3 | ||
|
|
41d3d7be34 | ||
|
|
4dc60c2113 | ||
|
|
3cf11eaa58 | ||
|
|
3b605545b1 | ||
|
|
eef3309080 | ||
|
|
4e3eaae1f6 | ||
|
|
2ddab18a59 | ||
|
|
6727b00b05 | ||
|
|
81c05f9954 | ||
|
|
ac5bf65ae9 | ||
|
|
66431a21eb | ||
|
|
8d662d6ce0 | ||
|
|
ad16285fd4 | ||
|
|
f024889ca8 | ||
|
|
d7df089d31 | ||
|
|
2cd3f76299 | ||
|
|
965e8dda92 | ||
|
|
c13c868143 | ||
|
|
e2f94e937c | ||
|
|
df74766a66 | ||
|
|
30305f42e1 | ||
|
|
41b2f322da | ||
|
|
946ab11dab | ||
|
|
886e39244e | ||
|
|
7ce8d9cdfa | ||
|
|
2868ab69c9 | ||
|
|
18428c4e82 | ||
|
|
df3dba4e2e | ||
|
|
d097cdfefe | ||
|
|
cee49e67f4 | ||
|
|
640c7b54f5 | ||
|
|
655020b54b | ||
|
|
5117c8b34e | ||
|
|
045912fe5c | ||
|
|
3673b3da59 | ||
|
|
d7db598cc6 | ||
|
|
f3a2856d65 | ||
|
|
f1045710a0 | ||
|
|
ed621633df | ||
|
|
c5d1ec9b1f | ||
|
|
5c225b405d | ||
|
|
bd5ec0e7c2 | ||
|
|
176fcc3008 | ||
|
|
945b3bc2e5 | ||
|
|
1bdd6a7eda | ||
|
|
f78ae63afa | ||
|
|
114f290cde | ||
|
|
1a15df4999 | ||
|
|
f9f6d75be8 | ||
|
|
782617a3e9 | ||
|
|
0ec109da2b | ||
|
|
b8b9ff2543 | ||
|
|
0b54bd1c43 | ||
|
|
cb27809665 | ||
|
|
252e53a793 | ||
|
|
05fc2b1422 | ||
|
|
839b9ac2e3 | ||
|
|
2091485345 | ||
|
|
ec2f9b3ecd | ||
|
|
a2c11050fc | ||
|
|
b3f9c44482 | ||
|
|
8aa10c9630 | ||
|
|
6c8f6cee5b | ||
|
|
60bfe4e02a | ||
|
|
9e022b24f7 | ||
|
|
be63c412be | ||
|
|
62f53ee605 | ||
|
|
81241b0cc9 | ||
|
|
90602b8f87 | ||
|
|
ff2e948623 | ||
|
|
a831ed164d |
26
.github/workflows/run_unit_tests.yaml
vendored
Normal file
26
.github/workflows/run_unit_tests.yaml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Run Unit Tests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- test/docker.database
|
||||
jobs:
|
||||
test-code-job:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12.3
|
||||
env:
|
||||
POSTGRES_DB: onepanel
|
||||
POSTGRES_USER: admin
|
||||
POSTGRES_PASSWORD: tester
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Run testing code
|
||||
uses: cedrickring/golang-action@1.5.2
|
||||
with:
|
||||
args: go test github.com/onepanelio/core/pkg -db=postgres
|
||||
5
Makefile
5
Makefile
@@ -34,3 +34,8 @@ docker-push:
|
||||
docker push onepanel/core:$(COMMIT_HASH)
|
||||
|
||||
docker: docker-build docker-push
|
||||
|
||||
run-tests:
|
||||
docker run --rm --name test-onepanel-postgres -p 5432:5432 -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=tester -e POSTGRES_DB=onepanel -d postgres:12.3
|
||||
go test github.com/onepanelio/core/pkg -count=1 ||:
|
||||
docker stop test-onepanel-postgres
|
||||
@@ -1707,57 +1707,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/apis/v1beta1/{namespace}/workflow_templates/{workflowTemplate.uid}/versions/{workflowTemplate.version}": {
|
||||
"put": {
|
||||
"operationId": "UpdateWorkflowTemplateVersion",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/WorkflowTemplate"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/grpc.gateway.runtime.Error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "namespace",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "workflowTemplate.uid",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "workflowTemplate.version",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/WorkflowTemplate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"WorkflowTemplateService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/apis/v1beta1/{namespace}/workspace_templates": {
|
||||
"get": {
|
||||
"operationId": "ListWorkspaceTemplates",
|
||||
|
||||
@@ -1093,7 +1093,7 @@ var file_workflow_template_proto_rawDesc = []byte{
|
||||
0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32, 0xa3, 0x0c, 0x0a, 0x17, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32, 0xbb, 0x0a, 0x0a, 0x17, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x12, 0x9b, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x61,
|
||||
@@ -1105,94 +1105,79 @@ var file_workflow_template_proto_rawDesc = []byte{
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x3a, 0x10, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12,
|
||||
0xe5, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0xc2, 0x01, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x12, 0x29, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c,
|
||||
0x61, 0x74, 0x65, 0x22, 0x81, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x7b, 0x1a, 0x67, 0x2f, 0x61,
|
||||
0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x69, 0x64,
|
||||
0x7d, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x7d, 0x3a, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54,
|
||||
0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0xc2, 0x01, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65,
|
||||
0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70,
|
||||
0x6c, 0x61, 0x74, 0x65, 0x22, 0x66, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x60, 0x22, 0x4c, 0x2f, 0x61,
|
||||
0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x69, 0x64,
|
||||
0x7d, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x10, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0xd3, 0x01, 0x0a,
|
||||
0x13, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70,
|
||||
0x6c, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f,
|
||||
0x6e, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x83, 0x01, 0x82,
|
||||
0xd3, 0xe4, 0x93, 0x02, 0x7d, 0x12, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62,
|
||||
0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d,
|
||||
0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x5a, 0x47, 0x12, 0x45, 0x2f, 0x61, 0x70,
|
||||
0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f,
|
||||
0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x7d, 0x12, 0xb8, 0x01, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x12, 0x28, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3d,
|
||||
0x12, 0x3b, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f,
|
||||
0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b,
|
||||
0x75, 0x69, 0x64, 0x7d, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x94, 0x01,
|
||||
0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65,
|
||||
0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d,
|
||||
0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34,
|
||||
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x12, 0x2c, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31,
|
||||
0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
|
||||
0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c,
|
||||
0x61, 0x74, 0x65, 0x73, 0x12, 0xe9, 0x01, 0x0a, 0x15, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x21,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x95, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
||||
0x8e, 0x01, 0x12, 0x3f, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61,
|
||||
0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73,
|
||||
0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x2f, 0x7b, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x7d, 0x5a, 0x4b, 0x12, 0x49, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62,
|
||||
0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d,
|
||||
0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x2f,
|
||||
0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x7b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x7d,
|
||||
0x12, 0xa8, 0x01, 0x0a, 0x17, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x42, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3c, 0x1a,
|
||||
0x3a, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75,
|
||||
0x69, 0x64, 0x7d, 0x2f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x66, 0x82, 0xd3,
|
||||
0xe4, 0x93, 0x02, 0x60, 0x22, 0x4c, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65,
|
||||
0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74,
|
||||
0x65, 0x73, 0x2f, 0x7b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70,
|
||||
0x6c, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x3a, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70,
|
||||
0x6c, 0x61, 0x74, 0x65, 0x12, 0xd3, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65,
|
||||
0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70,
|
||||
0x6c, 0x61, 0x74, 0x65, 0x22, 0x83, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x7d, 0x12, 0x32, 0x2f,
|
||||
0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64,
|
||||
0x7d, 0x5a, 0x47, 0x12, 0x45, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74,
|
||||
0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65,
|
||||
0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x2f, 0x7b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0xb8, 0x01, 0x0a, 0x1c, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c,
|
||||
0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65,
|
||||
0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65,
|
||||
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3d, 0x12, 0x3b, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f,
|
||||
0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
|
||||
0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d,
|
||||
0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x94, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x12,
|
||||
0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x12, 0x2c,
|
||||
0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x12, 0xe9, 0x01, 0x0a,
|
||||
0x15, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65,
|
||||
0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6c, 0x6f,
|
||||
0x6e, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65,
|
||||
0x22, 0x95, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x8e, 0x01, 0x12, 0x3f, 0x2f, 0x61, 0x70, 0x69,
|
||||
0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73,
|
||||
0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74,
|
||||
0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x63,
|
||||
0x6c, 0x6f, 0x6e, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x5a, 0x4b, 0x12, 0x49, 0x2f,
|
||||
0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64,
|
||||
0x7d, 0x2f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x7b,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x17, 0x41, 0x72, 0x63,
|
||||
0x68, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70,
|
||||
0x6c, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x72, 0x63, 0x68, 0x69,
|
||||
0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54,
|
||||
0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x42, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3c, 0x1a, 0x3a, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76,
|
||||
0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
|
||||
0x65, 0x7d, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x65, 0x6d, 0x70,
|
||||
0x6c, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x61, 0x72, 0x63, 0x68,
|
||||
0x69, 0x76, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1235,23 +1220,21 @@ var file_workflow_template_proto_depIdxs = []int32{
|
||||
10, // 6: api.WorkflowTemplate.stats:type_name -> api.WorkflowExecutionStatisticReport
|
||||
11, // 7: api.WorkflowTemplate.cronStats:type_name -> api.CronWorkflowStatisticsReport
|
||||
0, // 8: api.WorkflowTemplateService.CreateWorkflowTemplate:input_type -> api.CreateWorkflowTemplateRequest
|
||||
1, // 9: api.WorkflowTemplateService.UpdateWorkflowTemplateVersion:input_type -> api.UpdateWorkflowTemplateVersionRequest
|
||||
0, // 10: api.WorkflowTemplateService.CreateWorkflowTemplateVersion:input_type -> api.CreateWorkflowTemplateRequest
|
||||
2, // 11: api.WorkflowTemplateService.GetWorkflowTemplate:input_type -> api.GetWorkflowTemplateRequest
|
||||
4, // 12: api.WorkflowTemplateService.ListWorkflowTemplateVersions:input_type -> api.ListWorkflowTemplateVersionsRequest
|
||||
6, // 13: api.WorkflowTemplateService.ListWorkflowTemplates:input_type -> api.ListWorkflowTemplatesRequest
|
||||
3, // 14: api.WorkflowTemplateService.CloneWorkflowTemplate:input_type -> api.CloneWorkflowTemplateRequest
|
||||
8, // 15: api.WorkflowTemplateService.ArchiveWorkflowTemplate:input_type -> api.ArchiveWorkflowTemplateRequest
|
||||
12, // 16: api.WorkflowTemplateService.CreateWorkflowTemplate:output_type -> api.WorkflowTemplate
|
||||
12, // 17: api.WorkflowTemplateService.UpdateWorkflowTemplateVersion:output_type -> api.WorkflowTemplate
|
||||
12, // 18: api.WorkflowTemplateService.CreateWorkflowTemplateVersion:output_type -> api.WorkflowTemplate
|
||||
12, // 19: api.WorkflowTemplateService.GetWorkflowTemplate:output_type -> api.WorkflowTemplate
|
||||
5, // 20: api.WorkflowTemplateService.ListWorkflowTemplateVersions:output_type -> api.ListWorkflowTemplateVersionsResponse
|
||||
7, // 21: api.WorkflowTemplateService.ListWorkflowTemplates:output_type -> api.ListWorkflowTemplatesResponse
|
||||
12, // 22: api.WorkflowTemplateService.CloneWorkflowTemplate:output_type -> api.WorkflowTemplate
|
||||
9, // 23: api.WorkflowTemplateService.ArchiveWorkflowTemplate:output_type -> api.ArchiveWorkflowTemplateResponse
|
||||
16, // [16:24] is the sub-list for method output_type
|
||||
8, // [8:16] is the sub-list for method input_type
|
||||
0, // 9: api.WorkflowTemplateService.CreateWorkflowTemplateVersion:input_type -> api.CreateWorkflowTemplateRequest
|
||||
2, // 10: api.WorkflowTemplateService.GetWorkflowTemplate:input_type -> api.GetWorkflowTemplateRequest
|
||||
4, // 11: api.WorkflowTemplateService.ListWorkflowTemplateVersions:input_type -> api.ListWorkflowTemplateVersionsRequest
|
||||
6, // 12: api.WorkflowTemplateService.ListWorkflowTemplates:input_type -> api.ListWorkflowTemplatesRequest
|
||||
3, // 13: api.WorkflowTemplateService.CloneWorkflowTemplate:input_type -> api.CloneWorkflowTemplateRequest
|
||||
8, // 14: api.WorkflowTemplateService.ArchiveWorkflowTemplate:input_type -> api.ArchiveWorkflowTemplateRequest
|
||||
12, // 15: api.WorkflowTemplateService.CreateWorkflowTemplate:output_type -> api.WorkflowTemplate
|
||||
12, // 16: api.WorkflowTemplateService.CreateWorkflowTemplateVersion:output_type -> api.WorkflowTemplate
|
||||
12, // 17: api.WorkflowTemplateService.GetWorkflowTemplate:output_type -> api.WorkflowTemplate
|
||||
5, // 18: api.WorkflowTemplateService.ListWorkflowTemplateVersions:output_type -> api.ListWorkflowTemplateVersionsResponse
|
||||
7, // 19: api.WorkflowTemplateService.ListWorkflowTemplates:output_type -> api.ListWorkflowTemplatesResponse
|
||||
12, // 20: api.WorkflowTemplateService.CloneWorkflowTemplate:output_type -> api.WorkflowTemplate
|
||||
9, // 21: api.WorkflowTemplateService.ArchiveWorkflowTemplate:output_type -> api.ArchiveWorkflowTemplateResponse
|
||||
15, // [15:22] is the sub-list for method output_type
|
||||
8, // [8:15] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
@@ -1466,7 +1449,6 @@ const _ = grpc.SupportPackageIsVersion6
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type WorkflowTemplateServiceClient interface {
|
||||
CreateWorkflowTemplate(ctx context.Context, in *CreateWorkflowTemplateRequest, opts ...grpc.CallOption) (*WorkflowTemplate, error)
|
||||
UpdateWorkflowTemplateVersion(ctx context.Context, in *UpdateWorkflowTemplateVersionRequest, opts ...grpc.CallOption) (*WorkflowTemplate, error)
|
||||
CreateWorkflowTemplateVersion(ctx context.Context, in *CreateWorkflowTemplateRequest, opts ...grpc.CallOption) (*WorkflowTemplate, error)
|
||||
GetWorkflowTemplate(ctx context.Context, in *GetWorkflowTemplateRequest, opts ...grpc.CallOption) (*WorkflowTemplate, error)
|
||||
ListWorkflowTemplateVersions(ctx context.Context, in *ListWorkflowTemplateVersionsRequest, opts ...grpc.CallOption) (*ListWorkflowTemplateVersionsResponse, error)
|
||||
@@ -1492,15 +1474,6 @@ func (c *workflowTemplateServiceClient) CreateWorkflowTemplate(ctx context.Conte
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *workflowTemplateServiceClient) UpdateWorkflowTemplateVersion(ctx context.Context, in *UpdateWorkflowTemplateVersionRequest, opts ...grpc.CallOption) (*WorkflowTemplate, error) {
|
||||
out := new(WorkflowTemplate)
|
||||
err := c.cc.Invoke(ctx, "/api.WorkflowTemplateService/UpdateWorkflowTemplateVersion", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *workflowTemplateServiceClient) CreateWorkflowTemplateVersion(ctx context.Context, in *CreateWorkflowTemplateRequest, opts ...grpc.CallOption) (*WorkflowTemplate, error) {
|
||||
out := new(WorkflowTemplate)
|
||||
err := c.cc.Invoke(ctx, "/api.WorkflowTemplateService/CreateWorkflowTemplateVersion", in, out, opts...)
|
||||
@@ -1558,7 +1531,6 @@ func (c *workflowTemplateServiceClient) ArchiveWorkflowTemplate(ctx context.Cont
|
||||
// WorkflowTemplateServiceServer is the server API for WorkflowTemplateService service.
|
||||
type WorkflowTemplateServiceServer interface {
|
||||
CreateWorkflowTemplate(context.Context, *CreateWorkflowTemplateRequest) (*WorkflowTemplate, error)
|
||||
UpdateWorkflowTemplateVersion(context.Context, *UpdateWorkflowTemplateVersionRequest) (*WorkflowTemplate, error)
|
||||
CreateWorkflowTemplateVersion(context.Context, *CreateWorkflowTemplateRequest) (*WorkflowTemplate, error)
|
||||
GetWorkflowTemplate(context.Context, *GetWorkflowTemplateRequest) (*WorkflowTemplate, error)
|
||||
ListWorkflowTemplateVersions(context.Context, *ListWorkflowTemplateVersionsRequest) (*ListWorkflowTemplateVersionsResponse, error)
|
||||
@@ -1574,9 +1546,6 @@ type UnimplementedWorkflowTemplateServiceServer struct {
|
||||
func (*UnimplementedWorkflowTemplateServiceServer) CreateWorkflowTemplate(context.Context, *CreateWorkflowTemplateRequest) (*WorkflowTemplate, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateWorkflowTemplate not implemented")
|
||||
}
|
||||
func (*UnimplementedWorkflowTemplateServiceServer) UpdateWorkflowTemplateVersion(context.Context, *UpdateWorkflowTemplateVersionRequest) (*WorkflowTemplate, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateWorkflowTemplateVersion not implemented")
|
||||
}
|
||||
func (*UnimplementedWorkflowTemplateServiceServer) CreateWorkflowTemplateVersion(context.Context, *CreateWorkflowTemplateRequest) (*WorkflowTemplate, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateWorkflowTemplateVersion not implemented")
|
||||
}
|
||||
@@ -1618,24 +1587,6 @@ func _WorkflowTemplateService_CreateWorkflowTemplate_Handler(srv interface{}, ct
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WorkflowTemplateService_UpdateWorkflowTemplateVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateWorkflowTemplateVersionRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WorkflowTemplateServiceServer).UpdateWorkflowTemplateVersion(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/api.WorkflowTemplateService/UpdateWorkflowTemplateVersion",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WorkflowTemplateServiceServer).UpdateWorkflowTemplateVersion(ctx, req.(*UpdateWorkflowTemplateVersionRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WorkflowTemplateService_CreateWorkflowTemplateVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateWorkflowTemplateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -1752,10 +1703,6 @@ var _WorkflowTemplateService_serviceDesc = grpc.ServiceDesc{
|
||||
MethodName: "CreateWorkflowTemplate",
|
||||
Handler: _WorkflowTemplateService_CreateWorkflowTemplate_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateWorkflowTemplateVersion",
|
||||
Handler: _WorkflowTemplateService_UpdateWorkflowTemplateVersion_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateWorkflowTemplateVersion",
|
||||
Handler: _WorkflowTemplateService_CreateWorkflowTemplateVersion_Handler,
|
||||
|
||||
@@ -101,120 +101,6 @@ func local_request_WorkflowTemplateService_CreateWorkflowTemplate_0(ctx context.
|
||||
|
||||
}
|
||||
|
||||
func request_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0(ctx context.Context, marshaler runtime.Marshaler, client WorkflowTemplateServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateWorkflowTemplateVersionRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.WorkflowTemplate); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["namespace"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace")
|
||||
}
|
||||
|
||||
protoReq.Namespace, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err)
|
||||
}
|
||||
|
||||
val, ok = pathParams["workflowTemplate.uid"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "workflowTemplate.uid")
|
||||
}
|
||||
|
||||
err = runtime.PopulateFieldFromPath(&protoReq, "workflowTemplate.uid", val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "workflowTemplate.uid", err)
|
||||
}
|
||||
|
||||
val, ok = pathParams["workflowTemplate.version"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "workflowTemplate.version")
|
||||
}
|
||||
|
||||
err = runtime.PopulateFieldFromPath(&protoReq, "workflowTemplate.version", val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "workflowTemplate.version", err)
|
||||
}
|
||||
|
||||
msg, err := client.UpdateWorkflowTemplateVersion(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0(ctx context.Context, marshaler runtime.Marshaler, server WorkflowTemplateServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateWorkflowTemplateVersionRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.WorkflowTemplate); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["namespace"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace")
|
||||
}
|
||||
|
||||
protoReq.Namespace, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err)
|
||||
}
|
||||
|
||||
val, ok = pathParams["workflowTemplate.uid"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "workflowTemplate.uid")
|
||||
}
|
||||
|
||||
err = runtime.PopulateFieldFromPath(&protoReq, "workflowTemplate.uid", val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "workflowTemplate.uid", err)
|
||||
}
|
||||
|
||||
val, ok = pathParams["workflowTemplate.version"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "workflowTemplate.version")
|
||||
}
|
||||
|
||||
err = runtime.PopulateFieldFromPath(&protoReq, "workflowTemplate.version", val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "workflowTemplate.version", err)
|
||||
}
|
||||
|
||||
msg, err := server.UpdateWorkflowTemplateVersion(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_WorkflowTemplateService_CreateWorkflowTemplateVersion_0(ctx context.Context, marshaler runtime.Marshaler, client WorkflowTemplateServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CreateWorkflowTemplateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
@@ -975,26 +861,6 @@ func RegisterWorkflowTemplateServiceHandlerServer(ctx context.Context, mux *runt
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PUT", pattern_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_WorkflowTemplateService_CreateWorkflowTemplateVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -1216,26 +1082,6 @@ func RegisterWorkflowTemplateServiceHandlerClient(ctx context.Context, mux *runt
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PUT", pattern_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_WorkflowTemplateService_CreateWorkflowTemplateVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -1402,8 +1248,6 @@ func RegisterWorkflowTemplateServiceHandlerClient(ctx context.Context, mux *runt
|
||||
var (
|
||||
pattern_WorkflowTemplateService_CreateWorkflowTemplate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"apis", "v1beta1", "namespace", "workflow_templates"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"apis", "v1beta1", "namespace", "workflow_templates", "workflowTemplate.uid", "versions", "workflowTemplate.version"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_WorkflowTemplateService_CreateWorkflowTemplateVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"apis", "v1beta1", "namespace", "workflow_templates", "workflowTemplate.uid", "versions"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_WorkflowTemplateService_GetWorkflowTemplate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"apis", "v1beta1", "namespace", "workflow_templates", "uid"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
@@ -1424,8 +1268,6 @@ var (
|
||||
var (
|
||||
forward_WorkflowTemplateService_CreateWorkflowTemplate_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_WorkflowTemplateService_UpdateWorkflowTemplateVersion_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_WorkflowTemplateService_CreateWorkflowTemplateVersion_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_WorkflowTemplateService_GetWorkflowTemplate_0 = runtime.ForwardResponseMessage
|
||||
|
||||
@@ -13,13 +13,6 @@ service WorkflowTemplateService {
|
||||
};
|
||||
}
|
||||
|
||||
rpc UpdateWorkflowTemplateVersion (UpdateWorkflowTemplateVersionRequest) returns (WorkflowTemplate) {
|
||||
option (google.api.http) = {
|
||||
put: "/apis/v1beta1/{namespace}/workflow_templates/{workflowTemplate.uid}/versions/{workflowTemplate.version}"
|
||||
body: "workflowTemplate"
|
||||
};
|
||||
}
|
||||
|
||||
rpc CreateWorkflowTemplateVersion (CreateWorkflowTemplateRequest) returns (WorkflowTemplate) {
|
||||
option (google.api.http) = {
|
||||
post: "/apis/v1beta1/{namespace}/workflow_templates/{workflowTemplate.uid}/versions"
|
||||
|
||||
@@ -4,12 +4,12 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/onepanelio/core/db"
|
||||
migrations "github.com/onepanelio/core/db/go"
|
||||
v1 "github.com/onepanelio/core/pkg"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pressly/goose"
|
||||
)
|
||||
@@ -38,10 +38,8 @@ func main() {
|
||||
log.Fatalf("Failed to get system config: %v", err)
|
||||
}
|
||||
|
||||
databaseDataSourceName := fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=disable",
|
||||
config["databaseHost"], config["databaseUsername"], config["databasePassword"], config["databaseName"])
|
||||
|
||||
db := sqlx.MustConnect(config["databaseDriverName"], databaseDataSourceName)
|
||||
dbDriverName, dbDataSourceName := config.DatabaseConnection()
|
||||
db := sqlx.MustConnect(dbDriverName, dbDataSourceName)
|
||||
|
||||
command := args[0]
|
||||
|
||||
@@ -50,7 +48,14 @@ func main() {
|
||||
arguments = append(arguments, args[2:]...)
|
||||
}
|
||||
|
||||
if err := goose.Run(command, db.DB, *dir, arguments...); err != nil {
|
||||
log.Fatalf("goose %v: %v", command, err)
|
||||
goose.SetTableName("goose_db_version")
|
||||
if err := goose.Run(command, db.DB, filepath.Join(*dir, "sql"), arguments...); err != nil {
|
||||
log.Fatalf("Failed to run database sql migrations: %v %v", command, err)
|
||||
}
|
||||
|
||||
goose.SetTableName("goose_db_go_version")
|
||||
migrations.Initialize()
|
||||
if err := goose.Run(command, db.DB, filepath.Join(*dir, "go"), arguments...); err != nil {
|
||||
log.Fatalf("Failed to run database go migrations: %v %v", command, err)
|
||||
}
|
||||
}
|
||||
|
||||
25
db/db.go
25
db/db.go
@@ -1,25 +0,0 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jmoiron/sqlx"
|
||||
v1 "github.com/onepanelio/core/pkg"
|
||||
)
|
||||
|
||||
func getClient() (*v1.Client, error) {
|
||||
kubeConfig := v1.NewConfig()
|
||||
client, err := v1.NewClient(kubeConfig, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, err := client.GetSystemConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
databaseDataSourceName := fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=disable",
|
||||
config["databaseHost"], config["databaseUsername"], config["databasePassword"], config["databaseName"])
|
||||
client.DB = v1.NewDB(sqlx.MustConnect(config["databaseDriverName"], databaseDataSourceName))
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -71,8 +71,11 @@ routes:
|
||||
|
||||
const jupyterLabTemplateName = "JupyterLab"
|
||||
|
||||
func init() {
|
||||
goose.AddMigration(Up20200525160514, Down20200525160514)
|
||||
func initialize20200525160514() {
|
||||
if _, ok := initializedMigrations[20200525160514]; !ok {
|
||||
goose.AddMigration(Up20200525160514, Down20200525160514)
|
||||
initializedMigrations[20200525160514] = true
|
||||
}
|
||||
}
|
||||
|
||||
func Up20200525160514(tx *sql.Tx) error {
|
||||
@@ -81,6 +84,15 @@ func Up20200525160514(tx *sql.Tx) error {
|
||||
return err
|
||||
}
|
||||
|
||||
migrationsRan, err := getRanSQLMigrations(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := migrationsRan[20200525160514]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
namespaces, err := client.ListOnepanelEnabledNamespaces()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -110,8 +110,11 @@ routes:
|
||||
|
||||
const cvatTemplateName = "CVAT"
|
||||
|
||||
func init() {
|
||||
goose.AddMigration(Up20200528140124, Down20200528140124)
|
||||
func initialize20200528140124() {
|
||||
if _, ok := initializedMigrations[20200528140124]; !ok {
|
||||
goose.AddMigration(Up20200528140124, Down20200528140124)
|
||||
initializedMigrations[20200528140124] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Up20200528140124 will insert the cvatTemplate to each user.
|
||||
@@ -125,6 +128,15 @@ func Up20200528140124(tx *sql.Tx) error {
|
||||
return err
|
||||
}
|
||||
|
||||
migrationsRan, err := getRanSQLMigrations(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := migrationsRan[20200528140124]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
namespaces, err := client.ListOnepanelEnabledNamespaces()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -88,8 +88,11 @@ templates:
|
||||
|
||||
const pytorchMnistWorkflowTemplateName = "PyTorch Training"
|
||||
|
||||
func init() {
|
||||
goose.AddMigration(Up20200605090509, Down20200605090509)
|
||||
func initialize20200605090509() {
|
||||
if _, ok := initializedMigrations[20200605090509]; !ok {
|
||||
goose.AddMigration(Up20200605090509, Down20200605090509)
|
||||
initializedMigrations[20200605090509] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Up20200605090509 will insert a Pytorch workflow template to each user.
|
||||
@@ -101,6 +104,15 @@ func Up20200605090509(tx *sql.Tx) error {
|
||||
return err
|
||||
}
|
||||
|
||||
migrationsRan, err := getRanSQLMigrations(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := migrationsRan[20200605090509]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
namespaces, err := client.ListOnepanelEnabledNamespaces()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -88,8 +88,11 @@ templates:
|
||||
|
||||
const tensorflowWorkflowTemplateName = "TensorFlow Training"
|
||||
|
||||
func init() {
|
||||
goose.AddMigration(Up20200605090535, Down20200605090535)
|
||||
func initialize20200605090535() {
|
||||
if _, ok := initializedMigrations[20200605090535]; !ok {
|
||||
goose.AddMigration(Up20200605090535, Down20200605090535)
|
||||
initializedMigrations[20200605090535] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Up20200605090535 will insert a tensorflow workflow template to each user.
|
||||
@@ -101,6 +104,15 @@ func Up20200605090535(tx *sql.Tx) error {
|
||||
return err
|
||||
}
|
||||
|
||||
migrationsRan, err := getRanSQLMigrations(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := migrationsRan[20200605090535]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
namespaces, err := client.ListOnepanelEnabledNamespaces()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
v1 "github.com/onepanelio/core/pkg"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"github.com/pressly/goose"
|
||||
"time"
|
||||
)
|
||||
|
||||
const cvatWorkspaceTemplate2 = `# Docker containers that are part of the Workspace
|
||||
@@ -119,21 +118,30 @@ routes:
|
||||
# - -c
|
||||
`
|
||||
|
||||
func init() {
|
||||
goose.AddMigration(Up20200626113635, Down20200626113635)
|
||||
func initialize20200626113635() {
|
||||
if _, ok := initializedMigrations[20200626113635]; !ok {
|
||||
goose.AddMigration(Up20200626113635, Down20200626113635)
|
||||
initializedMigrations[20200626113635] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Up20200626113635 updates the CVAT template to a new version.
|
||||
func Up20200626113635(tx *sql.Tx) error {
|
||||
// This code is executed when the migration is applied.
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
client, err := getClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
migrationsRan, err := getRanSQLMigrations(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := migrationsRan[20200626113635]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
namespaces, err := client.ListOnepanelEnabledNamespaces()
|
||||
if err != nil {
|
||||
return err
|
||||
175
db/go/20200704151301_update_cvat_workspace_template.go
Normal file
175
db/go/20200704151301_update_cvat_workspace_template.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
v1 "github.com/onepanelio/core/pkg"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"github.com/pressly/goose"
|
||||
)
|
||||
|
||||
const cvatWorkspaceTemplate3 = `# Docker containers that are part of the Workspace
|
||||
containers:
|
||||
- name: cvat-db
|
||||
image: postgres:10-alpine
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
value: root
|
||||
- name: POSTGRES_DB
|
||||
value: cvat
|
||||
- name: POSTGRES_HOST_AUTH_METHOD
|
||||
value: trust
|
||||
- name: PGDATA
|
||||
value: /var/lib/psql/data
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: tcp
|
||||
volumeMounts:
|
||||
- name: db
|
||||
mountPath: /var/lib/psql
|
||||
- name: cvat-redis
|
||||
image: redis:4.0-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: tcp
|
||||
- name: cvat
|
||||
image: onepanel/cvat:v0.7.10-stable
|
||||
env:
|
||||
- name: DJANGO_MODWSGI_EXTRA_ARGS
|
||||
value: ""
|
||||
- name: ALLOWED_HOSTS
|
||||
value: '*'
|
||||
- name: CVAT_REDIS_HOST
|
||||
value: localhost
|
||||
- name: CVAT_POSTGRES_HOST
|
||||
value: localhost
|
||||
- name: CVAT_SHARE_URL
|
||||
value: /home/django/data
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /home/django/data
|
||||
- name: keys
|
||||
mountPath: /home/django/keys
|
||||
- name: logs
|
||||
mountPath: /home/django/logs
|
||||
- name: models
|
||||
mountPath: /home/django/models
|
||||
- name: share
|
||||
mountPath: /home/django/share
|
||||
- name: cvat-ui
|
||||
image: onepanel/cvat-ui:v0.7.10-stable
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: http
|
||||
# Uncomment following lines to enable S3 FileSyncer
|
||||
# Refer to https://docs.onepanel.ai/docs/getting-started/use-cases/computervision/annotation/cvat/cvat_quick_guide#setting-up-environment-variables
|
||||
#- name: filesyncer
|
||||
# image: onepanel/filesyncer:v0.0.4
|
||||
# command: ['python3', 'main.py']
|
||||
# volumeMounts:
|
||||
# - name: share
|
||||
# mountPath: /mnt/share
|
||||
ports:
|
||||
- name: cvat-ui
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 80
|
||||
- name: cvat
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
routes:
|
||||
- match:
|
||||
- uri:
|
||||
regex: /api/.*|/git/.*|/tensorflow/.*|/auto_annotation/.*|/analytics/.*|/static/.*|/admin/.*|/documentation/.*|/dextr/.*|/reid/.*
|
||||
- queryParams:
|
||||
id:
|
||||
regex: \d+.*
|
||||
route:
|
||||
- destination:
|
||||
port:
|
||||
number: 8080
|
||||
timeout: 600s
|
||||
- match:
|
||||
- uri:
|
||||
prefix: /
|
||||
route:
|
||||
- destination:
|
||||
port:
|
||||
number: 80
|
||||
timeout: 600s
|
||||
# DAG Workflow to be executed once a Workspace action completes (optional)
|
||||
# Uncomment the lines below if you want to send Slack notifications
|
||||
#postExecutionWorkflow:
|
||||
# entrypoint: main
|
||||
# templates:
|
||||
# - name: main
|
||||
# dag:
|
||||
# tasks:
|
||||
# - name: slack-notify
|
||||
# template: slack-notify
|
||||
# - name: slack-notify
|
||||
# container:
|
||||
# image: technosophos/slack-notify
|
||||
# args:
|
||||
# - SLACK_USERNAME=onepanel SLACK_TITLE="Your workspace is ready" SLACK_ICON=https://www.gravatar.com/avatar/5c4478592fe00878f62f0027be59c1bd SLACK_MESSAGE="Your workspace is now running" ./slack-notify
|
||||
# command:
|
||||
# - sh
|
||||
# - -c
|
||||
`
|
||||
|
||||
func initialize20200704151301() {
|
||||
if _, ok := initializedMigrations[20200704151301]; !ok {
|
||||
goose.AddMigration(Up20200704151301, Down20200704151301)
|
||||
initializedMigrations[20200704151301] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Up20200704151301 updates the CVAT template to a new version.
|
||||
func Up20200704151301(tx *sql.Tx) error {
|
||||
// This code is executed when the migration is applied.
|
||||
client, err := getClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
migrationsRan, err := getRanSQLMigrations(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := migrationsRan[20200704151301]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
namespaces, err := client.ListOnepanelEnabledNamespaces()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uid, err := uid2.GenerateUID(cvatTemplateName, 30)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
workspaceTemplate := &v1.WorkspaceTemplate{
|
||||
UID: uid,
|
||||
Name: cvatTemplateName,
|
||||
Manifest: cvatWorkspaceTemplate3,
|
||||
}
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Down20200704151301 removes the CVAT template update
|
||||
func Down20200704151301(tx *sql.Tx) error {
|
||||
// This code is executed when the migration is rolled back.
|
||||
return nil
|
||||
}
|
||||
58
db/go/db.go
Normal file
58
db/go/db.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/jmoiron/sqlx"
|
||||
v1 "github.com/onepanelio/core/pkg"
|
||||
)
|
||||
|
||||
// initializedMigrations is used to keep track of which migrations have been initialized.
|
||||
// if they are initialzed more than once, goose panics.
|
||||
var initializedMigrations = make(map[int]bool)
|
||||
|
||||
// Initialize sets up the go migrations.
|
||||
func Initialize() {
|
||||
initialize20200525160514()
|
||||
initialize20200528140124()
|
||||
initialize20200605090509()
|
||||
initialize20200605090535()
|
||||
initialize20200626113635()
|
||||
initialize20200704151301()
|
||||
}
|
||||
|
||||
func getClient() (*v1.Client, error) {
|
||||
kubeConfig := v1.NewConfig()
|
||||
client, err := v1.NewClient(kubeConfig, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, err := client.GetSystemConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dbDriverName, dbDataSourceName := config.DatabaseConnection()
|
||||
client.DB = v1.NewDB(sqlx.MustConnect(dbDriverName, dbDataSourceName))
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// getRanSQLMigrations returns a map where each key is a sql migration version ran.
|
||||
func getRanSQLMigrations(client *v1.Client) (map[uint64]bool, error) {
|
||||
sb := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
|
||||
|
||||
query := sb.Select("version_id").
|
||||
From("goose_db_version")
|
||||
|
||||
versions := make([]uint64, 0)
|
||||
if err := client.Selectx(&versions, query); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[uint64]bool)
|
||||
for _, version := range versions {
|
||||
result[version] = true
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -2,5 +2,4 @@
|
||||
ALTER TABLE workflow_template_versions DROP COLUMN uid;
|
||||
|
||||
-- +goose Down
|
||||
ALTER TABLE workflow_template_versions ADD COLUMN uid VARCHAR(30);
|
||||
UPDATE workflow_template_versions SET uid = version::text;
|
||||
11
db/sql/20200630112657_update_version_types.sql
Normal file
11
db/sql/20200630112657_update_version_types.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- +goose Up
|
||||
-- SQL in this section is executed when the migration is applied.
|
||||
ALTER TABLE workflow_template_versions ALTER COLUMN version TYPE BIGINT;
|
||||
ALTER TABLE workspace_template_versions ALTER COLUMN version TYPE BIGINT;
|
||||
ALTER TABLE workspaces ALTER COLUMN workspace_template_version TYPE BIGINT;
|
||||
|
||||
-- +goose Down
|
||||
-- SQL in this section is executed when the migration is rolled back.
|
||||
ALTER TABLE workflow_template_versions ALTER COLUMN version TYPE INT;
|
||||
ALTER TABLE workspace_template_versions ALTER COLUMN version TYPE INT;
|
||||
ALTER TABLE workspaces ALTER COLUMN workspace_template_version TYPE INT;
|
||||
8
go.mod
8
go.mod
@@ -4,6 +4,7 @@ go 1.14
|
||||
|
||||
require (
|
||||
github.com/Azure/go-autorest v14.0.0+incompatible // indirect
|
||||
cloud.google.com/go/storage v1.6.0
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.2 // indirect
|
||||
github.com/Masterminds/squirrel v1.1.0
|
||||
github.com/argoproj/argo v0.0.0-20200331233432-4d1175eb68f6
|
||||
@@ -14,11 +15,10 @@ require (
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||
github.com/golang/protobuf v1.4.1
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/handlers v1.4.2
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.4
|
||||
github.com/hashicorp/go-uuid v1.0.2
|
||||
github.com/hashicorp/go-uuid v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/lib/pq v1.3.0
|
||||
@@ -30,10 +30,14 @@ require (
|
||||
github.com/spf13/cobra v0.0.5 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
google.golang.org/api v0.20.0
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84
|
||||
google.golang.org/grpc v1.28.0
|
||||
google.golang.org/protobuf v1.22.0
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||
istio.io/api v0.0.0-20200107183329-ed4b507c54e1
|
||||
k8s.io/api v0.16.4
|
||||
k8s.io/apimachinery v0.16.7-beta.0
|
||||
|
||||
24
go.sum
24
go.sum
@@ -12,14 +12,18 @@ cloud.google.com/go v0.55.0 h1:eoz/lYxKSL4CNAiaUJ0ZfD1J3bfMYbU5B3rwM1C1EIU=
|
||||
cloud.google.com/go v0.55.0/go.mod h1:ZHmoY+/lIMNkN2+fBmuTiqZ4inFhvQad8ft7MT8IV5Y=
|
||||
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 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
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 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
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 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-autorest v11.1.2+incompatible h1:viZ3tV5l4gE2Sw0xrasFHytCGtzYCrT+um/rrSQ1BfA=
|
||||
@@ -31,8 +35,6 @@ github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+B
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.3 h1:O1AGG9Xig71FxdX9HO5pGNyZ7TbSyHaVg+5eJO/jSGw=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||
@@ -44,6 +46,7 @@ github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1Gn
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
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/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
@@ -207,6 +210,7 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSN
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
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=
|
||||
@@ -218,6 +222,7 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/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 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
|
||||
@@ -237,8 +242,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xC
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.4 h1:IOPK2xMPP3aV6/NPt4jt//ELFo3Vv8sDVD8j3+tleDU=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.4/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
|
||||
github.com/hashicorp/go-uuid v0.0.0-20180228145832-27454136f036/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
@@ -275,6 +278,7 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
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 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
@@ -437,6 +441,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
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 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
@@ -479,6 +484,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
|
||||
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 h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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=
|
||||
@@ -486,6 +492,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
|
||||
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 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -527,6 +534,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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 h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -608,6 +616,7 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
|
||||
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-20200317043434-63da46f3035e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200331202046-9d5940d49312 h1:2PHG+Ia3gK1K2kjxZnSylizb//eyaMG8gDFbOG7wLV8=
|
||||
golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
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=
|
||||
@@ -622,6 +631,7 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
|
||||
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.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
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=
|
||||
@@ -648,8 +658,6 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4
|
||||
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-20200317114155-1f3552e48f24/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200413115906-b5235f65be36 h1:j7CmVRD4Kec0+f8VuBAc2Ak2MFfXm5Q2/RxuJLL+76E=
|
||||
google.golang.org/genproto v0.0.0-20200413115906-b5235f65be36/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84 h1:pSLkPbrjnPyLDYUO2VM9mDLqo2V6CFBY84lFSZAfoi4=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -711,11 +719,14 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
istio.io/api v0.0.0-20200107183329-ed4b507c54e1 h1:q4xggEkhMn4RMRo8AJVNmMtNzy514DGiAUxRDDKPhZU=
|
||||
istio.io/api v0.0.0-20200107183329-ed4b507c54e1/go.mod h1:+cyHH83OwC0rFpwk8eXctzPNpiCAbB+r6kmMiAxxBHw=
|
||||
@@ -730,7 +741,6 @@ k8s.io/apimachinery v0.0.0-20191219145857-f69eda767ee8/go.mod h1:mhhO3hoLkWO+2eC
|
||||
k8s.io/apimachinery v0.16.4/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ=
|
||||
k8s.io/apimachinery v0.16.7-beta.0 h1:1cNiN7ZXJzlWq7dnWojG5UcrX1AIfQqpbyuzhu7Bhsc=
|
||||
k8s.io/apimachinery v0.16.7-beta.0/go.mod h1:mhhO3hoLkWO+2eCvqjPtH2Ly92l9nJDwsswzWKpkN2w=
|
||||
k8s.io/apimachinery v0.18.3 h1:pOGcbVAhxADgUYnjS08EFXs9QMl8qaH5U4fr5LGUrSk=
|
||||
k8s.io/client-go v0.0.0-20191225075139-73fd2ddc9180/go.mod h1:ksVkYlACXo9hR9AV+cYyCkuWL1xnWcGtAFxsfqMcozg=
|
||||
k8s.io/client-go v0.16.4 h1:sf+FEZXYhJNjpTZapQDLvvN+0kBeUTxCYxlXcVdhv2E=
|
||||
k8s.io/client-go v0.16.4/go.mod h1:ZgxhFDxSnoKY0J0U2/Y1C8obKDdlhGPZwA7oHH863Ok=
|
||||
|
||||
37
main.go
37
main.go
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
_ "github.com/onepanelio/core/db"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -15,6 +14,8 @@ import (
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
@@ -23,6 +24,7 @@ import (
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/onepanelio/core/api"
|
||||
migrations "github.com/onepanelio/core/db/go"
|
||||
v1 "github.com/onepanelio/core/pkg"
|
||||
"github.com/onepanelio/core/pkg/util/env"
|
||||
"github.com/onepanelio/core/server"
|
||||
@@ -67,16 +69,20 @@ func main() {
|
||||
log.Fatalf("Failed to get system config: %v", err)
|
||||
}
|
||||
|
||||
databaseDataSourceName := fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=disable",
|
||||
sysConfig["databaseHost"], sysConfig["databaseUsername"], sysConfig["databasePassword"], sysConfig["databaseName"])
|
||||
|
||||
dbDriverName, databaseDataSourceName := sysConfig.DatabaseConnection()
|
||||
// sqlx.MustConnect will panic when it can't connect to DB. In that case, this whole application will crash.
|
||||
// This is okay, as the pod will restart and try connecting to DB again.
|
||||
// dbDriverName may be nil, but sqlx will then panic.
|
||||
dbDriverName := sysConfig.DatabaseDriverName()
|
||||
db := sqlx.MustConnect(*dbDriverName, databaseDataSourceName)
|
||||
if err := goose.Run("up", db.DB, "db"); err != nil {
|
||||
log.Fatalf("Failed to run database migrations: %v", err)
|
||||
db := sqlx.MustConnect(dbDriverName, databaseDataSourceName)
|
||||
goose.SetTableName("goose_db_version")
|
||||
if err := goose.Run("up", db.DB, filepath.Join("db", "sql")); err != nil {
|
||||
log.Fatalf("Failed to run database sql migrations: %v", err)
|
||||
}
|
||||
|
||||
goose.SetTableName("goose_db_go_version")
|
||||
migrations.Initialize()
|
||||
if err := goose.Run("up", db.DB, filepath.Join("db", "go")); err != nil {
|
||||
log.Fatalf("Failed to run database go migrations: %v", err)
|
||||
}
|
||||
|
||||
s := startRPCServer(v1.NewDB(db), kubeConfig, sysConfig, stopCh)
|
||||
@@ -154,7 +160,7 @@ func startHTTPProxy() {
|
||||
|
||||
// Register gRPC server endpoint
|
||||
// Note: Make sure the gRPC server is running properly and accessible
|
||||
mux := runtime.NewServeMux()
|
||||
mux := runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(customHeaderMatcher))
|
||||
opts := []grpc.DialOption{grpc.WithInsecure()}
|
||||
|
||||
registerHandler(api.RegisterWorkflowTemplateServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
|
||||
@@ -246,3 +252,16 @@ func watchConfigmapChanges(client *v1.Client, namespace string, stopCh <-chan st
|
||||
neverStopCh := make(chan struct{})
|
||||
controller.Run(neverStopCh)
|
||||
}
|
||||
|
||||
// customHeaderMatcher is used to allow certain headers so we don't require a grpc-gateway prefix
|
||||
func customHeaderMatcher(key string) (string, bool) {
|
||||
lowerCaseKey := strings.ToLower(key)
|
||||
switch lowerCaseKey {
|
||||
case "onepanel-auth-token":
|
||||
return lowerCaseKey, true
|
||||
case "cookie":
|
||||
return lowerCaseKey, true
|
||||
default:
|
||||
return runtime.DefaultHeaderMatcher(key)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package v1
|
||||
import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
argoprojv1alpha1 "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1"
|
||||
"github.com/onepanelio/core/pkg/util/gcs"
|
||||
"github.com/onepanelio/core/pkg/util/s3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -64,7 +65,8 @@ func NewClient(config *Config, db *DB, systemConfig SystemConfig) (client *Clien
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetS3Client(namespace string, config *ArtifactRepositoryS3Config) (s3Client *s3.Client, err error) {
|
||||
// GetS3Client initializes a client to Amazon Cloud Storage.
|
||||
func (c *Client) GetS3Client(namespace string, config *ArtifactRepositoryS3Provider) (s3Client *s3.Client, err error) {
|
||||
s3Client, err = s3.NewClient(s3.Config{
|
||||
Endpoint: config.Endpoint,
|
||||
Region: config.Region,
|
||||
@@ -80,6 +82,10 @@ func (c *Client) GetS3Client(namespace string, config *ArtifactRepositoryS3Confi
|
||||
}).Error("getS3Client failed when initializing a new S3 client.")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetGCSClient initializes a client to Google Cloud Storage.
|
||||
func (c *Client) GetGCSClient(namespace string, config *ArtifactRepositoryGCSProvider) (gcsClient *gcs.Client, err error) {
|
||||
return gcs.NewClient(namespace, config.ServiceAccountJSON)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
argoFake "github.com/argoproj/argo/pkg/client/clientset/versioned/fake"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pressly/goose"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -15,6 +23,20 @@ var (
|
||||
},
|
||||
}
|
||||
|
||||
configArtifactRepository = `archiveLogs: true
|
||||
s3:
|
||||
keyFormat: artifacts/{{workflow.namespace}}/{{workflow.name}}/{{pod.name}}
|
||||
bucket: test.onepanel.io
|
||||
endpoint: s3.amazonaws.com
|
||||
insecure: false
|
||||
region: us-west-2
|
||||
accessKeySecret:
|
||||
name: onepanel
|
||||
key: artifactRepositoryS3AccessKey
|
||||
secretKeySecret:
|
||||
name: onepanel
|
||||
key: artifactRepositoryS3SecretKey`
|
||||
|
||||
mockSystemConfigMap = &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "onepanel",
|
||||
@@ -22,6 +44,8 @@ var (
|
||||
},
|
||||
Data: map[string]string{
|
||||
"ONEPANEL_HOST": "demo.onepanel.site",
|
||||
"ONEPANEL_DOMAIN": "demo.onepanel.site",
|
||||
"artifactRepository": configArtifactRepository,
|
||||
"applicationNodePoolLabel": "beta.kubernetes.io/instance-type",
|
||||
"applicationNodePoolOptions": `
|
||||
- name: 'CPU: 2, RAM: 8GB'
|
||||
@@ -34,8 +58,60 @@ var (
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
database *sqlx.DB
|
||||
)
|
||||
|
||||
func NewTestClient(objects ...runtime.Object) (client *Client) {
|
||||
return &Client{Interface: fake.NewSimpleClientset(objects...)}
|
||||
var flagDatabaseService = flag.String("db", "localhost", "Name to connect to db, defaults to localhost")
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// call flag.Parse() here if TestMain uses flags
|
||||
flag.Parse()
|
||||
|
||||
databaseDataSourceName := fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=disable",
|
||||
*flagDatabaseService, "admin", "tester", "onepanel")
|
||||
|
||||
dbDriverName := "postgres"
|
||||
database = sqlx.MustConnect(dbDriverName, databaseDataSourceName)
|
||||
|
||||
// We don't run the go migrations as those setup data that we don't use in our testing
|
||||
if err := goose.Run("up", database.DB, "../db/sql"); err != nil {
|
||||
log.Fatalf("Failed to run database migrations: %v", err)
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func NewTestClient(db *sqlx.DB, objects ...runtime.Object) (client *Client) {
|
||||
k8sFake := fake.NewSimpleClientset(objects...)
|
||||
argoFakeClient := argoFake.NewSimpleClientset()
|
||||
|
||||
return &Client{
|
||||
Interface: k8sFake,
|
||||
DB: NewDB(db),
|
||||
argoprojV1alpha1: argoFakeClient.ArgoprojV1alpha1(),
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultTestClient() *Client {
|
||||
return NewTestClient(database, mockSystemConfigMap, mockSystemSecret)
|
||||
}
|
||||
|
||||
func clearDatabase(t *testing.T) {
|
||||
// We do not delete from goose_db_version as we need it to mark the migrations as ran.
|
||||
query := `
|
||||
DELETE FROM labels;
|
||||
DELETE FROM workspaces;
|
||||
DELETE FROM workflow_executions;
|
||||
DELETE FROM cron_workflows;
|
||||
DELETE FROM workspace_templates;
|
||||
DELETE FROM workflow_templates;
|
||||
DELETE FROM workspace_template_versions;
|
||||
DELETE FROM workflow_template_versions;
|
||||
`
|
||||
|
||||
_, err := database.Exec(query)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
122
pkg/config.go
122
pkg/config.go
@@ -2,92 +2,13 @@ package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/onepanelio/core/pkg/util"
|
||||
"github.com/onepanelio/core/pkg/util/ptr"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SystemConfig is configuration loaded from kubernetes config and secrets that includes information about the
|
||||
// database, server, etc.
|
||||
type SystemConfig map[string]string
|
||||
|
||||
// GetValue returns the value in the underlying map if it exists, otherwise nil is returned
|
||||
// If the value does not exist, it is also logged.
|
||||
func (s SystemConfig) GetValue(name string) *string {
|
||||
value, ok := s[name]
|
||||
if !ok {
|
||||
log.WithFields(log.Fields{
|
||||
"Method": "SystemConfig.GetValue",
|
||||
"Name": name,
|
||||
"Error": "does not exist",
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return &value
|
||||
}
|
||||
|
||||
// Domain gets the ONEPANEL_DOMAIN value, or nil.
|
||||
func (s SystemConfig) Domain() *string {
|
||||
return s.GetValue("ONEPANEL_DOMAIN")
|
||||
}
|
||||
|
||||
// APIURL gets the ONEPANEL_API_URL, or nil.
|
||||
func (s SystemConfig) APIURL() *string {
|
||||
return s.GetValue("ONEPANEL_API_URL")
|
||||
}
|
||||
|
||||
// APIProtocol returns either http:// or https:// or nil.
|
||||
// It is based on the ONEPANEL_API_URL config value and checks if it has https or http
|
||||
func (s SystemConfig) APIProtocol() *string {
|
||||
url := s.APIURL()
|
||||
if url == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(*url, "https://") {
|
||||
return ptr.String("https://")
|
||||
}
|
||||
|
||||
return ptr.String("http://")
|
||||
}
|
||||
|
||||
// FQDN gets the ONEPANEL_FQDN value or nil.
|
||||
func (s SystemConfig) FQDN() *string {
|
||||
return s.GetValue("ONEPANEL_FQDN")
|
||||
}
|
||||
|
||||
// NodePoolLabel gets the applicationNodePoolLabel from the config or returns nil.
|
||||
func (s SystemConfig) NodePoolLabel() (label *string) {
|
||||
return s.GetValue("applicationNodePoolLabel")
|
||||
}
|
||||
|
||||
// NodePoolOptions loads and parses the applicationNodePoolOptions from the config.
|
||||
// If there is no data, an error is returned.
|
||||
func (s SystemConfig) NodePoolOptions() (options []*ParameterOption, err error) {
|
||||
data := s.GetValue("applicationNodePoolOptions")
|
||||
if data == nil {
|
||||
return nil, fmt.Errorf("no nodePoolOptions in config")
|
||||
}
|
||||
|
||||
if err = yaml.Unmarshal([]byte(*data), &options); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DatabaseDriverName gets the databaseDriverName value, or nil.
|
||||
func (s SystemConfig) DatabaseDriverName() *string {
|
||||
return s.GetValue("databaseDriverName")
|
||||
}
|
||||
|
||||
func (c *Client) getConfigMap(namespace, name string) (configMap *ConfigMap, err error) {
|
||||
cm, err := c.CoreV1().ConfigMaps(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
@@ -115,20 +36,19 @@ func (c *Client) GetSystemConfig() (config SystemConfig, err error) {
|
||||
}
|
||||
|
||||
namespace := "onepanel"
|
||||
configMap, err := c.getConfigMap(namespace, "onepanel")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config = configMap.Data
|
||||
name := "onepanel"
|
||||
|
||||
secret, err := c.GetSecret(namespace, "onepanel")
|
||||
configMap, err := c.getConfigMap(namespace, name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
databaseUsername, _ := base64.StdEncoding.DecodeString(secret.Data["databaseUsername"])
|
||||
config["databaseUsername"] = string(databaseUsername)
|
||||
databasePassword, _ := base64.StdEncoding.DecodeString(secret.Data["databasePassword"])
|
||||
config["databasePassword"] = string(databasePassword)
|
||||
|
||||
secret, err := c.GetSecret(namespace, name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
config, err = NewSystemConfig(configMap, secret)
|
||||
|
||||
c.systemConfig = config
|
||||
|
||||
@@ -152,11 +72,11 @@ func (c *Client) GetNamespaceConfig(namespace string) (config *NamespaceConfig,
|
||||
return
|
||||
}
|
||||
config = &NamespaceConfig{
|
||||
ArtifactRepository: ArtifactRepositoryConfig{},
|
||||
ArtifactRepository: ArtifactRepositoryProvider{},
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal([]byte(configMap.Data["artifactRepository"]), &config.ArtifactRepository)
|
||||
if err != nil || config.ArtifactRepository.S3 == nil {
|
||||
if err != nil || (config.ArtifactRepository.S3 == nil && config.ArtifactRepository.GCS == nil) {
|
||||
return nil, util.NewUserError(codes.NotFound, "Artifact repository config not found.")
|
||||
}
|
||||
|
||||
@@ -169,14 +89,22 @@ func (c *Client) GetNamespaceConfig(namespace string) (config *NamespaceConfig,
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: replace with switch statement to support additional object storage
|
||||
if config.ArtifactRepository.S3 == nil {
|
||||
switch {
|
||||
case config.ArtifactRepository.S3 != nil:
|
||||
{
|
||||
accessKey, _ := base64.StdEncoding.DecodeString(secret.Data[config.ArtifactRepository.S3.AccessKeySecret.Key])
|
||||
config.ArtifactRepository.S3.AccessKey = string(accessKey)
|
||||
secretKey, _ := base64.StdEncoding.DecodeString(secret.Data[config.ArtifactRepository.S3.SecretKeySecret.Key])
|
||||
config.ArtifactRepository.S3.Secretkey = string(secretKey)
|
||||
}
|
||||
case config.ArtifactRepository.GCS != nil:
|
||||
{
|
||||
serviceJSON, _ := base64.StdEncoding.DecodeString(secret.Data[config.ArtifactRepository.GCS.ServiceAccountKeySecret.Key])
|
||||
config.ArtifactRepository.GCS.ServiceAccountJSON = string(serviceJSON)
|
||||
}
|
||||
default:
|
||||
return nil, util.NewUserError(codes.NotFound, "Artifact repository config not found.")
|
||||
}
|
||||
accessKey, _ := base64.StdEncoding.DecodeString(secret.Data[config.ArtifactRepository.S3.AccessKeySecret.Key])
|
||||
config.ArtifactRepository.S3.AccessKey = string(accessKey)
|
||||
secretKey, _ := base64.StdEncoding.DecodeString(secret.Data[config.ArtifactRepository.S3.SecretKeySecret.Key])
|
||||
config.ArtifactRepository.S3.Secretkey = string(secretKey)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,27 +1,299 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/onepanelio/core/pkg/util/ptr"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8yaml "sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type ArtifactRepositoryS3Config struct {
|
||||
KeyFormat string
|
||||
// SystemConfig is configuration loaded from kubernetes config and secrets that includes information about the
|
||||
// database, server, etc.
|
||||
type SystemConfig map[string]string
|
||||
|
||||
// NodePoolOption extends ParameterOption to support resourceRequirements
|
||||
type NodePoolOption struct {
|
||||
ParameterOption
|
||||
Resources corev1.ResourceRequirements
|
||||
}
|
||||
|
||||
// NewSystemConfig creates a System config by getting the required data from a ConfigMap and Secret
|
||||
func NewSystemConfig(configMap *ConfigMap, secret *Secret) (config SystemConfig, err error) {
|
||||
config = configMap.Data
|
||||
|
||||
databaseUsername, err := base64.StdEncoding.DecodeString(secret.Data["databaseUsername"])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config["databaseUsername"] = string(databaseUsername)
|
||||
|
||||
databasePassword, err := base64.StdEncoding.DecodeString(secret.Data["databasePassword"])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config["databasePassword"] = string(databasePassword)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetValue returns the value in the underlying map if it exists, otherwise nil is returned
|
||||
// If the value does not exist, it is also logged.
|
||||
func (s SystemConfig) GetValue(name string) *string {
|
||||
value, ok := s[name]
|
||||
if !ok {
|
||||
log.WithFields(log.Fields{
|
||||
"Method": "SystemConfig.GetValue",
|
||||
"Name": name,
|
||||
"Error": "does not exist",
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return &value
|
||||
}
|
||||
|
||||
// Domain gets the ONEPANEL_DOMAIN value, or nil.
|
||||
func (s SystemConfig) Domain() *string {
|
||||
return s.GetValue("ONEPANEL_DOMAIN")
|
||||
}
|
||||
|
||||
// APIURL gets the ONEPANEL_API_URL, or nil.
|
||||
func (s SystemConfig) APIURL() *string {
|
||||
return s.GetValue("ONEPANEL_API_URL")
|
||||
}
|
||||
|
||||
// APIProtocol returns either http:// or https:// or nil.
|
||||
// It is based on the ONEPANEL_API_URL config value and checks if it has https or http
|
||||
func (s SystemConfig) APIProtocol() *string {
|
||||
url := s.APIURL()
|
||||
if url == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(*url, "https://") {
|
||||
return ptr.String("https://")
|
||||
}
|
||||
|
||||
return ptr.String("http://")
|
||||
}
|
||||
|
||||
// FQDN gets the ONEPANEL_FQDN value or nil.
|
||||
func (s SystemConfig) FQDN() *string {
|
||||
return s.GetValue("ONEPANEL_FQDN")
|
||||
}
|
||||
|
||||
// NodePoolLabel gets the applicationNodePoolLabel from the config or returns nil.
|
||||
func (s SystemConfig) NodePoolLabel() (label *string) {
|
||||
return s.GetValue("applicationNodePoolLabel")
|
||||
}
|
||||
|
||||
// NodePoolOptions loads and parses the applicationNodePoolOptions from the config.
|
||||
// If there is no data, an error is returned.
|
||||
func (s SystemConfig) NodePoolOptions() (options []*NodePoolOption, err error) {
|
||||
data := s.GetValue("applicationNodePoolOptions")
|
||||
if data == nil {
|
||||
return nil, fmt.Errorf("no nodePoolOptions in config")
|
||||
}
|
||||
|
||||
if err = k8yaml.Unmarshal([]byte(*data), &options); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NodePoolOptionByValue returns the nodePoolOption based on a given value
|
||||
func (s SystemConfig) NodePoolOptionByValue(value string) (option *NodePoolOption, err error) {
|
||||
options, err := s.NodePoolOptions()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, opt := range options {
|
||||
if opt.Value == value {
|
||||
option = opt
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DatabaseDriverName gets the databaseDriverName value, or nil.
|
||||
func (s SystemConfig) DatabaseDriverName() *string {
|
||||
return s.GetValue("databaseDriverName")
|
||||
}
|
||||
|
||||
// DatabaseConnection returns system config information to connect to a database
|
||||
func (s SystemConfig) DatabaseConnection() (driverName, dataSourceName string) {
|
||||
dataSourceName = fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=disable",
|
||||
s["databaseHost"], s["databaseUsername"], s["databasePassword"], s["databaseName"])
|
||||
|
||||
driverName = *s.DatabaseDriverName()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateNodePoolOptions will update the sys-node-pool parameter's options with runtime values
|
||||
// The original slice is unmodified, the returned slice has the updated values
|
||||
// If sys-node-pool is not present, nothing happens.
|
||||
func (s SystemConfig) UpdateNodePoolOptions(parameters []Parameter) ([]Parameter, error) {
|
||||
result := make([]Parameter, 0)
|
||||
|
||||
var nodePoolParameter *Parameter
|
||||
|
||||
// Copy the original parameters, skipping sys-node-pool
|
||||
for i := range parameters {
|
||||
parameter := parameters[i]
|
||||
if parameter.Name == "sys-node-pool" {
|
||||
nodePoolParameter = ¶meter
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, parameter)
|
||||
}
|
||||
|
||||
if nodePoolParameter == nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
nodePoolOptions, err := s.NodePoolOptions()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
options := make([]*ParameterOption, 0)
|
||||
for _, option := range nodePoolOptions {
|
||||
newOption := &ParameterOption{
|
||||
Name: option.Name,
|
||||
Value: option.Value,
|
||||
}
|
||||
|
||||
options = append(options, newOption)
|
||||
}
|
||||
|
||||
nodePoolParameter.Options = options
|
||||
|
||||
result = append(result, *nodePoolParameter)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ArtifactRepositoryS3Provider is meant to be used
|
||||
// by the CLI. CLI will marshal this struct into the correct
|
||||
// YAML structure for k8s configmap / secret.
|
||||
type ArtifactRepositoryS3Provider struct {
|
||||
KeyFormat string `yaml:"keyFormat"`
|
||||
Bucket string
|
||||
Endpoint string
|
||||
Insecure bool
|
||||
Region string
|
||||
AccessKeySecret corev1.SecretKeySelector
|
||||
SecretKeySecret corev1.SecretKeySelector
|
||||
AccessKey string
|
||||
Secretkey string
|
||||
AccessKeySecret ArtifactRepositorySecret `yaml:"accessKeySecret"`
|
||||
SecretKeySecret ArtifactRepositorySecret `yaml:"secretKeySecret"`
|
||||
AccessKey string `yaml:"accessKey,omitempty"`
|
||||
Secretkey string `yaml:"secretKey,omitempty"`
|
||||
}
|
||||
|
||||
// ArtifactRepositoryGCSProvider is meant to be used
|
||||
// by the CLI. CLI will marshal this struct into the correct
|
||||
// YAML structure for k8s configmap / secret.
|
||||
type ArtifactRepositoryGCSProvider struct {
|
||||
KeyFormat string `yaml:"keyFormat"`
|
||||
Bucket string
|
||||
Endpoint string
|
||||
Insecure bool
|
||||
ServiceAccountKey string `yaml:"serviceAccountKey,omitempty"`
|
||||
ServiceAccountKeySecret ArtifactRepositorySecret `yaml:"serviceAccountKeySecret"`
|
||||
ServiceAccountJSON string `yaml:"serviceAccountJSON,omitempty"`
|
||||
}
|
||||
|
||||
// ArtifactRepositoryProvider is used to setup access into AWS Cloud Storage
|
||||
// or Google Cloud storage.
|
||||
// - The relevant sub-struct (S3, GCS) is unmarshalled into from the cluster configmap.
|
||||
// Right now, either the S3 or GCS struct will be filled in. Multiple cloud
|
||||
// providers are not supported at the same time in params.yaml (manifests deployment).
|
||||
type ArtifactRepositoryProvider struct {
|
||||
S3 *ArtifactRepositoryS3Provider `yaml:"s3,omitempty"`
|
||||
GCS *ArtifactRepositoryGCSProvider `yaml:"gcs,omitempty"`
|
||||
}
|
||||
|
||||
// ArtifactRepositorySecret holds information about a kubernetes Secret.
|
||||
// - The "key" is the specific key inside the Secret.
|
||||
// - The "name" is the name of the Secret.
|
||||
// Usually, this is used to figure out what secret to look into for a specific value.
|
||||
type ArtifactRepositorySecret struct {
|
||||
Key string `yaml:"key"`
|
||||
Name string `yaml:"name"`
|
||||
}
|
||||
|
||||
// MarshalToYaml is used by the CLI to generate configmaps during deployment
|
||||
// or build operations.
|
||||
func (a *ArtifactRepositoryS3Provider) MarshalToYaml() (string, error) {
|
||||
builder := &strings.Builder{}
|
||||
encoder := yaml.NewEncoder(builder)
|
||||
encoder.SetIndent(6)
|
||||
defer encoder.Close()
|
||||
err := encoder.Encode(&ArtifactRepositoryProvider{
|
||||
S3: &ArtifactRepositoryS3Provider{
|
||||
KeyFormat: a.KeyFormat,
|
||||
Bucket: a.Bucket,
|
||||
Endpoint: a.Endpoint,
|
||||
Insecure: a.Insecure,
|
||||
Region: a.Region,
|
||||
AccessKeySecret: ArtifactRepositorySecret{
|
||||
Name: a.AccessKeySecret.Name,
|
||||
Key: a.AccessKeySecret.Key,
|
||||
},
|
||||
SecretKeySecret: ArtifactRepositorySecret{
|
||||
Name: a.SecretKeySecret.Name,
|
||||
Key: a.SecretKeySecret.Key,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
// MarshalToYaml is used by the CLI to generate configmaps during deployment
|
||||
// or build operations.
|
||||
func (g *ArtifactRepositoryGCSProvider) MarshalToYaml() (string, error) {
|
||||
builder := &strings.Builder{}
|
||||
encoder := yaml.NewEncoder(builder)
|
||||
encoder.SetIndent(6)
|
||||
defer encoder.Close()
|
||||
err := encoder.Encode(&ArtifactRepositoryProvider{
|
||||
GCS: &ArtifactRepositoryGCSProvider{
|
||||
KeyFormat: g.KeyFormat,
|
||||
Bucket: g.Bucket,
|
||||
Endpoint: g.Endpoint,
|
||||
Insecure: g.Insecure,
|
||||
ServiceAccountKeySecret: ArtifactRepositorySecret{
|
||||
Key: "artifactRepositoryGCSServiceAccountKey",
|
||||
Name: "onepanel",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
// FormatKey replaces placeholder values with their actual values and returns this string.
|
||||
// {{workflow.namespace}} -> namespace
|
||||
// {{workflow.name}} -> workflowName
|
||||
// {{pod.name}} -> podName
|
||||
func (a *ArtifactRepositoryS3Config) FormatKey(namespace, workflowName, podName string) string {
|
||||
func (a *ArtifactRepositoryS3Provider) FormatKey(namespace, workflowName, podName string) string {
|
||||
keyFormat := a.KeyFormat
|
||||
|
||||
keyFormat = strings.Replace(keyFormat, "{{workflow.namespace}}", namespace, -1)
|
||||
@@ -31,10 +303,20 @@ func (a *ArtifactRepositoryS3Config) FormatKey(namespace, workflowName, podName
|
||||
return keyFormat
|
||||
}
|
||||
|
||||
type ArtifactRepositoryConfig struct {
|
||||
S3 *ArtifactRepositoryS3Config
|
||||
// FormatKey replaces placeholder values with their actual values and returns this string.
|
||||
// {{workflow.namespace}} -> namespace
|
||||
// {{workflow.name}} -> workflowName
|
||||
// {{pod.name}} -> podName
|
||||
func (g *ArtifactRepositoryGCSProvider) FormatKey(namespace, workflowName, podName string) string {
|
||||
keyFormat := g.KeyFormat
|
||||
|
||||
keyFormat = strings.Replace(keyFormat, "{{workflow.namespace}}", namespace, -1)
|
||||
keyFormat = strings.Replace(keyFormat, "{{workflow.name}}", workflowName, -1)
|
||||
keyFormat = strings.Replace(keyFormat, "{{pod.name}}", podName, -1)
|
||||
|
||||
return keyFormat
|
||||
}
|
||||
|
||||
type NamespaceConfig struct {
|
||||
ArtifactRepository ArtifactRepositoryConfig
|
||||
ArtifactRepository ArtifactRepositoryProvider
|
||||
}
|
||||
|
||||
@@ -21,8 +21,9 @@ func testCreateNamespace(c *Client) {
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestListNamespace(t *testing.T) {
|
||||
c := NewTestClient()
|
||||
|
||||
func TestClient_ListNamespace(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
|
||||
testCreateNamespace(c)
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateSecret(t *testing.T) {
|
||||
c := NewTestClient()
|
||||
func TestClient_CreateSecret(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
|
||||
err := c.CreateSecret("namespace", &Secret{
|
||||
Name: "name",
|
||||
@@ -15,8 +15,8 @@ func TestCreateSecret(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestGetSecret(t *testing.T) {
|
||||
c := NewTestClient()
|
||||
func TestClient_GetSecret(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
|
||||
err := c.CreateSecret("namespace", &Secret{
|
||||
Name: "name",
|
||||
|
||||
57
pkg/util/gcs/gcs.go
Normal file
57
pkg/util/gcs/gcs.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package gcs
|
||||
|
||||
import (
|
||||
"cloud.google.com/go/storage"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/option"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Client is a struct used for accessing Google Cloud Storage.
|
||||
type Client struct {
|
||||
*storage.Client
|
||||
}
|
||||
|
||||
// NewClient handles the details of initializing the connection to Google Cloud Storage.
|
||||
// - Note that the permissions are set to ReadWrite.
|
||||
func NewClient(namespace string, serviceAccountJSON string) (gcsClient *Client, err error) {
|
||||
ctx := context.Background()
|
||||
creds, err := google.CredentialsFromJSON(ctx, []byte(serviceAccountJSON), storage.ScopeReadWrite)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"Namespace": namespace,
|
||||
"JSON": serviceAccountJSON,
|
||||
"Error": err.Error(),
|
||||
}).Error("GetGCSClient failed when initializing a new GCS client.")
|
||||
return
|
||||
}
|
||||
client, err := storage.NewClient(ctx, option.WithCredentials(creds))
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"Namespace": namespace,
|
||||
"JSON": serviceAccountJSON,
|
||||
"Error": err.Error(),
|
||||
}).Error("GetGCSClient failed when initializing a new GCS client.")
|
||||
return
|
||||
}
|
||||
|
||||
return &Client{Client: client}, nil
|
||||
}
|
||||
|
||||
/* GetObject retrieves a specific object from Google Cloud Storage.
|
||||
- Function Name is meant to be consistent with S3's.
|
||||
*/
|
||||
func (c *Client) GetObject(bucket, key string) (stream io.ReadCloser, err error) {
|
||||
ctx := context.Background()
|
||||
stream, err = c.Client.Bucket(bucket).Object(key).NewReader(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if stream == nil {
|
||||
defer stream.Close()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
99
pkg/workflow_execution_test.go
Normal file
99
pkg/workflow_execution_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestClient_CreateWorkflowExecution tests creating a workflow execution
|
||||
func TestClient_CreateWorkflowExecution(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
wt, _ = c.CreateWorkflowTemplate(namespace, wt)
|
||||
|
||||
we := &WorkflowExecution{
|
||||
Name: "test",
|
||||
}
|
||||
|
||||
we, err := c.CreateWorkflowExecution(namespace, we, wt)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// TestClient_GetWorkflowExecution tests getting a workflow execution that exists
|
||||
func TestClient_GetWorkflowExecution(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
wt, _ = c.CreateWorkflowTemplate(namespace, wt)
|
||||
|
||||
we := &WorkflowExecution{
|
||||
Name: "test",
|
||||
}
|
||||
|
||||
we, _ = c.CreateWorkflowExecution(namespace, we, wt)
|
||||
|
||||
getWe, err := c.GetWorkflowExecution(namespace, we.UID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, we.Name, getWe.Name)
|
||||
assert.Equal(t, we.UID, getWe.UID)
|
||||
}
|
||||
|
||||
// TestClient_GetWorkflowExecution tests getting a workflow execution that doesn't exist
|
||||
func TestClient_GetWorkflowExecution_NotExists(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
getWe, err := c.GetWorkflowExecution(namespace, "not-exist")
|
||||
assert.Nil(t, getWe)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// TestClient_ArchiveWorkflowExecution_NotExist makes sure there is no error if the workflow
|
||||
// execution does not exist
|
||||
func TestClient_ArchiveWorkflowExecution_NotExist(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
err := c.ArchiveWorkflowExecution("onepanel-no-exist", "test-no-exist")
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// TestClient_ArchiveWorkflowExecution_Exist makes sure we archive an existing workflow execution correctly
|
||||
func TestClient_ArchiveWorkflowExecution_Exist(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
weName := "test"
|
||||
|
||||
wt := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
wt, _ = c.CreateWorkflowTemplate(namespace, wt)
|
||||
|
||||
we := &WorkflowExecution{
|
||||
Name: weName,
|
||||
}
|
||||
|
||||
we, err := c.CreateWorkflowExecution(namespace, we, wt)
|
||||
|
||||
err = c.ArchiveWorkflowExecution(namespace, weName)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package v1
|
||||
import (
|
||||
"encoding/json"
|
||||
wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"github.com/onepanelio/core/util/sql"
|
||||
"time"
|
||||
)
|
||||
@@ -22,6 +23,7 @@ type WorkflowExecution struct {
|
||||
FinishedAt *time.Time `db:"finished_at"`
|
||||
WorkflowTemplate *WorkflowTemplate `db:"workflow_template"`
|
||||
Labels map[string]string
|
||||
ArgoWorkflow *wfv1.Workflow
|
||||
}
|
||||
|
||||
// WorkflowExecutionOptions are options you have for an executing workflow
|
||||
@@ -55,6 +57,18 @@ type WorkflowExecutionStatus struct {
|
||||
FinishedAt *time.Time `db:"finished_at" json:"finishedAt"`
|
||||
}
|
||||
|
||||
// GenerateUID generates a uid from the input name and sets it on the workflow execution
|
||||
func (we *WorkflowExecution) GenerateUID(name string) error {
|
||||
result, err := uid2.GenerateUID(name, 63)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
we.UID = result
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadParametersFromBytes loads Parameters from the WorkflowExecution's ParameterBytes field.
|
||||
func (we *WorkflowExecution) LoadParametersFromBytes() ([]Parameter, error) {
|
||||
loadedParameters := make([]Parameter, 0)
|
||||
@@ -75,6 +89,17 @@ func (we *WorkflowExecution) LoadParametersFromBytes() ([]Parameter, error) {
|
||||
return we.Parameters, err
|
||||
}
|
||||
|
||||
// GetParameterValue returns the value of the parameter with the given name, or nil if there is no such parameter
|
||||
func (we *WorkflowExecution) GetParameterValue(name string) *string {
|
||||
for _, p := range we.Parameters {
|
||||
if p.Name == name {
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getWorkflowExecutionColumns returns all of the columns for workflowExecution modified by alias, destination.
|
||||
// see formatColumnSelect
|
||||
func getWorkflowExecutionColumns(aliasAndDestination ...string) []string {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/onepanelio/core/pkg/util/pagination"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -21,23 +20,67 @@ import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (c *Client) createWorkflowTemplate(namespace string, workflowTemplate *WorkflowTemplate) (*WorkflowTemplate, *WorkflowTemplateVersion, error) {
|
||||
uid, err := uid2.GenerateUID(workflowTemplate.Name, 30)
|
||||
// createWorkflowTemplateVersionDB inserts a record into workflow_template_versions using the current time accurate to nanoseconds
|
||||
// the data is returned in the resulting WorkflowTemplateVersion struct.
|
||||
func createWorkflowTemplateVersionDB(runner sq.BaseRunner, workflowTemplateID uint64, manifest string, latest bool) (workflowTemplateVersion *WorkflowTemplateVersion, err error) {
|
||||
ts := time.Now().UnixNano()
|
||||
|
||||
workflowTemplateVersion = &WorkflowTemplateVersion{
|
||||
WorkflowTemplate: &WorkflowTemplate{
|
||||
ID: workflowTemplateID,
|
||||
},
|
||||
Manifest: manifest,
|
||||
IsLatest: latest,
|
||||
Version: ts,
|
||||
}
|
||||
|
||||
err = sb.Insert("workflow_template_versions").
|
||||
SetMap(sq.Eq{
|
||||
"workflow_template_id": workflowTemplateID,
|
||||
"version": ts,
|
||||
"is_latest": true,
|
||||
"manifest": manifest,
|
||||
}).
|
||||
Suffix("RETURNING id").
|
||||
RunWith(runner).
|
||||
QueryRow().
|
||||
Scan(&workflowTemplateVersion.ID)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// createLatestWorkflowTemplateVersionDB creates a new workflow template version and marks all previous versions as not latest.
|
||||
func createLatestWorkflowTemplateVersionDB(runner sq.BaseRunner, workflowTemplateID uint64, manifest string) (workflowTemplateVersion *WorkflowTemplateVersion, err error) {
|
||||
_, err = sb.Update("workflow_template_versions").
|
||||
Set("is_latest", false).
|
||||
Where(sq.Eq{
|
||||
"workflow_template_id": workflowTemplateID,
|
||||
}).
|
||||
RunWith(runner).
|
||||
Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return createWorkflowTemplateVersionDB(runner, workflowTemplateID, manifest, true)
|
||||
}
|
||||
|
||||
// createWorkflowTemplate creates a WorkflowTemplate and all of the DB/Argo/K8s related resources
|
||||
// The returned WorkflowTemplate has the ArgoWorkflowTemplate set to the newly created one.
|
||||
func (c *Client) createWorkflowTemplate(namespace string, workflowTemplate *WorkflowTemplate) (*WorkflowTemplate, *WorkflowTemplateVersion, error) {
|
||||
if err := workflowTemplate.GenerateUID(workflowTemplate.Name); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
workflowTemplate.UID = uid
|
||||
|
||||
tx, err := c.DB.Begin()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
versionUnix := time.Now().Unix()
|
||||
|
||||
err = sb.Insert("workflow_templates").
|
||||
SetMap(sq.Eq{
|
||||
"uid": uid,
|
||||
"uid": workflowTemplate.UID,
|
||||
"name": workflowTemplate.Name,
|
||||
"namespace": namespace,
|
||||
"is_system": workflowTemplate.IsSystem,
|
||||
@@ -50,33 +93,22 @@ func (c *Client) createWorkflowTemplate(namespace string, workflowTemplate *Work
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
workflowTemplateVersion := &WorkflowTemplateVersion{}
|
||||
err = sb.Insert("workflow_template_versions").
|
||||
SetMap(sq.Eq{
|
||||
"workflow_template_id": workflowTemplate.ID,
|
||||
"version": versionUnix,
|
||||
"is_latest": true,
|
||||
"manifest": workflowTemplate.Manifest,
|
||||
}).
|
||||
Suffix("RETURNING id").
|
||||
RunWith(tx).
|
||||
QueryRow().
|
||||
Scan(&workflowTemplateVersion.ID)
|
||||
workflowTemplateVersion, err := createWorkflowTemplateVersionDB(tx, workflowTemplate.ID, workflowTemplate.Manifest, true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
workflowTemplate.WorkflowTemplateVersionID = workflowTemplateVersion.ID
|
||||
|
||||
_, err = c.InsertLabelsRunner(tx, TypeWorkflowTemplateVersion, workflowTemplateVersion.ID, workflowTemplate.Labels)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
argoWft, err := createArgoWorkflowTemplate(workflowTemplate, versionUnix)
|
||||
argoWft, err := createArgoWorkflowTemplate(workflowTemplate, workflowTemplateVersion.Version)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
argoWft.Labels[label.WorkflowTemplateVersionUid] = strconv.FormatInt(versionUnix, 10)
|
||||
argoWft.Labels[label.WorkflowTemplateVersionUid] = strconv.FormatInt(workflowTemplateVersion.Version, 10)
|
||||
|
||||
if workflowTemplate.Resource != nil && workflowTemplate.ResourceUID != nil {
|
||||
if *workflowTemplate.Resource == TypeWorkspaceTemplate {
|
||||
@@ -96,7 +128,8 @@ func (c *Client) createWorkflowTemplate(namespace string, workflowTemplate *Work
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
workflowTemplate.Version = versionUnix
|
||||
workflowTemplate.ArgoWorkflowTemplate = argoWft
|
||||
workflowTemplate.Version = workflowTemplateVersion.Version
|
||||
|
||||
return workflowTemplate, workflowTemplateVersion, nil
|
||||
}
|
||||
@@ -131,6 +164,8 @@ func (c *Client) countWorkflowTemplateSelectBuilder(namespace string) sq.SelectB
|
||||
return sb
|
||||
}
|
||||
|
||||
// workflowTemplatesVersionSelectBuilder selects data from workflow template versions joined to a workflow template
|
||||
// the versions/template are filtered by the workflow template's namespace.
|
||||
func (c *Client) workflowTemplatesVersionSelectBuilder(namespace string) sq.SelectBuilder {
|
||||
sb := sb.Select(getWorkflowTemplateVersionColumns("wtv")...).
|
||||
From("workflow_template_versions wtv").
|
||||
@@ -142,11 +177,14 @@ func (c *Client) workflowTemplatesVersionSelectBuilder(namespace string) sq.Sele
|
||||
return sb
|
||||
}
|
||||
|
||||
// GetWorkflowTemplateDB returns a WorkflowTemplate from the database
|
||||
func (c *Client) GetWorkflowTemplateDB(namespace, name string) (workflowTemplate *WorkflowTemplate, err error) {
|
||||
// GetWorkflowTemplateDB returns a WorkflowTemplate from the database that is not archived, should one exist.
|
||||
func (c *Client) getWorkflowTemplateDB(namespace, name string) (workflowTemplate *WorkflowTemplate, err error) {
|
||||
workflowTemplate = &WorkflowTemplate{}
|
||||
|
||||
sb := c.workflowTemplatesSelectBuilder(namespace).
|
||||
Where(sq.Eq{
|
||||
"name": name,
|
||||
"wt.name": name,
|
||||
"wt.is_archived": false,
|
||||
})
|
||||
|
||||
err = c.DB.Getx(workflowTemplate, sb)
|
||||
@@ -154,9 +192,11 @@ func (c *Client) GetWorkflowTemplateDB(namespace, name string) (workflowTemplate
|
||||
return
|
||||
}
|
||||
|
||||
// GetWorkflowTemplateVersionDB will return a WorkflowTemplateVersion given the arguments.
|
||||
// getWorkflowTemplateVersionDB will return a WorkflowTemplateVersion given the arguments.
|
||||
// version can be a number as a string, or the string "latest" to get the latest.
|
||||
func (c *Client) GetWorkflowTemplateVersionDB(namespace, name, version string) (workflowTemplateVersion *WorkflowTemplateVersion, err error) {
|
||||
func (c *Client) getWorkflowTemplateVersionDB(namespace, name, version string) (workflowTemplateVersion *WorkflowTemplateVersion, err error) {
|
||||
workflowTemplateVersion = &WorkflowTemplateVersion{}
|
||||
|
||||
whereMap := sq.Eq{
|
||||
"wt.name": name,
|
||||
}
|
||||
@@ -176,8 +216,8 @@ func (c *Client) GetWorkflowTemplateVersionDB(namespace, name, version string) (
|
||||
}
|
||||
|
||||
// GetLatestWorkflowTemplateVersionDB returns the latest WorkflowTemplateVersion
|
||||
func (c *Client) GetLatestWorkflowTemplateVersionDB(namespace, name string) (workflowTemplateVersion *WorkflowTemplateVersion, err error) {
|
||||
return c.GetWorkflowTemplateVersionDB(namespace, name, "latest")
|
||||
func (c *Client) getLatestWorkflowTemplateVersionDB(namespace, name string) (workflowTemplateVersion *WorkflowTemplateVersion, err error) {
|
||||
return c.getWorkflowTemplateVersionDB(namespace, name, "latest")
|
||||
}
|
||||
|
||||
func (c *Client) getWorkflowTemplateById(id uint64) (workflowTemplate *WorkflowTemplate, err error) {
|
||||
@@ -197,13 +237,16 @@ func (c *Client) getWorkflowTemplateById(id uint64) (workflowTemplate *WorkflowT
|
||||
return
|
||||
}
|
||||
|
||||
// If version is 0, the latest workflow template is fetched.
|
||||
// getWorkflowTemplate gets the workflowtemplate given the input data.
|
||||
// it also loads the argo workflow and labels data.
|
||||
// If version is <= 0, the latest workflow template is fetched.
|
||||
// If not found, (nil, nil) is returned
|
||||
func (c *Client) getWorkflowTemplate(namespace, uid string, version int64) (workflowTemplate *WorkflowTemplate, err error) {
|
||||
workflowTemplate = &WorkflowTemplate{
|
||||
WorkflowExecutionStatisticReport: &WorkflowExecutionStatisticReport{},
|
||||
}
|
||||
|
||||
// A new workflow template version is created upon a change, so we use it's createdAt
|
||||
// A new workflow template version is created upon a change, so we use it's created_at
|
||||
// as a modified_at for the workflow template.
|
||||
sb := c.workflowTemplatesSelectBuilder(namespace).
|
||||
Columns("wtv.manifest", "wtv.version", "wtv.id workflow_template_version_id", "wtv.created_at modified_at").
|
||||
@@ -213,7 +256,7 @@ func (c *Client) getWorkflowTemplate(namespace, uid string, version int64) (work
|
||||
"wt.is_archived": false,
|
||||
})
|
||||
|
||||
if version == 0 {
|
||||
if version <= 0 {
|
||||
sb = sb.Where(sq.Eq{"wtv.is_latest": true})
|
||||
} else {
|
||||
sb = sb.Where(sq.Eq{"wtv.version": version})
|
||||
@@ -256,7 +299,7 @@ func (c *Client) getWorkflowTemplate(namespace, uid string, version int64) (work
|
||||
}
|
||||
|
||||
func (c *Client) listWorkflowTemplateVersions(namespace, uid string) (workflowTemplateVersions []*WorkflowTemplate, err error) {
|
||||
dbVersions, err := c.listDBWorkflowTemplateVersions(namespace, uid)
|
||||
dbVersions, err := c.selectWorkflowTemplateVersionsDB(namespace, uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -291,8 +334,10 @@ func (c *Client) listWorkflowTemplateVersions(namespace, uid string) (workflowTe
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) listWorkflowTemplates(namespace string, paginator *pagination.PaginationRequest) (workflowTemplateVersions []*WorkflowTemplate, err error) {
|
||||
workflowTemplateVersions = []*WorkflowTemplate{}
|
||||
// selectWorkflowTemplatesDB loads workflow templates from the database for the input namespace
|
||||
// it also selects the total number of versions and latest version id
|
||||
func (c *Client) selectWorkflowTemplatesDB(namespace string, paginator *pagination.PaginationRequest) (workflowTemplates []*WorkflowTemplate, err error) {
|
||||
workflowTemplates = make([]*WorkflowTemplate, 0)
|
||||
|
||||
sb := c.workflowTemplatesSelectBuilder(namespace).
|
||||
Column("COUNT(wtv.*) versions, MAX(wtv.id) workflow_template_version_id").
|
||||
@@ -303,28 +348,24 @@ func (c *Client) listWorkflowTemplates(namespace string, paginator *pagination.P
|
||||
"wt.is_system": false,
|
||||
}).
|
||||
OrderBy("wt.created_at DESC")
|
||||
|
||||
sb = *paginator.ApplyToSelect(&sb)
|
||||
query, args, err := sb.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.DB.Select(&workflowTemplateVersions, query, args...)
|
||||
err = c.DB.Selectx(&workflowTemplates, sb)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CountWorkflowTemplates counts the total number of workflow templates for the given namespace
|
||||
// archived, and system templates are ignored.
|
||||
func (c *Client) CountWorkflowTemplates(namespace string) (count int, err error) {
|
||||
err = sb.Select("COUNT( DISTINCT( wt.id ))").
|
||||
err = sb.Select("COUNT(*)").
|
||||
From("workflow_templates wt").
|
||||
Join("workflow_template_versions wtv ON wtv.workflow_template_id = wt.id").
|
||||
Where(sq.Eq{
|
||||
"wt.namespace": namespace,
|
||||
"wt.is_archived": false,
|
||||
"wt.is_system": false,
|
||||
}).
|
||||
RunWith(c.DB.DB).
|
||||
RunWith(c.DB).
|
||||
QueryRow().
|
||||
Scan(&count)
|
||||
|
||||
@@ -368,6 +409,11 @@ func (c *Client) CreateWorkflowTemplate(namespace string, workflowTemplate *Work
|
||||
return newWorkflowTemplate, nil
|
||||
}
|
||||
|
||||
// CreateWorkflowTemplateVersion creates a new workflow template version including argo resources.
|
||||
// It marks any older workflow template versions as not latest
|
||||
//
|
||||
// Pre-condition: a Workflow Template version already exists
|
||||
// Post-condition: the input workflow template will have it's fields updated so it matches the new version data.
|
||||
func (c *Client) CreateWorkflowTemplateVersion(namespace string, workflowTemplate *WorkflowTemplate) (*WorkflowTemplate, error) {
|
||||
if workflowTemplate.UID == "" {
|
||||
return nil, fmt.Errorf("uid required for CreateWorkflowTemplateVersion")
|
||||
@@ -378,8 +424,6 @@ func (c *Client) CreateWorkflowTemplateVersion(namespace string, workflowTemplat
|
||||
return nil, util.NewUserError(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
versionUnix := time.Now().Unix()
|
||||
|
||||
tx, err := c.DB.Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -391,75 +435,26 @@ func (c *Client) CreateWorkflowTemplateVersion(namespace string, workflowTemplat
|
||||
"wt.uid": workflowTemplate.UID,
|
||||
"wt.is_archived": false,
|
||||
})
|
||||
query, args, err := wftSb.ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workflowTemplateDb := &WorkflowTemplate{}
|
||||
if err = c.DB.Get(workflowTemplateDb, query, args...); err != nil {
|
||||
workflowTemplateDB := &WorkflowTemplate{}
|
||||
if err = c.DB.Getx(workflowTemplateDB, wftSb); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = sb.Update("workflow_template_versions").
|
||||
Set("is_latest", false).
|
||||
Where(sq.Eq{
|
||||
"workflow_template_id": workflowTemplateDb.ID,
|
||||
}).
|
||||
RunWith(tx).
|
||||
Exec()
|
||||
workflowTemplateVersion, err := createLatestWorkflowTemplateVersionDB(tx, workflowTemplateDB.ID, workflowTemplate.Manifest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workflowTemplate.WorkflowTemplateVersionID = workflowTemplateVersion.ID
|
||||
|
||||
workflowTemplateVersionID := uint64(0)
|
||||
err = sb.Insert("workflow_template_versions").
|
||||
SetMap(sq.Eq{
|
||||
"workflow_template_id": workflowTemplateDb.ID,
|
||||
"version": versionUnix,
|
||||
"is_latest": true,
|
||||
"manifest": workflowTemplate.Manifest,
|
||||
}).
|
||||
Suffix("RETURNING id").
|
||||
RunWith(tx).
|
||||
QueryRow().
|
||||
Scan(&workflowTemplateVersionID)
|
||||
updatedTemplate, err := createArgoWorkflowTemplate(workflowTemplate, workflowTemplateVersion.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workflowTemplate.WorkflowTemplateVersionID = workflowTemplateVersionID
|
||||
latest, err := c.getArgoWorkflowTemplate(namespace, workflowTemplate.UID, "latest")
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"Namespace": namespace,
|
||||
"WorkflowTemplate": workflowTemplate,
|
||||
"Error": err.Error(),
|
||||
}).Error("Could not get latest argo workflow template")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delete(latest.Labels, label.VersionLatest)
|
||||
|
||||
latest, err = c.ArgoprojV1alpha1().WorkflowTemplates(namespace).Update(latest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updatedTemplate, err := createArgoWorkflowTemplate(workflowTemplate, versionUnix)
|
||||
if err != nil {
|
||||
latest.Labels[label.VersionLatest] = "true"
|
||||
if _, err := c.ArgoprojV1alpha1().WorkflowTemplates(namespace).Update(latest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updatedTemplate.TypeMeta = v1.TypeMeta{}
|
||||
updatedTemplate.ObjectMeta.ResourceVersion = ""
|
||||
updatedTemplate.ObjectMeta.SetSelfLink("")
|
||||
updatedTemplate.Labels[label.WorkflowTemplateVersionUid] = strconv.FormatInt(versionUnix, 10)
|
||||
updatedTemplate.Labels[label.WorkflowTemplateVersionUid] = strconv.FormatInt(workflowTemplateVersion.Version, 10)
|
||||
|
||||
parametersMap, err := workflowTemplate.GetParametersKeyString()
|
||||
if err != nil {
|
||||
@@ -473,15 +468,32 @@ func (c *Client) CreateWorkflowTemplateVersion(namespace string, workflowTemplat
|
||||
updatedTemplate.Annotations[key] = value
|
||||
}
|
||||
|
||||
latest, err := c.getArgoWorkflowTemplate(namespace, workflowTemplate.UID, "latest")
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"Namespace": namespace,
|
||||
"WorkflowTemplate": workflowTemplate,
|
||||
"Error": err.Error(),
|
||||
}).Error("Could not get latest argo workflow template")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
delete(latest.Labels, label.VersionLatest)
|
||||
|
||||
if _, err := c.ArgoprojV1alpha1().WorkflowTemplates(namespace).Create(updatedTemplate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
latest, err = c.ArgoprojV1alpha1().WorkflowTemplates(namespace).Update(latest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workflowTemplate.Version = versionUnix
|
||||
workflowTemplate.Version = workflowTemplateVersion.Version
|
||||
|
||||
return workflowTemplate, nil
|
||||
}
|
||||
@@ -564,7 +576,7 @@ func (c *Client) ListWorkflowTemplateVersions(namespace, uid string) (workflowTe
|
||||
}
|
||||
|
||||
func (c *Client) ListWorkflowTemplates(namespace string, paginator *pagination.PaginationRequest) (workflowTemplateVersions []*WorkflowTemplate, err error) {
|
||||
workflowTemplateVersions, err = c.listWorkflowTemplates(namespace, paginator)
|
||||
workflowTemplateVersions, err = c.selectWorkflowTemplatesDB(namespace, paginator)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"Namespace": namespace,
|
||||
@@ -722,6 +734,8 @@ func (c *Client) ArchiveWorkflowTemplate(namespace, uid string) (archived bool,
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// createArgoWorkflowTemplate creates an argo workflow template from the workflowTemplate struct
|
||||
// the argo template stores the version information.
|
||||
func createArgoWorkflowTemplate(workflowTemplate *WorkflowTemplate, version int64) (*v1alpha1.WorkflowTemplate, error) {
|
||||
var argoWft *v1alpha1.WorkflowTemplate
|
||||
var jsonOpts []argojson.JSONOpt
|
||||
@@ -737,15 +751,14 @@ func createArgoWorkflowTemplate(workflowTemplate *WorkflowTemplate, version int6
|
||||
return nil, err
|
||||
}
|
||||
|
||||
worfklowTemplateName, err := uid2.GenerateUID(workflowTemplate.Name, 30)
|
||||
if err != nil {
|
||||
if err := workflowTemplate.GenerateUID(workflowTemplate.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
argoWft.Name = fmt.Sprintf("%v-v%v", worfklowTemplateName, version)
|
||||
argoWft.Name = fmt.Sprintf("%v-v%v", workflowTemplate.UID, version)
|
||||
|
||||
labels := map[string]string{
|
||||
label.WorkflowTemplate: worfklowTemplateName,
|
||||
label.WorkflowTemplate: workflowTemplate.UID,
|
||||
label.WorkflowTemplateUid: workflowTemplate.UID,
|
||||
label.Version: fmt.Sprintf("%v", version),
|
||||
label.VersionLatest: "true",
|
||||
@@ -757,9 +770,10 @@ func createArgoWorkflowTemplate(workflowTemplate *WorkflowTemplate, version int6
|
||||
return argoWft, nil
|
||||
}
|
||||
|
||||
// version "latest" will get the latest version.
|
||||
func (c *Client) getArgoWorkflowTemplate(namespace, workflowTemplateUid, version string) (*v1alpha1.WorkflowTemplate, error) {
|
||||
labelSelect := fmt.Sprintf("%v=%v", label.WorkflowTemplateUid, workflowTemplateUid)
|
||||
// getArgoWorkflowTemplate will load the argo workflow template.
|
||||
// version "latest" will get the latest version, otherwise a number (as a string) will be used.
|
||||
func (c *Client) getArgoWorkflowTemplate(namespace, workflowTemplateUID, version string) (*v1alpha1.WorkflowTemplate, error) {
|
||||
labelSelect := fmt.Sprintf("%v=%v", label.WorkflowTemplateUid, workflowTemplateUID)
|
||||
if version == "latest" {
|
||||
labelSelect += "," + label.VersionLatest + "=true"
|
||||
} else {
|
||||
@@ -799,28 +813,22 @@ func (c *Client) listArgoWorkflowTemplates(namespace, workflowTemplateUid string
|
||||
return &templates, nil
|
||||
}
|
||||
|
||||
func (c *Client) listDBWorkflowTemplateVersions(namespace, workflowTemplateUID string) ([]*WorkflowTemplateVersion, error) {
|
||||
versions := make([]*WorkflowTemplateVersion, 0)
|
||||
// listDBWorkflowTemplateVersions gets all of the workflow template versions for a specified workflow template uid
|
||||
// archived ones are ignored. Returned in created_at desc order.
|
||||
func (c *Client) selectWorkflowTemplateVersionsDB(namespace, workflowTemplateUID string) (versions []*WorkflowTemplateVersion, err error) {
|
||||
versions = make([]*WorkflowTemplateVersion, 0)
|
||||
|
||||
sb := c.workflowTemplatesVersionSelectBuilder(namespace).
|
||||
Columns(`wt.id "workflow_template.id"`, `wt.created_at "workflow_template.created_at"`).
|
||||
Columns(`wt.name "workflow_template.name"`, `wt.is_archived "workflow_template.is_archived"`).
|
||||
Columns(getWorkflowTemplateColumns("wt", "workflow_template")...).
|
||||
Where(sq.Eq{
|
||||
"wt.uid": workflowTemplateUID,
|
||||
"wt.is_archived": false,
|
||||
}).
|
||||
OrderBy("wtv.created_at DESC")
|
||||
|
||||
query, args, err := sb.ToSql()
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
err = c.DB.Selectx(&versions, sb)
|
||||
|
||||
if err := c.DB.Select(&versions, query, args...); err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
return versions, nil
|
||||
return
|
||||
}
|
||||
|
||||
// prefix is the label prefix.
|
||||
|
||||
345
pkg/workflow_template_test.go
Normal file
345
pkg/workflow_template_test.go
Normal file
@@ -0,0 +1,345 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/onepanelio/core/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc/codes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const defaultWorkflowTemplate = `entrypoint: main
|
||||
arguments:
|
||||
parameters:
|
||||
- name: source
|
||||
value: https://github.com/onepanelio/pytorch-examples.git
|
||||
- name: command
|
||||
value: "python mnist/main.py --epochs=1"
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
- metadata:
|
||||
name: output
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
templates:
|
||||
- name: main
|
||||
dag:
|
||||
tasks:
|
||||
- name: train-model
|
||||
template: pytorch
|
||||
# Uncomment section below to send metrics to Slack
|
||||
# - name: notify-in-slack
|
||||
# dependencies: [train-model]
|
||||
# template: slack-notify-success
|
||||
# arguments:
|
||||
# parameters:
|
||||
# - name: status
|
||||
# value: "{{tasks.train-model.status}}"
|
||||
# artifacts:
|
||||
# - name: metrics
|
||||
# from: "{{tasks.train-model.outputs.artifacts.sys-metrics}}"
|
||||
- name: pytorch
|
||||
inputs:
|
||||
artifacts:
|
||||
- name: src
|
||||
path: /mnt/src
|
||||
git:
|
||||
repo: "{{workflow.parameters.source}}"
|
||||
outputs:
|
||||
artifacts:
|
||||
- name: model
|
||||
path: /mnt/output
|
||||
optional: true
|
||||
archive:
|
||||
none: {}
|
||||
container:
|
||||
image: pytorch/pytorch:latest
|
||||
command: [sh,-c]
|
||||
args: ["{{workflow.parameters.command}}"]
|
||||
workingDir: /mnt/src
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /mnt/data
|
||||
- name: output
|
||||
mountPath: /mnt/output
|
||||
- name: slack-notify-success
|
||||
container:
|
||||
image: technosophos/slack-notify
|
||||
command: [sh,-c]
|
||||
args: ['SLACK_USERNAME=Worker SLACK_TITLE="{{workflow.name}} {{inputs.parameters.status}}" SLACK_ICON=https://www.gravatar.com/avatar/5c4478592fe00878f62f0027be59c1bd SLACK_MESSAGE=$(cat /tmp/metrics.json)} ./slack-notify']
|
||||
inputs:
|
||||
parameters:
|
||||
- name: status
|
||||
artifacts:
|
||||
- name: metrics
|
||||
path: /tmp/metrics.json
|
||||
optional: true
|
||||
`
|
||||
|
||||
// testClientGetWorkflowTemplateDBEmpty attempts to get a WorkflowTemplate when there isn't one.
|
||||
// this should fail.
|
||||
func testClientGetWorkflowTemplateDBEmpty(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
_, err := c.getWorkflowTemplateDB("test", "test")
|
||||
assert.Equal(t, sql.ErrNoRows, err)
|
||||
}
|
||||
|
||||
// testClientGetWorkflowTemplateDBExists gets a WorkflowTemplate when there is one
|
||||
// this should succeed
|
||||
func testClientGetWorkflowTemplateDBExists(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
_, err := c.CreateWorkflowTemplate("onepanel", workflowTemplate)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = c.getWorkflowTemplateDB("onepanel", "test")
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// TestClient_getWorkflowTemplateDB tests getting a workflow template from the database
|
||||
func TestClient_getWorkflowTemplateDB(t *testing.T) {
|
||||
testClientGetWorkflowTemplateDBEmpty(t)
|
||||
testClientGetWorkflowTemplateDBExists(t)
|
||||
}
|
||||
|
||||
// testClientCreateWorkflowTemplateSuccess makes sure a correct workflow template is created correctly
|
||||
func testClientCreateWorkflowTemplateSuccess(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
|
||||
wft, err := c.CreateWorkflowTemplate("onepanel", workflowTemplate)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, wft.ArgoWorkflowTemplate)
|
||||
}
|
||||
|
||||
// testClientCreateWorkflowTemplateTimestamp makes sure we can create mulitple
|
||||
// workflow templtate versions one after another with practically no time delay.
|
||||
// This handles an edge case where versions were set using second time precision and could fail in migrations
|
||||
// as they were created one after another.
|
||||
func testClientCreateWorkflowTemplateTimestamp(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
|
||||
// This method creates a workflow template version underneath
|
||||
wft, err := c.CreateWorkflowTemplate("onepanel", workflowTemplate)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, wft.ArgoWorkflowTemplate)
|
||||
|
||||
// This method creates a brand new version
|
||||
wft, err = c.CreateWorkflowTemplateVersion(namespace, workflowTemplate)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, wft.ArgoWorkflowTemplate)
|
||||
}
|
||||
|
||||
// testClientCreateWorkflowTemplateInsertSameName attempts to insert a WorkflowTemplate with the same name
|
||||
// this should fail
|
||||
func testClientCreateWorkflowTemplateInsertSameName(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
_, err := c.CreateWorkflowTemplate("onepanel", workflowTemplate)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = c.CreateWorkflowTemplate("onepanel", workflowTemplate)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
assert.IsType(t, &util.UserError{}, err)
|
||||
userErr := err.(*util.UserError)
|
||||
|
||||
assert.Equal(t, userErr.Code, codes.AlreadyExists)
|
||||
}
|
||||
|
||||
// TestClient_CreateWorkflowTemplate tests creating a workflow template
|
||||
func TestClient_CreateWorkflowTemplate(t *testing.T) {
|
||||
testClientCreateWorkflowTemplateInsertSameName(t)
|
||||
testClientCreateWorkflowTemplateSuccess(t)
|
||||
testClientCreateWorkflowTemplateTimestamp(t)
|
||||
}
|
||||
|
||||
// testClientPrivateGetWorkflowTemplateSuccess gets a workflow template with no error conditions encountered
|
||||
func testClientPrivateGetWorkflowTemplateSuccess(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
created, _ := c.CreateWorkflowTemplate(namespace, workflowTemplate)
|
||||
|
||||
wt, err := c.getWorkflowTemplate(namespace, created.UID, 0)
|
||||
assert.NotNil(t, wt)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// testClientGetWorkflowTemplateSuccessVersion gets a workflow template for a specific version with no error conditions encountered
|
||||
func testClientPrivateGetWorkflowTemplateSuccessVersion(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
created, _ := c.CreateWorkflowTemplate(namespace, workflowTemplate)
|
||||
c.CreateWorkflowTemplateVersion(namespace, workflowTemplate)
|
||||
|
||||
wt, err := c.getWorkflowTemplate(namespace, created.UID, created.Version)
|
||||
assert.NotNil(t, wt)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, created.Version, wt.Version)
|
||||
assert.Equal(t, created.Manifest, wt.Manifest)
|
||||
}
|
||||
|
||||
// testClientGetWorkflowTemplateNotFound attempts to get a not-found workflow template
|
||||
func testClientPrivateGetWorkflowTemplateNotFound(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
wt, err := c.getWorkflowTemplate("onepanel", "uid-not-found", 0)
|
||||
assert.Nil(t, wt)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// Test_getWorkflowTemplate tests getting a workflow template
|
||||
func Test_getWorkflowTemplate(t *testing.T) {
|
||||
testClientPrivateGetWorkflowTemplateSuccess(t)
|
||||
testClientPrivateGetWorkflowTemplateNotFound(t)
|
||||
testClientPrivateGetWorkflowTemplateSuccessVersion(t)
|
||||
}
|
||||
|
||||
func TestClient_getWorkflowTemplateVersionDB(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
name := "test"
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: name,
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
|
||||
original, _ := c.CreateWorkflowTemplate(namespace, workflowTemplate)
|
||||
|
||||
versionAsString := fmt.Sprintf("%v", original.Version)
|
||||
originalRes, err := c.getWorkflowTemplateVersionDB(namespace, name, versionAsString)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, original.Version, originalRes.Version)
|
||||
}
|
||||
|
||||
// testClientCreateWorkflowTemplateVersionNew makes sure you can successfully create a new workflow template version
|
||||
func testClientCreateWorkflowTemplateVersionNew(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
|
||||
c.CreateWorkflowTemplate(namespace, workflowTemplate)
|
||||
_, err := c.CreateWorkflowTemplateVersion(namespace, workflowTemplate)
|
||||
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// testClientCreateWorkflowTemplateVersionMarkOldNotLatest makes sure older versions are no longer marked as latest
|
||||
func testClientCreateWorkflowTemplateVersionMarkOldNotLatest(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
name := "test"
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: name,
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
|
||||
original, _ := c.CreateWorkflowTemplate(namespace, workflowTemplate)
|
||||
originalVersionAsString := fmt.Sprintf("%v", original.Version)
|
||||
c.CreateWorkflowTemplateVersion(namespace, workflowTemplate)
|
||||
|
||||
updated, _ := c.getWorkflowTemplateVersionDB(namespace, name, originalVersionAsString)
|
||||
|
||||
assert.False(t, updated.IsLatest)
|
||||
}
|
||||
|
||||
// Test_getWorkflowTemplate_SuccessVersion tests cases for creating a workflow template version
|
||||
func TestClient_CreateWorkflowTemplateVersion(t *testing.T) {
|
||||
testClientCreateWorkflowTemplateVersionNew(t)
|
||||
testClientCreateWorkflowTemplateVersionMarkOldNotLatest(t)
|
||||
}
|
||||
|
||||
// testGetWorkflowTemplateSuccess gets a workflow template with no error conditions encountered
|
||||
func testClientGetWorkflowTemplateSuccess(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
workflowTemplate := &WorkflowTemplate{
|
||||
Name: "test",
|
||||
Manifest: defaultWorkflowTemplate,
|
||||
}
|
||||
created, _ := c.CreateWorkflowTemplate(namespace, workflowTemplate)
|
||||
|
||||
wt, err := c.GetWorkflowTemplate(namespace, created.UID, 0)
|
||||
assert.NotNil(t, wt)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// testGetWorkflowTemplateNotFound attempts to get a not-found workflow template
|
||||
func testClientGetWorkflowTemplateNotFound(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
wt, err := c.GetWorkflowTemplate("onepanel", "uid-not-found", 0)
|
||||
assert.Nil(t, wt)
|
||||
|
||||
userErr, ok := err.(*util.UserError)
|
||||
assert.True(t, ok)
|
||||
|
||||
assert.Equal(t, codes.NotFound, userErr.Code)
|
||||
}
|
||||
|
||||
func TestClient_GetWorkflowTemplate(t *testing.T) {
|
||||
testClientGetWorkflowTemplateSuccess(t)
|
||||
testClientGetWorkflowTemplateNotFound(t)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1"
|
||||
"github.com/onepanelio/core/pkg/util/mapping"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"github.com/onepanelio/core/util/sql"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -13,6 +14,9 @@ import (
|
||||
|
||||
// WorkflowTemplate represents a Workflow Template backed by a database row
|
||||
// it stores information required to run an execution
|
||||
// A Workflow template is uniquely identified by
|
||||
// (namespace, uid, is_archived)
|
||||
// (namespace, name, is_archived) -- because we create a uid from the name.
|
||||
type WorkflowTemplate struct {
|
||||
ID uint64
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
@@ -35,6 +39,18 @@ type WorkflowTemplate struct {
|
||||
ResourceUID *string // see Resource field
|
||||
}
|
||||
|
||||
// GenerateUID generates a uid from the input name and sets it on the workflow template
|
||||
func (wt *WorkflowTemplate) GenerateUID(name string) error {
|
||||
result, err := uid2.GenerateUID(name, 30)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wt.UID = result
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetManifestBytes returns the manifest as []byte
|
||||
func (wt *WorkflowTemplate) GetManifestBytes() []byte {
|
||||
return []byte(wt.Manifest)
|
||||
|
||||
157
pkg/workspace.go
157
pkg/workspace.go
@@ -10,9 +10,9 @@ import (
|
||||
"github.com/onepanelio/core/pkg/util"
|
||||
"github.com/onepanelio/core/pkg/util/pagination"
|
||||
"github.com/onepanelio/core/pkg/util/ptr"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -33,16 +33,55 @@ func (c *Client) workspacesSelectBuilder(namespace string) sq.SelectBuilder {
|
||||
return sb
|
||||
}
|
||||
|
||||
func getWorkspaceParameterValue(parameters []Parameter, name string) *string {
|
||||
for _, p := range parameters {
|
||||
if p.Name == name {
|
||||
return p.Value
|
||||
}
|
||||
// workspaceStatusToFieldMap takes a status and creates a map of the fields that should be updated
|
||||
func workspaceStatusToFieldMap(status *WorkspaceStatus) sq.Eq {
|
||||
fieldMap := sq.Eq{
|
||||
"phase": status.Phase,
|
||||
"modified_at": time.Now().UTC(),
|
||||
}
|
||||
switch status.Phase {
|
||||
case WorkspaceLaunching:
|
||||
fieldMap["paused_at"] = pq.NullTime{}
|
||||
fieldMap["started_at"] = time.Now().UTC()
|
||||
break
|
||||
case WorkspacePausing:
|
||||
fieldMap["started_at"] = pq.NullTime{}
|
||||
fieldMap["paused_at"] = time.Now().UTC()
|
||||
break
|
||||
case WorkspaceUpdating:
|
||||
fieldMap["paused_at"] = pq.NullTime{}
|
||||
fieldMap["updated_at"] = time.Now().UTC()
|
||||
break
|
||||
case WorkspaceTerminating:
|
||||
fieldMap["started_at"] = pq.NullTime{}
|
||||
fieldMap["paused_at"] = pq.NullTime{}
|
||||
fieldMap["terminated_at"] = time.Now().UTC()
|
||||
break
|
||||
}
|
||||
|
||||
return nil
|
||||
return fieldMap
|
||||
}
|
||||
|
||||
// updateWorkspaceStatusBuilder creates an update builder that updates a workspace's status and related fields to match that status.
|
||||
func updateWorkspaceStatusBuilder(namespace, uid string, status *WorkspaceStatus) sq.UpdateBuilder {
|
||||
fieldMap := workspaceStatusToFieldMap(status)
|
||||
|
||||
ub := sb.Update("workspaces").
|
||||
SetMap(fieldMap).
|
||||
Where(sq.And{
|
||||
sq.Eq{
|
||||
"namespace": namespace,
|
||||
"uid": uid,
|
||||
}, sq.NotEq{
|
||||
"phase": WorkspaceTerminated,
|
||||
},
|
||||
})
|
||||
|
||||
return ub
|
||||
}
|
||||
|
||||
// mergeWorkspaceParameters combines two parameter arrays. If a parameter in newParameters is not in
|
||||
// the existing ones, it is added. If it is, it is ignored.
|
||||
func mergeWorkspaceParameters(existingParameters, newParameters []Parameter) (parameters []Parameter) {
|
||||
parameterMap := make(map[string]*string, 0)
|
||||
for _, p := range newParameters {
|
||||
@@ -74,10 +113,6 @@ func mergeWorkspaceParameters(existingParameters, newParameters []Parameter) (pa
|
||||
// sys-resource-action
|
||||
// sys-host
|
||||
func injectWorkspaceSystemParameters(namespace string, workspace *Workspace, workspaceAction, resourceAction string, config SystemConfig) (err error) {
|
||||
workspace.UID, err = uid2.GenerateUID(workspace.Name, 30)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
host := fmt.Sprintf("%v--%v.%v", workspace.UID, namespace, *config.Domain())
|
||||
systemParameters := []Parameter{
|
||||
{
|
||||
@@ -98,6 +133,10 @@ func injectWorkspaceSystemParameters(namespace string, workspace *Workspace, wor
|
||||
return
|
||||
}
|
||||
|
||||
// createWorkspace creates a workspace and related resources.
|
||||
// The following are required on the workspace:
|
||||
// WorkspaceTemplate.WorkflowTemplate.UID
|
||||
// WorkspaceTemplate.WorkflowTemplate.Version
|
||||
func (c *Client) createWorkspace(namespace string, parameters []byte, workspace *Workspace) (*Workspace, error) {
|
||||
systemConfig, err := c.GetSystemConfig()
|
||||
if err != nil {
|
||||
@@ -155,7 +194,11 @@ func (c *Client) createWorkspace(namespace string, parameters []byte, workspace
|
||||
QueryRow().
|
||||
Scan(&workspace.ID, &workspace.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, util.NewUserErrorWrap(err, "Workspace")
|
||||
if strings.Contains(err.Error(), "invalid input syntax for type json") {
|
||||
return nil, util.NewUserError(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
return nil, util.NewUserError(codes.Unknown, err.Error())
|
||||
}
|
||||
|
||||
return workspace, nil
|
||||
@@ -168,6 +211,10 @@ func (c *Client) CreateWorkspace(namespace string, workspace *Workspace) (*Works
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := workspace.GenerateUID(workspace.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parameters, err := json.Marshal(workspace.Parameters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -182,7 +229,7 @@ func (c *Client) CreateWorkspace(namespace string, workspace *Workspace) (*Works
|
||||
Value: ptr.String(workspace.UID),
|
||||
})
|
||||
|
||||
sysHost := getWorkspaceParameterValue(workspace.Parameters, "sys-host")
|
||||
sysHost := workspace.GetParameterValue("sys-host")
|
||||
if sysHost == nil {
|
||||
return nil, fmt.Errorf("sys-host parameter not found")
|
||||
}
|
||||
@@ -267,51 +314,31 @@ func (c *Client) GetWorkspace(namespace, uid string) (workspace *Workspace, err
|
||||
|
||||
// UpdateWorkspaceStatus updates workspace status and times based on phase
|
||||
func (c *Client) UpdateWorkspaceStatus(namespace, uid string, status *WorkspaceStatus) (err error) {
|
||||
fieldMap := sq.Eq{
|
||||
"phase": status.Phase,
|
||||
"modified_at": time.Now().UTC(),
|
||||
}
|
||||
switch status.Phase {
|
||||
case WorkspaceLaunching:
|
||||
fieldMap["paused_at"] = pq.NullTime{}
|
||||
fieldMap["started_at"] = time.Now().UTC()
|
||||
break
|
||||
case WorkspacePausing:
|
||||
fieldMap["started_at"] = pq.NullTime{}
|
||||
fieldMap["paused_at"] = time.Now().UTC()
|
||||
break
|
||||
case WorkspaceUpdating:
|
||||
fieldMap["paused_at"] = pq.NullTime{}
|
||||
fieldMap["updated_at"] = time.Now().UTC()
|
||||
break
|
||||
case WorkspaceTerminating:
|
||||
fieldMap["started_at"] = pq.NullTime{}
|
||||
fieldMap["paused_at"] = pq.NullTime{}
|
||||
fieldMap["terminated_at"] = time.Now().UTC()
|
||||
break
|
||||
}
|
||||
_, err = sb.Update("workspaces").
|
||||
SetMap(fieldMap).
|
||||
Where(sq.And{
|
||||
sq.Eq{
|
||||
"namespace": namespace,
|
||||
"uid": uid,
|
||||
}, sq.NotEq{
|
||||
"phase": WorkspaceTerminated,
|
||||
},
|
||||
}).
|
||||
RunWith(c.DB).Exec()
|
||||
result, err := updateWorkspaceStatusBuilder(namespace, uid, status).
|
||||
RunWith(c.DB).
|
||||
Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rowsAffected == 0 {
|
||||
return util.NewUserError(codes.NotFound, "Workspace not found.")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ListWorkspacesByTemplateID will return all the workspaces for a given workspace template id.
|
||||
// ListWorkspacesByTemplateID will return all the workspaces for a given workspace template id that are not terminated.
|
||||
// Sourced from database.
|
||||
// Includes labels.
|
||||
func (c *Client) ListWorkspacesByTemplateID(namespace string, templateID uint64) (workspaces []*Workspace, err error) {
|
||||
sb := sb.Select(getWorkspaceColumns("w")...).
|
||||
Columns(getWorkspaceStatusColumns("w", "status")...).
|
||||
From("workspaces w").
|
||||
Where(sq.And{
|
||||
sq.Eq{
|
||||
@@ -391,6 +418,7 @@ func (c *Client) CountWorkspaces(namespace string) (count int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// updateWorkspace updates the workspace to the indicated status
|
||||
func (c *Client) updateWorkspace(namespace, uid, workspaceAction, resourceAction string, status *WorkspaceStatus, parameters ...Parameter) (err error) {
|
||||
workspace, err := c.GetWorkspace(namespace, uid)
|
||||
if err != nil {
|
||||
@@ -444,32 +472,15 @@ func (c *Client) updateWorkspace(namespace, uid, workspaceAction, resourceAction
|
||||
return
|
||||
}
|
||||
|
||||
if err = c.UpdateWorkspaceStatus(namespace, uid, status); err != nil {
|
||||
return
|
||||
sb := updateWorkspaceStatusBuilder(namespace, uid, status)
|
||||
|
||||
// Update parameters if they are passed in
|
||||
if len(parameters) != 0 {
|
||||
sb.Set("parameters", parametersJSON)
|
||||
}
|
||||
|
||||
// Update parameters if they are passed
|
||||
if len(parameters) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = sb.Update("workspaces").
|
||||
SetMap(sq.Eq{
|
||||
"parameters": parametersJSON,
|
||||
}).
|
||||
Where(sq.And{
|
||||
sq.Eq{
|
||||
"namespace": namespace,
|
||||
"uid": uid,
|
||||
}, sq.NotEq{
|
||||
"phase": WorkspaceTerminated,
|
||||
},
|
||||
}).
|
||||
RunWith(c.DB).
|
||||
_, err = sb.RunWith(c.DB).
|
||||
Exec()
|
||||
if err != nil {
|
||||
return util.NewUserError(codes.NotFound, "Workspace not found.")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -492,6 +503,6 @@ func (c *Client) DeleteWorkspace(namespace, uid string) (err error) {
|
||||
|
||||
// ArchiveWorkspace archives by setting the workspace to delete or terminate.
|
||||
// Kicks off DB archiving and k8s cleaning.
|
||||
func (c *Client) ArchiveWorkspace(namespace, uid string) (err error) {
|
||||
return c.updateWorkspace(namespace, uid, "delete", "delete", &WorkspaceStatus{Phase: WorkspaceTerminating})
|
||||
func (c *Client) ArchiveWorkspace(namespace, uid string, parameters ...Parameter) (err error) {
|
||||
return c.updateWorkspace(namespace, uid, "delete", "delete", &WorkspaceStatus{Phase: WorkspaceTerminating}, parameters...)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/onepanelio/core/pkg/util/env"
|
||||
"github.com/onepanelio/core/pkg/util/pagination"
|
||||
"github.com/onepanelio/core/pkg/util/ptr"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
networking "istio.io/api/networking/v1alpha3"
|
||||
@@ -84,13 +83,20 @@ func generateRuntimeParameters(config SystemConfig) (parameters []Parameter, err
|
||||
})
|
||||
|
||||
// Node pool parameter and options
|
||||
options, err := config.NodePoolOptions()
|
||||
nodePoolOptions, err := config.NodePoolOptions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(options) == 0 {
|
||||
if len(nodePoolOptions) == 0 {
|
||||
return nil, fmt.Errorf("no node pool options in config")
|
||||
}
|
||||
var options []*ParameterOption
|
||||
for _, option := range nodePoolOptions {
|
||||
options = append(options, &ParameterOption{
|
||||
Name: option.Name,
|
||||
Value: option.Value,
|
||||
})
|
||||
}
|
||||
|
||||
parameters = append(parameters, Parameter{
|
||||
Name: "sys-node-pool-label",
|
||||
@@ -111,82 +117,6 @@ func generateRuntimeParameters(config SystemConfig) (parameters []Parameter, err
|
||||
return
|
||||
}
|
||||
|
||||
func generateStaticParameters() (parameters []Parameter, err error) {
|
||||
parameters = make([]Parameter, 0)
|
||||
|
||||
// Resource action parameter
|
||||
parameters = append(parameters, Parameter{
|
||||
Name: "sys-name",
|
||||
Type: "input.text",
|
||||
Value: ptr.String("name"),
|
||||
DisplayName: ptr.String("Workspace name"),
|
||||
Hint: ptr.String("Must be between 3-30 characters, contain only alphanumeric or `-` characters"),
|
||||
Required: true,
|
||||
})
|
||||
|
||||
// TODO: These can be removed when lint validation of workflows work
|
||||
// Resource action parameter
|
||||
parameters = append(parameters, Parameter{
|
||||
Name: "sys-resource-action",
|
||||
Value: ptr.String("apply"),
|
||||
Type: "input.hidden",
|
||||
})
|
||||
// Workspace action
|
||||
parameters = append(parameters, Parameter{
|
||||
Name: "sys-workspace-action",
|
||||
Value: ptr.String("create"),
|
||||
Type: "input.hidden",
|
||||
})
|
||||
|
||||
// UID placeholder
|
||||
parameters = append(parameters, Parameter{
|
||||
Name: "sys-uid",
|
||||
Value: ptr.String("uid"),
|
||||
Type: "input.hidden",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func generateVolumeParameters(spec *WorkspaceSpec) (parameters []Parameter, err error) {
|
||||
if spec == nil {
|
||||
return nil, fmt.Errorf("workspaceSpec is nil")
|
||||
}
|
||||
|
||||
parameters = make([]Parameter, 0)
|
||||
|
||||
// Map all the volumeClaimTemplates that have storage set
|
||||
volumeStorageQuantityIsSet := make(map[string]bool)
|
||||
for _, v := range spec.VolumeClaimTemplates {
|
||||
if v.Spec.Resources.Requests != nil {
|
||||
volumeStorageQuantityIsSet[v.ObjectMeta.Name] = true
|
||||
}
|
||||
}
|
||||
// Volume size parameters
|
||||
volumeClaimsMapped := make(map[string]bool)
|
||||
for _, c := range spec.Containers {
|
||||
for _, v := range c.VolumeMounts {
|
||||
// Skip if already mapped or storage size is set
|
||||
if volumeClaimsMapped[v.Name] || volumeStorageQuantityIsSet[v.Name] {
|
||||
continue
|
||||
}
|
||||
|
||||
parameters = append(parameters, Parameter{
|
||||
Name: fmt.Sprintf("sys-%v-volume-size", v.Name),
|
||||
Type: "input.number",
|
||||
Value: ptr.String("20480"),
|
||||
DisplayName: ptr.String(fmt.Sprintf("Disk size for \"%v\"", v.Name)),
|
||||
Hint: ptr.String(fmt.Sprintf("Disk size in MB for volume mounted at `%v`", v.MountPath)),
|
||||
Required: true,
|
||||
})
|
||||
|
||||
volumeClaimsMapped[v.Name] = true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func generateArguments(spec *WorkspaceSpec, config SystemConfig) (err error) {
|
||||
systemParameters := make([]Parameter, 0)
|
||||
// Resource action parameter
|
||||
@@ -360,7 +290,7 @@ func createStatefulSetManifest(spec *WorkspaceSpec, config map[string]string) (s
|
||||
env.PrependEnvVarToContainer(container, "ONEPANEL_API_URL", config["ONEPANEL_API_URL"])
|
||||
env.PrependEnvVarToContainer(container, "ONEPANEL_FQDN", config["ONEPANEL_FQDN"])
|
||||
env.PrependEnvVarToContainer(container, "ONEPANEL_DOMAIN", config["ONEPANEL_DOMAIN"])
|
||||
env.PrependEnvVarToContainer(container, "ONEPANEL_PROVIDER_TYPE", config["PROVIDER_TYPE"])
|
||||
env.PrependEnvVarToContainer(container, "ONEPANEL_PROVIDER", config["ONEPANEL_PROVIDER"])
|
||||
env.PrependEnvVarToContainer(container, "ONEPANEL_RESOURCE_NAMESPACE", "{{workflow.namespace}}")
|
||||
env.PrependEnvVarToContainer(container, "ONEPANEL_RESOURCE_UID", "{{workflow.parameters.sys-name}}")
|
||||
|
||||
@@ -719,15 +649,14 @@ metadata:
|
||||
}
|
||||
|
||||
func (c *Client) createWorkspaceTemplate(namespace string, workspaceTemplate *WorkspaceTemplate) (*WorkspaceTemplate, error) {
|
||||
uid, err := uid2.GenerateUID(workspaceTemplate.Name, 30)
|
||||
err := workspaceTemplate.GenerateUID(workspaceTemplate.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workspaceTemplate.UID = uid
|
||||
|
||||
workspaceTemplate.WorkflowTemplate.IsSystem = true
|
||||
workspaceTemplate.WorkflowTemplate.Resource = ptr.String(TypeWorkspaceTemplate)
|
||||
workspaceTemplate.WorkflowTemplate.ResourceUID = ptr.String(uid)
|
||||
workspaceTemplate.WorkflowTemplate.ResourceUID = &workspaceTemplate.UID
|
||||
|
||||
// validate workflow template
|
||||
if err := c.validateWorkflowTemplate(namespace, workspaceTemplate.WorkflowTemplate); err != nil {
|
||||
@@ -754,7 +683,7 @@ func (c *Client) createWorkspaceTemplate(namespace string, workspaceTemplate *Wo
|
||||
defer tx.Rollback()
|
||||
err = sb.Insert("workspace_templates").
|
||||
SetMap(sq.Eq{
|
||||
"uid": uid,
|
||||
"uid": workspaceTemplate.UID,
|
||||
"name": workspaceTemplate.Name,
|
||||
"namespace": namespace,
|
||||
"workflow_template_id": workspaceTemplate.WorkflowTemplate.ID,
|
||||
@@ -1042,26 +971,23 @@ func (c *Client) UpdateWorkspaceTemplate(namespace string, workspaceTemplate *Wo
|
||||
return workspaceTemplate, nil
|
||||
}
|
||||
|
||||
// ListWorkspaceTemplates returns a list of workspace templates that are not archived, sorted by most recent created first
|
||||
func (c *Client) ListWorkspaceTemplates(namespace string, paginator *pagination.PaginationRequest) (workspaceTemplates []*WorkspaceTemplate, err error) {
|
||||
sb := c.workspaceTemplatesSelectBuilder(namespace).
|
||||
Where(sq.Eq{
|
||||
"wt.is_archived": false,
|
||||
}).
|
||||
OrderBy("wt.created_at DESC")
|
||||
|
||||
sb = *paginator.ApplyToSelect(&sb)
|
||||
|
||||
query, args, err := sb.ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.DB.Select(&workspaceTemplates, query, args...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = c.DB.Selectx(&workspaceTemplates, sb)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ListWorkspaceTemplateVersions returns an array of WorkspaceTemplates with the version information loaded. Latest id is first.
|
||||
// Labels are also loaded.
|
||||
func (c *Client) ListWorkspaceTemplateVersions(namespace, uid string) (workspaceTemplates []*WorkspaceTemplate, err error) {
|
||||
sb := c.workspaceTemplateVersionsSelectBuilder(namespace, uid).
|
||||
Options("DISTINCT ON (wtv.version) wtv.version,").
|
||||
@@ -1070,11 +996,8 @@ func (c *Client) ListWorkspaceTemplateVersions(namespace, uid string) (workspace
|
||||
"wft.is_archived": false,
|
||||
}).
|
||||
OrderBy("wtv.version DESC")
|
||||
query, args, err := sb.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = c.DB.Select(&workspaceTemplates, query, args...); err != nil {
|
||||
|
||||
if err = c.DB.Selectx(&workspaceTemplates, sb); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1092,6 +1015,7 @@ func (c *Client) ListWorkspaceTemplateVersions(namespace, uid string) (workspace
|
||||
return
|
||||
}
|
||||
|
||||
// CountWorkspaceTemplates returns the total number of non-archived workspace templates for the input namespace
|
||||
func (c *Client) CountWorkspaceTemplates(namespace string) (count int, err error) {
|
||||
err = sb.Select("count(*)").
|
||||
From("workspace_templates wt").
|
||||
@@ -1182,6 +1106,9 @@ func (c *Client) ArchiveWorkspaceTemplate(namespace string, uid string) (archive
|
||||
}).Error("Get Workspace Template failed.")
|
||||
return false, util.NewUserError(codes.Unknown, "Unable to archive workspace template.")
|
||||
}
|
||||
if wsTemp == nil {
|
||||
return false, fmt.Errorf("not found")
|
||||
}
|
||||
|
||||
wsList, err := c.ListWorkspacesByTemplateID(namespace, wsTemp.WorkspaceTemplateVersionID)
|
||||
if err != nil {
|
||||
|
||||
@@ -52,9 +52,78 @@ routes:
|
||||
workspaceTemplate = WorkspaceTemplate{
|
||||
Manifest: workspaceSpecManifest,
|
||||
}
|
||||
|
||||
jupyterLabWorkspaceManifest = `# Docker containers that are part of the Workspace
|
||||
containers:
|
||||
- name: jupyterlab-tensorflow
|
||||
image: jupyter/tensorflow-notebook
|
||||
command: [start.sh, jupyter]
|
||||
workingDir: /data
|
||||
env:
|
||||
- name: tornado
|
||||
value: "{ 'headers': { 'Content-Security-Policy': \"frame-ancestors * 'self'\" } }"
|
||||
- name: GRANT_SUDO
|
||||
value: 1
|
||||
- name: CHOWN_EXTRA
|
||||
value: '/data'
|
||||
- name: CHOWN_EXTRA_OPTS
|
||||
value: '-R'
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
allowPrivilegeEscalation: false
|
||||
args:
|
||||
- lab
|
||||
- --LabApp.token=''
|
||||
- --LabApp.allow_remote_access=True
|
||||
- --LabApp.allow_origin="*"
|
||||
- --LabApp.disable_check_xsrf=True
|
||||
- --LabApp.trust_xheaders=True
|
||||
- --LabApp.tornado_settings=$(tornado)
|
||||
- --NotebookApp.notebook_dir='/data'
|
||||
ports:
|
||||
- containerPort: 8888
|
||||
name: jupyterlab
|
||||
# Volumes to be mounted in this container
|
||||
# Onepanel will automatically create these volumes and mount them to the container
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
# Ports that need to be exposed
|
||||
ports:
|
||||
- name: jupyterlab
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8888
|
||||
# Routes that will map to ports
|
||||
routes:
|
||||
- match:
|
||||
- uri:
|
||||
prefix: /
|
||||
route:
|
||||
- destination:
|
||||
port:
|
||||
number: 80
|
||||
# DAG Workflow to be executed once a Workspace action completes
|
||||
# postExecutionWorkflow:
|
||||
# entrypoint: main
|
||||
# templates:
|
||||
# - name: main
|
||||
# dag:
|
||||
# tasks:
|
||||
# - name: slack-notify
|
||||
# template: slack-notify
|
||||
# - name: slack-notify
|
||||
# container:
|
||||
# image: technosophos/slack-notify
|
||||
# args:
|
||||
# - SLACK_USERNAME=onepanel SLACK_TITLE="Your workspace is ready" SLACK_ICON=https://www.gravatar.com/avatar/5c4478592fe00878f62f0027be59c1bd SLACK_MESSAGE="Your workspace is now running" ./slack-notify
|
||||
# command:
|
||||
# - sh
|
||||
# - -c
|
||||
`
|
||||
)
|
||||
|
||||
func TestParseWorkspaceSpec(t *testing.T) {
|
||||
func Test_ParseWorkspaceSpec(t *testing.T) {
|
||||
workspaceSpec, err := parseWorkspaceSpec(workspaceSpecManifest)
|
||||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, workspaceSpec)
|
||||
@@ -65,3 +134,151 @@ func TestParseWorkspaceSpec(t *testing.T) {
|
||||
assert.Equal(t, workspaceSpec.Containers[0].Ports[0].ContainerPort, int32(80))
|
||||
assert.Equal(t, workspaceSpec.Containers[1].Ports[0].ContainerPort, int32(443))
|
||||
}
|
||||
|
||||
// testClientCreateWorkspaceTemplateNew creates a new workspace template
|
||||
func testClientCreateWorkspaceTemplateNew(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
_, err := c.CreateWorkspaceTemplate(namespace, wt)
|
||||
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// testClientCreateWorkspaceTemplateDuplicateName attempts to create a workspace template for a name that already exists
|
||||
// this should error
|
||||
func testClientCreateWorkspaceTemplateDuplicateName(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
_, err := c.CreateWorkspaceTemplate(namespace, wt)
|
||||
_, err = c.CreateWorkspaceTemplate(namespace, wt)
|
||||
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
// testClientCreateWorkspaceTemplateArchivedName attempts to create a workspace template for a name that has been archived
|
||||
// this should work
|
||||
func testClientCreateWorkspaceTemplateArchivedName(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
wtCreated, err := c.CreateWorkspaceTemplate(namespace, wt)
|
||||
_, err = c.ArchiveWorkspaceTemplate(namespace, wtCreated.UID)
|
||||
_, err = c.CreateWorkspaceTemplate(namespace, wt)
|
||||
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// TestClient_CreateWorkspaceTemplate tests creating a workspace template
|
||||
func TestClient_CreateWorkspaceTemplate(t *testing.T) {
|
||||
testClientCreateWorkspaceTemplateNew(t)
|
||||
testClientCreateWorkspaceTemplateDuplicateName(t)
|
||||
testClientCreateWorkspaceTemplateArchivedName(t)
|
||||
}
|
||||
|
||||
func testClientArchiveWorkspaceTemplateSuccess(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
testTemplate, _ := c.CreateWorkspaceTemplate(namespace, wt)
|
||||
archived, err := c.ArchiveWorkspaceTemplate(namespace, testTemplate.UID)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, archived)
|
||||
}
|
||||
|
||||
// testClientArchiveWorkspaceTemplateNotFound tests the case where you try to archive a non-existing workspace template
|
||||
func testClientArchiveWorkspaceTemplateNotFound(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
archived, err := c.ArchiveWorkspaceTemplate(namespace, "not-found")
|
||||
|
||||
assert.NotNil(t, err)
|
||||
assert.False(t, archived)
|
||||
}
|
||||
|
||||
// TestClient_ArchiveWorkspaceTemplate tests archiving a workspace template
|
||||
func TestClient_ArchiveWorkspaceTemplate(t *testing.T) {
|
||||
testClientArchiveWorkspaceTemplateSuccess(t)
|
||||
testClientArchiveWorkspaceTemplateNotFound(t)
|
||||
|
||||
// TODO we need more tests here to make sure the related resources are cleaned up, including workspaces and workflow templates
|
||||
}
|
||||
|
||||
// testClientListWorkspaceTemplatesEmpty tests listing workspace templates when there are none
|
||||
func testClientListWorkspaceTemplatesEmpty(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
templates, err := c.ListWorkspaceTemplates("onepanel", nil)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Empty(t, templates)
|
||||
}
|
||||
|
||||
// testClientListWorkspaceTemplatesNotEmpty tests listing workspaces when there are records that are
|
||||
// archived and not. It should only list the non-archived ones
|
||||
func testClientListWorkspaceTemplatesNotEmpty(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
testTemplate, _ := c.CreateWorkspaceTemplate(namespace, wt)
|
||||
c.ArchiveWorkspaceTemplate(namespace, testTemplate.UID)
|
||||
|
||||
wt2 := &WorkspaceTemplate{
|
||||
Name: "test2",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
wt2, _ = c.CreateWorkspaceTemplate(namespace, wt2)
|
||||
|
||||
templates, err := c.ListWorkspaceTemplates(namespace, nil)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(templates))
|
||||
assert.Equal(t, wt2.UID, templates[0].UID)
|
||||
}
|
||||
|
||||
// TestClient_ListWorkspaceTemplates tests listing workspace templates
|
||||
func TestClient_ListWorkspaceTemplates(t *testing.T) {
|
||||
testClientListWorkspaceTemplatesEmpty(t)
|
||||
testClientListWorkspaceTemplatesNotEmpty(t)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package v1
|
||||
import (
|
||||
"fmt"
|
||||
wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"github.com/onepanelio/core/util/sql"
|
||||
"sigs.k8s.io/yaml"
|
||||
"time"
|
||||
@@ -25,6 +26,18 @@ type WorkspaceTemplate struct {
|
||||
WorkflowTemplateID uint64 `db:"workflow_template_id"`
|
||||
}
|
||||
|
||||
// GenerateUID generates a uid from the input name and sets it on the workflow template
|
||||
func (wt *WorkspaceTemplate) GenerateUID(name string) error {
|
||||
result, err := uid2.GenerateUID(name, 30)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wt.UID = result
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InjectRuntimeParameters will inject all runtime variables into the WorkflowTemplate's manifest.
|
||||
func (wt *WorkspaceTemplate) InjectRuntimeParameters(config SystemConfig) error {
|
||||
if wt.WorkflowTemplate == nil {
|
||||
|
||||
314
pkg/workspace_test.go
Normal file
314
pkg/workspace_test.go
Normal file
@@ -0,0 +1,314 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/lib/pq"
|
||||
"github.com/onepanelio/core/pkg/util"
|
||||
"github.com/onepanelio/core/pkg/util/ptr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc/codes"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testWorkspaceStatusToFieldMapLaunching(t *testing.T) {
|
||||
fm := workspaceStatusToFieldMap(&WorkspaceStatus{Phase: WorkspaceLaunching})
|
||||
|
||||
assert.Equal(t, fm["phase"], WorkspaceLaunching)
|
||||
assert.Equal(t, fm["paused_at"], pq.NullTime{})
|
||||
|
||||
started := fm["started_at"].(time.Time)
|
||||
|
||||
assert.True(t, started.After(time.Time{}))
|
||||
}
|
||||
|
||||
func testWorkspaceStatusToFieldMapPausing(t *testing.T) {
|
||||
fm := workspaceStatusToFieldMap(&WorkspaceStatus{Phase: WorkspacePausing})
|
||||
|
||||
assert.Equal(t, fm["phase"], WorkspacePausing)
|
||||
assert.Equal(t, fm["started_at"], pq.NullTime{})
|
||||
|
||||
paused := fm["paused_at"].(time.Time)
|
||||
|
||||
assert.True(t, paused.After(time.Time{}))
|
||||
}
|
||||
|
||||
func testWorkspaceStatusToFieldMapUpdating(t *testing.T) {
|
||||
fm := workspaceStatusToFieldMap(&WorkspaceStatus{Phase: WorkspaceUpdating})
|
||||
|
||||
assert.Equal(t, fm["phase"], WorkspaceUpdating)
|
||||
assert.Equal(t, fm["paused_at"], pq.NullTime{})
|
||||
|
||||
updated := fm["updated_at"].(time.Time)
|
||||
|
||||
assert.True(t, updated.After(time.Time{}))
|
||||
}
|
||||
|
||||
func testWorkspaceStatusToFieldMapTerminating(t *testing.T) {
|
||||
fm := workspaceStatusToFieldMap(&WorkspaceStatus{Phase: WorkspaceTerminating})
|
||||
|
||||
assert.Equal(t, fm["phase"], WorkspaceTerminating)
|
||||
assert.Equal(t, fm["paused_at"], pq.NullTime{})
|
||||
assert.Equal(t, fm["started_at"], pq.NullTime{})
|
||||
|
||||
terminated := fm["terminated_at"].(time.Time)
|
||||
|
||||
assert.True(t, terminated.After(time.Time{}))
|
||||
}
|
||||
|
||||
func Test_WorkspaceStatusToFieldMap(t *testing.T) {
|
||||
testWorkspaceStatusToFieldMapLaunching(t)
|
||||
testWorkspaceStatusToFieldMapPausing(t)
|
||||
testWorkspaceStatusToFieldMapUpdating(t)
|
||||
testWorkspaceStatusToFieldMapTerminating(t)
|
||||
}
|
||||
|
||||
// testClientPrivateCreateWorkspaceNoWorkflowTemplate makes sure we get an error when there is no workflow template for the workspace
|
||||
func testClientPrivateCreateWorkspaceNoWorkflowTemplate(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
workspace := &Workspace{
|
||||
Name: "test",
|
||||
WorkspaceTemplate: &WorkspaceTemplate{
|
||||
WorkflowTemplate: &WorkflowTemplate{
|
||||
UID: "not-exist",
|
||||
Version: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
workspace.GenerateUID("test")
|
||||
|
||||
_, err := c.createWorkspace(namespace, []byte(""), workspace)
|
||||
|
||||
userErr, ok := err.(*util.UserError)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, userErr.Code, codes.NotFound)
|
||||
}
|
||||
|
||||
// testClientPrivateCreateWorkspaceSuccess tests creating a workspace successfully
|
||||
func testClientPrivateCreateWorkspaceSuccess(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
workspaceTemplate := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
workspaceTemplate, _ = c.CreateWorkspaceTemplate(namespace, workspaceTemplate)
|
||||
|
||||
workspace := &Workspace{
|
||||
Name: "test2",
|
||||
WorkspaceTemplate: workspaceTemplate,
|
||||
Parameters: []Parameter{
|
||||
{
|
||||
Name: "workflow-execution-name",
|
||||
Value: ptr.String("test2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
workspace.GenerateUID("test")
|
||||
|
||||
_, err := c.createWorkspace(namespace, []byte("{}"), workspace)
|
||||
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestClient_createWorkspace(t *testing.T) {
|
||||
testClientPrivateCreateWorkspaceNoWorkflowTemplate(t)
|
||||
testClientPrivateCreateWorkspaceSuccess(t)
|
||||
}
|
||||
|
||||
func testClientCreateWorkspaceSuccess(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
testTemplate, _ := c.CreateWorkspaceTemplate(namespace, wt)
|
||||
|
||||
workspace := &Workspace{
|
||||
Name: "test",
|
||||
WorkspaceTemplate: &WorkspaceTemplate{
|
||||
UID: testTemplate.UID,
|
||||
Version: testTemplate.Version,
|
||||
},
|
||||
Parameters: []Parameter{
|
||||
{
|
||||
Name: "workflow-execution-name",
|
||||
Value: ptr.String("test2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
createdWorkspace, err := c.CreateWorkspace(namespace, workspace)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, createdWorkspace)
|
||||
}
|
||||
|
||||
func TestClient_CreateWorkspace(t *testing.T) {
|
||||
testClientCreateWorkspaceSuccess(t)
|
||||
}
|
||||
|
||||
func TestClient_ArchiveWorkspace(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
workspaceTemplate := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
workspaceTemplate, _ = c.CreateWorkspaceTemplate(namespace, workspaceTemplate)
|
||||
|
||||
workspace := &Workspace{
|
||||
Name: "test2",
|
||||
WorkspaceTemplate: workspaceTemplate,
|
||||
Parameters: []Parameter{
|
||||
{
|
||||
Name: "workflow-execution-name",
|
||||
Value: ptr.String("test2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
workspace.GenerateUID("test")
|
||||
|
||||
createdWorkspace, _ := c.createWorkspace(namespace, []byte("[]"), workspace)
|
||||
|
||||
params := []Parameter{
|
||||
{
|
||||
Name: "workflow-execution-name",
|
||||
Value: ptr.String("test3"),
|
||||
},
|
||||
}
|
||||
err := c.ArchiveWorkspace(namespace, createdWorkspace.UID, params...)
|
||||
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// TestClient_ListWorkspacesByTemplateID tests listing workspaces by the template id
|
||||
func TestClient_ListWorkspacesByTemplateID(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
wt := &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
testTemplate, _ := c.CreateWorkspaceTemplate(namespace, wt)
|
||||
workspace := &Workspace{
|
||||
Name: "test",
|
||||
WorkspaceTemplate: testTemplate,
|
||||
Parameters: []Parameter{
|
||||
{
|
||||
Name: "workflow-execution-name",
|
||||
Value: ptr.String("test"),
|
||||
},
|
||||
},
|
||||
}
|
||||
workspace.GenerateUID("test")
|
||||
|
||||
c.createWorkspace(namespace, []byte("[]"), workspace)
|
||||
|
||||
wt2 := &WorkspaceTemplate{
|
||||
Name: "test2",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
}
|
||||
|
||||
testTemplate2, _ := c.CreateWorkspaceTemplate(namespace, wt2)
|
||||
workspace2 := &Workspace{
|
||||
Name: "test2",
|
||||
WorkspaceTemplate: testTemplate2,
|
||||
Parameters: []Parameter{
|
||||
{
|
||||
Name: "workflow-execution-name",
|
||||
Value: ptr.String("test2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
workspace2.GenerateUID("test2")
|
||||
|
||||
c.createWorkspace(namespace, []byte("[]"), workspace2)
|
||||
|
||||
workspaces, err := c.ListWorkspacesByTemplateID(namespace, testTemplate.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(workspaces))
|
||||
|
||||
params := []Parameter{
|
||||
{
|
||||
Name: "workflow-execution-name",
|
||||
Value: ptr.String("test3"),
|
||||
},
|
||||
}
|
||||
c.ArchiveWorkspace(namespace, testTemplate.UID, params...)
|
||||
|
||||
workspaces, err = c.ListWorkspacesByTemplateID(namespace, testTemplate.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, workspaces[0].Status.Phase == WorkspaceTerminating)
|
||||
}
|
||||
|
||||
func testUpdateWorkspaceStatusSuccess(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
namespace := "onepanel"
|
||||
|
||||
workspace := &Workspace{
|
||||
Name: "test",
|
||||
Parameters: []Parameter{
|
||||
{
|
||||
Name: "workflow-execution-name",
|
||||
Value: ptr.String("test"),
|
||||
},
|
||||
},
|
||||
WorkspaceTemplate: &WorkspaceTemplate{
|
||||
Name: "test",
|
||||
Manifest: jupyterLabWorkspaceManifest,
|
||||
WorkflowTemplate: &WorkflowTemplate{
|
||||
UID: "test",
|
||||
Version: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
workspace.GenerateUID("test")
|
||||
|
||||
c.CreateWorkspaceTemplate(namespace, workspace.WorkspaceTemplate)
|
||||
ws, _ := c.createWorkspace(namespace, []byte("[]"), workspace)
|
||||
|
||||
err := c.UpdateWorkspaceStatus(namespace, ws.UID, &WorkspaceStatus{Phase: WorkspacePausing})
|
||||
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func testUpdateWorkspaceStatusNotFound(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
err := c.UpdateWorkspaceStatus("not-found", "random", &WorkspaceStatus{Phase: WorkspacePausing})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
userErr, ok := err.(*util.UserError)
|
||||
assert.True(t, ok)
|
||||
|
||||
assert.Equal(t, userErr.Code, codes.NotFound)
|
||||
}
|
||||
|
||||
func Test_UpdateWorkspaceStatus(t *testing.T) {
|
||||
testUpdateWorkspaceStatusSuccess(t)
|
||||
testUpdateWorkspaceStatusNotFound(t)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package v1
|
||||
import (
|
||||
"fmt"
|
||||
wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"github.com/onepanelio/core/util/sql"
|
||||
networking "istio.io/api/networking/v1alpha3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -63,6 +64,29 @@ func (w *Workspace) GetURL(protocol, domain string) string {
|
||||
return fmt.Sprintf("%v%v--%v.%v", protocol, w.UID, w.Namespace, domain)
|
||||
}
|
||||
|
||||
// GetParameterValue returns the value of the parameter with the given name, or nil if there is no such parameter
|
||||
func (w *Workspace) GetParameterValue(name string) *string {
|
||||
for _, p := range w.Parameters {
|
||||
if p.Name == name {
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateUID generates a uid from the input name and sets it on the workspace
|
||||
func (w *Workspace) GenerateUID(name string) error {
|
||||
result, err := uid2.GenerateUID(name, 30)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.UID = result
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getWorkspaceColumns returns all of the columns for workspace modified by alias, destination.
|
||||
// see formatColumnSelect
|
||||
func getWorkspaceColumns(aliasAndDestination ...string) []string {
|
||||
|
||||
@@ -28,7 +28,7 @@ func assertWorkspaceNameValid(t *testing.T, name string) {
|
||||
assert.True(t, valid)
|
||||
}
|
||||
|
||||
func TestWorkspaceNameValidation_RegexValid(t *testing.T) {
|
||||
func Test_WorkspaceNameValidation_RegexValid(t *testing.T) {
|
||||
assertWorkspaceNameInvalid(t, "600s")
|
||||
|
||||
assertWorkspaceNameValid(t, "test-5")
|
||||
|
||||
@@ -50,6 +50,10 @@ func getBearerToken(ctx context.Context) (*string, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
for _, t := range md.Get("onepanel-auth-token") {
|
||||
return &t, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -98,6 +102,7 @@ func IsAuthorized(c *v1.Client, namespace, verb, group, resource, name string) (
|
||||
// 2. Is there a token? There should be a token for everything except logging in.
|
||||
func UnaryInterceptor(kubeConfig *v1.Config, db *v1.DB, sysConfig v1.SystemConfig) grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
|
||||
// Check if the provided token is valid. This does not require a token in the header.
|
||||
if info.FullMethod == "/api.AuthService/IsValidToken" {
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
|
||||
@@ -105,27 +105,6 @@ func (s *WorkflowTemplateServer) CreateWorkflowTemplateVersion(ctx context.Conte
|
||||
return req.WorkflowTemplate, nil
|
||||
}
|
||||
|
||||
func (s *WorkflowTemplateServer) UpdateWorkflowTemplateVersion(ctx context.Context, req *api.UpdateWorkflowTemplateVersionRequest) (*api.WorkflowTemplate, error) {
|
||||
client := getClient(ctx)
|
||||
allowed, err := auth.IsAuthorized(client, req.Namespace, "update", "argoproj.io", "workflowtemplates", req.WorkflowTemplate.Name)
|
||||
if err != nil || !allowed {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workflowTemplate := &v1.WorkflowTemplate{
|
||||
UID: req.WorkflowTemplate.Uid,
|
||||
Name: req.WorkflowTemplate.Name,
|
||||
Manifest: req.WorkflowTemplate.Manifest,
|
||||
Version: req.WorkflowTemplate.Version,
|
||||
}
|
||||
|
||||
req.WorkflowTemplate.Uid = workflowTemplate.UID
|
||||
req.WorkflowTemplate.Name = workflowTemplate.Name
|
||||
req.WorkflowTemplate.Version = workflowTemplate.Version
|
||||
|
||||
return req.WorkflowTemplate, nil
|
||||
}
|
||||
|
||||
func (s *WorkflowTemplateServer) GetWorkflowTemplate(ctx context.Context, req *api.GetWorkflowTemplateRequest) (*api.WorkflowTemplate, error) {
|
||||
client := getClient(ctx)
|
||||
allowed, err := auth.IsAuthorized(client, req.Namespace, "get", "argoproj.io", "workflowtemplates", "")
|
||||
|
||||
@@ -5,14 +5,20 @@ import (
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/onepanelio/core/api"
|
||||
v1 "github.com/onepanelio/core/pkg"
|
||||
"github.com/onepanelio/core/pkg/util"
|
||||
"github.com/onepanelio/core/pkg/util/pagination"
|
||||
"github.com/onepanelio/core/pkg/util/ptr"
|
||||
"github.com/onepanelio/core/server/auth"
|
||||
"github.com/onepanelio/core/server/converter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"time"
|
||||
)
|
||||
|
||||
var reservedWorkspaceNames = map[string]bool{
|
||||
"modeldb": true,
|
||||
}
|
||||
|
||||
type WorkspaceServer struct{}
|
||||
|
||||
func apiWorkspace(wt *v1.Workspace, config v1.SystemConfig) *api.Workspace {
|
||||
@@ -106,6 +112,10 @@ func (s *WorkspaceServer) CreateWorkspace(ctx context.Context, req *api.CreateWo
|
||||
})
|
||||
}
|
||||
|
||||
if _, isReserved := reservedWorkspaceNames[workspace.Name]; isReserved {
|
||||
return nil, util.NewUserError(codes.AlreadyExists, "That name is reserved, choose a different name for the workspace.")
|
||||
}
|
||||
|
||||
workspace, err = client.CreateWorkspace(req.Namespace, workspace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -147,6 +157,11 @@ func (s *WorkspaceServer) GetWorkspace(ctx context.Context, req *api.GetWorkspac
|
||||
return nil, err
|
||||
}
|
||||
|
||||
templateParameters, err = sysConfig.UpdateNodePoolOptions(templateParameters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiWorkspace.TemplateParameters = converter.ParametersToAPI(templateParameters)
|
||||
|
||||
return apiWorkspace, nil
|
||||
|
||||
Reference in New Issue
Block a user