HTTPS and File Uploads (#139)

* Add a few fixes

* Use CopyToContainer instead of bind mounts

* Remove a local compose file

* Changes according to the comments

* Rebase with master
This commit is contained in:
Jonathan Leibiusky
2017-05-12 16:20:09 -03:00
committed by Marcos Nils
parent 61a0bb4db1
commit 8df6373327
8 changed files with 267 additions and 54 deletions

View File

@@ -1,8 +1,11 @@
package services
import (
"archive/tar"
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strconv"
@@ -199,7 +202,64 @@ func ResizeConnection(name string, cols, rows uint) error {
return c.ContainerResize(context.Background(), name, types.ResizeOptions{Height: rows, Width: cols})
}
func CreateInstance(session *Session, dindImage string) (*Instance, error) {
func CopyToContainer(containerName, destination, fileName string, content io.Reader) error {
r, w := io.Pipe()
b, readErr := ioutil.ReadAll(content)
if readErr != nil {
return readErr
}
t := tar.NewWriter(w)
go func() {
t.WriteHeader(&tar.Header{Name: fileName, Mode: 0600, Size: int64(len(b))})
t.Write(b)
t.Close()
w.Close()
}()
return c.CopyToContainer(context.Background(), containerName, destination, r, types.CopyToContainerOptions{AllowOverwriteDirWithFile: true})
}
func CreateInstance(session *Session, conf InstanceConfig) (*Instance, error) {
var nodeName string
var containerName string
for i := 1; ; i++ {
nodeName = fmt.Sprintf("node%d", i)
containerName = fmt.Sprintf("%s_%s", session.Id[:8], nodeName)
exists := false
for _, instance := range session.Instances {
if instance.Name == containerName {
exists = true
break
}
}
if !exists {
break
}
}
// Make sure directories are available for the new instance container
containerDir := "/var/run/pwd"
containerCertDir := fmt.Sprintf("%s/certs", containerDir)
env := []string{}
// Write certs to container cert dir
if len(conf.ServerCert) > 0 {
env = append(env, "DOCKER_TLSCERT=/var/run/pwd/certs/cert.pem")
}
if len(conf.ServerKey) > 0 {
env = append(env, "DOCKER_TLSKEY=/var/run/pwd/certs/key.pem")
}
if len(conf.CACert) > 0 {
// if ca cert is specified, verify that clients that connects present a certificate signed by the CA
env = append(env, "DOCKER_TLSCACERT=/var/run/pwd/certs/ca.pem")
}
if len(conf.ServerCert) > 0 || len(conf.ServerKey) > 0 || len(conf.CACert) > 0 {
// if any of the certs is specified, enable TLS
env = append(env, "DOCKER_TLSENABLE=true")
} else {
env = append(env, "DOCKER_TLSENABLE=false")
}
h := &container.HostConfig{
NetworkMode: container.NetworkMode(session.Id),
Privileged: true,
@@ -222,42 +282,37 @@ func CreateInstance(session *Session, dindImage string) (*Instance, error) {
t := true
h.Resources.OomKillDisable = &t
var nodeName string
var containerName string
for i := 1; ; i++ {
nodeName = fmt.Sprintf("node%d", i)
containerName = fmt.Sprintf("%s_%s", session.Id[:8], nodeName)
exists := false
for _, instance := range session.Instances {
if instance.Name == containerName {
exists = true
break
}
}
if !exists {
break
}
}
conf := &container.Config{Hostname: nodeName,
env = append(env, fmt.Sprintf("PWD_IP_ADDRESS=%s", session.PwdIpAddress))
cf := &container.Config{Hostname: nodeName,
Image: dindImage,
Tty: true,
OpenStdin: true,
AttachStdin: true,
AttachStdout: true,
AttachStderr: true,
Env: []string{fmt.Sprintf("PWD_IP_ADDRESS=%s", session.PwdIpAddress)},
Env: env,
}
networkConf := &network.NetworkingConfig{
map[string]*network.EndpointSettings{
session.Id: &network.EndpointSettings{Aliases: []string{nodeName}},
},
}
container, err := c.ContainerCreate(context.Background(), conf, h, networkConf, containerName)
container, err := c.ContainerCreate(context.Background(), cf, h, networkConf, containerName)
if err != nil {
return nil, err
}
if err := copyIfSet(conf.ServerCert, "cert.pem", containerCertDir, containerName); err != nil {
return nil, err
}
if err := copyIfSet(conf.ServerKey, "key.pem", containerCertDir, containerName); err != nil {
return nil, err
}
if err := copyIfSet(conf.CACert, "ca.pem", containerCertDir, containerName); err != nil {
return nil, err
}
err = c.ContainerStart(context.Background(), container.ID, types.ContainerStartOptions{})
if err != nil {
return nil, err
@@ -271,6 +326,13 @@ func CreateInstance(session *Session, dindImage string) (*Instance, error) {
return &Instance{Name: containerName, Hostname: cinfo.Config.Hostname, IP: cinfo.NetworkSettings.Networks[session.Id].IPAddress}, nil
}
func copyIfSet(content []byte, fileName, path, containerName string) error {
if len(content) > 0 {
return CopyToContainer(containerName, path, fileName, bytes.NewReader(content))
}
return nil
}
func DeleteContainer(id string) error {
return c.ContainerRemove(context.Background(), id, types.ContainerRemoveOptions{Force: true, RemoveVolumes: true})
}

View File

@@ -3,9 +3,12 @@ package services
import (
"context"
"crypto/tls"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
@@ -42,6 +45,14 @@ type Instance struct {
cert *tls.Certificate `json:"-"`
}
type InstanceConfig struct {
ImageName string
Alias string
ServerCert []byte
ServerKey []byte
CACert []byte
}
func (i *Instance) setUsedPort(port uint16) {
rw.Lock()
defer rw.Unlock()
@@ -97,17 +108,17 @@ func getDindImageName() string {
return dindImage
}
func NewInstance(session *Session, imageName, alias string) (*Instance, error) {
if imageName == "" {
imageName = dindImage
func NewInstance(session *Session, conf InstanceConfig) (*Instance, error) {
if conf.ImageName == "" {
conf.ImageName = dindImage
}
log.Printf("NewInstance - using image: [%s]\n", imageName)
instance, err := CreateInstance(session, imageName)
log.Printf("NewInstance - using image: [%s]\n", conf.ImageName)
instance, err := CreateInstance(session, conf)
if err != nil {
return nil, err
}
instance.Alias = alias
instance.Alias = conf.Alias
instance.session = session
@@ -163,6 +174,29 @@ func (i *Instance) Attach() {
case <-i.ctx.Done():
}
}
func (i *Instance) UploadFromURL(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)
}
_, fileName := filepath.Split(url)
copyErr := CopyToContainer(i.Name, "/var/run/pwd/uploads", fileName, resp.Body)
if copyErr != nil {
return fmt.Errorf("Error while downloading file [%s]. Error: %s\n", url, copyErr)
}
return nil
}
func GetInstance(session *Session, name string) *Instance {
return session.Instances[name]
}