//downloadManifest downloads manifest file from s3 bucket func (m *updateManager) downloadManifest(log log.T, util updateutil.T, pluginInput *UpdatePluginInput, context *updateutil.InstanceContext, out *UpdatePluginOutput) (manifest *Manifest, err error) { //Download source var updateDownload = "" updateDownload, err = util.CreateUpdateDownloadFolder() if err != nil { return nil, err } downloadInput := artifact.DownloadInput{ SourceURL: pluginInput.Source, DestinationDirectory: updateDownload, } downloadOutput, downloadErr := fileDownload(log, downloadInput) if downloadErr != nil || downloadOutput.IsHashMatched == false || downloadOutput.LocalFilePath == "" { return nil, downloadErr } out.AppendInfo(log, "Successfully downloaded %v", downloadInput.SourceURL) return ParseManifest(log, downloadOutput.LocalFilePath, context, pluginInput.AgentName) }
//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 }