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  }