// downloadAndUnzipArtifact downloads installation package and unzips it func downloadAndUnzipArtifact( mgr *updateManager, log log.T, downloadInput artifact.DownloadInput, context *UpdateContext, version string) (err error) { log.Infof("Preparing source for version %v", version) // download installation zip files downloadOutput, err := downloadArtifact(log, downloadInput) if err != nil || downloadOutput.IsHashMatched == false || downloadOutput.LocalFilePath == "" { if err != nil { return fmt.Errorf("failed to download file reliably, %v", err.Error()) } return fmt.Errorf("failed to download file reliably") } // downloaded successfully, append message context.Current.AppendInfo(log, "Successfully downloaded %v", downloadInput.SourceURL) // uncompress installation package if err = uncompress( downloadOutput.LocalFilePath, updateutil.UpdateArtifactFolder(context.Current.UpdateRoot, context.Current.PackageName, version)); err != nil { return fmt.Errorf("failed to uncompress installation package, %v", err.Error()) } return nil }
// install executes the install script for the specific version of agent func installAgent(mgr *updateManager, log log.T, version string, context *UpdateContext) (err error) { log.Infof("Initiating %v %v installation", context.Current.PackageName, version) // find the path for the install script installerPath := updateutil.InstallerFilePath( context.Current.UpdateRoot, context.Current.PackageName, version) // calculate work directory workDir := updateutil.UpdateArtifactFolder( context.Current.UpdateRoot, context.Current.PackageName, version) // Install version if err = mgr.util.ExeCommand( log, installerPath, workDir, context.Current.UpdateRoot, context.Current.StdoutFileName, context.Current.StderrFileName, false); err != nil { return err } log.Infof("%v %v installed successfully", context.Current.PackageName, version) return nil }
//downloadUpdater downloads updater from the s3 bucket func (m *updateManager) downloadUpdater(log log.T, util updateutil.T, updaterPackageName string, manifest *Manifest, out *UpdatePluginOutput, context *updateutil.InstanceContext) (version string, err error) { var hash = "" var source = "" if version, err = manifest.LatestVersion(log, context, updaterPackageName); err != nil { return } if source, hash, err = manifest.DownloadURLAndHash(context, updaterPackageName, version); err != nil { return } var updateDownloadFolder = "" if updateDownloadFolder, err = util.CreateUpdateDownloadFolder(); err != nil { return } downloadInput := artifact.DownloadInput{ SourceURL: source, SourceHashValue: hash, SourceHashType: updateutil.HashType, DestinationDirectory: updateDownloadFolder, } downloadOutput, downloadErr := fileDownload(log, downloadInput) if downloadErr != nil || downloadOutput.IsHashMatched == false || downloadOutput.LocalFilePath == "" { errMessage := fmt.Sprintf("failed to download file reliably, %v", downloadInput.SourceURL) if downloadErr != nil { errMessage = fmt.Sprintf("%v, %v", errMessage, downloadErr.Error()) } return version, errors.New(errMessage) } out.AppendInfo(log, "Successfully downloaded %v", downloadInput.SourceURL) if uncompressErr := fileUncompress( downloadOutput.LocalFilePath, updateutil.UpdateArtifactFolder(appconfig.UpdaterArtifactsRoot, updaterPackageName, version)); uncompressErr != nil { return version, fmt.Errorf("failed to uncompress updater package, %v, %v", downloadOutput.LocalFilePath, uncompressErr.Error()) } return version, nil }
// updateAgent downloads the installation packages and update the agent func runUpdateAgent( p *Plugin, config contracts.Configuration, log log.T, manager pluginHelper, util updateutil.T, rawPluginInput interface{}, cancelFlag task.CancelFlag, outputS3BucketName string, outputS3KeyPrefix string, startTime time.Time) (out UpdatePluginOutput) { var pluginInput UpdatePluginInput var err error var context *updateutil.InstanceContext if isUpdateSupported, err := util.IsPlatformSupportedForUpdate(log); err == nil && !isUpdateSupported { out.Failed(log, fmt.Errorf("Unsupported platform for update")) return } if err = jsonutil.Remarshal(rawPluginInput, &pluginInput); err != nil { out.Failed(log, fmt.Errorf("invalid format in plugin properties %v;\nerror %v", rawPluginInput, err)) return } if context, err = util.CreateInstanceContext(log); err != nil { out.Failed(log, err) return } //Use default manifest location is the override is not present if len(pluginInput.Source) == 0 { pluginInput.Source = p.ManifestLocation } //Calculate manifest location base on current instance's region pluginInput.Source = strings.Replace(pluginInput.Source, updateutil.RegionHolder, context.Region, -1) //Calculate updater package name base on agent name pluginInput.UpdaterName = pluginInput.AgentName + updateutil.UpdaterPackageNamePrefix //Generate update output targetVersion := pluginInput.TargetVersion if len(targetVersion) == 0 { targetVersion = "latest" } out.AppendInfo(log, "Updating %v from %v to %v", pluginInput.AgentName, version.Version, targetVersion) //Download manifest file manifest, downloadErr := manager.downloadManifest(log, util, &pluginInput, context, &out) if downloadErr != nil { out.Failed(log, downloadErr) return } //Validate update details noNeedToUpdate := false if noNeedToUpdate, err = manager.validateUpdate(log, &pluginInput, context, manifest, &out); noNeedToUpdate { if err != nil { out.Failed(log, err) } return } //Download updater and retrieve the version number updaterVersion := "" if updaterVersion, err = manager.downloadUpdater( log, util, pluginInput.UpdaterName, manifest, &out, context); err != nil { out.Failed(log, err) return } //Generate update command base on the update detail cmd := "" if cmd, err = manager.generateUpdateCmd(log, manifest, &pluginInput, context, updateutil.UpdaterFilePath(appconfig.UpdaterArtifactsRoot, pluginInput.UpdaterName, updaterVersion), config.MessageId, p.StdoutFileName, p.StderrFileName, outputS3KeyPrefix, outputS3BucketName); err != nil { out.Failed(log, err) return } log.Debugf("Update command %v", cmd) //Save update plugin result to local file, updater will read it during agent update updatePluginResult := &updateutil.UpdatePluginResult{ StandOut: out.Stdout, StartDateTime: startTime, } if err = util.SaveUpdatePluginResult(log, appconfig.UpdaterArtifactsRoot, updatePluginResult); err != nil { out.Failed(log, err) return } // If disk space is not sufficient, fail the update to prevent installation and notify user in output // If loading disk space fails, continue to update (agent update is backed by rollback handler) log.Infof("Checking available disk space ...") if isDiskSpaceSufficient, err := util.IsDiskSpaceSufficientForUpdate(log); err == nil && !isDiskSpaceSufficient { out.Failed(log, errors.New("Insufficient available disk space")) return } log.Infof("Start Installation") log.Infof("Hand over update process to %v", pluginInput.UpdaterName) //Execute updater, hand over the update process workDir := updateutil.UpdateArtifactFolder( appconfig.UpdaterArtifactsRoot, pluginInput.UpdaterName, updaterVersion) if err = util.ExeCommand( log, cmd, workDir, appconfig.UpdaterArtifactsRoot, p.StdoutFileName, p.StderrFileName, true); err != nil { out.Failed(log, err) return } out.Pending() return }