Merge branch 'dev' into feat/provider-specific-config

This commit is contained in:
Rush Tehrani
2020-07-09 14:18:49 -07:00
committed by GitHub
63 changed files with 1935 additions and 895 deletions

26
.github/workflows/run_unit_tests.yaml vendored Normal file
View 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

View File

@@ -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

View File

@@ -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",

View File

@@ -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,

View File

@@ -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

View File

@@ -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"

View File

@@ -4,7 +4,6 @@ package main
import (
"flag"
"fmt"
"github.com/jmoiron/sqlx"
_ "github.com/onepanelio/core/db"
v1 "github.com/onepanelio/core/pkg"
@@ -38,10 +37,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]

View File

@@ -0,0 +1,167 @@
package migration
import (
"database/sql"
v1 "github.com/onepanelio/core/pkg"
uid2 "github.com/onepanelio/core/pkg/util/uid"
"github.com/pressly/goose"
"time"
)
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 init() {
goose.AddMigration(Up20200704151301, Down20200704151301)
}
// Up20200704151301 updates the CVAT template to a new version.
func Up20200704151301(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
}
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
}

View File

@@ -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
}

View File

@@ -71,7 +71,7 @@ routes:
const jupyterLabTemplateName = "JupyterLab"
func init() {
func initialize20200525160514() {
goose.AddMigration(Up20200525160514, Down20200525160514)
}
@@ -81,6 +81,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

View File

@@ -110,7 +110,7 @@ routes:
const cvatTemplateName = "CVAT"
func init() {
func initialize20200528140124() {
goose.AddMigration(Up20200528140124, Down20200528140124)
}
@@ -125,6 +125,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

View File

@@ -88,7 +88,7 @@ templates:
const pytorchMnistWorkflowTemplateName = "PyTorch Training"
func init() {
func initialize20200605090509() {
goose.AddMigration(Up20200605090509, Down20200605090509)
}
@@ -101,6 +101,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

View File

@@ -88,7 +88,7 @@ templates:
const tensorflowWorkflowTemplateName = "TensorFlow Training"
func init() {
func initialize20200605090535() {
goose.AddMigration(Up20200605090535, Down20200605090535)
}
@@ -101,6 +101,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

View File

@@ -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,27 @@ routes:
# - -c
`
func init() {
func initialize20200626113635() {
goose.AddMigration(Up20200626113635, Down20200626113635)
}
// 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

53
db/go/db.go Normal file
View File

@@ -0,0 +1,53 @@
package migration
import (
sq "github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx"
v1 "github.com/onepanelio/core/pkg"
)
// Initialize sets up the go migrations.
func Initialize() {
initialize20200525160514()
initialize20200528140124()
initialize20200605090509()
initialize20200605090535()
initialize20200626113635()
}
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
}

View File

@@ -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;

View 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;

20
main.go
View File

@@ -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"
@@ -23,6 +22,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 +67,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, "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, "db/go"); err != nil {
log.Fatalf("Failed to run database go migrations: %v", err)
}
s := startRPCServer(v1.NewDB(db), kubeConfig, sysConfig, stopCh)

View File

@@ -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)
}
}

View File

@@ -36,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

View File

@@ -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)

View File

@@ -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",

View File

@@ -2,6 +2,7 @@ package v1
import (
"bufio"
"database/sql"
"encoding/json"
"errors"
"fmt"
@@ -85,6 +86,18 @@ func UnmarshalWorkflows(wfBytes []byte, strict bool) (wfs []wfv1.Workflow, err e
return
}
// getWorkflowsFromWorkflowTemplate parses the WorkflowTemplate manifest and returns the argo workflows from it
func getWorkflowsFromWorkflowTemplate(wt *WorkflowTemplate) (wfs []wfv1.Workflow, err error) {
manifest, err := wt.GetWorkflowManifestBytes()
if err != nil {
return nil, err
}
wfs, err = UnmarshalWorkflows(manifest, true)
return
}
// appendArtifactRepositoryConfigIfMissing appends default artifact repository config to artifacts that have a key.
// Artifacts that contain anything other than key are skipped.
func injectArtifactRepositoryConfig(artifact *wfv1.Artifact, namespaceConfig *NamespaceConfig) {
@@ -265,11 +278,19 @@ func (c *Client) injectAutomatedFields(namespace string, wf *wfv1.Workflow, opts
return
}
// ArchiveWorkflowExecution marks a WorkflowExecution as archived in database
// and deletes the argo workflow.
//
// If the database record does not exist, we still try to delete the argo workflow record.
// No errors are returned if the records do not exist.
func (c *Client) ArchiveWorkflowExecution(namespace, uid string) error {
_, err := sb.Update("workflow_executions").Set("is_archived", true).Where(sq.Eq{
"uid": uid,
"namespace": namespace,
}).RunWith(c.DB).Exec()
_, err := sb.Update("workflow_executions").
Set("is_archived", true).
Where(sq.Eq{
"uid": uid,
"namespace": namespace,
}).RunWith(c.DB).
Exec()
if err != nil {
return err
}
@@ -285,11 +306,10 @@ func (c *Client) ArchiveWorkflowExecution(namespace, uid string) error {
return nil
}
/*
Name is == to UID, no user friendly name.
Workflow execution name == uid, example: name = my-friendly-wf-name-8skjz, uid = my-friendly-wf-name-8skjz
*/
func (c *Client) createWorkflow(namespace string, workflowTemplateId uint64, workflowTemplateVersionId uint64, wf *wfv1.Workflow, opts *WorkflowExecutionOptions) (newDbId uint64, createdWorkflow *wfv1.Workflow, err error) {
// createWorkflow creates the workflow in the database and argo.
// Name is == to UID, no user friendly name.
// Workflow execution name == uid, example: name = my-friendly-wf-name-8skjz, uid = my-friendly-wf-name-8skjz
func (c *Client) createWorkflow(namespace string, workflowTemplateID uint64, workflowTemplateVersionID uint64, wf *wfv1.Workflow, opts *WorkflowExecutionOptions) (createdWorkflow *WorkflowExecution, err error) {
if opts == nil {
opts = &WorkflowExecutionOptions{}
}
@@ -330,34 +350,41 @@ func (c *Client) createWorkflow(namespace string, workflowTemplateId uint64, wor
wf.ObjectMeta.Labels = opts.Labels
}
err = injectWorkflowExecutionStatusCaller(wf, wfv1.NodeRunning)
if err != nil {
return 0, nil, err
if err = injectWorkflowExecutionStatusCaller(wf, wfv1.NodeRunning); err != nil {
return nil, err
}
err = injectExitHandlerWorkflowExecutionStatistic(wf, &workflowTemplateId)
if err != nil {
return 0, nil, err
if err = injectExitHandlerWorkflowExecutionStatistic(wf, &workflowTemplateID); err != nil {
return nil, err
}
if err = c.injectAutomatedFields(namespace, wf, opts); err != nil {
return 0, nil, err
return nil, err
}
createdWorkflow, err = c.ArgoprojV1alpha1().Workflows(namespace).Create(wf)
createdArgoWorkflow, err := c.ArgoprojV1alpha1().Workflows(namespace).Create(wf)
if err != nil {
return 0, nil, err
return nil, err
}
uid, err := uid2.GenerateUID(createdWorkflow.Name, 63)
if err != nil {
return 0, nil, err
createdWorkflow = &WorkflowExecution{
Name: createdArgoWorkflow.Name,
CreatedAt: createdArgoWorkflow.CreationTimestamp.UTC(),
ArgoWorkflow: createdArgoWorkflow,
WorkflowTemplate: &WorkflowTemplate{
WorkflowTemplateVersionID: workflowTemplateVersionID,
},
Parameters: opts.Parameters,
}
if err = createdWorkflow.GenerateUID(createdArgoWorkflow.Name); err != nil {
return nil, err
}
//Create an entry for workflow_executions statistic
//CURL code will hit the API endpoint that will update the db row
newDbId, err = c.insertPreWorkflowExecutionStatistic(namespace, createdWorkflow.Name, workflowTemplateVersionId, createdWorkflow.CreationTimestamp.UTC(), uid, opts.Parameters)
if err != nil {
return 0, nil, err
if err := c.createWorkflowExecutionDB(namespace, createdWorkflow); err != nil {
return nil, err
}
return
@@ -376,7 +403,9 @@ func (c *Client) ValidateWorkflowExecution(namespace string, manifest []byte) (e
wftmplGetter := templateresolution.WrapWorkflowTemplateInterface(c.ArgoprojV1alpha1().WorkflowTemplates(namespace))
for _, wf := range workflows {
c.injectAutomatedFields(namespace, &wf, &WorkflowExecutionOptions{})
if err = c.injectAutomatedFields(namespace, &wf, &WorkflowExecutionOptions{}); err != nil {
return err
}
_, err = validate.ValidateWorkflow(wftmplGetter, &wf, validate.ValidateOpts{})
if err != nil {
return
@@ -398,16 +427,22 @@ func (c *Client) ValidateWorkflowExecution(namespace string, manifest []byte) (e
}
// CreateWorkflowExecution creates an argo workflow execution and related resources.
// Note that the workflow template is loaded from the database/k8s, so workflow.WorkflowTemplate.Manifest is not used.
// Required:
// * workflow.Parameters
// * workflow.Labels (optional)
// If workflow.Name is set, it is used instead of a generated name.
// If there is a parameter named "workflow-execution-name" in workflow.Parameters, it is set as the name.
func (c *Client) CreateWorkflowExecution(namespace string, workflow *WorkflowExecution, workflowTemplate *WorkflowTemplate) (*WorkflowExecution, error) {
opts := &WorkflowExecutionOptions{
Labels: make(map[string]string),
Parameters: workflow.Parameters,
}
if workflow.Name != "" {
opts.Name = workflow.Name
}
if workflowExecutionName := workflow.GetParameterValue("workflow-execution-name"); workflowExecutionName != nil {
opts.Name = *workflowExecutionName
}
nameUID, err := uid2.GenerateUID(workflowTemplate.Name, 63)
if err != nil {
return nil, err
@@ -418,19 +453,16 @@ func (c *Client) CreateWorkflowExecution(namespace string, workflow *WorkflowExe
opts.Labels[workflowTemplateVersionLabelKey] = fmt.Sprint(workflowTemplate.Version)
label.MergeLabelsPrefix(opts.Labels, workflow.Labels, label.TagPrefix)
// @todo we need to enforce the below requirement in API.
//UX will prevent multiple workflows
manifest, err := workflowTemplate.GetWorkflowManifestBytes()
workflows, err := getWorkflowsFromWorkflowTemplate(workflowTemplate)
if err != nil {
log.WithFields(log.Fields{
"Namespace": namespace,
"WorkflowTemplate": workflowTemplate,
"Error": err.Error(),
}).Error("Error with getting WorkflowManifest from workflow template")
return nil, err
}
workflows, err := UnmarshalWorkflows(manifest, true)
if len(workflows) != 1 {
return nil, fmt.Errorf("workflow Template contained more than 1 workflow execution")
}
createdWorkflow, err := c.createWorkflow(namespace, workflowTemplate.ID, workflowTemplate.WorkflowTemplateVersionID, &workflows[0], opts)
if err != nil {
log.WithFields(log.Fields{
"Namespace": namespace,
@@ -440,35 +472,14 @@ func (c *Client) CreateWorkflowExecution(namespace string, workflow *WorkflowExe
return nil, err
}
id, createdWorkflow, err := c.createWorkflow(namespace, workflowTemplate.ID, workflowTemplate.WorkflowTemplateVersionID, &workflows[0], opts)
if err != nil {
log.WithFields(log.Fields{
"Namespace": namespace,
"Workflow": workflow,
"Error": err.Error(),
}).Error("Error parsing workflow.")
if _, err := c.InsertLabels(TypeWorkflowExecution, createdWorkflow.ID, workflow.Labels); err != nil {
return nil, err
}
if _, err := c.InsertLabels(TypeWorkflowExecution, id, workflow.Labels); err != nil {
return nil, err
}
if createdWorkflow == nil {
err = errors.New("unable to create workflow")
log.WithFields(log.Fields{
"Namespace": namespace,
"WorkflowTemplate": workflowTemplate,
"Error": err.Error(),
}).Error("Error parsing workflow.")
return nil, err
}
workflow.ID = id
workflow.ID = createdWorkflow.ID
workflow.Name = createdWorkflow.Name
workflow.CreatedAt = createdWorkflow.CreationTimestamp.UTC()
workflow.UID = createdWorkflow.Name
workflow.CreatedAt = createdWorkflow.CreatedAt.UTC()
workflow.UID = createdWorkflow.UID
workflow.WorkflowTemplate = workflowTemplate
return workflow, nil
@@ -494,44 +505,41 @@ func (c *Client) CloneWorkflowExecution(namespace, uid string) (*WorkflowExecuti
return c.CreateWorkflowExecution(namespace, workflowExecution, workflowTemplate)
}
func (c *Client) insertPreWorkflowExecutionStatistic(namespace, name string, workflowTemplateVersionId uint64, createdAt time.Time, uid string, parameters []Parameter) (newId uint64, err error) {
tx, err := c.DB.Begin()
// createWorkflowExecutionDB inserts a workflow execution into the database.
// Required fields
// * name
// * createdAt // we sync the argo created at with the db
// * parameters, if any
// * WorkflowTemplate.WorkflowTemplateVersionID
//
// After success, the passed in WorkflowExecution will have it's ID set to the new db record.
func (c *Client) createWorkflowExecutionDB(namespace string, workflowExecution *WorkflowExecution) (err error) {
parametersJSON, err := json.Marshal(workflowExecution.Parameters)
if err != nil {
return 0, err
}
defer tx.Rollback()
parametersJSON, err := json.Marshal(parameters)
if err != nil {
return 0, err
return err
}
insertMap := sq.Eq{
"uid": uid,
"workflow_template_version_id": workflowTemplateVersionId,
"name": name,
"namespace": namespace,
"created_at": createdAt.UTC(),
"phase": wfv1.NodePending,
"parameters": string(parametersJSON),
"is_archived": false,
if err := workflowExecution.GenerateUID(workflowExecution.Name); err != nil {
return err
}
err = sb.Insert("workflow_executions").
SetMap(insertMap).
SetMap(sq.Eq{
"UID": workflowExecution.UID,
"workflow_template_version_id": workflowExecution.WorkflowTemplate.WorkflowTemplateVersionID,
"name": workflowExecution.Name,
"namespace": namespace,
"created_at": workflowExecution.CreatedAt.UTC(),
"phase": wfv1.NodePending,
"parameters": string(parametersJSON),
"is_archived": false,
}).
Suffix("RETURNING id").
RunWith(tx).
RunWith(c.DB).
QueryRow().
Scan(&newId)
Scan(&workflowExecution.ID)
if err != nil {
return 0, err
}
err = tx.Commit()
if err != nil {
return 0, err
}
return newId, err
return
}
func (c *Client) FinishWorkflowExecutionStatisticViaExitHandler(namespace, name string, workflowTemplateID int64, phase wfv1.NodePhase, startedAt time.Time) (err error) {
@@ -562,32 +570,20 @@ func (c *Client) FinishWorkflowExecutionStatisticViaExitHandler(namespace, name
}
func (c *Client) CronStartWorkflowExecutionStatisticInsert(namespace, uid string, workflowTemplateID int64) (err error) {
query, args, err := c.workflowTemplatesSelectBuilder(namespace).
queryWt := c.workflowTemplatesSelectBuilder(namespace).
Where(sq.Eq{
"wt.id": workflowTemplateID,
}).
ToSql()
if err != nil {
return err
}
})
workflowTemplate := &WorkflowTemplate{}
if err := c.DB.Get(workflowTemplate, query, args...); err != nil {
if err := c.DB.Getx(workflowTemplate, queryWt); err != nil {
return err
}
query, args, err = c.cronWorkflowSelectBuilder(namespace, workflowTemplate.UID).ToSql()
if err != nil {
return err
}
queryCw := c.cronWorkflowSelectBuilder(namespace, workflowTemplate.UID)
cronWorkflow := &CronWorkflow{}
if err := c.DB.Get(cronWorkflow, query, args...); err != nil {
return err
}
cronLabels, err := c.GetDbLabels(TypeCronWorkflow, cronWorkflow.ID)
if err != nil {
if err := c.DB.Getx(cronWorkflow, queryCw); err != nil {
return err
}
@@ -602,49 +598,43 @@ func (c *Client) CronStartWorkflowExecutionStatisticInsert(namespace, uid string
return err
}
insertMap := sq.Eq{
"uid": uid,
"workflow_template_version_id": cronWorkflow.WorkflowTemplateVersionID,
"name": uid,
"namespace": namespace,
"phase": wfv1.NodeRunning,
"started_at": time.Now().UTC(),
"cron_workflow_id": cronWorkflow.ID,
"parameters": string(parametersJSON),
}
workflowExecutionId := uint64(0)
workflowExecutionID := uint64(0)
err = sb.Insert("workflow_executions").
SetMap(insertMap).
SetMap(sq.Eq{
"uid": uid,
"workflow_template_version_id": cronWorkflow.WorkflowTemplateVersionID,
"name": uid,
"namespace": namespace,
"phase": wfv1.NodeRunning,
"started_at": time.Now().UTC(),
"cron_workflow_id": cronWorkflow.ID,
"parameters": string(parametersJSON),
}).
Suffix("RETURNING id").
RunWith(tx).
QueryRow().
Scan(&workflowExecutionId)
Scan(&workflowExecutionID)
if err != nil {
return err
}
if len(cronLabels) > 0 {
labelsMapped := LabelsToMapping(cronLabels...)
_, err = c.InsertLabelsBuilder(TypeWorkflowExecution, workflowExecutionId, labelsMapped).
RunWith(tx).
Exec()
if err != nil {
return err
}
cronLabels, err := c.GetDBLabelsMapped(TypeCronWorkflow, cronWorkflow.ID)
if err != nil {
return err
}
labelsMapped := cronLabels[cronWorkflow.ID]
if _, err := c.InsertLabelsRunner(tx, TypeWorkflowExecution, workflowExecutionID, labelsMapped); err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
return err
}
func (c *Client) GetWorkflowExecution(namespace, uid string) (workflow *WorkflowExecution, err error) {
workflow = &WorkflowExecution{}
query, args, err := sb.Select(getWorkflowExecutionColumns("we", "")...).
query := sb.Select(getWorkflowExecutionColumns("we")...).
Columns(getWorkflowTemplateColumns("wt", "workflow_template")...).
Columns(`wtv.manifest "workflow_template.manifest"`).
From("workflow_executions we").
@@ -654,12 +644,13 @@ func (c *Client) GetWorkflowExecution(namespace, uid string) (workflow *Workflow
"wt.namespace": namespace,
"we.name": uid,
"we.is_archived": false,
}).
ToSql()
if err != nil {
return nil, err
}
if err := c.DB.Get(workflow, query, args...); err != nil {
})
if err := c.DB.Getx(workflow, query); err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, err
}
@@ -677,7 +668,7 @@ func (c *Client) GetWorkflowExecution(namespace, uid string) (workflow *Workflow
version, err := strconv.ParseInt(
wf.ObjectMeta.Labels[workflowTemplateVersionLabelKey],
10,
32,
64,
)
if err != nil {
log.WithFields(log.Fields{
@@ -713,6 +704,7 @@ func (c *Client) GetWorkflowExecution(namespace, uid string) (workflow *Workflow
return
}
// ListWorkflowExecutions gets a list of WorkflowExecutions ordered by most recently created first.
func (c *Client) ListWorkflowExecutions(namespace, workflowTemplateUID, workflowTemplateVersion string, paginator *pagination.PaginationRequest) (workflows []*WorkflowExecution, err error) {
sb := workflowExecutionsSelectBuilder(namespace, workflowTemplateUID, workflowTemplateVersion).
OrderBy("we.created_at DESC")
@@ -725,10 +717,11 @@ func (c *Client) ListWorkflowExecutions(namespace, workflowTemplateUID, workflow
return
}
// CountWorkflowExecutions returns the number of workflow executions
func (c *Client) CountWorkflowExecutions(namespace, workflowTemplateUID, workflowTemplateVersion string) (count int, err error) {
err = workflowExecutionsSelectBuilderNoColumns(namespace, workflowTemplateUID, workflowTemplateVersion).
Columns("COUNT(*)").
RunWith(c.DB.DB).
RunWith(c.DB).
QueryRow().
Scan(&count)
@@ -1069,8 +1062,9 @@ func (c *Client) SuspendWorkflowExecution(namespace, uid string) (err error) {
return
}
// TerminateWorkflowExecution marks a workflows execution as terminated in DB and terminates the argo resource.
func (c *Client) TerminateWorkflowExecution(namespace, uid string) (err error) {
query, args, err := sb.Update("workflow_executions").
_, err = sb.Update("workflow_executions").
Set("phase", "Terminated").
Set("started_at", time.Time.UTC(time.Now())).
Set("finished_at", time.Time.UTC(time.Now())).
@@ -1078,16 +1072,12 @@ func (c *Client) TerminateWorkflowExecution(namespace, uid string) (err error) {
"uid": uid,
"namespace": namespace,
}).
ToSql()
RunWith(c.DB).
Exec()
if err != nil {
return err
}
if _, err := c.DB.Exec(query, args...); err != nil {
return err
}
err = argoutil.TerminateWorkflow(c.ArgoprojV1alpha1().Workflows(namespace), uid)
return
@@ -1605,7 +1595,7 @@ func workflowExecutionsSelectBuilder(namespace, workflowTemplateUID, workflowTem
}
func (c *Client) getWorkflowExecutionAndTemplate(namespace string, uid string) (workflow *WorkflowExecution, err error) {
query, args, err := sb.Select(getWorkflowExecutionColumns("we", "")...).
sb := sb.Select(getWorkflowExecutionColumns("we", "")...).
Columns(getWorkflowTemplateColumns("wt", "workflow_template")...).
Columns(`wtv.manifest "workflow_template.manifest"`, `wtv.version "workflow_template.version"`).
From("workflow_executions we").
@@ -1615,16 +1605,10 @@ func (c *Client) getWorkflowExecutionAndTemplate(namespace string, uid string) (
"wt.namespace": namespace,
"we.name": uid,
"we.is_archived": false,
}).
ToSql()
if err != nil {
return nil, err
}
// TODO DB call
})
workflow = &WorkflowExecution{}
if err = c.DB.Get(workflow, query, args...); err != nil {
if err = c.DB.Getx(workflow, sb); err != nil {
return nil, err
}

View 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)
}

View File

@@ -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 {

View File

@@ -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.

View 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)
}

View File

@@ -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)

View File

@@ -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...)
}

View File

@@ -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"
@@ -118,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
@@ -726,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 {
@@ -761,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,
@@ -1049,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,").
@@ -1077,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
}
@@ -1099,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").
@@ -1189,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 {

View File

@@ -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)
}

View File

@@ -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
View 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)
}

View File

@@ -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 {

View File

@@ -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")

View File

@@ -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", "")