Search code examples
godockerdocker-composedockerfiledocker-registry

How can I create a map[string][]string in docker registry api for image name with its tags?


I am using Docker Registry API, to first list all images on the registry using List repositories method and then looping in the images to create a map[string] []string :image []tags using Listing image tags method.

I tried this

func GetImages(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
res, err := http.Get(fmt.Sprintf("%s/%s", sconf.RegistryConf.url, sconf.RegistryConf.listrepo))
if err != nil {
    w.WriteHeader(500)
    log.Errorf("Could not get repositories: %s", err)
    return
}
log.Info("Registry accessed")
js, err := ioutil.ReadAll(res.Body)
if err != nil {
    w.WriteHeader(500)
    log.Errorf("Could not read response: %s", err)
    return
}
log.Infof("response read successfully")
var Repositories map[string][]string
err = json.Unmarshal(js, &Repositories)
if err != nil {
    w.WriteHeader(500)
    log.Errorf("Could not transform json to map: %s", err)
    return
}

res.Body.Close()

if err != nil {
    log.Warnf("Could not close body")
}
var Images []string
Images = Repositories["repositories"]
//map_image_tags := make(map[string][]string)
var map_image_tags map[string]interface{}

map_images_tags := make(map[string][]string)
log.Debugf("OK")
for i := 0; i < len(Images); i++ {
    log.Debugf("OK")
    res2, err := http.Get(fmt.Sprintf("%s/v2/%s/tags/lists", sconf.RegistryConf.url, Images[i]))
    if err != nil {
        w.WriteHeader(500)
        log.Errorf("could not get tags: %s", err)
        return
    }
    log.Debugf("OK")
    js2, err := ioutil.ReadAll(res2.Body)
    if err != nil {
        w.WriteHeader(500)
        log.Errorf("could not read body: %s", err)
        return
    }
    log.Debugf("OK")
    log.Debugf("%v", []byte(js2))
    err = json.Unmarshal(js2, &map_image_tags)
    log.Debugf("map:", map_image_tags)
    log.Debugf("OK")
    if err != nil {
        w.WriteHeader(500)
        log.Errorf("could not unmarshal json: %s", err)
        return
    }
    log.Debugf("OK")
    //map_images_tags[map_image_tags["name"]] = map_image_tags["tags"]

}
response, err := json.MarshalIndent(map_images_tags, "", " ")
if err != nil {
    w.WriteHeader(500)
    log.Errorf("Could not transform map to json: %s", err)
    return
}
log.Infof("Get Registry Images: success")
fmt.Fprintf(w, string(response))

}

But its not working, can anybody show me my mistakes or show me how can i do this from scratch?


Solution

  • As far as I can see you can not unmarshal array into Go value of type map[string][]string. As JimB says you should make interface and then unmarshal to that.

    This is your Docker response from API for images (from: Docker api):

    j := []byte(`[
      {
         "RepoTags": [
           "ubuntu:12.04",
           "ubuntu:precise",
           "ubuntu:latest"
         ],
         "Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
         "Created": 1365714795,
         "Size": 131506275,
         "VirtualSize": 131506275,
         "Labels": {}
      },
      {
         "RepoTags": [
           "ubuntu:12.10",
           "ubuntu:quantal"
         ],
         "ParentId": "27cf784147099545",
         "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
         "Created": 1364102658,
         "Size": 24653,
         "VirtualSize": 180116135,
         "Labels": {
            "com.example.version": "v1"
         }
      }
    ]`)
    

    It is obvious you can not unpack into map[string][]string (Go playground here)

    If you want to use your thingy for this then do make interface and unpack to that interface. Also use this for JSON https://github.com/antonholmquist/jason. It is much simpler that original encoding/json