Skip to content

Commit

Permalink
fix: CRD synchronisation in the devbox (#6008)
Browse files Browse the repository at this point in the history
* fix: CRD synchronisation in the devbox
* fix: avoid rebuilding applications in devbox for consecutive changes (100ms bucket)
  • Loading branch information
rangoo94 authored Nov 6, 2024
1 parent 797e762 commit c2a75ac
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 8 deletions.
8 changes: 7 additions & 1 deletion cmd/tcl/kubectl-testkube/devbox/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func NewDevBoxCommand() *cobra.Command {
pterm.Error.Printfln("Failed to load config file: %s", err.Error())
return
}
cfg.CloudContext.AgentUri = "https://agent-dev.testkube.dev"
cloud, err := devutils.NewCloud(cfg.CloudContext, cmd)
if err != nil {
pterm.Error.Printfln("Failed to connect to Cloud: %s", err.Error())
Expand Down Expand Up @@ -358,7 +359,7 @@ func NewDevBoxCommand() *cobra.Command {
if !termlink.SupportsHyperlinks() {
return name
}
return termlink.Link(name, cloud.DashboardUrl(env.Slug, fmt.Sprintf("dashboard/test-workflow-templates/%s", name)))
return name + " " + termlink.ColorLink("(open)", cloud.DashboardUrl(env.Slug, fmt.Sprintf("dashboard/test-workflow-templates/%s", name)), "magenta")
}

// Propagate changes from CRDSync to Cloud
Expand Down Expand Up @@ -450,6 +451,11 @@ func NewDevBoxCommand() *cobra.Command {
fmt.Println("Waiting for file changes...")

rebuild := func(ctx context.Context) {
select {
case <-ctx.Done():
return
case <-time.After(100 * time.Millisecond):
}
g, _ := errgroup.WithContext(ctx)
ts := time.Now()
fmt.Println(color.Yellow.Render("Rebuilding applications..."))
Expand Down
84 changes: 77 additions & 7 deletions cmd/tcl/kubectl-testkube/devbox/devutils/crdsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ package devutils
import (
"bytes"
"context"
"encoding/json"
"io"
"io/fs"
"os"
Expand Down Expand Up @@ -106,8 +105,18 @@ func (c *CRDSync) Next(ctx context.Context) (*CRDSyncUpdate, error) {
func (c *CRDSync) processWorkflow(sourcePath string, workflow testworkflowsv1.TestWorkflow) error {
for i := range c.workflows {
if c.workflows[i].Workflow.Name == workflow.Name {
v1, _ := json.Marshal(c.workflows[i].Workflow)
v2, _ := json.Marshal(workflow)
v1, _ := common.SerializeCRD(c.workflows[i].Workflow, common.SerializeOptions{
OmitCreationTimestamp: true,
CleanMeta: true,
Kind: "TestWorkflow",
GroupVersion: &testworkflowsv1.GroupVersion,
})
v2, _ := common.SerializeCRD(workflow, common.SerializeOptions{
OmitCreationTimestamp: true,
CleanMeta: true,
Kind: "TestWorkflow",
GroupVersion: &testworkflowsv1.GroupVersion,
})
c.workflows[i].SourcePath = sourcePath
if !bytes.Equal(v1, v2) {
c.workflows[i].Workflow = workflow
Expand All @@ -124,10 +133,20 @@ func (c *CRDSync) processWorkflow(sourcePath string, workflow testworkflowsv1.Te
func (c *CRDSync) processTemplate(sourcePath string, template testworkflowsv1.TestWorkflowTemplate) error {
for i := range c.templates {
if c.templates[i].Template.Name == template.Name {
v1, _ := json.Marshal(c.templates[i].Template)
v2, _ := json.Marshal(template)
v1, _ := common.SerializeCRD(c.templates[i].Template, common.SerializeOptions{
OmitCreationTimestamp: true,
CleanMeta: true,
Kind: "TestWorkflowTemplate",
GroupVersion: &testworkflowsv1.GroupVersion,
})
v2, _ := common.SerializeCRD(template, common.SerializeOptions{
OmitCreationTimestamp: true,
CleanMeta: true,
Kind: "TestWorkflowTemplate",
GroupVersion: &testworkflowsv1.GroupVersion,
})
c.templates[i].SourcePath = sourcePath
if !bytes.Equal(v1, v2) {
c.templates[i].SourcePath = sourcePath
c.templates[i].Template = template
c.updates = append(c.updates, CRDSyncUpdate{Template: &template, Op: CRDSyncUpdateOpUpdate})
return nil
Expand All @@ -139,6 +158,34 @@ func (c *CRDSync) processTemplate(sourcePath string, template testworkflowsv1.Te
return nil
}

func (c *CRDSync) deleteTemplate(name string) {
for i := 0; i < len(c.templates); i++ {
if c.templates[i].Template.Name == name {
c.updates = append(c.updates, CRDSyncUpdate{
Template: &testworkflowsv1.TestWorkflowTemplate{ObjectMeta: metav1.ObjectMeta{Name: c.templates[i].Template.Name}},
Op: CRDSyncUpdateOpDelete,
})
c.templates = append(c.templates[:i], c.templates[i+1:]...)
i--
return
}
}
}

func (c *CRDSync) deleteWorkflow(name string) {
for i := 0; i < len(c.workflows); i++ {
if c.workflows[i].Workflow.Name == name {
c.updates = append(c.updates, CRDSyncUpdate{
Workflow: &testworkflowsv1.TestWorkflow{ObjectMeta: metav1.ObjectMeta{Name: c.workflows[i].Workflow.Name}},
Op: CRDSyncUpdateOpDelete,
})
c.workflows = append(c.workflows[:i], c.workflows[i+1:]...)
i--
return
}
}
}

func (c *CRDSync) deleteFile(path string) error {
for i := 0; i < len(c.templates); i++ {
if c.templates[i].SourcePath == path {
Expand All @@ -153,7 +200,7 @@ func (c *CRDSync) deleteFile(path string) error {
for i := 0; i < len(c.workflows); i++ {
if c.workflows[i].SourcePath == path {
c.updates = append(c.updates, CRDSyncUpdate{
Template: &testworkflowsv1.TestWorkflowTemplate{ObjectMeta: metav1.ObjectMeta{Name: c.templates[i].Template.Name}},
Workflow: &testworkflowsv1.TestWorkflow{ObjectMeta: metav1.ObjectMeta{Name: c.workflows[i].Workflow.Name}},
Op: CRDSyncUpdateOpDelete,
})
c.workflows = append(c.workflows[:i], c.workflows[i+1:]...)
Expand All @@ -178,6 +225,19 @@ func (c *CRDSync) loadFile(path string) error {
return nil
}

prevTemplates := map[string]struct{}{}
for i := range c.templates {
if c.templates[i].SourcePath == path {
prevTemplates[c.templates[i].Template.Name] = struct{}{}
}
}
prevWorkflows := map[string]struct{}{}
for i := range c.workflows {
if c.workflows[i].SourcePath == path {
prevWorkflows[c.workflows[i].Workflow.Name] = struct{}{}
}
}

// TODO: Handle deleted entries
decoder := yaml.NewDecoder(file)
for {
Expand All @@ -204,6 +264,7 @@ func (c *CRDSync) loadFile(path string) error {
if err != nil {
continue
}
delete(prevWorkflows, tw.Name)
c.processWorkflow(path, tw)
} else if obj["kind"].(string) == "TestWorkflowTemplate" {
bytes, _ := yaml.Marshal(obj)
Expand All @@ -215,10 +276,19 @@ func (c *CRDSync) loadFile(path string) error {
if err != nil {
continue
}
delete(prevTemplates, tw.Name)
c.processTemplate(path, tw)
}
}
file.Close()

for t := range prevTemplates {
c.deleteTemplate(t)
}
for t := range prevWorkflows {
c.deleteWorkflow(t)
}

return nil
}

Expand Down

0 comments on commit c2a75ac

Please sign in to comment.