From 9e27b2495f9315419b21661028c3dd21bd83220a Mon Sep 17 00:00:00 2001 From: Nate Jones Date: Fri, 30 Dec 2016 22:54:19 -0800 Subject: [PATCH 1/7] initial work at volume based homedir --- api.go | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- build.go | 7 ++++++- create.go | 22 ++++++++++++---------- docker.go | 34 ++++++++++++++++++++++++++++++++++ rebuild.go | 18 ++++++++++-------- 5 files changed, 112 insertions(+), 20 deletions(-) diff --git a/api.go b/api.go index dc39c9a..c2eb093 100644 --- a/api.go +++ b/api.go @@ -54,6 +54,7 @@ type CreateOpts struct { Volumes []string ProjectDir string ForceBuild bool + DockerVolume bool Build BuildOpts } @@ -125,6 +126,23 @@ func DestroyEnvironment(dc DockerClient, sc SystemClient, envName string) error return err } + volumeName := fmt.Sprintf("%s_%s_%s", CONT_PREFIX, sc.Username(), envName) + logrus.Debugf("removing docker volume (%s), if it exists", volumeName) + + vols, err := dc.ListVolumes() + if err != nil { + return err + } + + for _, vol := range vols { + if vol.Name == volumeName { + err = dc.RemoveVolume(volumeName) + if err != nil { + return err + } + } + } + return nil } @@ -181,6 +199,8 @@ func RebuildEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output } } + // TODO: look at skeg.io/container/docker_volume to see if DockerVolume needs to be set + // fmt.Println(co) logrus.Debugf("Stopping environment") @@ -245,10 +265,38 @@ func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output * return err } + labels := make(map[string]string) + homeDir := fmt.Sprintf("/home/%s", sc.Username()) logrus.Debugf("Creating container") volumes := co.Volumes - volumes = append(volumes, fmt.Sprintf("%s:%s", path, homeDir)) + if co.DockerVolume { + volumeName := fmt.Sprintf("%s_%s_%s", CONT_PREFIX, sc.Username(), co.Name) + + // check for existence of volume + vols, err := dc.ListVolumes() + if err != nil { + return err + } + + volumeFound := false + for _, vol := range vols { + if vol.Name == volumeName { + volumeFound = true + } + } + + if !volumeFound { + dc.CreateVolume(CreateVolumeOpts{Name: volumeName, Labels: map[string]string{"skeg": "true"}}) + if err != nil { + return err + } + } + volumes = append(volumes, fmt.Sprintf("%s:%s", volumeName, homeDir)) + } else { + volumes = append(volumes, fmt.Sprintf("%s:%s", path, homeDir)) + } + labels["skeg.io/container/docker_volume"] = fmt.Sprintf("%v", co.DockerVolume) workdirParts := strings.Split(co.ProjectDir, string(os.PathSeparator)) if len(co.ProjectDir) > 0 { volumes = append(volumes, fmt.Sprintf("%s:%s/%s", co.ProjectDir, homeDir, workdirParts[len(workdirParts)-1])) @@ -276,6 +324,7 @@ func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output * Hostname: co.Name, Ports: ports, Volumes: volumes, + Labels: labels, } err = dc.CreateContainer(ccont) if err != nil { diff --git a/build.go b/build.go index fafabb8..b8b923b 100644 --- a/build.go +++ b/build.go @@ -41,7 +41,12 @@ func (x *BuildCommand) Execute(args []string) error { return err } - image, err := BuildImage(dc, sc, buildCommand.toBuildOpts(sc), os.Stdout) + key, err := sc.EnsureSSHKey() + if err != nil { + return err + } + + image, err := BuildImage(dc, sc, key, buildCommand.toBuildOpts(sc), os.Stdout) if err != nil { return err } diff --git a/create.go b/create.go index a8d8780..1f3d6d2 100644 --- a/create.go +++ b/create.go @@ -7,11 +7,12 @@ import ( type CreateCommand struct { BuildCommand - Directory string `short:"d" long:"directory" description:"Directory to mount inside (defaults to $PWD)."` - Ports []string `short:"p" long:"port" description:"Ports to expose (similar to docker -p)."` - Volumes []string `long:"volume" description:"Volume to mount (similar to docker -v)."` - ForceBuild bool `long:"force-build" description:"Force building of new user image."` - Args struct { + Directory string `short:"d" long:"directory" description:"Directory to mount inside (defaults to $PWD)."` + Ports []string `short:"p" long:"port" description:"Ports to expose (similar to docker -p)."` + Volumes []string `long:"volume" description:"Volume to mount (similar to docker -v)."` + ForceBuild bool `long:"force-build" description:"Force building of new user image."` + DockerVolume bool `long:"docker-volume" description:"Use docker volume for homedir instead of skeg dir"` + Args struct { Name string `description:"Name of environment."` } `positional-args:"yes" required:"yes"` } @@ -24,11 +25,12 @@ func (ccommand *CreateCommand) toCreateOpts(sc SystemClient, workingDir string) projectDir = workingDir } return CreateOpts{ - Name: ccommand.Args.Name, - ProjectDir: projectDir, - Ports: ccommand.Ports, - Volumes: ccommand.Volumes, - ForceBuild: ccommand.ForceBuild || ccommand.ForcePull, + Name: ccommand.Args.Name, + ProjectDir: projectDir, + Ports: ccommand.Ports, + Volumes: ccommand.Volumes, + DockerVolume: ccommand.DockerVolume, + ForceBuild: ccommand.ForceBuild || ccommand.ForcePull, Build: BuildOpts{ Image: ImageOpts{ Type: ccommand.Type, diff --git a/docker.go b/docker.go index 827d27c..f23def2 100644 --- a/docker.go +++ b/docker.go @@ -45,6 +45,12 @@ type CreateContainerOpts struct { Ports []Port Volumes []string Image string + Labels map[string]string +} + +type CreateVolumeOpts struct { + Name string + Labels map[string]string } type DockerClient interface { @@ -60,6 +66,9 @@ type DockerClient interface { StopContainer(name string) error RemoveContainer(name string) error ParseRepositoryTag(repoTag string) (string, string) + ListVolumes() ([]docker.Volume, error) + CreateVolume(CreateVolumeOpts) error + RemoveVolume(string) error } type RealDockerClient struct { @@ -111,6 +120,7 @@ func (rdc *RealDockerClient) CreateContainer(cco CreateContainerOpts) error { ExposedPorts: exposedPorts, Image: cco.Image, Hostname: cco.Hostname, + Labels: cco.Labels, } hostConfig := docker.HostConfig{ Binds: cco.Volumes, @@ -125,6 +135,30 @@ func (rdc *RealDockerClient) CreateContainer(cco CreateContainerOpts) error { return nil } +func (rdc *RealDockerClient) CreateVolume(cvo CreateVolumeOpts) error { + _, err := rdc.dcl.CreateVolume(docker.CreateVolumeOptions{Name: cvo.Name, Labels: cvo.Labels}) + if err != nil { + return err + } + + return nil +} + +func (rdc *RealDockerClient) ListVolumes() ([]docker.Volume, error) { + var volumes []docker.Volume + + volumes, err := rdc.dcl.ListVolumes(docker.ListVolumesOptions{}) + if err != nil { + return volumes, err + } + + return volumes, nil +} + +func (rdc *RealDockerClient) RemoveVolume(name string) error { + return rdc.dcl.RemoveVolume(name) +} + func (rdc *RealDockerClient) BuildImage(name string, dockerfile string, output io.Writer) error { length := len(dockerfile) diff --git a/rebuild.go b/rebuild.go index 88d6d0c..f2da8d4 100644 --- a/rebuild.go +++ b/rebuild.go @@ -7,20 +7,22 @@ import ( type RebuildCommand struct { BuildCommand - Ports []string `short:"p" long:"port" description:"Ports to expose (similar to docker -p)."` - Volumes []string `long:"volume" description:"Volume to mount (similar to docker -v)."` - ForceBuild bool `long:"force-build" description:"Force building of new user image."` - Args struct { + Ports []string `short:"p" long:"port" description:"Ports to expose (similar to docker -p)."` + Volumes []string `long:"volume" description:"Volume to mount (similar to docker -v)."` + DockerVolume bool `long:"docker-volume" description:"Use docker volume for homedir instead of skeg dir"` + ForceBuild bool `long:"force-build" description:"Force building of new user image."` + Args struct { Name string `description:"Name of environment."` } `positional-args:"yes" required:"yes"` } func (ccommand *RebuildCommand) toCreateOpts(sc SystemClient) CreateOpts { return CreateOpts{ - Name: ccommand.Args.Name, - Ports: ccommand.Ports, - Volumes: ccommand.Volumes, - ForceBuild: ccommand.ForceBuild || ccommand.ForcePull, + Name: ccommand.Args.Name, + Ports: ccommand.Ports, + Volumes: ccommand.Volumes, + DockerVolume: ccommand.DockerVolume, + ForceBuild: ccommand.ForceBuild || ccommand.ForcePull, Build: BuildOpts{ Image: ImageOpts{ Type: ccommand.Type, From 7b08e283e722bc483d47053cfcbfcf123429c824 Mon Sep 17 00:00:00 2001 From: Nate Jones Date: Fri, 30 Dec 2016 22:55:46 -0800 Subject: [PATCH 2/7] move ssh key out of homedir --- api.go | 22 +++++++++++++++++----- docker.go | 9 +++++---- system.go | 20 ++------------------ 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/api.go b/api.go index c2eb093..5657e45 100644 --- a/api.go +++ b/api.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "io/ioutil" "os" "regexp" "sort" @@ -250,7 +251,7 @@ func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output * } logrus.Debugf("Building customized docker image") - imageName, err = BuildImage(dc, sc, co.Build, output) + imageName, err = BuildImage(dc, sc, key, co.Build, output) if err != nil { return err } @@ -260,7 +261,7 @@ func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output * } logrus.Debugf("Preparing local environment directory") - path, err := sc.EnsureEnvironmentDir(co.Name, key) + path, err := sc.EnsureEnvironmentDir(co.Name) if err != nil { return err } @@ -436,7 +437,7 @@ func ResolveImage(dc DockerClient, io ImageOpts) (string, error) { return image, nil } -func BuildImage(dc DockerClient, sc SystemClient, bo BuildOpts, output *os.File) (string, error) { +func BuildImage(dc DockerClient, sc SystemClient, key SSHKey, bo BuildOpts, output *os.File) (string, error) { var err error logrus.Debugf("Figuring out which image to use") image, err := ResolveImage(dc, bo.Image) @@ -462,7 +463,12 @@ func BuildImage(dc DockerClient, sc SystemClient, bo BuildOpts, output *os.File) RUN (addgroup --gid {{ .Gid }} {{ .Username }} || /bin/true) && \ adduser --uid {{ .Uid }} --gid {{ .Gid }} {{ .Username }} --gecos "" --disabled-password && \ - echo "{{ .Username }} ALL=NOPASSWD: ALL" >> /etc/sudoers + echo "{{ .Username }} ALL=NOPASSWD: ALL" >> /etc/sudoers && \ + echo "AuthorizedKeysFile /etc/ssh/keys/authorized_keys" >> /etc/ssh/sshd_config + +COPY ssh_pub /etc/ssh/keys/authorized_keys +RUN chown -R {{ .Gid }}:{{ .Uid }} /etc/ssh/keys && \ + chmod 600 /etc/ssh/keys/authorized_keys {{ .TzSet }} @@ -496,7 +502,13 @@ LABEL skeg.io/image/username={{ .Username }} \ } imageName := fmt.Sprintf("%s-%s-%s", CONT_PREFIX, bo.Username, now.Format("20060102150405")) - err = dc.BuildImage(imageName, dockerfileBytes.String(), output) + + data, err := ioutil.ReadFile(key.publicPath) + if err != nil { + return "", err + } + + err = dc.BuildImage(imageName, dockerfileBytes.String(), string(data), output) if err != nil { return "", err diff --git a/docker.go b/docker.go index f23def2..76bb4a5 100644 --- a/docker.go +++ b/docker.go @@ -60,7 +60,7 @@ type DockerClient interface { ListImages() ([]docker.APIImages, error) ListImagesWithLabels(labels []string) ([]docker.APIImages, error) PullImage(image string, output *os.File) error - BuildImage(name string, dockerfile string, output io.Writer) error + BuildImage(name string, dockerfile string, sshkey string, output io.Writer) error CreateContainer(cco CreateContainerOpts) error StartContainer(name string) error StopContainer(name string) error @@ -159,14 +159,15 @@ func (rdc *RealDockerClient) RemoveVolume(name string) error { return rdc.dcl.RemoveVolume(name) } -func (rdc *RealDockerClient) BuildImage(name string, dockerfile string, output io.Writer) error { - length := len(dockerfile) +func (rdc *RealDockerClient) BuildImage(name string, dockerfile, sshkey string, output io.Writer) error { t := time.Now() inputbuf := bytes.NewBuffer(nil) tr := tar.NewWriter(inputbuf) - tr.WriteHeader(&tar.Header{Name: "Dockerfile", Size: int64(length), ModTime: t, AccessTime: t, ChangeTime: t}) + tr.WriteHeader(&tar.Header{Name: "Dockerfile", Size: int64(len(dockerfile)), ModTime: t, AccessTime: t, ChangeTime: t}) tr.Write([]byte(dockerfile)) + tr.WriteHeader(&tar.Header{Name: "ssh_pub", Size: int64(len(sshkey)), ModTime: t, AccessTime: t, ChangeTime: t}) + tr.Write([]byte(sshkey)) tr.Close() opts := docker.BuildImageOptions{ diff --git a/system.go b/system.go index 693428b..db7c8e4 100644 --- a/system.go +++ b/system.go @@ -20,7 +20,7 @@ import ( type SystemClient interface { EnvironmentDirs() ([]string, error) DetectTimeZone() string - EnsureEnvironmentDir(envName string, keys SSHKey) (string, error) + EnsureEnvironmentDir(envName string) (string, error) RemoveEnvironmentDir(envName string) error EnsureSSHKey() (SSHKey, error) Username() string @@ -87,7 +87,7 @@ func (rsc *RealSystemClient) GID() int { return rsc.gid } -func (rsc *RealSystemClient) EnsureEnvironmentDir(envName string, keys SSHKey) (string, error) { +func (rsc *RealSystemClient) EnsureEnvironmentDir(envName string) (string, error) { envPath := filepath.Join(rsc.baseDir, envName) err := os.MkdirAll(envPath, 0755) @@ -95,22 +95,6 @@ func (rsc *RealSystemClient) EnsureEnvironmentDir(envName string, keys SSHKey) ( return "", err } - sshPath := filepath.Join(envPath, ".ssh") - err = os.MkdirAll(sshPath, 0700) - if err != nil { - return "", err - } - - akPath := filepath.Join(sshPath, "authorized_keys") - data, err := ioutil.ReadFile(keys.publicPath) - if err != nil { - return "", err - } - err = ioutil.WriteFile(akPath, data, 0700) - if err != nil { - return "", err - } - return envPath, nil } From e3b682b713c0898be1a8f76790ab179c4e1352b5 Mon Sep 17 00:00:00 2001 From: Nate Jones Date: Sat, 31 Dec 2016 20:31:31 +0000 Subject: [PATCH 3/7] detect docker volume homedir in rebuild and remove docker volume homedir option from rebuild cli --- api.go | 4 +++- rebuild.go | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api.go b/api.go index 5657e45..dae150d 100644 --- a/api.go +++ b/api.go @@ -200,7 +200,9 @@ func RebuildEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output } } - // TODO: look at skeg.io/container/docker_volume to see if DockerVolume needs to be set + if dockerVolume, ok := env.Container.Labels["skeg.io/container/docker_volume"]; ok { + co.DockerVolume = (dockerVolume == "true") + } // fmt.Println(co) diff --git a/rebuild.go b/rebuild.go index f2da8d4..2f17355 100644 --- a/rebuild.go +++ b/rebuild.go @@ -9,7 +9,6 @@ type RebuildCommand struct { BuildCommand Ports []string `short:"p" long:"port" description:"Ports to expose (similar to docker -p)."` Volumes []string `long:"volume" description:"Volume to mount (similar to docker -v)."` - DockerVolume bool `long:"docker-volume" description:"Use docker volume for homedir instead of skeg dir"` ForceBuild bool `long:"force-build" description:"Force building of new user image."` Args struct { Name string `description:"Name of environment."` @@ -21,7 +20,6 @@ func (ccommand *RebuildCommand) toCreateOpts(sc SystemClient) CreateOpts { Name: ccommand.Args.Name, Ports: ccommand.Ports, Volumes: ccommand.Volumes, - DockerVolume: ccommand.DockerVolume, ForceBuild: ccommand.ForceBuild || ccommand.ForcePull, Build: BuildOpts{ Image: ImageOpts{ From f815019762b536e25f960acfcf57f46747a4f586 Mon Sep 17 00:00:00 2001 From: Nate Jones Date: Sat, 31 Dec 2016 13:10:13 -0800 Subject: [PATCH 4/7] force image rebuild if image capabilities change --- api.go | 16 ++++++++++++---- constants.go | 14 ++++++++++++++ images.go | 2 +- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/api.go b/api.go index dae150d..2cfa2eb 100644 --- a/api.go +++ b/api.go @@ -28,6 +28,7 @@ type UserImage struct { Name string EnvCount int Labels map[string]string + Version int } type BaseImage struct { @@ -240,7 +241,7 @@ func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output * var imageName string userImages, err := UserImages(dc, sc, co.Build.Image) - if co.ForceBuild || len(userImages) == 0 { + if co.ForceBuild || len(userImages) == 0 || (len(userImages) > 0 && userImages[0].Version < IMAGE_VERSION) { // TODO: consider whether this is the best default (new image inherits // previous image's time zone) @@ -479,7 +480,8 @@ LABEL skeg.io/image/username={{ .Username }} \ skeg.io/image/uid={{ .Uid }} \ skeg.io/image/base={{ .Image }} \ skeg.io/image/buildtime="{{ .Time }}" \ - skeg.io/image/timezone="{{ .Tz }}" + skeg.io/image/timezone="{{ .Tz }}" \ + skeg.io/image/version="{{ .Version }}" ` // TODO: make timezone setting work on other distributions @@ -490,9 +492,9 @@ LABEL skeg.io/image/username={{ .Username }} \ dockerfileData := struct { Username, Image, Time, TzSet, Tz string - Uid, Gid int + Uid, Gid, Version int }{ - bo.Username, image, now.Format(time.UnixDate), tzenv, bo.TimeZone, bo.UID, bo.GID, + bo.Username, image, now.Format(time.UnixDate), tzenv, bo.TimeZone, bo.UID, bo.GID, IMAGE_VERSION, } tmpl := template.Must(template.New("dockerfile").Parse(dockerfileTmpl)) @@ -559,11 +561,17 @@ func UserImages(dc DockerClient, sc SystemClient, io ImageOpts) ([]UserImage, er for _, dockerImage := range dockerImages { tags := dockerImage.RepoTags + imageVersion := 0 + if ver, ok := dockerImage.Labels["skeg.io/image/version"]; ok { + imageVersion, _ = strconv.Atoi(ver) + } + imageUses, _ := uses[tags[0]] images = append(images, UserImage{ tags[0], imageUses, dockerImage.Labels, + imageVersion, }) } diff --git a/constants.go b/constants.go index e182a18..5711f1e 100644 --- a/constants.go +++ b/constants.go @@ -1,5 +1,19 @@ package main +// CONT_PREFIX is the prefix string used for containers, images, and volumes. const CONT_PREFIX string = "skeg" + +// DOCKER_HUB_ORG is the name of the organization on Docker Hub where +// predefined images can be found. const DOCKER_HUB_ORG string = "skegio" + +// ENVS_DIR is the directory in the user's homedir where data is created const ENVS_DIR string = "skegs" + +// IMAGE_VERSION defines image capabilities as defined by the BuildImage +// function. When new capabilities are added to images, this number should be +// incremented to force building a new user image on environment creation. +// +// version 0: user/tz creation +// version 1: ssh key inclusion +const IMAGE_VERSION int = 1 diff --git a/images.go b/images.go index 462c08f..326433a 100644 --- a/images.go +++ b/images.go @@ -63,7 +63,7 @@ func listImages(images []*BaseImage) error { func listUserImages(images []UserImage) error { for _, im := range images { - fmt.Printf("%s (%d envs)\n", im.Name, im.EnvCount) + fmt.Printf("%s (ver: %d) (%d envs)\n", im.Name, im.Version, im.EnvCount) fmt.Printf(" build time: %s\n", im.Labels["skeg.io/image/buildtime"]) fmt.Printf(" time zone: %s\n", im.Labels["skeg.io/image/timezone"]) } From 9aedbdedf77862677d45e94b571f839df2ca63db Mon Sep 17 00:00:00 2001 From: Nate Jones Date: Sat, 31 Dec 2016 13:29:05 -0800 Subject: [PATCH 5/7] change option to volume-home --- api.go | 10 +++++----- create.go | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/api.go b/api.go index 2cfa2eb..cd25c29 100644 --- a/api.go +++ b/api.go @@ -56,7 +56,7 @@ type CreateOpts struct { Volumes []string ProjectDir string ForceBuild bool - DockerVolume bool + VolumeHome bool Build BuildOpts } @@ -201,8 +201,8 @@ func RebuildEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output } } - if dockerVolume, ok := env.Container.Labels["skeg.io/container/docker_volume"]; ok { - co.DockerVolume = (dockerVolume == "true") + if volumeHome, ok := env.Container.Labels["skeg.io/container/volume_home"]; ok { + co.VolumeHome = (volumeHome == "true") } // fmt.Println(co) @@ -274,7 +274,7 @@ func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output * homeDir := fmt.Sprintf("/home/%s", sc.Username()) logrus.Debugf("Creating container") volumes := co.Volumes - if co.DockerVolume { + if co.VolumeHome { volumeName := fmt.Sprintf("%s_%s_%s", CONT_PREFIX, sc.Username(), co.Name) // check for existence of volume @@ -300,7 +300,7 @@ func CreateEnvironment(dc DockerClient, sc SystemClient, co CreateOpts, output * } else { volumes = append(volumes, fmt.Sprintf("%s:%s", path, homeDir)) } - labels["skeg.io/container/docker_volume"] = fmt.Sprintf("%v", co.DockerVolume) + labels["skeg.io/container/volume_home"] = fmt.Sprintf("%v", co.VolumeHome) workdirParts := strings.Split(co.ProjectDir, string(os.PathSeparator)) if len(co.ProjectDir) > 0 { volumes = append(volumes, fmt.Sprintf("%s:%s/%s", co.ProjectDir, homeDir, workdirParts[len(workdirParts)-1])) diff --git a/create.go b/create.go index 1f3d6d2..e9b9abb 100644 --- a/create.go +++ b/create.go @@ -7,12 +7,12 @@ import ( type CreateCommand struct { BuildCommand - Directory string `short:"d" long:"directory" description:"Directory to mount inside (defaults to $PWD)."` - Ports []string `short:"p" long:"port" description:"Ports to expose (similar to docker -p)."` - Volumes []string `long:"volume" description:"Volume to mount (similar to docker -v)."` - ForceBuild bool `long:"force-build" description:"Force building of new user image."` - DockerVolume bool `long:"docker-volume" description:"Use docker volume for homedir instead of skeg dir"` - Args struct { + Directory string `short:"d" long:"directory" description:"Directory to mount inside (defaults to $PWD)."` + Ports []string `short:"p" long:"port" description:"Ports to expose (similar to docker -p)."` + Volumes []string `long:"volume" description:"Volume to mount (similar to docker -v)."` + ForceBuild bool `long:"force-build" description:"Force building of new user image."` + VolumeHome bool `long:"volume-home" description:"Use docker volume for homedir instead of skeg dir"` + Args struct { Name string `description:"Name of environment."` } `positional-args:"yes" required:"yes"` } @@ -25,12 +25,12 @@ func (ccommand *CreateCommand) toCreateOpts(sc SystemClient, workingDir string) projectDir = workingDir } return CreateOpts{ - Name: ccommand.Args.Name, - ProjectDir: projectDir, - Ports: ccommand.Ports, - Volumes: ccommand.Volumes, - DockerVolume: ccommand.DockerVolume, - ForceBuild: ccommand.ForceBuild || ccommand.ForcePull, + Name: ccommand.Args.Name, + ProjectDir: projectDir, + Ports: ccommand.Ports, + Volumes: ccommand.Volumes, + VolumeHome: ccommand.VolumeHome, + ForceBuild: ccommand.ForceBuild || ccommand.ForcePull, Build: BuildOpts{ Image: ImageOpts{ Type: ccommand.Type, From 73f29fe6da74f7fb760c40214d589c750f6f2f1f Mon Sep 17 00:00:00 2001 From: Nate Jones Date: Tue, 28 Feb 2017 21:33:46 -0800 Subject: [PATCH 6/7] fix uid/gid --- api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.go b/api.go index cd25c29..c2edaef 100644 --- a/api.go +++ b/api.go @@ -470,7 +470,7 @@ RUN (addgroup --gid {{ .Gid }} {{ .Username }} || /bin/true) && \ echo "AuthorizedKeysFile /etc/ssh/keys/authorized_keys" >> /etc/ssh/sshd_config COPY ssh_pub /etc/ssh/keys/authorized_keys -RUN chown -R {{ .Gid }}:{{ .Uid }} /etc/ssh/keys && \ +RUN chown -R {{ .Uid }}:{{ .Gid }} /etc/ssh/keys && \ chmod 600 /etc/ssh/keys/authorized_keys {{ .TzSet }} From 87a93167e50cd032b9189573970a7d069a0dc0cd Mon Sep 17 00:00:00 2001 From: Nate Jones Date: Tue, 28 Feb 2017 21:43:36 -0800 Subject: [PATCH 7/7] get tests back to passing --- api_test.go | 34 +++++++++++++++++++++------------- system_test.go | 18 +----------------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/api_test.go b/api_test.go index fc954a4..b474821 100644 --- a/api_test.go +++ b/api_test.go @@ -81,7 +81,7 @@ func (rdc *TestDockerClient) PullImage(fullImage string, output *os.File) error return nil } -func (rdc *TestDockerClient) BuildImage(name string, dockerfile string, output io.Writer) error { +func (rdc *TestDockerClient) BuildImage(name string, dockerfile string, key string, output io.Writer) error { return nil } @@ -139,6 +139,18 @@ func (rdc *TestDockerClient) AddImage(image docker.APIImages) error { return nil } +func (rdc *TestDockerClient) ListVolumes() ([]docker.Volume, error) { + return []docker.Volume{}, nil +} + +func (rdc *TestDockerClient) CreateVolume(cvo CreateVolumeOpts) error { + return nil +} + +func (rdc *TestDockerClient) RemoveVolume(name string) error { + return nil +} + type TestSystemClient struct { environments []string sshArgs [][]string @@ -168,7 +180,7 @@ func (tsc *TestSystemClient) GID() int { return 1000 } -func (tsc *TestSystemClient) EnsureEnvironmentDir(envName string, keys SSHKey) (string, error) { +func (tsc *TestSystemClient) EnsureEnvironmentDir(envName string) (string, error) { if err, ok := tsc.fails.failures["EnsureEnvironmentDir"]; ok { return envName, err } @@ -228,8 +240,7 @@ func TestEnvironments(t *testing.T) { }, }, ) - key, _ := sc.EnsureSSHKey() - sc.EnsureEnvironmentDir("foo", key) + sc.EnsureEnvironmentDir("foo") var envs map[string]Environment var err error @@ -400,8 +411,7 @@ func TestEnsureStopped(t *testing.T) { }, }, ) - key, _ := sc.EnsureSSHKey() - sc.EnsureEnvironmentDir("foo", key) + sc.EnsureEnvironmentDir("foo") var env Environment var err error @@ -448,8 +458,7 @@ func TestEnsureRunning(t *testing.T) { }, }, ) - key, _ := sc.EnsureSSHKey() - sc.EnsureEnvironmentDir("foo", key) + sc.EnsureEnvironmentDir("foo") var env Environment var err error @@ -477,7 +486,6 @@ func TestConnectEnvironment(t *testing.T) { assert := assert.New(t) sc := NewTestSystemClient() - key, _ := sc.EnsureSSHKey() dc := NewTestDockerClient() dc.AddContainer( @@ -494,7 +502,7 @@ func TestConnectEnvironment(t *testing.T) { }, }, ) - sc.EnsureEnvironmentDir("foo", key) + sc.EnsureEnvironmentDir("foo") dc.AddContainer( docker.APIContainers{ ID: "qux", @@ -507,7 +515,7 @@ func TestConnectEnvironment(t *testing.T) { }, }, ) - sc.EnsureEnvironmentDir("buz", key) + sc.EnsureEnvironmentDir("buz") dc.AddContainer( docker.APIContainers{ ID: "buz", @@ -522,8 +530,8 @@ func TestConnectEnvironment(t *testing.T) { }, }, ) - sc.EnsureEnvironmentDir("qux", key) - sc.EnsureEnvironmentDir("oof", key) + sc.EnsureEnvironmentDir("qux") + sc.EnsureEnvironmentDir("oof") var env Environment var err error diff --git a/system_test.go b/system_test.go index fc2dd8d..2f99611 100644 --- a/system_test.go +++ b/system_test.go @@ -38,23 +38,7 @@ func TestDir(t *testing.T) { sc, _ := NewSystemClientWithBase(base) - key, err := sc.EnsureSSHKey() - assert.Nil(err) - - path, err := sc.EnsureEnvironmentDir("foo", key) + path, err := sc.EnsureEnvironmentDir("foo") assert.Nil(err) assert.NotEmpty(path) - - sshPath := filepath.Join(path, ".ssh") - authorizedPath := filepath.Join(sshPath, "authorized_keys") - stat, err := os.Stat(sshPath) - assert.Nil(err) - assert.Equal(stat.Mode(), os.FileMode(0700|os.ModeDir)) - stat, err = os.Stat(authorizedPath) - assert.Nil(err) - assert.Equal(stat.Mode(), os.FileMode(0700)) - - orig, _ := ioutil.ReadFile(key.publicPath) - copy, _ := ioutil.ReadFile(authorizedPath) - assert.Equal(orig, copy) }