Compare commits

...

6 Commits

Author SHA1 Message Date
Guillaume J. Charmes
30d327d37e Add TestCommitAutoRun 2013-04-25 17:03:13 -07:00
Guillaume J. Charmes
724e2d6b0a Update unit test in order to comply with new api 2013-04-25 17:02:38 -07:00
Guillaume J. Charmes
51d6228261 Implement -config and -command in CmdCommit in order to allow autorun 2013-04-25 16:48:31 -07:00
Guillaume J. Charmes
ee298d1420 Specify a different bridge for tests than for regular runtime 2013-04-24 17:43:41 -07:00
Solomon Hykes
03855b0027 Merge pull request #466 from dotcloud/441-vagrant-improve
* Packaging: simplify Vagrantfile
2013-04-24 17:25:20 -07:00
Daniel Mizyrycki
2726e3649a vagrant; issue #441: Improve main config including aws ubuntu lts dependency 2013-04-24 11:30:15 -07:00
12 changed files with 181 additions and 225 deletions

67
Vagrantfile vendored
View File

@@ -1,55 +1,27 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
def v10(config)
config.vm.box = 'precise64'
config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
BOX_NAME = "ubuntu"
BOX_URI = "http://files.vagrantup.com/precise64.box"
PPA_KEY = "E61D797F63561DC6"
# Install ubuntu packaging dependencies and create ubuntu packages
config.vm.provision :shell, :inline => "echo 'deb http://ppa.launchpad.net/dotcloud/lxc-docker/ubuntu precise main' >>/etc/apt/sources.list"
config.vm.provision :shell, :inline => 'export DEBIAN_FRONTEND=noninteractive; apt-get -qq update; apt-get install -qq -y --force-yes lxc-docker'
end
Vagrant::VERSION < "1.1.0" and Vagrant::Config.run do |config|
v10(config)
end
Vagrant::VERSION >= "1.1.0" and Vagrant.configure("1") do |config|
v10(config)
Vagrant::Config.run do |config|
# Setup virtual machine box. This VM configuration code is always executed.
config.vm.box = BOX_NAME
config.vm.box_url = BOX_URI
# Add docker PPA key to the local repository and install docker
pkg_cmd = "apt-key adv --keyserver keyserver.ubuntu.com --recv-keys #{PPA_KEY}; "
pkg_cmd << "echo 'deb http://ppa.launchpad.net/dotcloud/lxc-docker/ubuntu precise main' >>/etc/apt/sources.list; "
pkg_cmd << "apt-get update -qq; apt-get install -q -y lxc-docker"
if ARGV.include?("--provider=aws".downcase)
# Add AUFS dependency to amazon's VM
pkg_cmd << "; apt-get install linux-image-extra-3.2.0-40-virtual"
end
config.vm.provision :shell, :inline => pkg_cmd
end
# Providers were added on Vagrant >= 1.1.0
Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
config.vm.provider :aws do |aws|
config.vm.box = "dummy"
config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
aws.access_key_id = ENV["AWS_ACCESS_KEY_ID"]
aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
aws.keypair_name = ENV["AWS_KEYPAIR_NAME"]
aws.ssh_private_key_path = ENV["AWS_SSH_PRIVKEY"]
aws.region = "us-east-1"
aws.ami = "ami-d0f89fb9"
aws.ssh_username = "ubuntu"
aws.instance_type = "t1.micro"
end
config.vm.provider :rackspace do |rs|
config.vm.box = "dummy"
config.vm.box_url = "https://github.com/mitchellh/vagrant-rackspace/raw/master/dummy.box"
config.ssh.private_key_path = ENV["RS_PRIVATE_KEY"]
rs.username = ENV["RS_USERNAME"]
rs.api_key = ENV["RS_API_KEY"]
rs.public_key_path = ENV["RS_PUBLIC_KEY"]
rs.flavor = /512MB/
rs.image = /Ubuntu/
end
config.vm.provider :virtualbox do |vb|
config.vm.box = 'precise64'
config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
end
end
Vagrant::VERSION >= "1.2.0" and Vagrant.configure("2") do |config|
config.vm.provider :aws do |aws, override|
config.vm.box = "dummy"
config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
@@ -75,8 +47,7 @@ Vagrant::VERSION >= "1.2.0" and Vagrant.configure("2") do |config|
end
config.vm.provider :virtualbox do |vb|
config.vm.box = 'precise64'
config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
config.vm.box = BOX_NAME
config.vm.box_url = BOX_URI
end
end

View File

