Conflicts:
docker/docker.go
docs/sources/installation/archlinux.rst
docs/sources/installation/index.rst
docs/sources/installation/ubuntulinux.rst
runtime.go
utils.go
| ... | ... |
@@ -150,6 +150,82 @@ func TestMultipleAttachRestart(t *testing.T) {
|
| 150 | 150 |
} |
| 151 | 151 |
} |
| 152 | 152 |
|
| 153 |
+func TestDiff(t *testing.T) {
|
|
| 154 |
+ runtime, err := newTestRuntime() |
|
| 155 |
+ if err != nil {
|
|
| 156 |
+ t.Fatal(err) |
|
| 157 |
+ } |
|
| 158 |
+ defer nuke(runtime) |
|
| 159 |
+ |
|
| 160 |
+ // Create a container and remove a file |
|
| 161 |
+ container1, err := runtime.Create( |
|
| 162 |
+ &Config{
|
|
| 163 |
+ Image: GetTestImage(runtime).Id, |
|
| 164 |
+ Cmd: []string{"/bin/rm", "/etc/passwd"},
|
|
| 165 |
+ }, |
|
| 166 |
+ ) |
|
| 167 |
+ if err != nil {
|
|
| 168 |
+ t.Fatal(err) |
|
| 169 |
+ } |
|
| 170 |
+ defer runtime.Destroy(container1) |
|
| 171 |
+ |
|
| 172 |
+ if err := container1.Run(); err != nil {
|
|
| 173 |
+ t.Fatal(err) |
|
| 174 |
+ } |
|
| 175 |
+ |
|
| 176 |
+ // Check the changelog |
|
| 177 |
+ c, err := container1.Changes() |
|
| 178 |
+ if err != nil {
|
|
| 179 |
+ t.Fatal(err) |
|
| 180 |
+ } |
|
| 181 |
+ success := false |
|
| 182 |
+ for _, elem := range c {
|
|
| 183 |
+ if elem.Path == "/etc/passwd" && elem.Kind == 2 {
|
|
| 184 |
+ success = true |
|
| 185 |
+ } |
|
| 186 |
+ } |
|
| 187 |
+ if !success {
|
|
| 188 |
+ t.Fatalf("/etc/passwd as been removed but is not present in the diff")
|
|
| 189 |
+ } |
|
| 190 |
+ |
|
| 191 |
+ // Commit the container |
|
| 192 |
+ rwTar, err := container1.ExportRw() |
|
| 193 |
+ if err != nil {
|
|
| 194 |
+ t.Error(err) |
|
| 195 |
+ } |
|
| 196 |
+ img, err := runtime.graph.Create(rwTar, container1, "unit test commited image - diff", "") |
|
| 197 |
+ if err != nil {
|
|
| 198 |
+ t.Error(err) |
|
| 199 |
+ } |
|
| 200 |
+ |
|
| 201 |
+ // Create a new container from the commited image |
|
| 202 |
+ container2, err := runtime.Create( |
|
| 203 |
+ &Config{
|
|
| 204 |
+ Image: img.Id, |
|
| 205 |
+ Cmd: []string{"cat", "/etc/passwd"},
|
|
| 206 |
+ }, |
|
| 207 |
+ ) |
|
| 208 |
+ if err != nil {
|
|
| 209 |
+ t.Fatal(err) |
|
| 210 |
+ } |
|
| 211 |
+ defer runtime.Destroy(container2) |
|
| 212 |
+ |
|
| 213 |
+ if err := container2.Run(); err != nil {
|
|
| 214 |
+ t.Fatal(err) |
|
| 215 |
+ } |
|
| 216 |
+ |
|
| 217 |
+ // Check the changelog |
|
| 218 |
+ c, err = container2.Changes() |
|
| 219 |
+ if err != nil {
|
|
| 220 |
+ t.Fatal(err) |
|
| 221 |
+ } |
|
| 222 |
+ for _, elem := range c {
|
|
| 223 |
+ if elem.Path == "/etc/passwd" {
|
|
| 224 |
+ t.Fatalf("/etc/passwd should not be present in the diff after commit.")
|
|
| 225 |
+ } |
|
| 226 |
+ } |
|
| 227 |
+} |
|
| 228 |
+ |
|
| 153 | 229 |
func TestCommitRun(t *testing.T) {
|
| 154 | 230 |
runtime, err := newTestRuntime() |
| 155 | 231 |
if err != nil {
|
| ... | ... |
@@ -7,9 +7,11 @@ import ( |
| 7 | 7 |
"github.com/dotcloud/docker/rcli" |
| 8 | 8 |
"github.com/dotcloud/docker/term" |
| 9 | 9 |
"io" |
| 10 |
+ "io/ioutil" |
|
| 10 | 11 |
"log" |
| 11 | 12 |
"os" |
| 12 | 13 |
"os/signal" |
| 14 |
+ "strconv" |
|
| 13 | 15 |
"syscall" |
| 14 | 16 |
) |
| 15 | 17 |
|
| ... | ... |
@@ -54,8 +56,13 @@ func main() {
|
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 | 56 |
func createPidFile(pidfile string) error {
|
| 57 |
- if _, err := os.Stat(pidfile); err == nil {
|
|
| 58 |
- return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
|
|
| 57 |
+ if pidString, err := ioutil.ReadFile(pidfile); err == nil {
|
|
| 58 |
+ pid, err := strconv.Atoi(string(pidString)) |
|
| 59 |
+ if err == nil {
|
|
| 60 |
+ if _, err := os.Stat(fmt.Sprintf("/proc/%d/", pid)); err == nil {
|
|
| 61 |
+ return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
|
|
| 62 |
+ } |
|
| 63 |
+ } |
|
| 59 | 64 |
} |
| 60 | 65 |
|
| 61 | 66 |
file, err := os.Create(pidfile) |
| 0 | 9 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,69 @@ |
| 0 |
+package docker |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bytes" |
|
| 4 |
+ "strconv" |
|
| 5 |
+ "strings" |
|
| 6 |
+ "syscall" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+func getKernelVersion() (*KernelVersionInfo, error) {
|
|
| 10 |
+ var ( |
|
| 11 |
+ uts syscall.Utsname |
|
| 12 |
+ flavor string |
|
| 13 |
+ kernel, major, minor int |
|
| 14 |
+ err error |
|
| 15 |
+ ) |
|
| 16 |
+ |
|
| 17 |
+ if err := syscall.Uname(&uts); err != nil {
|
|
| 18 |
+ return nil, err |
|
| 19 |
+ } |
|
| 20 |
+ |
|
| 21 |
+ release := make([]byte, len(uts.Release)) |
|
| 22 |
+ |
|
| 23 |
+ i := 0 |
|
| 24 |
+ for _, c := range uts.Release {
|
|
| 25 |
+ release[i] = byte(c) |
|
| 26 |
+ i++ |
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ // Remove the \x00 from the release for Atoi to parse correctly |
|
| 30 |
+ release = release[:bytes.IndexByte(release, 0)] |
|
| 31 |
+ |
|
| 32 |
+ tmp := strings.SplitN(string(release), "-", 2) |
|
| 33 |
+ tmp2 := strings.SplitN(tmp[0], ".", 3) |
|
| 34 |
+ |
|
| 35 |
+ if len(tmp2) > 0 {
|
|
| 36 |
+ kernel, err = strconv.Atoi(tmp2[0]) |
|
| 37 |
+ if err != nil {
|
|
| 38 |
+ return nil, err |
|
| 39 |
+ } |
|
| 40 |
+ } |
|
| 41 |
+ |
|
| 42 |
+ if len(tmp2) > 1 {
|
|
| 43 |
+ major, err = strconv.Atoi(tmp2[1]) |
|
| 44 |
+ if err != nil {
|
|
| 45 |
+ return nil, err |
|
| 46 |
+ } |
|
| 47 |
+ } |
|
| 48 |
+ |
|
| 49 |
+ if len(tmp2) > 2 {
|
|
| 50 |
+ minor, err = strconv.Atoi(tmp2[2]) |
|
| 51 |
+ if err != nil {
|
|
| 52 |
+ return nil, err |
|
| 53 |
+ } |
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 56 |
+ if len(tmp) == 2 {
|
|
| 57 |
+ flavor = tmp[1] |
|
| 58 |
+ } else {
|
|
| 59 |
+ flavor = "" |
|
| 60 |
+ } |
|
| 61 |
+ |
|
| 62 |
+ return &KernelVersionInfo{
|
|
| 63 |
+ Kernel: kernel, |
|
| 64 |
+ Major: major, |
|
| 65 |
+ Minor: minor, |
|
| 66 |
+ Flavor: flavor, |
|
| 67 |
+ }, nil |
|
| 68 |
+} |
| ... | ... |
@@ -92,7 +92,7 @@ func MountAUFS(ro []string, rw string, target string) error {
|
| 92 | 92 |
rwBranch := fmt.Sprintf("%v=rw", rw)
|
| 93 | 93 |
roBranches := "" |
| 94 | 94 |
for _, layer := range ro {
|
| 95 |
- roBranches += fmt.Sprintf("%v=ro:", layer)
|
|
| 95 |
+ roBranches += fmt.Sprintf("%v=ro+wh:", layer)
|
|
| 96 | 96 |
} |
| 97 | 97 |
branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)
|
| 98 | 98 |
|
| ... | ... |
@@ -136,34 +136,9 @@ func (image *Image) Mount(root, rw string) error {
|
| 136 | 136 |
if err := os.Mkdir(rw, 0755); err != nil && !os.IsExist(err) {
|
| 137 | 137 |
return err |
| 138 | 138 |
} |
| 139 |
- // FIXME: @creack shouldn't we do this after going over changes? |
|
| 140 | 139 |
if err := MountAUFS(layers, rw, root); err != nil {
|
| 141 | 140 |
return err |
| 142 | 141 |
} |
| 143 |
- // FIXME: Create tests for deletion |
|
| 144 |
- // FIXME: move this part to change.go |
|
| 145 |
- // Retrieve the changeset from the parent and apply it to the container |
|
| 146 |
- // - Retrieve the changes |
|
| 147 |
- changes, err := Changes(layers, layers[0]) |
|
| 148 |
- if err != nil {
|
|
| 149 |
- return err |
|
| 150 |
- } |
|
| 151 |
- // Iterate on changes |
|
| 152 |
- for _, c := range changes {
|
|
| 153 |
- // If there is a delete |
|
| 154 |
- if c.Kind == ChangeDelete {
|
|
| 155 |
- // Make sure the directory exists |
|
| 156 |
- file_path, file_name := path.Dir(c.Path), path.Base(c.Path) |
|
| 157 |
- if err := os.MkdirAll(path.Join(rw, file_path), 0755); err != nil {
|
|
| 158 |
- return err |
|
| 159 |
- } |
|
| 160 |
- // And create the whiteout (we just need to create empty file, discard the return) |
|
| 161 |
- if _, err := os.Create(path.Join(path.Join(rw, file_path), |
|
| 162 |
- ".wh."+path.Base(file_name))); err != nil {
|
|
| 163 |
- return err |
|
| 164 |
- } |
|
| 165 |
- } |
|
| 166 |
- } |
|
| 167 | 142 |
return nil |
| 168 | 143 |
} |
| 169 | 144 |
|
| ... | ... |
@@ -295,14 +295,13 @@ func NewRuntime() (*Runtime, error) {
|
| 295 | 295 |
return nil, err |
| 296 | 296 |
} |
| 297 | 297 |
|
| 298 |
- k, err := GetKernelVersion() |
|
| 299 |
- if err != nil {
|
|
| 300 |
- return nil, err |
|
| 301 |
- } |
|
| 302 |
- runtime.kernelVersion = k |
|
| 303 |
- |
|
| 304 |
- if CompareKernelVersion(k, &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
|
|
| 305 |
- log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
|
|
| 298 |
+ if k, err := GetKernelVersion(); err != nil {
|
|
| 299 |
+ log.Printf("WARNING: %s\n", err)
|
|
| 300 |
+ } else {
|
|
| 301 |
+ runtime.kernelVersion = k |
|
| 302 |
+ if CompareKernelVersion(k, &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
|
|
| 303 |
+ log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
|
|
| 304 |
+ } |
|
| 306 | 305 |
} |
| 307 | 306 |
|
| 308 | 307 |
if cgroupMemoryMountpoint, err := FindCgroupMountpoint("memory"); err != nil {
|
| ... | ... |
@@ -14,10 +14,8 @@ import ( |
| 14 | 14 |
"path/filepath" |
| 15 | 15 |
"regexp" |
| 16 | 16 |
"runtime" |
| 17 |
- "strconv" |
|
| 18 | 17 |
"strings" |
| 19 | 18 |
"sync" |
| 20 |
- "syscall" |
|
| 21 | 19 |
"time" |
| 22 | 20 |
) |
| 23 | 21 |
|
| ... | ... |
@@ -407,52 +405,7 @@ type KernelVersionInfo struct {
|
| 407 | 407 |
|
| 408 | 408 |
// FIXME: this doens't build on Darwin |
| 409 | 409 |
func GetKernelVersion() (*KernelVersionInfo, error) {
|
| 410 |
- var uts syscall.Utsname |
|
| 411 |
- |
|
| 412 |
- if err := syscall.Uname(&uts); err != nil {
|
|
| 413 |
- return nil, err |
|
| 414 |
- } |
|
| 415 |
- |
|
| 416 |
- release := make([]byte, len(uts.Release)) |
|
| 417 |
- |
|
| 418 |
- i := 0 |
|
| 419 |
- for _, c := range uts.Release {
|
|
| 420 |
- release[i] = byte(c) |
|
| 421 |
- i++ |
|
| 422 |
- } |
|
| 423 |
- |
|
| 424 |
- tmp := strings.SplitN(string(release), "-", 2) |
|
| 425 |
- if len(tmp) != 2 {
|
|
| 426 |
- return nil, fmt.Errorf("Unrecognized kernel version")
|
|
| 427 |
- } |
|
| 428 |
- tmp2 := strings.SplitN(tmp[0], ".", 3) |
|
| 429 |
- if len(tmp2) != 3 {
|
|
| 430 |
- return nil, fmt.Errorf("Unrecognized kernel version")
|
|
| 431 |
- } |
|
| 432 |
- |
|
| 433 |
- kernel, err := strconv.Atoi(tmp2[0]) |
|
| 434 |
- if err != nil {
|
|
| 435 |
- return nil, err |
|
| 436 |
- } |
|
| 437 |
- |
|
| 438 |
- major, err := strconv.Atoi(tmp2[1]) |
|
| 439 |
- if err != nil {
|
|
| 440 |
- return nil, err |
|
| 441 |
- } |
|
| 442 |
- |
|
| 443 |
- minor, err := strconv.Atoi(tmp2[2]) |
|
| 444 |
- if err != nil {
|
|
| 445 |
- return nil, err |
|
| 446 |
- } |
|
| 447 |
- |
|
| 448 |
- flavor := tmp[1] |
|
| 449 |
- |
|
| 450 |
- return &KernelVersionInfo{
|
|
| 451 |
- Kernel: kernel, |
|
| 452 |
- Major: major, |
|
| 453 |
- Minor: minor, |
|
| 454 |
- Flavor: flavor, |
|
| 455 |
- }, nil |
|
| 410 |
+ return getKernelVersion() |
|
| 456 | 411 |
} |
| 457 | 412 |
|
| 458 | 413 |
func (k *KernelVersionInfo) String() string {
|