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

     1  package porter
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"time"
     7  
     8  	"get.porter.sh/porter/pkg/cnab"
     9  	"get.porter.sh/porter/pkg/tracing"
    10  	"github.com/Masterminds/semver/v3"
    11  )
    12  
    13  var _ BundleAction = NewUpgradeOptions()
    14  
    15  // UpgradeOptions that may be specified when upgrading a bundle.
    16  // Porter handles defaulting any missing values.
    17  type UpgradeOptions struct {
    18  	*BundleExecutionOptions
    19  
    20  	// Version of the bundle to upgrade to
    21  	Version string
    22  
    23  	// ForceUpgrade allows the upgrade to run even if the current installation is marked as failed.
    24  	ForceUpgrade bool
    25  }
    26  
    27  func NewUpgradeOptions() *UpgradeOptions {
    28  	return &UpgradeOptions{
    29  		BundleExecutionOptions: NewBundleExecutionOptions(),
    30  	}
    31  }
    32  
    33  func (o *UpgradeOptions) Validate(ctx context.Context, args []string, p *Porter) error {
    34  	if o.Version != "" && o.Reference != "" {
    35  		return errors.New("either --version or --reference may be set, but not both")
    36  	}
    37  
    38  	if o.Version != "" {
    39  		v, err := semver.NewVersion(o.Version)
    40  		if err != nil {
    41  			return errors.New("invalid bundle version --version. Must be a semantic version, for example 1.2.3")
    42  		}
    43  
    44  		o.Version = v.String()
    45  	}
    46  
    47  	return o.BundleExecutionOptions.Validate(ctx, args, p)
    48  }
    49  
    50  func (o *UpgradeOptions) GetAction() string {
    51  	return cnab.ActionUpgrade
    52  }
    53  
    54  func (o *UpgradeOptions) GetActionVerb() string {
    55  	return "upgrading"
    56  }
    57  
    58  // UpgradeBundle accepts a set of pre-validated UpgradeOptions and uses
    59  // them to upgrade a bundle.
    60  func (p *Porter) UpgradeBundle(ctx context.Context, opts *UpgradeOptions) error {
    61  	ctx, span := tracing.StartSpan(ctx)
    62  	defer span.EndSpan()
    63  
    64  	// Sync any changes specified by the user to the installation before running upgrade
    65  	i, err := p.Installations.GetInstallation(ctx, opts.Namespace, opts.Name)
    66  	if err != nil {
    67  		return span.Errorf("could not find installation %s/%s: %w", opts.Namespace, opts.Name, err)
    68  	}
    69  
    70  	if !i.IsInstalled() && !opts.ForceUpgrade {
    71  		return span.Errorf("The installation cannot be upgraded, because it is not installed. Verify the installation name and namespace, and if correct, use porter install.")
    72  	}
    73  
    74  	if opts.Reference != "" {
    75  		i.TrackBundle(opts.GetReference())
    76  	} else if opts.Version != "" {
    77  		i.Bundle.Version = opts.Version
    78  		i.Bundle.Digest = ""
    79  		i.Bundle.Tag = ""
    80  	}
    81  
    82  	err = p.applyActionOptionsToInstallation(ctx, opts, &i)
    83  	if err != nil {
    84  		return span.Errorf("could not apply options to installation: %w", err)
    85  	}
    86  	i.Status.Modified = time.Now()
    87  
    88  	checkStrategy := p.GetSchemaCheckStrategy(ctx)
    89  	err = i.Validate(ctx, checkStrategy)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	err = p.Installations.UpdateInstallation(ctx, i)
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	// Re-resolve the bundle after we have figured out the version we are upgrading to
   100  	opts.UnsetBundleReference()
   101  	if _, err := opts.GetBundleReference(ctx, p); err != nil {
   102  		return err
   103  	}
   104  
   105  	return p.ExecuteAction(ctx, i, opts)
   106  }