github.com/cloudcredo/cloudrocker@v0.0.0-20160108110610-1320f8cc2dfd/docker/parser.go (about)

     1  package docker
     2  
     3  import (
     4  	"io/ioutil"
     5  	"log"
     6  	"os/user"
     7  	"sort"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/cloudcredo/cloudrocker/Godeps/_workspace/src/github.com/fsouza/go-dockerclient"
    12  	"github.com/cloudcredo/cloudrocker/config"
    13  )
    14  
    15  func ParseCreateContainerOptions(config *config.ContainerConfig) docker.CreateContainerOptions {
    16  	var options = docker.CreateContainerOptions{
    17  		Name: config.ContainerName,
    18  		Config: &docker.Config{
    19  			User:         userID(),
    20  			Env:          parseEnvVars(config.EnvVars),
    21  			Image:        config.SrcImageTag,
    22  			Cmd:          config.Command,
    23  			Mounts:       parseMounts(config.Mounts),
    24  			AttachStdout: parseDaemon(config.Daemon),
    25  			AttachStderr: parseDaemon(config.Daemon),
    26  			ExposedPorts: parseExposedPorts(config.PublishedPorts),
    27  		},
    28  		HostConfig: &docker.HostConfig{
    29  			Binds:        parseBinds(config.Mounts),
    30  			PortBindings: parsePublishedPorts(config.PublishedPorts),
    31  			NetworkMode:  "bridge",
    32  		},
    33  	}
    34  	return options
    35  }
    36  
    37  func WriteRuntimeDockerfile(config *config.ContainerConfig) {
    38  	var dockerfile string
    39  
    40  	dockerfile = runtimeInitialDockerfileString()
    41  	dockerfile = dockerfile + envVarDockerfileString(config.EnvVars)
    42  	dockerfile = dockerfile + commandDockerfileString(config.Command)
    43  
    44  	ioutil.WriteFile(config.DropletDir+"/Dockerfile", []byte(dockerfile), 0644)
    45  }
    46  
    47  func WriteBaseImageDockerfile(config *config.ContainerConfig) {
    48  	var dockerfile string
    49  
    50  	dockerfile = baseImageDockerfileString(config.SrcImageTag)
    51  
    52  	ioutil.WriteFile(config.BaseConfigDir+"/Dockerfile", []byte(dockerfile), 0644)
    53  }
    54  
    55  func userID() string {
    56  	var thisUser *user.User
    57  	var err error
    58  	if thisUser, err = user.Current(); err != nil {
    59  		log.Fatalf(" %s", err)
    60  	}
    61  	return thisUser.Uid
    62  }
    63  
    64  type ByHostPath []docker.Mount
    65  
    66  func (slice ByHostPath) Len() int           { return len(slice) }
    67  func (slice ByHostPath) Swap(i, j int)      { slice[i], slice[j] = slice[j], slice[i] }
    68  func (slice ByHostPath) Less(i, j int) bool { return slice[i].Source < slice[j].Source }
    69  
    70  func parseMounts(mounts map[string]string) (parsedMounts []docker.Mount) {
    71  	for hostPath, containerPath := range mounts {
    72  		parsedMounts = append(parsedMounts, docker.Mount{
    73  			Source:      hostPath,
    74  			Destination: containerPath,
    75  			RW:          true,
    76  		})
    77  	}
    78  	sort.Sort(ByHostPath(parsedMounts))
    79  	return
    80  }
    81  
    82  func parseBinds(mounts map[string]string) (parsedBinds []string) {
    83  	for hostPath, containerPath := range mounts {
    84  		parsedBinds = append(parsedBinds, hostPath+":"+containerPath)
    85  	}
    86  	sort.Strings(parsedBinds)
    87  	return
    88  }
    89  
    90  func parseExposedPorts(publishedPorts map[int]int) map[docker.Port]struct{} {
    91  	var parsedExposedPorts = make(map[docker.Port]struct{})
    92  	for hostPort := range publishedPorts {
    93  		parsedExposedPorts[convertHostPort(hostPort)] = struct{}{}
    94  	}
    95  	return parsedExposedPorts
    96  }
    97  
    98  func parsePublishedPorts(publishedPorts map[int]int) map[docker.Port][]docker.PortBinding {
    99  	var parsedPublishedPorts = make(map[docker.Port][]docker.PortBinding)
   100  	for hostPort, containerPort := range publishedPorts {
   101  		parsedPublishedPorts[convertHostPort(hostPort)] = []docker.PortBinding{
   102  			{
   103  				HostPort: strconv.Itoa(containerPort),
   104  			},
   105  		}
   106  	}
   107  	return parsedPublishedPorts
   108  }
   109  
   110  func convertHostPort(hostPort int) docker.Port {
   111  	return docker.Port(strconv.Itoa(hostPort) + "/tcp")
   112  }
   113  
   114  func parseEnvVars(envVars map[string]string) (parsedEnvVars []string) {
   115  	for key, val := range envVars {
   116  		if val != "" {
   117  			parsedEnvVars = append(parsedEnvVars, key+"="+val)
   118  		}
   119  	}
   120  	sort.Strings(parsedEnvVars)
   121  	return
   122  }
   123  
   124  func parseDaemon(daemon bool) bool {
   125  	return !daemon
   126  }
   127  
   128  func runtimeInitialDockerfileString() string {
   129  	return `FROM cloudrocker-base:latest
   130  COPY droplet.tgz /app/
   131  RUN chown vcap:vcap /app && cd /app && su vcap -c "tar zxf droplet.tgz" && rm droplet.tgz
   132  EXPOSE 8080
   133  USER vcap
   134  WORKDIR /app
   135  `
   136  }
   137  
   138  func baseImageDockerfileString(srcImageTag string) string {
   139  	return `FROM ` + srcImageTag + `
   140  RUN id vcap || /usr/sbin/useradd -mU -u ` + userID() + ` -d /app -s /bin/bash vcap
   141  RUN mkdir -p /app/tmp && chown -R vcap:vcap /app
   142  `
   143  }
   144  
   145  func envVarDockerfileString(envVars map[string]string) string {
   146  	var envVarStrings []string
   147  	for envVarKey, envVarVal := range envVars {
   148  		if envVarVal != "" {
   149  			envVarStrings = append(envVarStrings, "ENV "+envVarKey+" "+envVarVal+"\n")
   150  		}
   151  	}
   152  	sort.Strings(envVarStrings)
   153  	return strings.Join(envVarStrings, "")
   154  }
   155  
   156  func commandDockerfileString(command []string) string {
   157  	for index, commandElement := range command {
   158  		command[index] = strings.Replace(commandElement, `"`, `\"`, -1)
   159  	}
   160  	commandString := `CMD ["`
   161  	commandString = commandString + strings.Join(command, `", "`)
   162  	commandString = commandString + "\"]\n"
   163  	return commandString
   164  }