github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/internal/versions/versions.go (about) 1 package versions 2 3 import ( 4 "context" 5 "encoding/json" 6 "io/ioutil" 7 "os" 8 "path" 9 "path/filepath" 10 "sort" 11 12 registryclient "github.com/docker/cli/cli/registry/client" 13 clitypes "github.com/docker/cli/types" 14 "github.com/docker/distribution/reference" 15 ver "github.com/hashicorp/go-version" 16 "github.com/pkg/errors" 17 "github.com/sirupsen/logrus" 18 ) 19 20 const ( 21 // defaultRuntimeMetadataDir is the location where the metadata file is stored 22 defaultRuntimeMetadataDir = "/var/lib/docker-engine" 23 ) 24 25 // GetEngineVersions reports the versions of the engine that are available 26 func GetEngineVersions(ctx context.Context, registryClient registryclient.RegistryClient, registryPrefix, imageName, versionString string) (clitypes.AvailableVersions, error) { 27 28 if imageName == "" { 29 var err error 30 localMetadata, err := GetCurrentRuntimeMetadata("") 31 if err != nil { 32 return clitypes.AvailableVersions{}, err 33 } 34 imageName = localMetadata.EngineImage 35 } 36 imageRef, err := reference.ParseNormalizedNamed(path.Join(registryPrefix, imageName)) 37 if err != nil { 38 return clitypes.AvailableVersions{}, err 39 } 40 41 tags, err := registryClient.GetTags(ctx, imageRef) 42 if err != nil { 43 return clitypes.AvailableVersions{}, err 44 } 45 46 return parseTags(tags, versionString) 47 } 48 49 func parseTags(tags []string, currentVersion string) (clitypes.AvailableVersions, error) { 50 var ret clitypes.AvailableVersions 51 currentVer, err := ver.NewVersion(currentVersion) 52 if err != nil { 53 return ret, errors.Wrapf(err, "failed to parse existing version %s", currentVersion) 54 } 55 downgrades := []clitypes.DockerVersion{} 56 patches := []clitypes.DockerVersion{} 57 upgrades := []clitypes.DockerVersion{} 58 currentSegments := currentVer.Segments() 59 for _, tag := range tags { 60 tmp, err := ver.NewVersion(tag) 61 if err != nil { 62 logrus.Debugf("Unable to parse %s: %s", tag, err) 63 continue 64 } 65 testVersion := clitypes.DockerVersion{Version: *tmp, Tag: tag} 66 if testVersion.LessThan(currentVer) { 67 downgrades = append(downgrades, testVersion) 68 continue 69 } 70 testSegments := testVersion.Segments() 71 // lib always provides min 3 segments 72 if testSegments[0] == currentSegments[0] && 73 testSegments[1] == currentSegments[1] { 74 patches = append(patches, testVersion) 75 } else { 76 upgrades = append(upgrades, testVersion) 77 } 78 } 79 sort.Slice(downgrades, func(i, j int) bool { 80 return downgrades[i].Version.LessThan(&downgrades[j].Version) 81 }) 82 sort.Slice(patches, func(i, j int) bool { 83 return patches[i].Version.LessThan(&patches[j].Version) 84 }) 85 sort.Slice(upgrades, func(i, j int) bool { 86 return upgrades[i].Version.LessThan(&upgrades[j].Version) 87 }) 88 ret.Downgrades = downgrades 89 ret.Patches = patches 90 ret.Upgrades = upgrades 91 return ret, nil 92 } 93 94 // GetCurrentRuntimeMetadata loads the current daemon runtime metadata information from the local host 95 func GetCurrentRuntimeMetadata(metadataDir string) (*clitypes.RuntimeMetadata, error) { 96 if metadataDir == "" { 97 metadataDir = defaultRuntimeMetadataDir 98 } 99 filename := filepath.Join(metadataDir, clitypes.RuntimeMetadataName+".json") 100 101 data, err := ioutil.ReadFile(filename) 102 if err != nil { 103 return nil, err 104 } 105 var res clitypes.RuntimeMetadata 106 err = json.Unmarshal(data, &res) 107 if err != nil { 108 return nil, errors.Wrapf(err, "malformed runtime metadata file %s", filename) 109 } 110 return &res, nil 111 } 112 113 // WriteRuntimeMetadata stores the metadata on the local system 114 func WriteRuntimeMetadata(metadataDir string, metadata *clitypes.RuntimeMetadata) error { 115 if metadataDir == "" { 116 metadataDir = defaultRuntimeMetadataDir 117 } 118 filename := filepath.Join(metadataDir, clitypes.RuntimeMetadataName+".json") 119 120 data, err := json.Marshal(metadata) 121 if err != nil { 122 return err 123 } 124 125 os.Remove(filename) 126 return ioutil.WriteFile(filename, data, 0644) 127 }