... | ... |
@@ -6,8 +6,10 @@ import ( |
6 | 6 |
"errors" |
7 | 7 |
"fmt" |
8 | 8 |
"github.com/dotcloud/docker/auth" |
9 |
+ "github.com/dotcloud/docker/graph" |
|
9 | 10 |
"github.com/dotcloud/docker/rcli" |
10 | 11 |
"io" |
12 |
+ "io/ioutil" |
|
11 | 13 |
"log" |
12 | 14 |
"math/rand" |
13 | 15 |
"net/http" |
... | ... |
@@ -400,6 +402,173 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...stri |
400 | 400 |
return nil |
401 | 401 |
} |
402 | 402 |
|
403 |
+func (srv *Server) CmdPush(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
404 |
+ cmd := rcli.Subcmd(stdout, "push", "[OPTIONS] IMAGE", "Push an image to the registry") |
|
405 |
+ if err := cmd.Parse(args); err != nil { |
|
406 |
+ return nil |
|
407 |
+ } |
|
408 |
+ if cmd.NArg() == 0 { |
|
409 |
+ cmd.Usage() |
|
410 |
+ return nil |
|
411 |
+ } |
|
412 |
+ |
|
413 |
+ client := &http.Client{} |
|
414 |
+ if img, err := srv.runtime.graph.Get(cmd.Arg(0)); err != nil { |
|
415 |
+ return nil |
|
416 |
+ } else { |
|
417 |
+ img.WalkHistory(func(img *graph.Image) { |
|
418 |
+ fmt.Fprintf(stdout, "Pushing %s\n", img.Id) |
|
419 |
+ |
|
420 |
+ data := strings.NewReader("{\"id\": \"ddd\", \"created\": \"2013-03-21T00:18:18-07:00\"}") |
|
421 |
+ |
|
422 |
+ req, err := http.NewRequest("PUT", "http://192.168.56.1:5000/v1/images/"+img.Id+"/json", data) |
|
423 |
+ res, err := client.Do(req) |
|
424 |
+ if err != nil || res.StatusCode != 200 { |
|
425 |
+ switch res.StatusCode { |
|
426 |
+ case 400: |
|
427 |
+ fmt.Fprintf(stdout, "Error: Invalid Json\n") |
|
428 |
+ return |
|
429 |
+ default: |
|
430 |
+ fmt.Fprintf(stdout, "Error: Internal server error\n") |
|
431 |
+ return |
|
432 |
+ } |
|
433 |
+ fmt.Fprintf(stdout, "Error trying to push image {%s} (json): %s\n", img.Id, err) |
|
434 |
+ return |
|
435 |
+ } |
|
436 |
+ |
|
437 |
+ req2, err := http.NewRequest("PUT", "http://192.168.56.1:5000/v1/images/"+img.Id+"/layer", nil) |
|
438 |
+ res2, err := client.Do(req2) |
|
439 |
+ if err != nil || res2.StatusCode != 307 { |
|
440 |
+ fmt.Fprintf(stdout, "Error trying to push image {%s} (layer 1): %s\n", img.Id, err) |
|
441 |
+ return |
|
442 |
+ } |
|
443 |
+ url, err := res2.Location() |
|
444 |
+ if err != nil || url == nil { |
|
445 |
+ fmt.Fprintf(stdout, "Fail to retrieve layer storage URL for image {%s}: %s\n", img.Id, err) |
|
446 |
+ return |
|
447 |
+ } |
|
448 |
+ |
|
449 |
+ req3, err := http.NewRequest("PUT", url.String(), data) |
|
450 |
+ res3, err := client.Do(req3) |
|
451 |
+ if err != nil { |
|
452 |
+ fmt.Fprintf(stdout, "Error trying to push image {%s} (layer 2): %s\n", img.Id, err) |
|
453 |
+ return |
|
454 |
+ } |
|
455 |
+ fmt.Fprintf(stdout, "Status code storage: %d\n", res3.StatusCode) |
|
456 |
+ }) |
|
457 |
+ } |
|
458 |
+ return nil |
|
459 |
+} |
|
460 |
+ |
|
461 |
+func newImgJson(src []byte) (*graph.Image, error) { |
|
462 |
+ ret := &graph.Image{} |
|
463 |
+ |
|
464 |
+ fmt.Printf("Json string: {%s}\n", src) |
|
465 |
+ // FIXME: Is there a cleaner way to "puryfy" the input json? |
|
466 |
+ src = []byte(strings.Replace(string(src), "null", "\"\"", -1)) |
|
467 |
+ |
|
468 |
+ if err := json.Unmarshal(src, ret); err != nil { |
|
469 |
+ return nil, err |
|
470 |
+ } |
|
471 |
+ return ret, nil |
|
472 |
+} |
|
473 |
+ |
|
474 |
+func newMultipleImgJson(src []byte) (map[*graph.Image]graph.Archive, error) { |
|
475 |
+ ret := map[*graph.Image]graph.Archive{} |
|
476 |
+ |
|
477 |
+ fmt.Printf("Json string2: {%s}\n", src) |
|
478 |
+ dec := json.NewDecoder(strings.NewReader(strings.Replace(string(src), "null", "\"\"", -1))) |
|
479 |
+ for { |
|
480 |
+ m := &graph.Image{} |
|
481 |
+ if err := dec.Decode(m); err == io.EOF { |
|
482 |
+ break |
|
483 |
+ } else if err != nil { |
|
484 |
+ return nil, err |
|
485 |
+ } |
|
486 |
+ ret[m] = nil |
|
487 |
+ } |
|
488 |
+ return ret, nil |
|
489 |
+} |
|
490 |
+ |
|
491 |
+func getHistory(base_uri, id string) (map[*graph.Image]graph.Archive, error) { |
|
492 |
+ res, err := http.Get(base_uri + id + "/history") |
|
493 |
+ if err != nil { |
|
494 |
+ return nil, fmt.Errorf("Error while getting from the server: %s\n", err) |
|
495 |
+ } |
|
496 |
+ defer res.Body.Close() |
|
497 |
+ |
|
498 |
+ jsonString, err := ioutil.ReadAll(res.Body) |
|
499 |
+ if err != nil { |
|
500 |
+ return nil, fmt.Errorf("Error while reading the http response: %s\n", err) |
|
501 |
+ } |
|
502 |
+ |
|
503 |
+ history, err := newMultipleImgJson(jsonString) |
|
504 |
+ if err != nil { |
|
505 |
+ return nil, fmt.Errorf("Error while parsing the json: %s\n", err) |
|
506 |
+ } |
|
507 |
+ return history, nil |
|
508 |
+} |
|
509 |
+ |
|
510 |
+func getRemoteImage(base_uri, id string) (*graph.Image, graph.Archive, error) { |
|
511 |
+ // Get the Json |
|
512 |
+ res, err := http.Get(base_uri + id + "/json") |
|
513 |
+ if err != nil { |
|
514 |
+ return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err) |
|
515 |
+ } |
|
516 |
+ defer res.Body.Close() |
|
517 |
+ |
|
518 |
+ jsonString, err := ioutil.ReadAll(res.Body) |
|
519 |
+ if err != nil { |
|
520 |
+ return nil, nil, fmt.Errorf("Error while reading the http response: %s\n", err) |
|
521 |
+ } |
|
522 |
+ |
|
523 |
+ img, err := newImgJson(jsonString) |
|
524 |
+ if err != nil { |
|
525 |
+ return nil, nil, fmt.Errorf("Error while parsing the json: %s\n", err) |
|
526 |
+ } |
|
527 |
+ img.Id = id |
|
528 |
+ |
|
529 |
+ // Get the layer |
|
530 |
+ res, err = http.Get(base_uri + id + "/layer") |
|
531 |
+ if err != nil { |
|
532 |
+ return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err) |
|
533 |
+ } |
|
534 |
+ return img, res.Body, nil |
|
535 |
+} |
|
536 |
+ |
|
537 |
+func (srv *Server) CmdPulli(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
538 |
+ cmd := rcli.Subcmd(stdout, "pulli", "[OPTIONS] IMAGE", "Pull an image from the registry") |
|
539 |
+ if err := cmd.Parse(args); err != nil { |
|
540 |
+ return nil |
|
541 |
+ } |
|
542 |
+ if cmd.NArg() == 0 { |
|
543 |
+ cmd.Usage() |
|
544 |
+ return nil |
|
545 |
+ } |
|
546 |
+ |
|
547 |
+ // First, retrieve the history |
|
548 |
+ base_uri := "http://192.168.56.1:5000/v1/images/" |
|
549 |
+ |
|
550 |
+ // Now we have the history, remove the images we already have |
|
551 |
+ history, err := getHistory(base_uri, cmd.Arg(0)) |
|
552 |
+ if err != nil { |
|
553 |
+ return err |
|
554 |
+ } |
|
555 |
+ for j := range history { |
|
556 |
+ if !srv.runtime.graph.Exists(j.Id) { |
|
557 |
+ img, layer, err := getRemoteImage(base_uri, j.Id) |
|
558 |
+ if err != nil { |
|
559 |
+ // FIXME: Keep goging in case of error? |
|
560 |
+ return err |
|
561 |
+ } |
|
562 |
+ if err = srv.runtime.graph.Register(layer, img); err != nil { |
|
563 |
+ return err |
|
564 |
+ } |
|
565 |
+ } |
|
566 |
+ } |
|
567 |
+ return nil |
|
568 |
+} |
|
569 |
+ |
|
403 | 570 |
func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
404 | 571 |
cmd := rcli.Subcmd(stdout, "images", "[OPTIONS] [NAME]", "List images") |
405 | 572 |
//limit := cmd.Int("l", 0, "Only show the N most recent versions of each image") |