internal/cni/install.go (82 lines of code) (raw):

package cni import ( "context" "os" "path/filepath" "github.com/pkg/errors" "go.uber.org/zap" "github.com/aws/eks-hybrid/internal/artifact" "github.com/aws/eks-hybrid/internal/tracker" ) const ( rootDir = "/opt/cni" // BinPath is the path to the cni plugins binary. BinPath = "/opt/cni/bin" // TgzPath is the path to install the cni-plugins tgz file TgzPath = "/opt/cni/plugins/cni-plugins.tgz" artifactName = "cni-plugins" ) // Source represents a source that serves a cni plugins binary. type Source interface { GetCniPlugins(context.Context) (artifact.Source, error) } type InstallOptions struct { // InstallRoot is optionally the root directory of the installation // If not provided, the default will be / InstallRoot string Logger *zap.Logger Source Source Tracker *tracker.Tracker } func Install(ctx context.Context, opts InstallOptions) error { if err := installFromSource(ctx, opts); err != nil { return err } if err := opts.Tracker.Add(artifact.CniPlugins); err != nil { return errors.Wrap(err, "adding cni-plugins to tracker") } return nil } func installFromSource(ctx context.Context, opts InstallOptions) error { if err := downloadFileWithRetries(ctx, opts); err != nil { return errors.Wrap(err, "installing cni-plugins") } if err := artifact.InstallTarGz(filepath.Join(opts.InstallRoot, BinPath), filepath.Join(opts.InstallRoot, TgzPath)); err != nil { return errors.Wrap(err, "extracting and installing cni-plugins") } return nil } func downloadFileWithRetries(ctx context.Context, opts InstallOptions) error { // Retry up to 3 times to download and validate the checksum var err error for range 3 { err = downloadFileTo(ctx, opts) if err == nil { break } opts.Logger.Error("Downloading cni-plugins failed. Retrying...", zap.Error(err)) } return err } func downloadFileTo(ctx context.Context, opts InstallOptions) error { cniPlugins, err := opts.Source.GetCniPlugins(ctx) if err != nil { return errors.Wrap(err, "getting cni-plugins source") } defer cniPlugins.Close() if err := artifact.InstallFile(filepath.Join(opts.InstallRoot, TgzPath), cniPlugins, 0o755); err != nil { return errors.Wrap(err, "installing cni-plugins archive") } if !cniPlugins.VerifyChecksum() { return errors.Errorf("cni-plugins checksum mismatch: %v", artifact.NewChecksumError(cniPlugins)) } return nil } func Uninstall() error { return os.RemoveAll(rootDir) } // Upgrade re-installs the cni-plugins available from the source // Since cni-plugins is delivered as a tarball, its not possible to check if they are due for an upgrade // todo: (@vignesh-goutham) check if we can publish cni-plugins independently with their checksum on our manifest func Upgrade(ctx context.Context, src Source, log *zap.Logger) error { opts := InstallOptions{ Source: src, Logger: log, } if err := installFromSource(ctx, opts); err != nil { return errors.Wrapf(err, "upgrading cni-plugins") } log.Info("Upgraded", zap.String("artifact", artifactName)) return nil }