| ... | ... |
@@ -203,6 +203,18 @@ func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http. |
| 203 | 203 |
} |
| 204 | 204 |
} |
| 205 | 205 |
|
| 206 |
+func getImagesViz(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 207 |
+ if version > 1.6 {
|
|
| 208 |
+ w.WriteHeader(http.StatusNotFound) |
|
| 209 |
+ return fmt.Errorf("This is now implemented in the client.")
|
|
| 210 |
+ } |
|
| 211 |
+ |
|
| 212 |
+ if err := srv.ImagesViz(w); err != nil {
|
|
| 213 |
+ return err |
|
| 214 |
+ } |
|
| 215 |
+ return nil |
|
| 216 |
+} |
|
| 217 |
+ |
|
| 206 | 218 |
func getInfo(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
| 207 | 219 |
return writeJSON(w, http.StatusOK, srv.DockerInfo()) |
| 208 | 220 |
} |
| ... | ... |
@@ -1039,6 +1051,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
| 1039 | 1039 |
"/info": getInfo, |
| 1040 | 1040 |
"/version": getVersion, |
| 1041 | 1041 |
"/images/json": getImagesJSON, |
| 1042 |
+ "/images/viz": getImagesViz, |
|
| 1042 | 1043 |
"/images/search": getImagesSearch, |
| 1043 | 1044 |
"/images/{name:.*}/history": getImagesHistory,
|
| 1044 | 1045 |
"/images/{name:.*}/json": getImagesByName,
|
| ... | ... |
@@ -233,6 +233,44 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils. |
| 233 | 233 |
return img.ShortID(), nil |
| 234 | 234 |
} |
| 235 | 235 |
|
| 236 |
+func (srv *Server) ImagesViz(out io.Writer) error {
|
|
| 237 |
+ images, _ := srv.runtime.graph.Map() |
|
| 238 |
+ if images == nil {
|
|
| 239 |
+ return nil |
|
| 240 |
+ } |
|
| 241 |
+ out.Write([]byte("digraph docker {\n"))
|
|
| 242 |
+ |
|
| 243 |
+ var ( |
|
| 244 |
+ parentImage *Image |
|
| 245 |
+ err error |
|
| 246 |
+ ) |
|
| 247 |
+ for _, image := range images {
|
|
| 248 |
+ parentImage, err = image.GetParent() |
|
| 249 |
+ if err != nil {
|
|
| 250 |
+ return fmt.Errorf("Error while getting parent image: %v", err)
|
|
| 251 |
+ } |
|
| 252 |
+ if parentImage != nil {
|
|
| 253 |
+ out.Write([]byte(" \"" + parentImage.ShortID() + "\" -> \"" + image.ShortID() + "\"\n"))
|
|
| 254 |
+ } else {
|
|
| 255 |
+ out.Write([]byte(" base -> \"" + image.ShortID() + "\" [style=invis]\n"))
|
|
| 256 |
+ } |
|
| 257 |
+ } |
|
| 258 |
+ |
|
| 259 |
+ reporefs := make(map[string][]string) |
|
| 260 |
+ |
|
| 261 |
+ for name, repository := range srv.runtime.repositories.Repositories {
|
|
| 262 |
+ for tag, id := range repository {
|
|
| 263 |
+ reporefs[utils.TruncateID(id)] = append(reporefs[utils.TruncateID(id)], fmt.Sprintf("%s:%s", name, tag))
|
|
| 264 |
+ } |
|
| 265 |
+ } |
|
| 266 |
+ |
|
| 267 |
+ for id, repos := range reporefs {
|
|
| 268 |
+ out.Write([]byte(" \"" + id + "\" [label=\"" + id + "\\n" + strings.Join(repos, "\\n") + "\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n"))
|
|
| 269 |
+ } |
|
| 270 |
+ out.Write([]byte(" base [style=invisible]\n}\n"))
|
|
| 271 |
+ return nil |
|
| 272 |
+} |
|
| 273 |
+ |
|
| 236 | 274 |
func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
|
| 237 | 275 |
var ( |
| 238 | 276 |
allImages map[string]*Image |