зеркало из https://github.com/docker/compose-cli.git
Merge pull request #165 from docker/azure_private_images
Allow pulling private images from hub or other registries
This commit is contained in:
Коммит
e77513c1c8
|
@ -42,14 +42,21 @@ func ToContainerGroup(aciContext store.AciContext, p compose.Project) (container
|
||||||
} else {
|
} else {
|
||||||
volumes = &allVolumes
|
volumes = &allVolumes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registryCreds, err := getRegistryCredentials(p, newCliRegistryConfLoader())
|
||||||
|
if err != nil {
|
||||||
|
return containerinstance.ContainerGroup{}, err
|
||||||
|
}
|
||||||
|
|
||||||
var containers []containerinstance.Container
|
var containers []containerinstance.Container
|
||||||
groupDefinition := containerinstance.ContainerGroup{
|
groupDefinition := containerinstance.ContainerGroup{
|
||||||
Name: &containerGroupName,
|
Name: &containerGroupName,
|
||||||
Location: &aciContext.Location,
|
Location: &aciContext.Location,
|
||||||
ContainerGroupProperties: &containerinstance.ContainerGroupProperties{
|
ContainerGroupProperties: &containerinstance.ContainerGroupProperties{
|
||||||
OsType: containerinstance.Linux,
|
OsType: containerinstance.Linux,
|
||||||
Containers: &containers,
|
Containers: &containers,
|
||||||
Volumes: volumes,
|
Volumes: volumes,
|
||||||
|
ImageRegistryCredentials: ®istryCreds,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Azure/azure-sdk-for-go/profiles/latest/containerinstance/mgmt/containerinstance"
|
||||||
|
"github.com/Azure/go-autorest/autorest/to"
|
||||||
|
"github.com/docker/cli/cli/config"
|
||||||
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
|
"github.com/docker/cli/cli/config/types"
|
||||||
|
|
||||||
|
"github.com/docker/api/compose"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Specific username from ACR docs : https://github.com/Azure/acr/blob/master/docs/AAD-OAuth.md#getting-credentials-programatically
|
||||||
|
const (
|
||||||
|
tokenUsername = "00000000-0000-0000-0000-000000000000"
|
||||||
|
dockerHub = "index.docker.io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type registryConfLoader interface {
|
||||||
|
getAllRegistryCredentials() (map[string]types.AuthConfig, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cliRegistryConfLoader struct {
|
||||||
|
cfg *configfile.ConfigFile
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c cliRegistryConfLoader) getAllRegistryCredentials() (map[string]types.AuthConfig, error) {
|
||||||
|
return c.cfg.GetAllCredentials()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCliRegistryConfLoader() cliRegistryConfLoader {
|
||||||
|
return cliRegistryConfLoader{
|
||||||
|
cfg: config.LoadDefaultConfigFile(os.Stderr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRegistryCredentials(project compose.Project, registryLoader registryConfLoader) ([]containerinstance.ImageRegistryCredential, error) {
|
||||||
|
allCreds, err := registryLoader.getAllRegistryCredentials()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
usedRegistries := map[string]bool{}
|
||||||
|
for _, service := range project.Services {
|
||||||
|
imageName := service.Image
|
||||||
|
tokens := strings.Split(imageName, "/")
|
||||||
|
registry := tokens[0]
|
||||||
|
if len(tokens) == 1 { // ! image names can include "." ...
|
||||||
|
registry = dockerHub
|
||||||
|
} else if !strings.Contains(registry, ".") {
|
||||||
|
registry = dockerHub
|
||||||
|
}
|
||||||
|
usedRegistries[registry] = true
|
||||||
|
}
|
||||||
|
var registryCreds []containerinstance.ImageRegistryCredential
|
||||||
|
for name, oneCred := range allCreds {
|
||||||
|
parsedURL, err := url.Parse(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname := parsedURL.Host
|
||||||
|
if hostname == "" {
|
||||||
|
hostname = parsedURL.Path
|
||||||
|
}
|
||||||
|
if _, ok := usedRegistries[hostname]; ok {
|
||||||
|
if oneCred.Username != "" {
|
||||||
|
aciCredential := containerinstance.ImageRegistryCredential{
|
||||||
|
Server: to.StringPtr(hostname),
|
||||||
|
Password: to.StringPtr(oneCred.Password),
|
||||||
|
Username: to.StringPtr(oneCred.Username),
|
||||||
|
}
|
||||||
|
registryCreds = append(registryCreds, aciCredential)
|
||||||
|
} else if oneCred.IdentityToken != "" {
|
||||||
|
aciCredential := containerinstance.ImageRegistryCredential{
|
||||||
|
Server: to.StringPtr(hostname),
|
||||||
|
Password: to.StringPtr(oneCred.IdentityToken),
|
||||||
|
Username: to.StringPtr(tokenUsername),
|
||||||
|
}
|
||||||
|
registryCreds = append(registryCreds, aciCredential)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return registryCreds, nil
|
||||||
|
}
|
|
@ -0,0 +1,192 @@
|
||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest/to"
|
||||||
|
"github.com/compose-spec/compose-go/types"
|
||||||
|
cliconfigtypes "github.com/docker/cli/cli/config/types"
|
||||||
|
|
||||||
|
"github.com/docker/api/compose"
|
||||||
|
|
||||||
|
"github.com/Azure/azure-sdk-for-go/profiles/latest/containerinstance/mgmt/containerinstance"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
const getAllCredentials = "getAllRegistryCredentials"
|
||||||
|
|
||||||
|
type RegistryConvertTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
loader *MockRegistryLoader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *RegistryConvertTestSuite) BeforeTest(suiteName, testName string) {
|
||||||
|
suite.loader = &MockRegistryLoader{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *RegistryConvertTestSuite) TestHubPrivateImage() {
|
||||||
|
suite.loader.On(getAllCredentials).Return(registry("https://index.docker.io", userPwdCreds("toto", "pwd")), nil)
|
||||||
|
|
||||||
|
creds, err := getRegistryCredentials(composeServices("gtardif/privateimg"), suite.loader)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(creds).To(Equal([]containerinstance.ImageRegistryCredential{
|
||||||
|
{
|
||||||
|
Server: to.StringPtr(dockerHub),
|
||||||
|
Username: to.StringPtr("toto"),
|
||||||
|
Password: to.StringPtr("pwd"),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *RegistryConvertTestSuite) TestRegistryNameWithoutProtocol() {
|
||||||
|
suite.loader.On(getAllCredentials).Return(registry("index.docker.io", userPwdCreds("toto", "pwd")), nil)
|
||||||
|
|
||||||
|
creds, err := getRegistryCredentials(composeServices("gtardif/privateimg"), suite.loader)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(creds).To(Equal([]containerinstance.ImageRegistryCredential{
|
||||||
|
{
|
||||||
|
Server: to.StringPtr(dockerHub),
|
||||||
|
Username: to.StringPtr("toto"),
|
||||||
|
Password: to.StringPtr("pwd"),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *RegistryConvertTestSuite) TestImageWithDotInName() {
|
||||||
|
suite.loader.On(getAllCredentials).Return(registry("index.docker.io", userPwdCreds("toto", "pwd")), nil)
|
||||||
|
|
||||||
|
creds, err := getRegistryCredentials(composeServices("my.image"), suite.loader)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(creds).To(Equal([]containerinstance.ImageRegistryCredential{
|
||||||
|
{
|
||||||
|
Server: to.StringPtr(dockerHub),
|
||||||
|
Username: to.StringPtr("toto"),
|
||||||
|
Password: to.StringPtr("pwd"),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *RegistryConvertTestSuite) TestAcrPrivateImage() {
|
||||||
|
suite.loader.On(getAllCredentials).Return(registry("https://mycontainerregistrygta.azurecr.io", tokenCreds("123456")), nil)
|
||||||
|
|
||||||
|
creds, err := getRegistryCredentials(composeServices("mycontainerregistrygta.azurecr.io/privateimg"), suite.loader)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(creds).To(Equal([]containerinstance.ImageRegistryCredential{
|
||||||
|
{
|
||||||
|
Server: to.StringPtr("mycontainerregistrygta.azurecr.io"),
|
||||||
|
Username: to.StringPtr(tokenUsername),
|
||||||
|
Password: to.StringPtr("123456"),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *RegistryConvertTestSuite) TestNoMoreRegistriesThanImages() {
|
||||||
|
configs := map[string]cliconfigtypes.AuthConfig{
|
||||||
|
"https://mycontainerregistrygta.azurecr.io": tokenCreds("123456"),
|
||||||
|
"https://index.docker.io": userPwdCreds("toto", "pwd"),
|
||||||
|
}
|
||||||
|
suite.loader.On(getAllCredentials).Return(configs, nil)
|
||||||
|
|
||||||
|
creds, err := getRegistryCredentials(composeServices("mycontainerregistrygta.azurecr.io/privateimg"), suite.loader)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(creds).To(Equal([]containerinstance.ImageRegistryCredential{
|
||||||
|
{
|
||||||
|
Server: to.StringPtr("mycontainerregistrygta.azurecr.io"),
|
||||||
|
Username: to.StringPtr(tokenUsername),
|
||||||
|
Password: to.StringPtr("123456"),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
creds, err = getRegistryCredentials(composeServices("someuser/privateimg"), suite.loader)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(creds).To(Equal([]containerinstance.ImageRegistryCredential{
|
||||||
|
{
|
||||||
|
Server: to.StringPtr(dockerHub),
|
||||||
|
Username: to.StringPtr("toto"),
|
||||||
|
Password: to.StringPtr("pwd"),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *RegistryConvertTestSuite) TestHubAndSeveralACRRegistries() {
|
||||||
|
configs := map[string]cliconfigtypes.AuthConfig{
|
||||||
|
"https://mycontainerregistry1.azurecr.io": tokenCreds("123456"),
|
||||||
|
"https://mycontainerregistry2.azurecr.io": tokenCreds("456789"),
|
||||||
|
"https://mycontainerregistry3.azurecr.io": tokenCreds("123456789"),
|
||||||
|
"https://index.docker.io": userPwdCreds("toto", "pwd"),
|
||||||
|
"https://other.registry.io": userPwdCreds("user", "password"),
|
||||||
|
}
|
||||||
|
suite.loader.On(getAllCredentials).Return(configs, nil)
|
||||||
|
|
||||||
|
creds, err := getRegistryCredentials(composeServices("mycontainerregistry1.azurecr.io/privateimg", "someuser/privateImg2", "mycontainerregistry2.azurecr.io/privateimg"), suite.loader)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(creds).To(ContainElement(containerinstance.ImageRegistryCredential{
|
||||||
|
Server: to.StringPtr("mycontainerregistry1.azurecr.io"),
|
||||||
|
Username: to.StringPtr(tokenUsername),
|
||||||
|
Password: to.StringPtr("123456"),
|
||||||
|
}))
|
||||||
|
Expect(creds).To(ContainElement(containerinstance.ImageRegistryCredential{
|
||||||
|
Server: to.StringPtr("mycontainerregistry2.azurecr.io"),
|
||||||
|
Username: to.StringPtr(tokenUsername),
|
||||||
|
Password: to.StringPtr("456789"),
|
||||||
|
}))
|
||||||
|
Expect(creds).To(ContainElement(containerinstance.ImageRegistryCredential{
|
||||||
|
Server: to.StringPtr(dockerHub),
|
||||||
|
Username: to.StringPtr("toto"),
|
||||||
|
Password: to.StringPtr("pwd"),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func composeServices(images ...string) compose.Project {
|
||||||
|
var services []types.ServiceConfig
|
||||||
|
for index, name := range images {
|
||||||
|
service := types.ServiceConfig{
|
||||||
|
Name: "service" + strconv.Itoa(index),
|
||||||
|
Image: name,
|
||||||
|
}
|
||||||
|
services = append(services, service)
|
||||||
|
}
|
||||||
|
return compose.Project{
|
||||||
|
Config: types.Config{
|
||||||
|
Services: services,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registry(host string, configregistryData cliconfigtypes.AuthConfig) map[string]cliconfigtypes.AuthConfig {
|
||||||
|
return map[string]cliconfigtypes.AuthConfig{
|
||||||
|
host: configregistryData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userPwdCreds(user string, password string) cliconfigtypes.AuthConfig {
|
||||||
|
return cliconfigtypes.AuthConfig{
|
||||||
|
Username: user,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenCreds(token string) cliconfigtypes.AuthConfig {
|
||||||
|
return cliconfigtypes.AuthConfig{
|
||||||
|
IdentityToken: token,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistryConvertTestSuite(t *testing.T) {
|
||||||
|
RegisterTestingT(t)
|
||||||
|
suite.Run(t, new(RegistryConvertTestSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockRegistryLoader struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockRegistryLoader) getAllRegistryCredentials() (map[string]cliconfigtypes.AuthConfig, error) {
|
||||||
|
args := s.Called()
|
||||||
|
return args.Get(0).(map[string]cliconfigtypes.AuthConfig), args.Error(1)
|
||||||
|
}
|
3
go.mod
3
go.mod
|
@ -18,8 +18,10 @@ require (
|
||||||
github.com/compose-spec/compose-go v0.0.0-20200423124427-63dcf8c22cae
|
github.com/compose-spec/compose-go v0.0.0-20200423124427-63dcf8c22cae
|
||||||
github.com/containerd/console v1.0.0
|
github.com/containerd/console v1.0.0
|
||||||
github.com/containerd/containerd v1.3.4 // indirect
|
github.com/containerd/containerd v1.3.4 // indirect
|
||||||
|
github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8
|
||||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
|
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
|
||||||
|
github.com/docker/docker-credential-helpers v0.6.3 // indirect
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
|
||||||
github.com/gobwas/pool v0.2.0 // indirect
|
github.com/gobwas/pool v0.2.0 // indirect
|
||||||
|
@ -33,6 +35,7 @@ require (
|
||||||
github.com/onsi/gomega v1.9.0
|
github.com/onsi/gomega v1.9.0
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||||
|
github.com/opencontainers/runc v0.1.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/prometheus/client_golang v1.5.1 // indirect
|
github.com/prometheus/client_golang v1.5.1 // indirect
|
||||||
github.com/robpike/filter v0.0.0-20150108201509-2984852a2183
|
github.com/robpike/filter v0.0.0-20150108201509-2984852a2183
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -80,10 +80,17 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||||
|
github.com/docker/cli v0.0.0-20200303162255-7d407207c304 h1:A7SYzidcyuQ/yS4wezWGYeUioUFJQk8HYWY9aMYTF4I=
|
||||||
|
github.com/docker/cli v0.0.0-20200303162255-7d407207c304/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 h1:JRquW4uqIU+eSilDhuo9X9QFX4NEmGj5B1x97ZA8djM=
|
||||||
|
github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/cli v17.12.1-ce-rc2+incompatible h1:ESUycEAqvFuLglAHkUW66rCc2djYtd3i1x231svLq9o=
|
||||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible h1:G2hY8RD7jB9QaSmcb8mYEIg8QbEvVAB7se8+lXHZHfg=
|
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible h1:G2hY8RD7jB9QaSmcb8mYEIg8QbEvVAB7se8+lXHZHfg=
|
||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
|
||||||
|
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||||
|
@ -207,6 +214,8 @@ github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2i
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
|
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
|
||||||
|
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
|
Загрузка…
Ссылка в новой задаче