manager

package
v0.0.0-...-56cb166 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 19, 2025 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package manager defines an interface which can carry out numerous package-management related operations on the local system and the respective implementations on apt and yum-based systems.

Index

Constants

This section is empty.

Variables

View Source
var (
	// SnapExitCodes is used to indicate a retryable failure for Snap.
	// See list of failures.
	//
	// Test the following exit codes. 1 and 2 are failures and depending on the
	// error message can be retried. There is a exit code of 10, which can be
	// blindly retried, but that's not implemented yet.
	SnapExitCodes = []int{1, 2}

	// SnapAttempts describe the number of attempts to retry each command.
	SnapAttempts = 3

	// SnapDelay is the time to wait between retries.
	SnapDelay = 10 * time.Second
)
View Source
var CommandOutput = (*exec.Cmd).CombinedOutput

CommandOutput is cmd.Output. It was aliased for testing purposes.

View Source
var ProcessStateSys = (*os.ProcessState).Sys

ProcessStateSys is ps.Sys. It was aliased for testing purposes.

View Source
var RunCommandWithRetry = func(cmd string, retryable Retryable, policy RetryPolicy) (output string, code int, _ error) {

	args := strings.Fields(cmd)
	if len(args) <= 1 {
		return "", -1, errors.New(fmt.Sprintf("too few arguments: expected at least 2, got %d", len(args)))
	}

	logger.Infof(context.TODO(), "Running: %s", cmd)

	// Retry operation, sleeping between attempts. This avoids failure in the
	// case of something else having the, for example, dpkg lock.
	var (
		out      []byte
		fatalErr error
	)
	retryErr := retry.Call(retry.CallArgs{
		Clock:    clock.WallClock,
		Delay:    policy.Delay,
		Attempts: policy.Attempts,
		NotifyFunc: func(lastError error, attempt int) {
			logger.Infof(context.TODO(), "Retrying: %s", cmd)
		},
		Func: func() error {

			command := exec.Command(args[0], args[1:]...)

			var err error
			out, err = CommandOutput(command)
			return errors.Trace(err)
		},
		IsFatalError: func(err error) bool {
			exitError, ok := errors.Cause(err).(*exec.ExitError)
			if !ok {
				logger.Errorf(context.TODO(), "unexpected error type %T", err)
				return true
			}
			waitStatus, ok := ProcessStateSys(exitError.ProcessState).(exitStatuser)
			if !ok {
				logger.Errorf(context.TODO(), "unexpected process state type %T", exitError.ProcessState.Sys())
				return true
			}

			code = waitStatus.ExitStatus()
			fatal := !retryable.IsRetryable(code, string(out))
			if fatal {

				if trans, ok := retryable.(ErrorTransformer); ok {
					maskedErr := trans.MaskError(code, string(out))
					fatalErr = errors.Annotatef(maskedErr, "encountered fatal error")
				}
			}

			return fatal
		},
	})
	if fatalErr != nil {
		retryErr = fatalErr
	}

	if retryErr != nil {
		logger.Errorf(context.TODO(), "packaging command failed: %v; cmd: %q; output: %s",
			retryErr, cmd, string(out))
		return string(out), code, errors.Errorf("packaging command failed: %v", retryErr)
	}

	return string(out), 0, nil
}

RunCommandWithRetry is a helper function which tries to execute the given command. It tries to do so for 30 times with a 10 second sleep between commands. It returns the output of the command, the exit code, and an error, if one occurs, logging along the way. It was aliased for testing purposes.

Functions

This section is empty.

Types

type ErrorTransformer

type ErrorTransformer interface {

	// MaskError masks a potential error from the fatal error if not retryable.
	MaskError(int, string) error
}

ErrorTransformer masks a potential error from one to another.

type RetryPolicy

type RetryPolicy struct {
	Delay    time.Duration
	Attempts int
}

RetryPolicy defines a policy for describing how retries should be executed.

type Retryable

type Retryable interface {
	// IsRetryable defines a method for working out if a retry is actually
	// retryable.
	IsRetryable(int, string) bool
}

Retryable allows the caller to define if a retry is retryable based on the incoming error, command exit code or the stderr message.

type Snap

type Snap struct {
	// contains filtered or unexported fields
}

Snap is the PackageManager implementation for snap-based systems.

func NewSnapPackageManager

func NewSnapPackageManager() *Snap

NewSnapPackageManager returns a PackageManager for snap-based systems.

func (*Snap) ChangeChannel

func (snap *Snap) ChangeChannel(pack, channel string) error

ChangeChannel updates the tracked channel for an installed snap.

func (*Snap) Install

func (snap *Snap) Install(packs ...string) error

Install is defined on the PackageManager interface.

func (*Snap) InstalledChannel

func (snap *Snap) InstalledChannel(pack string) string

InstalledChannel returns the snap channel for an installed package.

func (*Snap) IsRetryable

func (snap *Snap) IsRetryable(code int, output string) bool

IsRetryable returns whether the following error code and/or message is retryable.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL