github.com/cloudfoundry-attic/ltc@v0.0.0-20151123212628-098adc7919fc/docker_runner/docker_metadata_fetcher/docker_metadata_fetcher.go (about) 1 package docker_metadata_fetcher 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/cloudfoundry-incubator/ltc/docker_runner/docker_repository_name_formatter" 9 "github.com/docker/docker/image" 10 "github.com/docker/docker/pkg/nat" 11 ) 12 13 type ImageMetadata struct { 14 User string 15 WorkingDir string 16 ExposedPorts []uint16 17 StartCommand []string 18 Env []string 19 } 20 21 //go:generate counterfeiter -o fake_docker_metadata_fetcher/fake_docker_metadata_fetcher.go . DockerMetadataFetcher 22 type DockerMetadataFetcher interface { 23 FetchMetadata(dockerPath string) (*ImageMetadata, error) 24 } 25 26 type dockerMetadataFetcher struct { 27 dockerSessionFactory DockerSessionFactory 28 } 29 30 func New(sessionFactory DockerSessionFactory) DockerMetadataFetcher { 31 return &dockerMetadataFetcher{ 32 dockerSessionFactory: sessionFactory, 33 } 34 } 35 36 func (fetcher *dockerMetadataFetcher) FetchMetadata(dockerPath string) (*ImageMetadata, error) { 37 indexName, remoteName, tag, err := docker_repository_name_formatter.ParseRepoNameAndTagFromImageReference(dockerPath) 38 if err != nil { 39 return nil, err 40 } 41 42 var reposName string 43 if len(indexName) > 0 { 44 reposName = fmt.Sprintf("%s/%s", indexName, remoteName) 45 } else { 46 reposName = remoteName 47 } 48 49 var session DockerSession 50 if session, err = fetcher.dockerSessionFactory.MakeSession(reposName, false); err != nil { 51 if !strings.Contains(err.Error(), "this private registry supports only HTTP or HTTPS with an unknown CA certificate") { 52 return nil, err 53 } 54 55 session, err = fetcher.dockerSessionFactory.MakeSession(reposName, true) 56 if err != nil { 57 return nil, err 58 } 59 } 60 61 repoData, err := session.GetRepositoryData(remoteName) 62 if err != nil { 63 return nil, err 64 } 65 66 tagsList, err := session.GetRemoteTags(repoData.Endpoints, remoteName) 67 if err != nil { 68 return nil, err 69 } 70 71 imgID, ok := tagsList[tag] 72 if !ok { 73 return nil, fmt.Errorf("Unknown tag: %s:%s", remoteName, tag) 74 } 75 76 var img *image.Image 77 endpoint := repoData.Endpoints[0] 78 imgJSON, _, err := session.GetRemoteImageJSON(imgID, endpoint) 79 if err != nil { 80 return nil, err 81 } 82 83 img, err = image.NewImgJSON(imgJSON) 84 if err != nil { 85 return nil, fmt.Errorf("Error parsing remote image json for specified docker image:\n%s", err) 86 } 87 if img.Config == nil { 88 return nil, fmt.Errorf("Parsing start command failed") 89 } 90 91 startCommand := append(img.Config.Entrypoint.Slice(), img.Config.Cmd.Slice()...) 92 exposedPorts := sortPorts(img.ContainerConfig.ExposedPorts) 93 94 return &ImageMetadata{ 95 WorkingDir: img.Config.WorkingDir, 96 User: img.Config.User, 97 StartCommand: startCommand, 98 ExposedPorts: exposedPorts, 99 Env: img.Config.Env, 100 }, nil 101 } 102 103 func sortPorts(dockerExposedPorts map[nat.Port]struct{}) []uint16 { 104 intPorts := make([]int, 0) 105 for natPort, _ := range dockerExposedPorts { 106 if natPort.Proto() == "tcp" { 107 intPorts = append(intPorts, natPort.Int()) 108 } 109 } 110 sort.IntSlice(intPorts).Sort() 111 112 exposedPorts := make([]uint16, 0) 113 for _, port := range intPorts { 114 exposedPorts = append(exposedPorts, uint16(port)) 115 } 116 return exposedPorts 117 }