github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-cluster/pkg/workflow/argo.go (about) 1 // Copyright 2024 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package workflow 5 6 import ( 7 "bytes" 8 "context" 9 "embed" 10 "fmt" 11 "sort" 12 "time" 13 14 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" 15 wfclientset "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned" 16 wftypes "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned/typed/workflow/v1alpha1" 17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 restclient "k8s.io/client-go/rest" 19 "sigs.k8s.io/yaml" 20 ) 21 22 //go:embed *.yaml 23 var workflowsFS embed.FS 24 25 type ArgoService struct { 26 wfClient wftypes.WorkflowInterface 27 template *v1alpha1.Workflow 28 } 29 30 func NewArgoService() (*ArgoService, error) { 31 kubeConfig, err := restclient.InClusterConfig() 32 if err != nil { 33 return nil, err 34 } 35 namespace := "default" 36 wfClient := wfclientset.NewForConfigOrDie(kubeConfig).ArgoprojV1alpha1().Workflows(namespace) 37 templateData, err := workflowsFS.ReadFile("template.yaml") 38 if err != nil { 39 return nil, err 40 } 41 var wf v1alpha1.Workflow 42 err = yaml.Unmarshal(templateData, &wf) 43 if err != nil { 44 return nil, err 45 } 46 return &ArgoService{ 47 wfClient: wfClient, 48 template: &wf, 49 }, nil 50 } 51 52 // TODO: substitute the proper (non-dev) Docker image names. 53 func (w *ArgoService) Start(sessionID string) error { 54 workflow := w.template.DeepCopy() 55 workflow.ObjectMeta.Labels = map[string]string{ 56 "workflow-id": sessionID, 57 } 58 for i, param := range workflow.Spec.Arguments.Parameters { 59 if param.Name == "session-id" { 60 workflow.Spec.Arguments.Parameters[i].Value = v1alpha1.AnyStringPtr(sessionID) 61 } 62 } 63 _, err := w.wfClient.Create(context.Background(), workflow, metav1.CreateOptions{}) 64 return err 65 } 66 67 func (w *ArgoService) Status(sessionID string) (Status, []byte, error) { 68 listOptions := metav1.ListOptions{ 69 LabelSelector: fmt.Sprintf("workflow-id=%s", sessionID), 70 } 71 workflows, err := w.wfClient.List(context.Background(), listOptions) 72 if err != nil || len(workflows.Items) == 0 { 73 return StatusNotFound, nil, err 74 } 75 wf := workflows.Items[0] 76 log := w.generateLog(wf.Status.Nodes) 77 switch wf.Status.Phase { 78 case v1alpha1.WorkflowRunning, v1alpha1.WorkflowPending: 79 return StatusRunning, log, nil 80 case v1alpha1.WorkflowSucceeded: 81 return StatusFinished, log, nil 82 } 83 return StatusFailed, log, nil 84 } 85 86 func (w *ArgoService) generateLog(nodes v1alpha1.Nodes) []byte { 87 var list []v1alpha1.NodeStatus 88 for _, node := range nodes { 89 list = append(list, node) 90 } 91 sort.Slice(list, func(i, j int) bool { 92 a, b := list[i], list[j] 93 if !a.StartedAt.Equal(&b.StartedAt) { 94 return a.StartedAt.Before(&b.StartedAt) 95 } 96 return a.Name < b.Name 97 }) 98 var buf bytes.Buffer 99 for i, val := range list { 100 if i > 0 { 101 buf.WriteString("---------\n") 102 } 103 fmt.Fprintf(&buf, "Name: %s\n", val.Name) 104 fmt.Fprintf(&buf, "Phase: %s\n", val.Phase) 105 fmt.Fprintf(&buf, "StartedAt: %s\n", val.StartedAt) 106 fmt.Fprintf(&buf, "FinishedAt: %s\n", val.FinishedAt) 107 fmt.Fprintf(&buf, "Input: %s\n", val.Inputs) 108 fmt.Fprintf(&buf, "Output: %s\n", val.Outputs) 109 } 110 return buf.Bytes() 111 } 112 113 func (w *ArgoService) PollPeriod() time.Duration { 114 return 30 * time.Second 115 }