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  }