forked from play-with-docker/play-with-docker
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
351 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
package provisioner | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net" | ||
"net/http" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/play-with-docker/play-with-docker/config" | ||
"github.com/play-with-docker/play-with-docker/docker" | ||
"github.com/play-with-docker/play-with-docker/pwd/types" | ||
"github.com/play-with-docker/play-with-docker/router" | ||
) | ||
|
||
type DinD struct { | ||
factory docker.FactoryApi | ||
} | ||
|
||
func NewDinD(f docker.FactoryApi) *DinD { | ||
return &DinD{factory: f} | ||
} | ||
|
||
func checkHostnameExists(session *types.Session, hostname string) bool { | ||
containerName := fmt.Sprintf("%s_%s", session.Id[:8], hostname) | ||
exists := false | ||
for _, instance := range session.Instances { | ||
if instance.Name == containerName { | ||
exists = true | ||
break | ||
} | ||
} | ||
return exists | ||
} | ||
|
||
func (d *DinD) InstanceAllowedImages() []string { | ||
return []string{ | ||
config.GetDindImageName(), | ||
"franela/dind:overlay2-dev", | ||
"franela/ucp:2.4.1", | ||
} | ||
} | ||
|
||
func (d *DinD) InstanceNew(session *types.Session, conf types.InstanceConfig) (*types.Instance, error) { | ||
if conf.ImageName == "" { | ||
conf.ImageName = config.GetDindImageName() | ||
} | ||
log.Printf("NewInstance - using image: [%s]\n", conf.ImageName) | ||
if conf.Hostname == "" { | ||
var nodeName string | ||
for i := 1; ; i++ { | ||
nodeName = fmt.Sprintf("node%d", i) | ||
exists := checkHostnameExists(session, nodeName) | ||
if !exists { | ||
break | ||
} | ||
} | ||
conf.Hostname = nodeName | ||
} | ||
containerName := fmt.Sprintf("%s_%s", session.Id[:8], conf.Hostname) | ||
opts := docker.CreateContainerOpts{ | ||
Image: conf.ImageName, | ||
SessionId: session.Id, | ||
PwdIpAddress: session.PwdIpAddress, | ||
ContainerName: containerName, | ||
Hostname: conf.Hostname, | ||
ServerCert: conf.ServerCert, | ||
ServerKey: conf.ServerKey, | ||
CACert: conf.CACert, | ||
Privileged: false, | ||
HostFQDN: conf.Host, | ||
} | ||
|
||
for _, imageName := range d.InstanceAllowedImages() { | ||
if conf.ImageName == imageName { | ||
opts.Privileged = true | ||
break | ||
} | ||
} | ||
|
||
dockerClient, err := d.factory.GetForSession(session.Id) | ||
if err != nil { | ||
return nil, err | ||
} | ||
ip, err := dockerClient.CreateContainer(opts) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
instance := &types.Instance{} | ||
instance.Image = opts.Image | ||
instance.IP = ip | ||
instance.SessionId = session.Id | ||
instance.Name = containerName | ||
instance.Hostname = conf.Hostname | ||
instance.Cert = conf.Cert | ||
instance.Key = conf.Key | ||
instance.ServerCert = conf.ServerCert | ||
instance.ServerKey = conf.ServerKey | ||
instance.CACert = conf.CACert | ||
instance.Session = session | ||
instance.ProxyHost = router.EncodeHost(session.Id, ip, router.HostOpts{}) | ||
instance.SessionHost = session.Host | ||
// For now this condition holds through. In the future we might need a more complex logic. | ||
instance.IsDockerHost = opts.Privileged | ||
|
||
return instance, nil | ||
} | ||
|
||
func (d *DinD) InstanceDelete(session *types.Session, instance *types.Instance) error { | ||
dockerClient, err := d.factory.GetForSession(session.Id) | ||
if err != nil { | ||
return err | ||
} | ||
err = dockerClient.DeleteContainer(instance.Name) | ||
if err != nil && !strings.Contains(err.Error(), "No such container") { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (d *DinD) InstanceResizeTerminal(instance *types.Instance, rows, cols uint) error { | ||
dockerClient, err := d.factory.GetForSession(instance.SessionId) | ||
if err != nil { | ||
return err | ||
} | ||
return dockerClient.ContainerResize(instance.Name, rows, cols) | ||
} | ||
|
||
func (d *DinD) InstanceGetTerminal(instance *types.Instance) (net.Conn, error) { | ||
dockerClient, err := d.factory.GetForSession(instance.SessionId) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return dockerClient.CreateAttachConnection(instance.Name) | ||
} | ||
|
||
func (d *DinD) InstanceUploadFromUrl(instance *types.Instance, fileName, dest, url string) error { | ||
log.Printf("Downloading file [%s]\n", url) | ||
resp, err := http.Get(url) | ||
if err != nil { | ||
return fmt.Errorf("Could not download file [%s]. Error: %s\n", url, err) | ||
} | ||
defer resp.Body.Close() | ||
if resp.StatusCode != 200 { | ||
return fmt.Errorf("Could not download file [%s]. Status code: %d\n", url, resp.StatusCode) | ||
} | ||
dockerClient, err := d.factory.GetForSession(instance.SessionId) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
copyErr := dockerClient.CopyToContainer(instance.Name, dest, fileName, resp.Body) | ||
|
||
if copyErr != nil { | ||
return fmt.Errorf("Error while downloading file [%s]. Error: %s\n", url, copyErr) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (d *DinD) getInstanceCWD(instance *types.Instance) (string, error) { | ||
dockerClient, err := d.factory.GetForSession(instance.SessionId) | ||
if err != nil { | ||
return "", err | ||
} | ||
b := bytes.NewBufferString("") | ||
|
||
if c, err := dockerClient.ExecAttach(instance.Name, []string{"bash", "-c", `pwdx $(</var/run/cwd)`}, b); c > 0 { | ||
return "", fmt.Errorf("Error %d trying to get CWD", c) | ||
} else if err != nil { | ||
return "", err | ||
} | ||
|
||
cwd := strings.TrimSpace(strings.Split(b.String(), ":")[1]) | ||
|
||
return cwd, nil | ||
} | ||
|
||
func (d *DinD) InstanceUploadFromReader(instance *types.Instance, fileName, dest string, reader io.Reader) error { | ||
dockerClient, err := d.factory.GetForSession(instance.SessionId) | ||
if err != nil { | ||
return err | ||
} | ||
var finalDest string | ||
if filepath.IsAbs(dest) { | ||
finalDest = dest | ||
} else { | ||
if cwd, err := d.getInstanceCWD(instance); err != nil { | ||
return err | ||
} else { | ||
finalDest = fmt.Sprintf("%s/%s", cwd, dest) | ||
} | ||
} | ||
|
||
copyErr := dockerClient.CopyToContainer(instance.Name, finalDest, fileName, reader) | ||
|
||
if copyErr != nil { | ||
return fmt.Errorf("Error while uploading file [%s]. Error: %s\n", fileName, copyErr) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package provisioner | ||
|
||
import ( | ||
"io" | ||
"net" | ||
|
||
"github.com/play-with-docker/play-with-docker/pwd/types" | ||
) | ||
|
||
type ProvisionerApi interface { | ||
InstanceNew(session *types.Session, conf types.InstanceConfig) (*types.Instance, error) | ||
InstanceDelete(session *types.Session, instance *types.Instance) error | ||
|
||
InstanceResizeTerminal(instance *types.Instance, cols, rows uint) error | ||
InstanceGetTerminal(instance *types.Instance) (net.Conn, error) | ||
|
||
InstanceUploadFromUrl(instance *types.Instance, fileName, dest, url string) error | ||
InstanceUploadFromReader(instance *types.Instance, fileName, dest string, reader io.Reader) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package provisioner | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"net" | ||
|
||
"github.com/play-with-docker/play-with-docker/docker" | ||
"github.com/play-with-docker/play-with-docker/pwd/types" | ||
) | ||
|
||
type windows struct { | ||
factory docker.FactoryApi | ||
} | ||
|
||
func NewWindows(f docker.FactoryApi) *windows { | ||
return &windows{factory: f} | ||
} | ||
|
||
func (d *windows) InstanceNew(session *types.Session, conf types.InstanceConfig) (*types.Instance, error) { | ||
return nil, fmt.Errorf("Not implemented") | ||
} | ||
|
||
func (d *windows) InstanceDelete(session *types.Session, instance *types.Instance) error { | ||
return fmt.Errorf("Not implemented") | ||
} | ||
|
||
func (d *windows) InstanceResizeTerminal(instance *types.Instance, cols, rows uint) error { | ||
return fmt.Errorf("Not implemented") | ||
} | ||
|
||
func (d *windows) InstanceGetTerminal(instance *types.Instance) (net.Conn, error) { | ||
return nil, fmt.Errorf("Not implemented") | ||
} | ||
|
||
func (d *windows) InstanceUploadFromUrl(instance *types.Instance, fileName, dest, url string) error { | ||
return fmt.Errorf("Not implemented") | ||
} | ||
|
||
func (d *windows) InstanceUploadFromReader(instance *types.Instance, fileName, dest string, reader io.Reader) error { | ||
return fmt.Errorf("Not implemented") | ||
} |
Oops, something went wrong.