mirror of
https://github.com/onepanelio/onepanel.git
synced 2025-09-26 17:51:13 +08:00
update: updated tests to have method calls for particular cases. Added more tests.
This commit is contained in:
@@ -44,6 +44,7 @@ s3:
|
||||
},
|
||||
Data: map[string]string{
|
||||
"ONEPANEL_HOST": "demo.onepanel.site",
|
||||
"ONEPANEL_DOMAIN": "demo.onepanel.site",
|
||||
"artifactRepository": configArtifactRepository,
|
||||
"applicationNodePoolLabel": "beta.kubernetes.io/instance-type",
|
||||
"applicationNodePoolOptions": `
|
||||
|
@@ -340,6 +340,7 @@ func (c *Client) ValidateWorkflowExecution(namespace string, manifest []byte) (e
|
||||
|
||||
// CreateWorkflowExecution creates an argo workflow execution and related resources.
|
||||
// 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),
|
||||
@@ -350,6 +351,10 @@ func (c *Client) CreateWorkflowExecution(namespace string, workflow *WorkflowExe
|
||||
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
|
||||
|
@@ -75,6 +75,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 {
|
||||
|
@@ -164,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").
|
||||
@@ -176,7 +178,7 @@ func (c *Client) workflowTemplatesVersionSelectBuilder(namespace string) sq.Sele
|
||||
}
|
||||
|
||||
// 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) {
|
||||
func (c *Client) getWorkflowTemplateDB(namespace, name string) (workflowTemplate *WorkflowTemplate, err error) {
|
||||
workflowTemplate = &WorkflowTemplate{}
|
||||
|
||||
sb := c.workflowTemplatesSelectBuilder(namespace).
|
||||
@@ -190,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,
|
||||
}
|
||||
@@ -212,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) {
|
||||
@@ -233,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").
|
||||
@@ -249,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})
|
||||
@@ -292,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
|
||||
}
|
||||
@@ -327,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").
|
||||
@@ -339,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)
|
||||
|
||||
@@ -406,6 +411,9 @@ func (c *Client) CreateWorkflowTemplate(namespace string, workflowTemplate *Work
|
||||
|
||||
// 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")
|
||||
@@ -568,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,
|
||||
@@ -805,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.
|
||||
|
@@ -2,6 +2,7 @@ package v1
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/onepanelio/core/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -85,19 +86,19 @@ templates:
|
||||
optional: true
|
||||
`
|
||||
|
||||
// Test_GetWorkflowTemplateDB_Empty attempts to get a WorkflowTemplate when there isn't one.
|
||||
// testClientGetWorkflowTemplateDBEmpty attempts to get a WorkflowTemplate when there isn't one.
|
||||
// this should fail.
|
||||
func Test_GetWorkflowTemplateDB_Empty(t *testing.T) {
|
||||
func testClientGetWorkflowTemplateDBEmpty(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
_, err := c.GetWorkflowTemplateDB("test", "test")
|
||||
_, err := c.getWorkflowTemplateDB("test", "test")
|
||||
assert.Equal(t, sql.ErrNoRows, err)
|
||||
}
|
||||
|
||||
// Test_GetWorkflowTemplateDB_Exists gets a WorkflowTemplate when there is one
|
||||
// testClientGetWorkflowTemplateDBExists gets a WorkflowTemplate when there is one
|
||||
// this should succeed
|
||||
func Test_GetWorkflowTemplateDB_Exists(t *testing.T) {
|
||||
func testClientGetWorkflowTemplateDBExists(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
@@ -108,34 +109,18 @@ func Test_GetWorkflowTemplateDB_Exists(t *testing.T) {
|
||||
_, err := c.CreateWorkflowTemplate("onepanel", workflowTemplate)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = c.GetWorkflowTemplateDB("onepanel", "test")
|
||||
_, err = c.getWorkflowTemplateDB("onepanel", "test")
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// Test_GetWorkflowTemplateDB_InsertSameName attempts to insert a WorkflowTemplate with the same name
|
||||
// this should fail
|
||||
func Test_GetWorkflowTemplateDB_InsertSameName(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_getWorkflowTemplateDB tests getting a workflow template from the database
|
||||
func TestClient_getWorkflowTemplateDB(t *testing.T) {
|
||||
testClientGetWorkflowTemplateDBEmpty(t)
|
||||
testClientGetWorkflowTemplateDBExists(t)
|
||||
}
|
||||
|
||||
// TestClient_CreateWorkflowTemplate_Success makes sure a correct workflow template is created correctly
|
||||
func TestClient_CreateWorkflowTemplate_Success(t *testing.T) {
|
||||
// testClientCreateWorkflowTemplateSuccess makes sure a correct workflow template is created correctly
|
||||
func testClientCreateWorkflowTemplateSuccess(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
@@ -149,11 +134,11 @@ func TestClient_CreateWorkflowTemplate_Success(t *testing.T) {
|
||||
assert.NotNil(t, wft.ArgoWorkflowTemplate)
|
||||
}
|
||||
|
||||
// TestClient_CreateWorkflowTemplate_Timestamp makes sure we can create mulitple
|
||||
// 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 TestClient_CreateWorkflowTemplate_Timestamp(t *testing.T) {
|
||||
func testClientCreateWorkflowTemplateTimestamp(t *testing.T) {
|
||||
c := DefaultTestClient()
|
||||
clearDatabase(t)
|
||||
|
||||
@@ -174,3 +159,187 @@ func TestClient_CreateWorkflowTemplate_Timestamp(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
|
@@ -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,8 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -73,10 +65,10 @@ func mergeWorkspaceParameters(existingParameters, newParameters []Parameter) (pa
|
||||
// sys-workspace-action
|
||||
// sys-resource-action
|
||||
// sys-host
|
||||
// TODO why does this generate the UID?
|
||||
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
|
||||
if err := workspace.GenerateUID(workspace.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
host := fmt.Sprintf("%v--%v.%v", workspace.UID, namespace, *config.Domain())
|
||||
systemParameters := []Parameter{
|
||||
@@ -98,6 +90,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 +151,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
|
||||
@@ -182,7 +182,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")
|
||||
}
|
||||
|
@@ -719,15 +719,14 @@ metadata:
|
||||
}
|
||||
|
||||
func (c *Client) createWorkspaceTemplate(namespace string, workspaceTemplate *WorkspaceTemplate) (*WorkspaceTemplate, error) {
|
||||
uid, err := uid2.GenerateUID(workspaceTemplate.Name, 30)
|
||||
err := workspaceTemplate.GenerateUID(workspaceTemplate.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workspaceTemplate.UID = uid
|
||||
|
||||
workspaceTemplate.WorkflowTemplate.IsSystem = true
|
||||
workspaceTemplate.WorkflowTemplate.Resource = ptr.String(TypeWorkspaceTemplate)
|
||||
workspaceTemplate.WorkflowTemplate.ResourceUID = ptr.String(uid)
|
||||
workspaceTemplate.WorkflowTemplate.ResourceUID = &workspaceTemplate.UID
|
||||
|
||||
// validate workflow template
|
||||
if err := c.validateWorkflowTemplate(namespace, workspaceTemplate.WorkflowTemplate); err != nil {
|
||||
@@ -754,7 +753,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,
|
||||
|
@@ -52,6 +52,75 @@ 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) {
|
||||
@@ -65,3 +134,44 @@ 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)
|
||||
}
|
||||
|
||||
func TestClient_CreateWorkspaceTemplate(t *testing.T) {
|
||||
testClientCreateWorkspaceTemplateNew(t)
|
||||
testClientCreateWorkspaceTemplateDuplicateName(t)
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package v1
|
||||
import (
|
||||
"fmt"
|
||||
wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"github.com/onepanelio/core/util/sql"
|
||||
"sigs.k8s.io/yaml"
|
||||
"time"
|
||||
@@ -25,6 +26,18 @@ type WorkspaceTemplate struct {
|
||||
WorkflowTemplateID uint64 `db:"workflow_template_id"`
|
||||
}
|
||||
|
||||
// GenerateUID generates a uid from the input name and sets it on the workflow template
|
||||
func (wt *WorkspaceTemplate) GenerateUID(name string) error {
|
||||
result, err := uid2.GenerateUID(name, 30)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wt.UID = result
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InjectRuntimeParameters will inject all runtime variables into the WorkflowTemplate's manifest.
|
||||
func (wt *WorkspaceTemplate) InjectRuntimeParameters(config SystemConfig) error {
|
||||
if wt.WorkflowTemplate == nil {
|
||||
|
@@ -1 +1,74 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/onepanelio/core/pkg/util"
|
||||
"github.com/onepanelio/core/pkg/util/ptr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc/codes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 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 TestClient_CreateWorkspace(t *testing.T) {
|
||||
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package v1
|
||||
import (
|
||||
"fmt"
|
||||
wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1"
|
||||
uid2 "github.com/onepanelio/core/pkg/util/uid"
|
||||
"github.com/onepanelio/core/util/sql"
|
||||
networking "istio.io/api/networking/v1alpha3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -63,6 +64,29 @@ func (w *Workspace) GetURL(protocol, domain string) string {
|
||||
return fmt.Sprintf("%v%v--%v.%v", protocol, w.UID, w.Namespace, domain)
|
||||
}
|
||||
|
||||
// GetParameterValue returns the value of the parameter with the given name, or nil if there is no such parameter
|
||||
func (w *Workspace) GetParameterValue(name string) *string {
|
||||
for _, p := range w.Parameters {
|
||||
if p.Name == name {
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateUID generates a uid from the input name and sets it on the workspace
|
||||
func (w *Workspace) GenerateUID(name string) error {
|
||||
result, err := uid2.GenerateUID(name, 30)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.UID = result
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getWorkspaceColumns returns all of the columns for workspace modified by alias, destination.
|
||||
// see formatColumnSelect
|
||||
func getWorkspaceColumns(aliasAndDestination ...string) []string {
|
||||
|
Reference in New Issue
Block a user