diff --git a/api/api.swagger.json b/api/api.swagger.json index 83c3bf1..1bd95dc 100644 --- a/api/api.swagger.json +++ b/api/api.swagger.json @@ -2690,6 +2690,10 @@ "manifest": { "type": "string" }, + "isLatest": { + "type": "boolean", + "format": "boolean" + }, "createdAt": { "type": "string" }, diff --git a/api/workspace_template.pb.go b/api/workspace_template.pb.go index 4e6dcaf..d66553d 100644 --- a/api/workspace_template.pb.go +++ b/api/workspace_template.pb.go @@ -95,8 +95,9 @@ type WorkspaceTemplate struct { Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` Manifest string `protobuf:"bytes,4,opt,name=manifest,proto3" json:"manifest,omitempty"` - CreatedAt string `protobuf:"bytes,5,opt,name=createdAt,proto3" json:"createdAt,omitempty"` - WorkflowTemplate *WorkflowTemplate `protobuf:"bytes,6,opt,name=workflowTemplate,proto3" json:"workflowTemplate,omitempty"` + IsLatest bool `protobuf:"varint,5,opt,name=isLatest,proto3" json:"isLatest,omitempty"` + CreatedAt string `protobuf:"bytes,6,opt,name=createdAt,proto3" json:"createdAt,omitempty"` + WorkflowTemplate *WorkflowTemplate `protobuf:"bytes,7,opt,name=workflowTemplate,proto3" json:"workflowTemplate,omitempty"` } func (x *WorkspaceTemplate) Reset() { @@ -159,6 +160,13 @@ func (x *WorkspaceTemplate) GetManifest() string { return "" } +func (x *WorkspaceTemplate) GetIsLatest() bool { + if x != nil { + return x.IsLatest + } + return false +} + func (x *WorkspaceTemplate) GetCreatedAt() string { if x != nil { return x.CreatedAt @@ -192,33 +200,34 @@ var file_workspace_template_proto_rawDesc = []byte{ 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x11, 0x57, 0x6f, 0x72, 0x6b, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0xec, 0x01, 0x0a, 0x11, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 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, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x41, 0x0a, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x66, - 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x32, 0xbd, 0x01, 0x0a, 0x18, 0x57, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x57, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x22, 0x48, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x22, 0x2d, 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, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x3a, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x4c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x4c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x41, 0x0a, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x32, 0xbd, 0x01, 0x0a, 0x18, 0x57, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, + 0x23, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x48, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x42, 0x22, 0x2d, 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, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x73, 0x3a, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/workspace_template.proto b/api/workspace_template.proto index 94bc272..3e464ce 100644 --- a/api/workspace_template.proto +++ b/api/workspace_template.proto @@ -27,7 +27,8 @@ message WorkspaceTemplate { string name = 2; int64 version = 3; string manifest = 4; - string createdAt = 5; - WorkflowTemplate workflowTemplate = 6; + bool isLatest = 5; + string createdAt = 6; + WorkflowTemplate workflowTemplate = 7; } diff --git a/db/20200425172611_workspace_templates.sql b/db/20200425172611_workspace_templates.sql index 9ac4823..4535f3b 100644 --- a/db/20200425172611_workspace_templates.sql +++ b/db/20200425172611_workspace_templates.sql @@ -5,7 +5,6 @@ CREATE TABLE workspace_templates uid varchar(36) UNIQUE NOT NULL CHECK(uid <> ''), name text NOT NULL CHECK(name <> ''), namespace varchar(36) NOT NULL, - is_archived boolean DEFAULT false, workflow_template_id integer NOT NULL REFERENCES workflow_templates ON DELETE CASCADE, diff --git a/pkg/types.go b/pkg/types.go index c7e3c95..2467118 100644 --- a/pkg/types.go +++ b/pkg/types.go @@ -425,6 +425,7 @@ type WorkspaceTemplate struct { Name string Version int64 Manifest string + IsLatest bool CreatedAt time.Time `db:"created_at"` WorkflowTemplate *WorkflowTemplate } diff --git a/pkg/workspace_template.go b/pkg/workspace_template.go index 84559f7..e931799 100644 --- a/pkg/workspace_template.go +++ b/pkg/workspace_template.go @@ -1,11 +1,14 @@ package v1 import ( + "database/sql" "fmt" sq "github.com/Masterminds/squirrel" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" v1 "github.com/onepanelio/core/pkg/apis/core/v1" + "github.com/onepanelio/core/pkg/util" "github.com/onepanelio/core/pkg/util/ptr" + "google.golang.org/grpc/codes" networking "istio.io/api/networking/v1alpha3" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -340,6 +343,7 @@ func (c *Client) createWorkspaceTemplate(namespace string, workspaceTemplate *Wo } workspaceTemplate.Version = workspaceTemplate.WorkflowTemplate.Version + workspaceTemplate.IsLatest = true err = sb.Insert("workspace_templates"). SetMap(sq.Eq{ @@ -348,38 +352,75 @@ func (c *Client) createWorkspaceTemplate(namespace string, workspaceTemplate *Wo "namespace": namespace, "workflow_template_id": workspaceTemplate.WorkflowTemplate.ID, }). - Suffix("RETURNING id"). + Suffix("RETURNING id, created_at"). RunWith(tx). - QueryRow().Scan(&workspaceTemplate.ID) + QueryRow().Scan(&workspaceTemplate.ID, &workspaceTemplate.CreatedAt) if err != nil { - _, err := c.archiveWorkflowTemplate(namespace, workspaceTemplate.WorkflowTemplate.UID) + _, err := c.ArchiveWorkflowTemplate(namespace, workspaceTemplate.WorkflowTemplate.UID) return nil, err } _, err = sb.Insert("workspace_template_versions"). SetMap(sq.Eq{ "version": workspaceTemplate.Version, - "is_latest": true, + "is_latest": workspaceTemplate.IsLatest, "manifest": workspaceTemplate.Manifest, "workspace_template_id": workspaceTemplate.ID, }). RunWith(tx). Exec() if err != nil { - _, err := c.archiveWorkflowTemplate(namespace, workspaceTemplate.WorkflowTemplate.UID) + _, err := c.ArchiveWorkflowTemplate(namespace, workspaceTemplate.WorkflowTemplate.UID) return nil, err } if err = tx.Commit(); err != nil { - _, err := c.archiveWorkflowTemplate(namespace, workspaceTemplate.WorkflowTemplate.UID) + _, err := c.ArchiveWorkflowTemplate(namespace, workspaceTemplate.WorkflowTemplate.UID) return nil, err } return workspaceTemplate, nil } +func (c *Client) workspaceTemplatesSelectBuilder(namespace string) sq.SelectBuilder { + sb := sb.Select("wt.id", "wt.created_at", "wt.uid", "wt.name"). + From("workspace_templates wt"). + Where(sq.Eq{ + "wt.namespace": namespace, + }) + + return sb +} + +func (c *Client) getWorkspaceTemplateByName(namespace, name string) (workspaceTemplate *WorkspaceTemplate, err error) { + workspaceTemplate = &WorkspaceTemplate{} + + sb := c.workspaceTemplatesSelectBuilder(namespace). + Where(sq.Eq{"wt.name": name}). + Limit(1) + query, args, err := sb.ToSql() + if err != nil { + return + } + + if err = c.DB.Get(workspaceTemplate, query, args...); err == sql.ErrNoRows { + err = nil + workspaceTemplate = nil + } + + return +} + // CreateWorkspaceTemplate creates a template for Workspaces func (c *Client) CreateWorkspaceTemplate(namespace string, workspaceTemplate *WorkspaceTemplate) (*WorkspaceTemplate, error) { + existingWorkspaceTemplate, err := c.getWorkspaceTemplateByName(namespace, workspaceTemplate.Name) + if err != nil { + return nil, err + } + if existingWorkspaceTemplate != nil { + return nil, util.NewUserError(codes.AlreadyExists, "Workspace template already exists.") + } + config, err := c.GetSystemConfig() if err != nil { return nil, err diff --git a/server/workspace_template_server.go b/server/workspace_template_server.go index af2a8dd..78463a3 100644 --- a/server/workspace_template_server.go +++ b/server/workspace_template_server.go @@ -5,17 +5,19 @@ import ( "github.com/onepanelio/core/api" v1 "github.com/onepanelio/core/pkg" "github.com/onepanelio/core/server/auth" + "time" ) type WorkspaceTemplateServer struct{} func apiWorkspaceTemplate(wt *v1.WorkspaceTemplate) *api.WorkspaceTemplate { res := &api.WorkspaceTemplate{ - Uid: wt.UID, - Name: wt.Name, - Version: wt.Version, - Manifest: wt.Manifest, - //CreatedAt: wt.CreatedAt.UTC().Format(time.RFC3339), + Uid: wt.UID, + Name: wt.Name, + Version: wt.Version, + Manifest: wt.Manifest, + IsLatest: wt.IsLatest, + CreatedAt: wt.CreatedAt.UTC().Format(time.RFC3339), } if wt.WorkflowTemplate != nil {