get.porter.sh/porter@v1.3.0/pkg/plugins/runner.go (about)

     1  package plugins
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"get.porter.sh/porter/pkg/config"
    10  	"get.porter.sh/porter/pkg/portercontext"
    11  	"get.porter.sh/porter/pkg/tracing"
    12  	"go.opentelemetry.io/otel/attribute"
    13  )
    14  
    15  type CommandOptions struct {
    16  	Command string
    17  }
    18  
    19  type PluginRunner struct {
    20  	*portercontext.Context
    21  	pluginName string
    22  }
    23  
    24  func NewRunner(pluginName string) *PluginRunner {
    25  	return &PluginRunner{
    26  		Context:    portercontext.New(),
    27  		pluginName: pluginName,
    28  	}
    29  }
    30  
    31  func (r *PluginRunner) Validate() error {
    32  	if r.pluginName == "" {
    33  		return errors.New("Plugin not specified")
    34  	}
    35  
    36  	pluginPath, err := config.New().GetPluginPath(r.pluginName)
    37  	if err != nil {
    38  		return fmt.Errorf("Failed to get plugin path for %s: %w", r.pluginName, err)
    39  	}
    40  
    41  	exists, err := r.FileSystem.Exists(pluginPath)
    42  	if err != nil {
    43  		return fmt.Errorf("Failed to stat path %s: %w", pluginPath, err)
    44  	}
    45  	if !exists {
    46  		return fmt.Errorf("Plugin %s doesn't exist in filesystem with path %s", r.pluginName, pluginPath)
    47  	}
    48  
    49  	return nil
    50  }
    51  
    52  func (r *PluginRunner) Run(ctx context.Context, commandOpts CommandOptions) error {
    53  	ctx, span := tracing.StartSpan(ctx,
    54  		attribute.String("name", r.pluginName),
    55  		attribute.String("partial-command", commandOpts.Command),
    56  	)
    57  	defer span.EndSpan()
    58  
    59  	pluginPath, err := config.New().GetPluginPath(r.pluginName)
    60  	if err != nil {
    61  		return span.Error(fmt.Errorf("Failed to get plugin path for %s: %w", r.pluginName, err))
    62  	}
    63  	span.SetAttributes(attribute.String("plugin-path", pluginPath))
    64  
    65  	cmdArgs := strings.Split(commandOpts.Command, " ")
    66  	cmd := r.NewCommand(ctx, pluginPath, cmdArgs...)
    67  
    68  	// Pipe the output from the plugin to porter
    69  	cmd.Stdout = r.Out
    70  	cmd.Stderr = r.Err
    71  
    72  	prettyCmd := fmt.Sprintf("%s%s", cmd.Dir, strings.Join(cmd.Args, " "))
    73  	span.SetAttributes(attribute.String("full-command", prettyCmd))
    74  
    75  	err = cmd.Start()
    76  	if err != nil {
    77  		return span.Error(fmt.Errorf("could not run plugin command %s: %w", prettyCmd, err))
    78  	}
    79  
    80  	return span.Error(cmd.Wait())
    81  }