@@ -18,6 +18,7 @@ package hyper
18
18
19
19
import (
20
20
"bytes"
21
+ "crypto/rand"
21
22
"encoding/json"
22
23
"errors"
23
24
"fmt"
@@ -31,6 +32,7 @@ import (
31
32
"strings"
32
33
33
34
"github.com/docker/docker/pkg/parsers"
35
+ "github.com/docker/docker/pkg/term"
34
36
"github.com/golang/glog"
35
37
"time"
36
38
)
@@ -94,6 +96,7 @@ type AttachToContainerOptions struct {
94
96
InputStream io.Reader
95
97
OutputStream io.Writer
96
98
ErrorStream io.Writer
99
+ TTY bool
97
100
}
98
101
99
102
type ContainerLogsOptions struct {
@@ -107,11 +110,21 @@ type ContainerLogsOptions struct {
107
110
TailLines int64
108
111
}
109
112
113
+ type ExecInContainerOptions struct {
114
+ Container string
115
+ InputStream io.Reader
116
+ OutputStream io.Writer
117
+ ErrorStream io.Writer
118
+ Commands []string
119
+ TTY bool
120
+ }
121
+
110
122
type hijackOptions struct {
111
123
in io.Reader
112
124
stdout io.Writer
113
125
stderr io.Writer
114
126
data interface {}
127
+ tty bool
115
128
}
116
129
117
130
func NewHyperClient () * HyperClient {
@@ -527,6 +540,40 @@ func (client *HyperClient) CreatePod(podArgs string) (map[string]interface{}, er
527
540
return result , nil
528
541
}
529
542
543
+ func (c * HyperClient ) GetExitCode (container , tag string ) error {
544
+ v := url.Values {}
545
+ v .Set ("container" , container )
546
+ v .Set ("tag" , tag )
547
+ code := - 1
548
+
549
+ body , _ , err := c .call ("GET" , "/exitcode?" + v .Encode (), "" , nil )
550
+ if err != nil {
551
+ return err
552
+ }
553
+
554
+ err = json .Unmarshal (body , & code )
555
+ if err != nil {
556
+ return err
557
+ }
558
+
559
+ if code != 0 {
560
+ return fmt .Errorf ("Exit code %d" , code )
561
+ }
562
+
563
+ return nil
564
+ }
565
+
566
+ func (c * HyperClient ) GetTag () string {
567
+ dictionary := "0123456789abcdefghijklmnopqrstuvwxyz"
568
+
569
+ var bytes = make ([]byte , 8 )
570
+ rand .Read (bytes )
571
+ for k , v := range bytes {
572
+ bytes [k ] = dictionary [v % byte (len (dictionary ))]
573
+ }
574
+ return string (bytes )
575
+ }
576
+
530
577
func (c * HyperClient ) hijack (method , path string , hijackOptions hijackOptions ) error {
531
578
var params io.Reader
532
579
if hijackOptions .data != nil {
@@ -537,12 +584,18 @@ func (c *HyperClient) hijack(method, path string, hijackOptions hijackOptions) e
537
584
params = bytes .NewBuffer (buf )
538
585
}
539
586
540
- if hijackOptions .stdout == nil {
541
- hijackOptions .stdout = ioutil .Discard
542
- }
543
- if hijackOptions .stderr == nil {
544
- hijackOptions .stderr = ioutil .Discard
587
+ if hijackOptions .tty {
588
+ in , isTerm := term .GetFdInfo (hijackOptions .in )
589
+ if isTerm {
590
+ state , err := term .SetRawTerminal (in )
591
+ if err != nil {
592
+ return err
593
+ }
594
+
595
+ defer term .RestoreTerminal (in , state )
596
+ }
545
597
}
598
+
546
599
req , err := http .NewRequest (method , fmt .Sprintf ("/v%s%s" , HYPER_MINVERSION , path ), params )
547
600
if err != nil {
548
601
return err
@@ -571,9 +624,22 @@ func (c *HyperClient) hijack(method, path string, hijackOptions hijackOptions) e
571
624
errChanIn := make (chan error , 1 )
572
625
exit := make (chan bool )
573
626
627
+ if hijackOptions .stdout == nil && hijackOptions .stderr == nil {
628
+ close (errChanOut )
629
+ }
630
+ if hijackOptions .stdout == nil {
631
+ hijackOptions .stdout = ioutil .Discard
632
+ }
633
+ if hijackOptions .stderr == nil {
634
+ hijackOptions .stderr = ioutil .Discard
635
+ }
636
+
574
637
go func () {
575
- defer close (exit )
576
- defer close (errChanOut )
638
+ defer func () {
639
+ close (errChanOut )
640
+ close (exit )
641
+ }()
642
+
577
643
_ , err := io .Copy (hijackOptions .stdout , br )
578
644
errChanOut <- err
579
645
}()
@@ -584,11 +650,11 @@ func (c *HyperClient) hijack(method, path string, hijackOptions hijackOptions) e
584
650
if hijackOptions .in != nil {
585
651
_ , err := io .Copy (rwc , hijackOptions .in )
586
652
errChanIn <- err
587
- }
588
653
589
- rwc .(interface {
590
- CloseWrite () error
591
- }).CloseWrite ()
654
+ rwc .(interface {
655
+ CloseWrite () error
656
+ }).CloseWrite ()
657
+ }
592
658
}()
593
659
594
660
<- exit
@@ -598,22 +664,63 @@ func (c *HyperClient) hijack(method, path string, hijackOptions hijackOptions) e
598
664
case err = <- errChanOut :
599
665
return err
600
666
}
667
+
668
+ return nil
601
669
}
602
670
603
671
func (client * HyperClient ) Attach (opts AttachToContainerOptions ) error {
604
672
if opts .Container == "" {
605
673
return fmt .Errorf ("No Such Container %s" , opts .Container )
606
674
}
607
675
676
+ tag := client .GetTag ()
608
677
v := url.Values {}
609
678
v .Set (KEY_TYPE , TYPE_CONTAINER )
610
679
v .Set (KEY_VALUE , opts .Container )
680
+ v .Set ("tag" , tag )
611
681
path := "/attach?" + v .Encode ()
612
- return client .hijack ("POST" , path , hijackOptions {
682
+ err := client .hijack ("POST" , path , hijackOptions {
683
+ in : opts .InputStream ,
684
+ stdout : opts .OutputStream ,
685
+ stderr : opts .ErrorStream ,
686
+ tty : opts .TTY ,
687
+ })
688
+
689
+ if err != nil {
690
+ return err
691
+ }
692
+
693
+ return client .GetExitCode (opts .Container , tag )
694
+ }
695
+
696
+ func (client * HyperClient ) Exec (opts ExecInContainerOptions ) error {
697
+ if opts .Container == "" {
698
+ return fmt .Errorf ("No Such Container %s" , opts .Container )
699
+ }
700
+
701
+ command , err := json .Marshal (opts .Commands )
702
+ if err != nil {
703
+ return err
704
+ }
705
+
706
+ v := url.Values {}
707
+ tag := client .GetTag ()
708
+ v .Set (KEY_TYPE , TYPE_CONTAINER )
709
+ v .Set (KEY_VALUE , opts .Container )
710
+ v .Set ("tag" , tag )
711
+ v .Set ("command" , string (command ))
712
+ path := "/exec?" + v .Encode ()
713
+ err = client .hijack ("POST" , path , hijackOptions {
613
714
in : opts .InputStream ,
614
715
stdout : opts .OutputStream ,
615
716
stderr : opts .ErrorStream ,
717
+ tty : opts .TTY ,
616
718
})
719
+ if err != nil {
720
+ return err
721
+ }
722
+
723
+ return client .GetExitCode (opts .Container , tag )
617
724
}
618
725
619
726
func (client * HyperClient ) ContainerLogs (opts ContainerLogsOptions ) error {
0 commit comments