github.com/criteo/command-launcher@v0.0.0-20230407142452-fb616f546e98/internal/backend/package-source.go (about)

     1  package backend
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/criteo/command-launcher/internal/remote"
     9  	"github.com/criteo/command-launcher/internal/repository"
    10  	"github.com/criteo/command-launcher/internal/updater"
    11  	"github.com/criteo/command-launcher/internal/user"
    12  
    13  	log "github.com/sirupsen/logrus"
    14  )
    15  
    16  const (
    17  	SYNC_POLICY_NEVER   = "never"
    18  	SYNC_POLICY_ALWAYS  = "always"
    19  	SYNC_POLICY_HOURLY  = "hourly"
    20  	SYNC_POLICY_DAILY   = "daily"
    21  	SYNC_POLICY_WEEKLY  = "weekly"
    22  	SYNC_POLICY_MONTHLY = "monthly"
    23  )
    24  
    25  type PackageSource struct {
    26  	Name              string
    27  	RepoDir           string
    28  	RemoteBaseURL     string
    29  	RemoteRegistryURL string
    30  	SyncPolicy        string
    31  	IsManaged         bool
    32  
    33  	Repo    repository.PackageRepository
    34  	Failure error
    35  
    36  	Updater *updater.CmdUpdater
    37  }
    38  
    39  func NewDropinSource(repoDir string) *PackageSource {
    40  	return &PackageSource{
    41  		Name:              "dropin",
    42  		RepoDir:           repoDir,
    43  		RemoteBaseURL:     "",
    44  		RemoteRegistryURL: "",
    45  		IsManaged:         false,
    46  		SyncPolicy:        SYNC_POLICY_NEVER,
    47  	}
    48  }
    49  
    50  func NewManagedSource(name, repoDir, remoteBaseURL string, syncPolicy string) *PackageSource {
    51  	return &PackageSource{
    52  		Name:              name,
    53  		RepoDir:           repoDir,
    54  		RemoteBaseURL:     remoteBaseURL,
    55  		RemoteRegistryURL: fmt.Sprintf("%s/index.json", remoteBaseURL),
    56  		IsManaged:         true,
    57  		SyncPolicy:        SYNC_POLICY_ALWAYS,
    58  	}
    59  }
    60  
    61  func (src *PackageSource) InitUpdater(user *user.User, timeout time.Duration, enableCI bool, lockFile string, verifyChecksum bool, verifySignature bool) *updater.CmdUpdater {
    62  	if src.SyncPolicy == SYNC_POLICY_NEVER {
    63  		return nil
    64  	}
    65  	src.Updater = &updater.CmdUpdater{
    66  		LocalRepo:            src.Repo,
    67  		CmdRepositoryBaseUrl: src.RemoteBaseURL,
    68  		User:                 *user,
    69  		Timeout:              timeout,
    70  		EnableCI:             enableCI,
    71  		PackageLockFile:      lockFile,
    72  		VerifyChecksum:       verifyChecksum,
    73  		VerifySignature:      verifySignature,
    74  	}
    75  	return src.Updater
    76  }
    77  
    78  func (src PackageSource) IsInstalled() bool {
    79  	if src.Repo == nil {
    80  		// nothing to install
    81  		return true
    82  	}
    83  	return len(src.Repo.InstalledCommands()) > 0
    84  }
    85  
    86  func (src *PackageSource) InitialInstallCommands(user *user.User, enableCI bool, lockFilePath string, verifyChecksum bool, verifySignature bool) error {
    87  	remote := remote.CreateRemoteRepository(src.RemoteBaseURL)
    88  	errors := make([]string, 0)
    89  
    90  	// check locked packages if ci is enabled
    91  	lockedPackages := map[string]string{}
    92  	if enableCI {
    93  		pkgs, err := src.Updater.LoadLockedPackages(lockFilePath)
    94  		if err == nil {
    95  			lockedPackages = pkgs
    96  		}
    97  	}
    98  
    99  	if pkgs, err := remote.PackageNames(); err == nil {
   100  		for _, pkgName := range pkgs {
   101  			pkgVersion := "unspecified"
   102  			if lockedVersion, ok := lockedPackages[pkgName]; ok {
   103  				pkgVersion = lockedVersion
   104  			} else {
   105  				latest, err := remote.LatestPackageInfo(pkgName)
   106  				if err != nil {
   107  					log.Error(err)
   108  					errors = append(errors, fmt.Sprintf("cannot get the latest version of the package %s: %v", latest.Name, err))
   109  					continue
   110  				}
   111  				if !user.InPartition(latest.StartPartition, latest.EndPartition) {
   112  					log.Infof("Skip installing package %s, user not in partition (%d %d)\n", latest.Name, latest.StartPartition, latest.EndPartition)
   113  					continue
   114  				}
   115  				pkgVersion = latest.Version
   116  			}
   117  
   118  			pkg, err := remote.Package(pkgName, pkgVersion)
   119  			if err != nil {
   120  				log.Error(err)
   121  				errors = append(errors, fmt.Sprintf("cannot get the package %s: %v", pkgName, err))
   122  				continue
   123  			}
   124  			if ok, err := remote.Verify(pkg,
   125  				verifyChecksum,
   126  				verifySignature,
   127  			); !ok || err != nil {
   128  				log.Error(err)
   129  				errors = append(errors, fmt.Sprintf("failed to verify package %s, skip it: %v", pkgName, err))
   130  				continue
   131  			}
   132  			err = src.Repo.Install(pkg)
   133  			if err != nil {
   134  				errors = append(errors, fmt.Sprintf("cannot install the package %s: %v", pkgName, err))
   135  				continue
   136  			}
   137  		}
   138  	} else {
   139  		errors = append(errors, fmt.Sprintf("cannot get remote packages: %v", err))
   140  	}
   141  
   142  	if len(errors) > 0 {
   143  		return fmt.Errorf("install failed for the following reasons: [%s]", strings.Join(errors, ", "))
   144  	}
   145  
   146  	return nil
   147  }