@@ -477,7 +477,7 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout rcli.DockerConn, args .
}
archive = ProgressReader(resp.Body, int(resp.ContentLength), stdout, "Importing %v/%v (%v)")
}
img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "")
img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
if err != nil {
return err
}
@@ -726,6 +726,8 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri
"Create a new image from a container's changes")
flComment := cmd.String("m", "", "Commit message")
flAuthor := cmd.String("author", "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
flConfig := cmd.String("config", "", "Config automatically applied when the image is run. This option must be the last one.")
flCommand := cmd.String("command", "", "Command to run when starting the image")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -734,7 +736,22 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri
cmd.Usage()
return nil
}
img, err := srv.runtime.Commit(containerName, repository, tag, *flComment, *flAuthor)
var config []string
if *flConfig != "" {
config = strings.Split(*flConfig, " ")
}
if *flCommand != "" {
config = append(config, "", "/bin/sh", "-c", *flCommand)
} else if *flConfig != "" {
config = append(config, "", "")
}
c, err := ParseRun(config, stdout, srv.runtime.capabilities)
if err != nil {
return err
}
img, err := srv.runtime.Commit(containerName, repository, tag, *flComment, *flAuthor, c)
if err != nil {
return err
}
@@ -925,10 +942,6 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s
fmt.Fprintln(stdout, "Error: Image not specified")
return fmt.Errorf("Image not specified")
}
if len(config.Cmd) == 0 {
fmt.Fprintln(stdout, "Error: Command not specified")
return fmt.Errorf("Command not specified")
}
if config.Tty {
stdout.SetOptionRawTerminal()

View File

@@ -193,7 +193,7 @@ func TestDiff(t *testing.T) {
if err != nil {
t.Error(err)
}
img, err := runtime.graph.Create(rwTar, container1, "unit test commited image - diff", "")
img, err := runtime.graph.Create(rwTar, container1, "unit test commited image - diff", "", nil)
if err != nil {
t.Error(err)
}
@@ -226,6 +226,84 @@ func TestDiff(t *testing.T) {
}
}
func TestCommitAutoRun(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
container1, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).Id,
Cmd: []string{"/bin/sh", "-c", "echo hello > /world"},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container1)
if container1.State.Running {
t.Errorf("Container shouldn't be running")
}
if err := container1.Run(); err != nil {
t.Fatal(err)
}
if container1.State.Running {
t.Errorf("Container shouldn't be running")
}
rwTar, err := container1.ExportRw()
if err != nil {
t.Error(err)
}
img, err := runtime.graph.Create(rwTar, container1, "unit test commited image", "", &Config{Cmd: []string{"cat", "/world"}})
if err != nil {
t.Error(err)
}
// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
container2, err := runtime.Create(
&Config{
Image: img.Id,
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container2)
stdout, err := container2.StdoutPipe()
if err != nil {
t.Fatal(err)
}
stderr, err := container2.StderrPipe()
if err != nil {
t.Fatal(err)
}
if err := container2.Start(); err != nil {
t.Fatal(err)
}
container2.Wait()
output, err := ioutil.ReadAll(stdout)
if err != nil {
t.Fatal(err)
}
output2, err := ioutil.ReadAll(stderr)
if err != nil {
t.Fatal(err)
}
if err := stdout.Close(); err != nil {
t.Fatal(err)
}
if err := stderr.Close(); err != nil {
t.Fatal(err)
}
if string(output) != "hello\n" {
t.Fatalf("Unexpected output. Expected %s, received: %s (err: %s)", "hello\n", output, output2)
}
}
func TestCommitRun(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
@@ -258,7 +336,7 @@ func TestCommitRun(t *testing.T) {
if err != nil {
t.Error(err)
}
img, err := runtime.graph.Create(rwTar, container1, "unit test commited image", "")
img, err := runtime.graph.Create(rwTar, container1, "unit test commited image", "", nil)
if err != nil {
t.Error(err)
}

View File

@@ -84,13 +84,14 @@ func (graph *Graph) Get(name string) (*Image, error) {
}
// Create creates a new image and registers it in the graph.
func (graph *Graph) Create(layerData Archive, container *Container, comment, author string) (*Image, error) {
func (graph *Graph) Create(layerData Archive, container *Container, comment, author string, config *Config) (*Image, error) {
img := &Image{
Id: GenerateId(),
Comment: comment,
Created: time.Now(),
DockerVersion: VERSION,
Author: author,
Config: config,
}
if container != nil {
img.Parent = container.Image

View File

@@ -62,7 +62,7 @@ func TestGraphCreate(t *testing.T) {
if err != nil {
t.Fatal(err)
}
image, err := graph.Create(archive, nil, "Testing", "")
image, err := graph.Create(archive, nil, "Testing", "", nil)
if err != nil {
t.Fatal(err)
}
@@ -122,7 +122,7 @@ func TestMount(t *testing.T) {
if err != nil {
t.Fatal(err)
}
image, err := graph.Create(archive, nil, "Testing", "")
image, err := graph.Create(archive, nil, "Testing", "", nil)
if err != nil {
t.Fatal(err)
}
@@ -166,7 +166,7 @@ func createTestImage(graph *Graph, t *testing.T) *Image {
if err != nil {
t.Fatal(err)
}
img, err := graph.Create(archive, nil, "Test image", "")
img, err := graph.Create(archive, nil, "Test image", "", nil)
if err != nil {
t.Fatal(err)
}
@@ -181,7 +181,7 @@ func TestDelete(t *testing.T) {
t.Fatal(err)
}
assertNImages(graph, t, 0)
img, err := graph.Create(archive, nil, "Bla bla", "")
img, err := graph.Create(archive, nil, "Bla bla", "", nil)
if err != nil {
t.Fatal(err)
}
@@ -192,11 +192,11 @@ func TestDelete(t *testing.T) {
assertNImages(graph, t, 0)
// Test 2 create (same name) / 1 delete
img1, err := graph.Create(archive, nil, "Testing", "")
img1, err := graph.Create(archive, nil, "Testing", "", nil)
if err != nil {
t.Fatal(err)
}
if _, err = graph.Create(archive, nil, "Testing", ""); err != nil {
if _, err = graph.Create(archive, nil, "Testing", "", nil); err != nil {
t.Fatal(err)
}
assertNImages(graph, t, 2)

View File

@@ -24,6 +24,7 @@ type Image struct {
ContainerConfig Config `json:"container_config,omitempty"`
DockerVersion string `json:"docker_version,omitempty"`
Author string `json:"author,omitempty"`
Config *Config `json:"config,omitempty"`
graph *Graph
}

View File

@@ -1,17 +0,0 @@
node default {
exec {
"apt_update" :
command => "/usr/bin/apt-get update"
}
Package {
require => Exec['apt_update']
}
group { "puppet":
ensure => "present"
}
include "docker"
}

View File

@@ -1,99 +0,0 @@
class virtualbox {
Package { ensure => "installed" }
# remove some files from the base vagrant image because they're old
file { "/home/vagrant/docker-master":
ensure => absent,
recurse => true,
force => true,
purge => true,
}
file { "/usr/local/bin/dockerd":
ensure => absent,
}
file { "/usr/local/bin/docker":
ensure => absent,
}
# Set up VirtualBox guest utils
package { "virtualbox-guest-utils": }
exec { "vbox-add" :
command => "/etc/init.d/vboxadd setup",
require => [
Package["virtualbox-guest-utils"],
Package["linux-headers-3.5.0-25-generic"], ],
}
}
class docker {
# update this with latest go binary dist
$go_url = "http://go.googlecode.com/files/go1.0.3.linux-amd64.tar.gz"
Package { ensure => "installed" }
package { ["lxc", "debootstrap", "wget", "bsdtar", "git",
"linux-image-3.5.0-25-generic",
"linux-image-extra-3.5.0-25-generic",
"linux-headers-3.5.0-25-generic"]: }
$ec2_version = file("/etc/ec2_version", "/dev/null")
$rax_version = inline_template("<%= %x{/usr/bin/xenstore-read vm-data/provider_data/provider} %>")
if ($ec2_version) {
$vagrant_user = "ubuntu"
$vagrant_home = "/home/ubuntu"
} elsif ($rax_version) {
$vagrant_user = "root"
$vagrant_home = "/root"
} else {
# virtualbox is the vagrant default, so it should be safe to assume
$vagrant_user = "vagrant"
$vagrant_home = "/home/vagrant"
include virtualbox
}
exec { "fetch-go":
require => Package["wget"],
command => "/usr/bin/wget -O - $go_url | /bin/tar xz -C /usr/local",
creates => "/usr/local/go/bin/go",
}
file { "/etc/init/dockerd.conf":
mode => 600,
owner => "root",
group => "root",
content => template("docker/dockerd.conf"),
}
file { "/opt/go":
owner => $vagrant_user,
group => $vagrant_user,
recurse => true,
}
file { "${vagrant_home}/.profile":
mode => 644,
owner => $vagrant_user,
group => $vagrant_user,
content => template("docker/profile"),
}
exec { "build-docker" :
cwd => "/opt/go/src/github.com/dotcloud/docker",
user => $vagrant_user,
environment => "GOPATH=/opt/go",
command => "/usr/local/go/bin/go get -v ./... && /usr/local/go/bin/go install ./docker",
creates => "/opt/go/bin/docker",
logoutput => "on_failure",
require => [ Exec["fetch-go"], File["/opt/go"] ],
}
service { "dockerd" :
ensure => "running",
start => "/sbin/initctl start dockerd",
stop => "/sbin/initctl stop dockerd",
require => [ Exec["build-docker"], File["/etc/init/dockerd.conf"] ],
name => "dockerd",
provider => "base"
}
}

View File

@@ -1,12 +0,0 @@
description "Run dockerd"
stop on runlevel [!2345]
start on runlevel [3]
# if you want it to automatically restart if it crashes, leave the next line in
respawn
script
test -f /etc/default/locale && . /etc/default/locale || true
LANG=$LANG LC_ALL=$LANG /opt/go/bin/docker -d >> /var/log/dockerd 2>&1
end script

View File

@@ -1,30 +0,0 @@
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.
# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
export GOPATH=/opt/go
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
docker=/opt/go/src/github.com/dotcloud/docker
if [ -d $docker ]; then
cd $docker
fi

View File

@@ -77,12 +77,59 @@ func (runtime *Runtime) containerRoot(id string) string {
return path.Join(runtime.repository, id)
}
func (runtime *Runtime) mergeConfig(userConf, imageConf *Config) {
if userConf.Hostname != "" {
userConf.Hostname = imageConf.Hostname
}
if userConf.User != "" {
userConf.User = imageConf.User
}
if userConf.Memory == 0 {
userConf.Memory = imageConf.Memory
}
if userConf.MemorySwap == 0 {
userConf.MemorySwap = imageConf.MemorySwap
}
if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
userConf.PortSpecs = imageConf.PortSpecs
}
if !userConf.Tty {
userConf.Tty = userConf.Tty
}
if !userConf.OpenStdin {
userConf.OpenStdin = imageConf.OpenStdin
}
if !userConf.StdinOnce {
userConf.StdinOnce = imageConf.StdinOnce
}
if userConf.Env == nil || len(userConf.Env) == 0 {
userConf.Env = imageConf.Env
}
if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
userConf.Cmd = imageConf.Cmd
}
if userConf.Dns == nil || len(userConf.Dns) == 0 {
userConf.Dns = imageConf.Dns
}
}
func (runtime *Runtime) Create(config *Config) (*Container, error) {
// Lookup image
img, err := runtime.repositories.LookupImage(config.Image)
if err != nil {
return nil, err
}
//runtime.mergeConfig(config, img.Config)
if img.Config != nil {
config = img.Config
}
if config.Cmd == nil {
return nil, fmt.Errorf("No command specified")
}
// Generate id
id := GenerateId()
// Generate default hostname
@@ -103,6 +150,7 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) {
// FIXME: do we need to store this in the container?
SysInitPath: sysInitPath,
}
container.root = runtime.containerRoot(container.Id)
// Step 1: create the container directory.
// This doubles as a barrier to avoid race conditions.
@@ -249,7 +297,7 @@ func (runtime *Runtime) Destroy(container *Container) error {
// Commit creates a new filesystem image from the current state of a container.
// The image can optionally be tagged into a repository
func (runtime *Runtime) Commit(id, repository, tag, comment, author string) (*Image, error) {
func (runtime *Runtime) Commit(id, repository, tag, comment, author string, config *Config) (*Image, error) {
container := runtime.Get(id)
if container == nil {
return nil, fmt.Errorf("No such container: %s", id)
@@ -261,7 +309,7 @@ func (runtime *Runtime) Commit(id, repository, tag, comment, author string) (*Im
return nil, err
}
// Create a new image from the container's base layers + a new layer from container changes
img, err := runtime.graph.Create(rwTar, container, comment, author)
img, err := runtime.graph.Create(rwTar, container, comment, author, config)
if err != nil {
return nil, err
}
@@ -314,13 +362,13 @@ func NewRuntime() (*Runtime, error) {
_, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes"))
runtime.capabilities.MemoryLimit = err1 == nil && err2 == nil
if !runtime.capabilities.MemoryLimit {
log.Printf("WARNING: Your kernel does not support cgroup memory limit.")
log.Printf("WARNING: Your kernel does not support cgroup memory limit.")
}
_, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes"))
runtime.capabilities.SwapLimit = err == nil
if !runtime.capabilities.SwapLimit {
log.Printf("WARNING: Your kernel does not support cgroup swap limit.")
log.Printf("WARNING: Your kernel does not support cgroup swap limit.")
}
}
return runtime, nil

View File

@@ -60,6 +60,8 @@ func init() {
panic("docker tests needs to be run as root")
}
NetworkBridgeIface = "testdockbr0"
// Make it our Store root
runtime, err := NewRuntimeFromDirectory(unitTestStoreBase)
if err != nil {