github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/cmd/bacalhau/describe.go (about)

     1  package bacalhau
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"github.com/filecoin-project/bacalhau/pkg/bacerrors"
     8  	"github.com/filecoin-project/bacalhau/pkg/util/templates"
     9  	"github.com/spf13/cobra"
    10  	"k8s.io/kubectl/pkg/util/i18n"
    11  	"sigs.k8s.io/yaml"
    12  )
    13  
    14  var (
    15  	//nolint:lll // Documentation
    16  	describeLong = templates.LongDesc(i18n.T(`
    17  		Full description of a job, in yaml format. Use 'bacalhau list' to get a list of all ids. Short form and long form of the job id are accepted.
    18  `))
    19  	//nolint:lll // Documentation
    20  	describeExample = templates.Examples(i18n.T(`
    21  		# Describe a job with the full ID
    22  		bacalhau describe e3f8c209-d683-4a41-b840-f09b88d087b9
    23  
    24  		# Describe a job with the a shortened ID
    25  		bacalhau describe 47805f5c
    26  
    27  		# Describe a job and include all server and local events
    28  		bacalhau describe --include-events b6ad164a 
    29  `))
    30  )
    31  
    32  type DescribeOptions struct {
    33  	Filename      string // Filename for job (can be .json or .yaml)
    34  	IncludeEvents bool   // Include events in the description
    35  	OutputSpec    bool   // Print Just the jobspec to stdout
    36  	JSON          bool   // Print description as JSON
    37  }
    38  
    39  func NewDescribeOptions() *DescribeOptions {
    40  	return &DescribeOptions{
    41  		IncludeEvents: false,
    42  		OutputSpec:    false,
    43  		JSON:          false,
    44  	}
    45  }
    46  
    47  func newDescribeCmd() *cobra.Command {
    48  	OD := NewDescribeOptions()
    49  
    50  	describeCmd := &cobra.Command{
    51  		Use:     "describe [id]",
    52  		Short:   "Describe a job on the network",
    53  		Long:    describeLong,
    54  		Example: describeExample,
    55  		Args:    cobra.ExactArgs(1),
    56  		PreRun:  applyPorcelainLogLevel,
    57  		RunE: func(cmd *cobra.Command, cmdArgs []string) error { // nolintunparam // incorrectly suggesting unused
    58  			return describe(cmd, cmdArgs, OD)
    59  		},
    60  	}
    61  
    62  	describeCmd.PersistentFlags().BoolVar(
    63  		&OD.OutputSpec, "spec", OD.OutputSpec,
    64  		`Output Jobspec to stdout`,
    65  	)
    66  	describeCmd.PersistentFlags().BoolVar(
    67  		&OD.IncludeEvents, "include-events", OD.IncludeEvents,
    68  		`Include events in the description (could be noisy)`,
    69  	)
    70  	describeCmd.PersistentFlags().BoolVar(
    71  		&OD.JSON, "json", OD.JSON,
    72  		`Output description as JSON (if not included will be outputted as YAML by default)`,
    73  	)
    74  
    75  	return describeCmd
    76  }
    77  
    78  func describe(cmd *cobra.Command, cmdArgs []string, OD *DescribeOptions) error {
    79  	ctx := cmd.Context()
    80  
    81  	if err := cmd.ParseFlags(cmdArgs[1:]); err != nil {
    82  		Fatal(cmd, fmt.Sprintf("Failed to parse flags: %v\n", err), 1)
    83  	}
    84  
    85  	var err error
    86  	inputJobID := cmdArgs[0]
    87  	if inputJobID == "" {
    88  		var byteResult []byte
    89  		byteResult, err = ReadFromStdinIfAvailable(cmd, cmdArgs)
    90  		// If there's no input ond no stdin, then cmdArgs is nil, and byteResult is nil.
    91  		if err != nil {
    92  			Fatal(cmd, fmt.Sprintf("Unknown error reading from file: %s\n", err), 1)
    93  			return err
    94  		}
    95  		inputJobID = string(byteResult)
    96  	}
    97  	j, foundJob, err := GetAPIClient().Get(ctx, inputJobID)
    98  
    99  	if err != nil {
   100  		if er, ok := err.(*bacerrors.ErrorResponse); ok {
   101  			Fatal(cmd, er.Message, 1)
   102  			return nil
   103  		} else {
   104  			Fatal(cmd, fmt.Sprintf("Unknown error trying to get job (ID: %s): %+v", inputJobID, err), 1)
   105  			return nil
   106  		}
   107  	}
   108  
   109  	if !foundJob {
   110  		cmd.Printf(err.Error() + "\n")
   111  		Fatal(cmd, "", 1)
   112  	}
   113  
   114  	jobDesc := j
   115  
   116  	if OD.IncludeEvents {
   117  		jobEvents, innerErr := GetAPIClient().GetEvents(ctx, j.Job.Metadata.ID)
   118  		if innerErr != nil {
   119  			Fatal(cmd, fmt.Sprintf("Failure retrieving job events '%s': %s\n", j.Job.Metadata.ID, innerErr), 1)
   120  		}
   121  		jobDesc.History = jobEvents
   122  	}
   123  
   124  	//b, err := model.JSONMarshalIndentWithMax(jobDesc, 3)
   125  	b, err := json.Marshal(jobDesc)
   126  	if err != nil {
   127  		Fatal(cmd, fmt.Sprintf("Failure marshaling job description '%s': %s\n", j.Job.Metadata.ID, err), 1)
   128  	}
   129  
   130  	if !OD.JSON {
   131  		// Convert Json to Yaml
   132  		y, err := yaml.JSONToYAML(b)
   133  		if err != nil {
   134  			Fatal(cmd, fmt.Sprintf("Able to marshal to YAML but not JSON whatttt '%s': %s\n", j.Job.Metadata.ID, err), 1)
   135  		}
   136  		cmd.Print(string(y))
   137  	} else {
   138  		// Print as Json
   139  		cmd.Print(string(b))
   140  	}
   141  
   142  	return nil
   143  }