github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/api/server/router/image/image_routes.go (about) 1 package image 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "io" 8 "net/http" 9 "strconv" 10 "strings" 11 12 "github.com/docker/docker/api/server/httputils" 13 "github.com/docker/docker/api/types" 14 "github.com/docker/docker/api/types/backend" 15 "github.com/docker/docker/api/types/container" 16 "github.com/docker/docker/api/types/filters" 17 "github.com/docker/docker/api/types/versions" 18 "github.com/docker/docker/pkg/ioutils" 19 "github.com/docker/docker/pkg/streamformatter" 20 "github.com/docker/docker/registry" 21 "golang.org/x/net/context" 22 ) 23 24 func (s *imageRouter) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 25 if err := httputils.ParseForm(r); err != nil { 26 return err 27 } 28 29 if err := httputils.CheckForJSON(r); err != nil { 30 return err 31 } 32 33 cname := r.Form.Get("container") 34 35 pause := httputils.BoolValue(r, "pause") 36 version := httputils.VersionFromContext(ctx) 37 if r.FormValue("pause") == "" && versions.GreaterThanOrEqualTo(version, "1.13") { 38 pause = true 39 } 40 41 c, _, _, err := s.decoder.DecodeConfig(r.Body) 42 if err != nil && err != io.EOF { //Do not fail if body is empty. 43 return err 44 } 45 if c == nil { 46 c = &container.Config{} 47 } 48 49 commitCfg := &backend.ContainerCommitConfig{ 50 ContainerCommitConfig: types.ContainerCommitConfig{ 51 Pause: pause, 52 Repo: r.Form.Get("repo"), 53 Tag: r.Form.Get("tag"), 54 Author: r.Form.Get("author"), 55 Comment: r.Form.Get("comment"), 56 Config: c, 57 MergeConfigs: true, 58 }, 59 Changes: r.Form["changes"], 60 } 61 62 imgID, err := s.backend.Commit(cname, commitCfg) 63 if err != nil { 64 return err 65 } 66 67 return httputils.WriteJSON(w, http.StatusCreated, &types.IDResponse{ 68 ID: string(imgID), 69 }) 70 } 71 72 // Creates an image from Pull or from Import 73 func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 74 if err := httputils.ParseForm(r); err != nil { 75 return err 76 } 77 78 var ( 79 image = r.Form.Get("fromImage") 80 repo = r.Form.Get("repo") 81 tag = r.Form.Get("tag") 82 message = r.Form.Get("message") 83 err error 84 output = ioutils.NewWriteFlusher(w) 85 ) 86 defer output.Close() 87 88 w.Header().Set("Content-Type", "application/json") 89 90 if image != "" { //pull 91 metaHeaders := map[string][]string{} 92 for k, v := range r.Header { 93 if strings.HasPrefix(k, "X-Meta-") { 94 metaHeaders[k] = v 95 } 96 } 97 98 authEncoded := r.Header.Get("X-Registry-Auth") 99 authConfig := &types.AuthConfig{} 100 if authEncoded != "" { 101 authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) 102 if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil { 103 // for a pull it is not an error if no auth was given 104 // to increase compatibility with the existing api it is defaulting to be empty 105 authConfig = &types.AuthConfig{} 106 } 107 } 108 109 err = s.backend.PullImage(ctx, image, tag, metaHeaders, authConfig, output) 110 } else { //import 111 src := r.Form.Get("fromSrc") 112 // 'err' MUST NOT be defined within this block, we need any error 113 // generated from the download to be available to the output 114 // stream processing below 115 err = s.backend.ImportImage(src, repo, tag, message, r.Body, output, r.Form["changes"]) 116 } 117 if err != nil { 118 if !output.Flushed() { 119 return err 120 } 121 output.Write(streamformatter.FormatError(err)) 122 } 123 124 return nil 125 } 126 127 func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 128 metaHeaders := map[string][]string{} 129 for k, v := range r.Header { 130 if strings.HasPrefix(k, "X-Meta-") { 131 metaHeaders[k] = v 132 } 133 } 134 if err := httputils.ParseForm(r); err != nil { 135 return err 136 } 137 authConfig := &types.AuthConfig{} 138 139 authEncoded := r.Header.Get("X-Registry-Auth") 140 if authEncoded != "" { 141 // the new format is to handle the authConfig as a header 142 authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) 143 if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil { 144 // to increase compatibility to existing api it is defaulting to be empty 145 authConfig = &types.AuthConfig{} 146 } 147 } else { 148 // the old format is supported for compatibility if there was no authConfig header 149 if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil { 150 return fmt.Errorf("Bad parameters and missing X-Registry-Auth: %v", err) 151 } 152 } 153 154 image := vars["name"] 155 tag := r.Form.Get("tag") 156 157 output := ioutils.NewWriteFlusher(w) 158 defer output.Close() 159 160 w.Header().Set("Content-Type", "application/json") 161 162 if err := s.backend.PushImage(ctx, image, tag, metaHeaders, authConfig, output); err != nil { 163 if !output.Flushed() { 164 return err 165 } 166 output.Write(streamformatter.FormatError(err)) 167 } 168 return nil 169 } 170 171 func (s *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 172 if err := httputils.ParseForm(r); err != nil { 173 return err 174 } 175 176 w.Header().Set("Content-Type", "application/x-tar") 177 178 output := ioutils.NewWriteFlusher(w) 179 defer output.Close() 180 var names []string 181 if name, ok := vars["name"]; ok { 182 names = []string{name} 183 } else { 184 names = r.Form["names"] 185 } 186 187 if err := s.backend.ExportImage(names, output); err != nil { 188 if !output.Flushed() { 189 return err 190 } 191 output.Write(streamformatter.FormatError(err)) 192 } 193 return nil 194 } 195 196 func (s *imageRouter) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 197 if err := httputils.ParseForm(r); err != nil { 198 return err 199 } 200 quiet := httputils.BoolValueOrDefault(r, "quiet", true) 201 202 w.Header().Set("Content-Type", "application/json") 203 204 output := ioutils.NewWriteFlusher(w) 205 defer output.Close() 206 if err := s.backend.LoadImage(r.Body, output, quiet); err != nil { 207 output.Write(streamformatter.FormatError(err)) 208 } 209 return nil 210 } 211 212 func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 213 if err := httputils.ParseForm(r); err != nil { 214 return err 215 } 216 217 name := vars["name"] 218 219 if strings.TrimSpace(name) == "" { 220 return fmt.Errorf("image name cannot be blank") 221 } 222 223 force := httputils.BoolValue(r, "force") 224 prune := !httputils.BoolValue(r, "noprune") 225 226 list, err := s.backend.ImageDelete(name, force, prune) 227 if err != nil { 228 return err 229 } 230 231 return httputils.WriteJSON(w, http.StatusOK, list) 232 } 233 234 func (s *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 235 imageInspect, err := s.backend.LookupImage(vars["name"]) 236 if err != nil { 237 return err 238 } 239 240 return httputils.WriteJSON(w, http.StatusOK, imageInspect) 241 } 242 243 func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 244 if err := httputils.ParseForm(r); err != nil { 245 return err 246 } 247 248 imageFilters, err := filters.FromParam(r.Form.Get("filters")) 249 if err != nil { 250 return err 251 } 252 253 filterParam := r.Form.Get("filter") 254 // FIXME(vdemeester) This has been deprecated in 1.13, and is target for removal for v17.12 255 if filterParam != "" { 256 imageFilters.Add("reference", filterParam) 257 } 258 259 images, err := s.backend.Images(imageFilters, httputils.BoolValue(r, "all"), false) 260 if err != nil { 261 return err 262 } 263 264 return httputils.WriteJSON(w, http.StatusOK, images) 265 } 266 267 func (s *imageRouter) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 268 name := vars["name"] 269 history, err := s.backend.ImageHistory(name) 270 if err != nil { 271 return err 272 } 273 274 return httputils.WriteJSON(w, http.StatusOK, history) 275 } 276 277 func (s *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 278 if err := httputils.ParseForm(r); err != nil { 279 return err 280 } 281 if err := s.backend.TagImage(vars["name"], r.Form.Get("repo"), r.Form.Get("tag")); err != nil { 282 return err 283 } 284 w.WriteHeader(http.StatusCreated) 285 return nil 286 } 287 288 func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 289 if err := httputils.ParseForm(r); err != nil { 290 return err 291 } 292 var ( 293 config *types.AuthConfig 294 authEncoded = r.Header.Get("X-Registry-Auth") 295 headers = map[string][]string{} 296 ) 297 298 if authEncoded != "" { 299 authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) 300 if err := json.NewDecoder(authJSON).Decode(&config); err != nil { 301 // for a search it is not an error if no auth was given 302 // to increase compatibility with the existing api it is defaulting to be empty 303 config = &types.AuthConfig{} 304 } 305 } 306 for k, v := range r.Header { 307 if strings.HasPrefix(k, "X-Meta-") { 308 headers[k] = v 309 } 310 } 311 limit := registry.DefaultSearchLimit 312 if r.Form.Get("limit") != "" { 313 limitValue, err := strconv.Atoi(r.Form.Get("limit")) 314 if err != nil { 315 return err 316 } 317 limit = limitValue 318 } 319 query, err := s.backend.SearchRegistryForImages(ctx, r.Form.Get("filters"), r.Form.Get("term"), limit, config, headers) 320 if err != nil { 321 return err 322 } 323 return httputils.WriteJSON(w, http.StatusOK, query.Results) 324 } 325 326 func (s *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 327 if err := httputils.ParseForm(r); err != nil { 328 return err 329 } 330 331 pruneFilters, err := filters.FromParam(r.Form.Get("filters")) 332 if err != nil { 333 return err 334 } 335 336 pruneReport, err := s.backend.ImagesPrune(ctx, pruneFilters) 337 if err != nil { 338 return err 339 } 340 return httputils.WriteJSON(w, http.StatusOK, pruneReport) 341 }