// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may not // use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, // either express or implied. See the License for the specific language governing // permissions and limitations under the License. //go:build windows // +build windows // Package updateec2config implements the UpdateEC2Config plugin. package updateec2config import ( "encoding/json" "fmt" "io/ioutil" "path/filepath" "strings" "github.com/aws/amazon-ssm-agent/agent/log" "github.com/aws/amazon-ssm-agent/agent/updateutil" "github.com/aws/amazon-ssm-agent/agent/updateutil/updateconstants" "github.com/aws/amazon-ssm-agent/agent/updateutil/updateinfo" "github.com/aws/amazon-ssm-agent/agent/versionutil" ) // Manifest represents the json structure of online manifest file. type Manifest struct { SchemaVersion string `json:"SchemaVersion"` URIFormat string `json:"UriFormat"` Packages []*PackageContent `json:"Packages"` } // PackageContent section in the Manifest json. type PackageContent struct { Name string `json:"Name"` FileName string `json:"FileName"` AvailableVersions []*PackageVersion `json:"AvailableVersions"` } // PackageVersion section in the PackageContent type PackageVersion struct { Version string `json:"Version"` Checksum string `json:"Checksum"` } // ParseManifest parses the public manifest file to provide agent update information. func ParseManifest(log log.T, fileName string) (parsedManifest *Manifest, err error) { //Load specified file from file system var result = []byte{} if result, err = ioutil.ReadFile(fileName); err != nil { return } // parse manifest file if err = json.Unmarshal([]byte(result), &parsedManifest); err != nil { return } err = validateManifest(log, parsedManifest) return } // HasVersion returns if manifest file has particular version for package func (m *Manifest) HasVersion(info updateinfo.T, version string) bool { for _, p := range m.Packages { if p.Name == EC2UpdaterPackageName && p.FileName == EC2UpdaterFileName { for _, v := range p.AvailableVersions { if v.Version == version || version == PipelineTestVersion { return true } } } } return false } // LatestVersion returns latest version for specific package func (m *Manifest) LatestVersion(log log.T, info updateinfo.T) (result string, err error) { var version = minimumVersion var compareResult = 0 for _, p := range m.Packages { if p.Name == EC2UpdaterPackageName && p.FileName == EC2UpdaterFileName { for _, v := range p.AvailableVersions { if compareResult, err = versionutil.VersionCompare(v.Version, version); err != nil { return version, err } if compareResult > 0 { version = v.Version } } } } if version == minimumVersion { log.Debugf("Filename: %v", EC2UpdaterFileName) log.Debugf("Package Name: %v", EC2UpdaterPackageName) log.Debugf("Manifest: %v", m) return version, fmt.Errorf("cannot find the latest version for package %v", EC2UpdaterPackageName) } log.Debugf("EC2Config manifest latest version: %v", version) return version, nil } // DownloadURLAndHash returns download source url and hash value func (m *Manifest) DownloadURLAndHash( packageName string, version string, filename string, toformat string, fromformat string, region string) (result string, hash string, err error) { for _, p := range m.Packages { if p.Name == packageName && p.FileName == filename { for _, v := range p.AvailableVersions { if version == v.Version || version == PipelineTestVersion { m.URIFormat = strings.Replace(m.URIFormat, fromformat, toformat, 1) result = m.URIFormat result = strings.Replace(result, updateconstants.RegionHolder, region, -1) result = strings.Replace(result, updateconstants.PackageNameHolder, packageName, -1) result = strings.Replace(result, PackageVersionHolder, version, -1) result = strings.Replace(result, updateconstants.FileNameHolder, p.FileName, -1) if version == PipelineTestVersion { return result, "", nil } return result, v.Checksum, nil } } } } return "", "", fmt.Errorf("incorrect package name or version, %v, %v", packageName, version) } // validateManifest makes sure all the fields are provided. func validateManifest(log log.T, parsedManifest *Manifest) error { if len(parsedManifest.URIFormat) == 0 { return fmt.Errorf("folder format cannot be null in the Manifest file") } for _, p := range parsedManifest.Packages { if p.Name == EC2UpdaterPackageName && p.FileName == EC2UpdaterFileName { if len(p.AvailableVersions) == 0 { return fmt.Errorf("at least one available version is required for the %v", EC2UpdaterFileName) } log.Debugf("validate manifest found package %v", EC2UpdaterPackageName) log.Debugf("validate manifest found file %v", EC2UpdaterFileName) return nil } } return fmt.Errorf("cannot find the %v or %v information in the Manifest file", EC2UpdaterPackageName, EC2UpdaterFileName) } // UpdaterFilePath returns updater file path func UpdaterFilePath(updateRoot string, updaterPackageName string, version string) string { return filepath.Join(updateutil.UpdateArtifactFolder(updateRoot, updaterPackageName, version), Updater) }