diff --git a/blueprints/docker-for-mac/base.yml b/blueprints/docker-for-mac/base.yml index f15c6ded9..2f3e91ff9 100644 --- a/blueprints/docker-for-mac/base.yml +++ b/blueprints/docker-for-mac/base.yml @@ -19,10 +19,10 @@ onboot: image: linuxkit/binfmt:0bde4ebd422099f45c5ee03217413523ad2223e5 # Format and mount the disk image in /var/lib/docker - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib"] # create docker dir on mounted drive if it doesn't exist - name: mkdir-docker image: alpine:3.6 diff --git a/docs/external-disk.md b/docs/external-disk.md index cba2ac2b2..5716e178d 100644 --- a/docs/external-disk.md +++ b/docs/external-disk.md @@ -19,45 +19,112 @@ The `-disk` specification may be repeated for multiple disks, although a limited **TODO:** GCP -## Mount the Disk -A disk created or used via `hyperkit run` will be available inside the image at `/dev/vda` with the first partition at `/dev/vda1`. +## Format the disk -In order to use the disk, you need to do several steps to make it available: +`pkg/format` creates a partition table and format drives for use with LinuxKit -1. Create a partition table if it does not have one. -2. Create a filesystem if it does not have one. -3. `fsck` the filesystem. -4. Mount it. +### Example Usage -To simplify the process, two `onboot` images are available for you to use: +This packages supports two modes of use: -1. `format`, which: - * checks for a partition table and creates one if necessary - * checks for a filesystem on the partition and creates one if necessary - * runs `fsck` on the filesystem -2. `mount` which mounts the filesystem to a provided path - -```yml +``` onboot: - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 - - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/external"] + image: linuxkit/format: ``` -Notice several key points: +In this mode of operation, the first disk found that does not have a valid partition table +will have one linux partition created that fills the entire disk -1. format container - * The format container needs to have bind mounts for `/dev` - * The format container needs `CAP_SYS_ADMIN` and `CAP_MKNOD` capabilities - * The format container only needs to run **once**, not matter how many external disks or partitions are provided. It finds all block devices under `/dev` and processes them. - * The default container config should be sufficient -2. mount container - * The mount container `command` is `mount.sh` followed by the desired mount point. Remember that nearly everything in a linuxkit image is read-only except under `/var`, so mount it there. - * The mount container needs to have bind mounts for `/dev` and `/var` - * The mount container needs `CAP_SYS_ADMIN` capabilities - * The mount container needs `rootfsPropagation: shared` - * The default container config should be sufficient, though the `mount.sh` command needs to be specified +### Options + +``` +onboot: + - name: format + image: linuxkit/format: + command: ["/usr/bin/format", "-type", "ext4", "-label", "DATA", "/dev/vda"] +``` + +`-type` can be used to specify the type. This is `ext4` by default but `btrfs` and `xfs` are also supported +`-label` can be used to give the disk a label +The final (optional) argument specifies the device name + +## Mount the disk + +Once a disk has been prepared it will need to be mounted using `pkg/mount` + +### Usage + +**NOTE: Block devices may only be mounted in `/var` unless you have explicitly added an additional bind mount** + +If no additional arguments are provided the first unmounted linux partition on the first block device is mounted to the mountpoint provided. + +``` +onboot: + - name: mount + image: linuxkit/mount: + command: ["/usr/bin/mountie", "/var/lib/docker"] +``` + +### Options + +You can provide either a partition label, device name or disk UUID to specify which disk should be used. +For example: + +``` +onboot: + - name: mount + image: linuxkit/mount: + command: ["/usr/bin/mountie", "-label", "DATA", "/var/lib/docker" ] +``` + +``` +onboot: + - name: mount + image: linuxkit/mount: + command: ["/usr/bin/mountie", "-uuid", "a-proper-uuid", "/var/lib/docker" ] +``` + +``` +onboot: + - name: mount + image: linuxkit/mount: + command: ["/usr/bin/mountie", "-device", "/dev/sda1", "/var/lib/docker" ] +``` + +For compatibility with the standard `mount` command we also support providing the device name as a positional argument. +E.g + +``` +onboot: + - name: mount + image: linuxkit/mount: + command: ["/usr/bin/mountie", "/dev/sda1", "/var/lib/docker" ] +``` + +## Extending Partitions + +`pkg/extend` can extends a single partition to fill the entire disk + +### Usage + +In the default mode of operation, any disks that are found and have a single partition and free space will have that partition extended. + +``` +onboot: + - name: extend + image: linuxkit/extend: +``` + +### Options + +`-type` can be used to specify the type. The default is `ext4` but `btrfs` and `xfs` are also supported. +If you know the name of the disk that you wish to extend you may supply this as an argument + +``` +onboot: + - name: extend + image: linuxkit/extend: + command: ["/usr/bin/extend", "-type", "btrfs", "/dev/vda"] +``` -With the above in place, if run with the current disk options, the image will make the external disk available as `/dev/vda1` and mount it at `/var/external`. diff --git a/examples/docker.yml b/examples/docker.yml index 48e953b01..9be2f0bf5 100644 --- a/examples/docker.yml +++ b/examples/docker.yml @@ -14,10 +14,10 @@ onboot: - name: binfmt image: linuxkit/binfmt:0bde4ebd422099f45c5ee03217413523ad2223e5 - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib/docker"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] services: - name: getty image: linuxkit/getty:894eef1e5f62f3bc31de8ffaff2b6c0e093c4595 diff --git a/examples/swap.yml b/examples/swap.yml index ac210923b..4530d672e 100644 --- a/examples/swap.yml +++ b/examples/swap.yml @@ -13,10 +13,10 @@ onboot: image: linuxkit/dhcpcd:17423c1ccced74e3c005fd80486e8177841fe02b command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/external"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/external"] - name: swap image: linuxkit/swap:b6d447b55da3c28bdd8a3f4e30fb42c1fa0157bb # to use unencrypted swap, use: diff --git a/pkg/extend/Dockerfile b/pkg/extend/Dockerfile new file mode 100644 index 000000000..2eda64f4e --- /dev/null +++ b/pkg/extend/Dockerfile @@ -0,0 +1,33 @@ +FROM linuxkit/alpine:488aa6f5dd2d8121a3c5c5c7a1ecf97c424b96ac AS mirror + +RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ +RUN apk add --no-cache --initdb -p /out \ + alpine-baselayout \ + busybox \ + e2fsprogs \ + e2fsprogs-extra \ + btrfs-progs \ + xfsprogs \ + xfsprogs-extra \ + musl \ + sfdisk \ + util-linux \ + && true +RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache + +FROM linuxkit/alpine:488aa6f5dd2d8121a3c5c5c7a1ecf97c424b96ac AS build + +RUN apk add --no-cache go musl-dev +ENV GOPATH=/go PATH=$PATH:/go/bin + +COPY extend.go /go/src/extend/ +RUN go-compile.sh /go/src/extend + +FROM scratch +ENTRYPOINT [] +CMD [] +WORKDIR / +COPY --from=mirror /out/ / +COPY --from=build /go/bin/extend usr/bin/extend +CMD ["/usr/bin/extend"] +LABEL org.mobyproject.config='{"binds": ["/dev:/dev"], "capabilities": ["CAP_SYS_ADMIN", "CAP_MKNOD"], "net": "new", "ipc": "new"}' diff --git a/pkg/extend/Makefile b/pkg/extend/Makefile new file mode 100644 index 000000000..eaa9d62b2 --- /dev/null +++ b/pkg/extend/Makefile @@ -0,0 +1,4 @@ +IMAGE=extend +DEPS=extend.go + +include ../package.mk diff --git a/pkg/extend/extend.go b/pkg/extend/extend.go new file mode 100644 index 000000000..a5d489156 --- /dev/null +++ b/pkg/extend/extend.go @@ -0,0 +1,290 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "regexp" + "sort" + "strings" + "syscall" + "time" +) + +const timeout = 60 + +var ( + fsTypeVar string + driveKeys []string +) + +// Fdisk is the JSON output from libfdisk +type Fdisk struct { + PartitionTable struct { + Label string `json:"label"` + ID string `json:"id"` + Device string `json:"device"` + Unit string `json:"unit"` + FirstLBA int `json:"firstlba"` + LastLBA int `json:"lastlba"` + Partitions []Partition + } `json:"partitionTable"` +} + +// Partition represents a single partition +type Partition struct { + Node string `json:"node"` + Start int `json:"start"` + Size int `json:"size"` + Type string `json:"type"` + UUID string `json:"uuid"` + Name string `json:"name"` +} + +func autoextend(fsType string) error { + for _, d := range driveKeys { + err := exec.Command("sfdisk", "-d", d).Run() + if err != nil { + log.Printf("No partition table found on device %s. Skipping.", d) + continue + } + if err := extend(d, fsType); err != nil { + return err + } + } + return nil +} + +func extend(d, fsType string) error { + mountpoint := "/mnt/tmp" + + data, err := exec.Command("sfdisk", "-J", d).Output() + if err != nil { + log.Fatalf("Unable to get drive data for %s from sfdisk: %v", d, err) + } + + f := Fdisk{} + if err := json.Unmarshal(data, &f); err != nil { + return fmt.Errorf("Unable to unmarshal partition table from sfdisk: %v", err) + } + + if len(f.PartitionTable.Partitions) > 1 { + log.Printf("Disk %s has more than 1 partition. Skipping", d) + return nil + } + + partition := f.PartitionTable.Partitions[0] + if partition.Type != "83" { + return fmt.Errorf("Partition 1 on disk %s is not a Linux Partition", d) + } + + if partition.Start+partition.Size == f.PartitionTable.LastLBA { + log.Printf("No free space on device to extend partition") + return nil + } + + switch fsType { + case "ext4": + if err := e2fsck(partition.Node, false); err != nil { + return fmt.Errorf("Initial e2fsck failed: %v", err) + } + // resize2fs fails unless we set force=true here + if err := e2fsck(partition.Node, true); err != nil { + return fmt.Errorf("e2fsck before resize failed: %v", err) + } + + if err := createPartition(d, partition); err != nil { + return err + } + + if err := exec.Command("resize2fs", partition.Node).Run(); err != nil { + return fmt.Errorf("Error running resize2fs: %v", err) + } + + if err := e2fsck(partition.Node, false); err != nil { + return fmt.Errorf("e2fsck after resize failed: %v", err) + } + case "btrfs": + // We don't check btrfs before or after mount as it's less susceptible to consistency errors + // than it's extfs cousins. + if err := os.MkdirAll(mountpoint, os.ModeDir); err != nil { + return err + } + if err := createPartition(d, partition); err != nil { + return err + } + if out, err := exec.Command("mount", partition.Node, mountpoint).CombinedOutput(); err != nil { + return fmt.Errorf("Error mounting partition: %s", string(out)) + } + if out, err := exec.Command("btrfs", "filesystem", "resize", "max", mountpoint).CombinedOutput(); err != nil { + return fmt.Errorf("Error resizing partition: %s\n%s", err, string(out)) + } + if out, err := exec.Command("umount", mountpoint).CombinedOutput(); err != nil { + return fmt.Errorf("Error unmounting partition: %s", string(out)) + } + case "xfs": + // We don't check xfs before mounting as the xfs_check or xfs_repair utilities + // should be used only if we suspect a file system consistency problem. + if err := os.MkdirAll(mountpoint, os.ModeDir); err != nil { + return err + } + if err := createPartition(d, partition); err != nil { + return err + } + if out, err := exec.Command("mount", partition.Node, mountpoint).CombinedOutput(); err != nil { + return fmt.Errorf("Error mounting partition: %s", string(out)) + } + if out, err := exec.Command("xfs_growfs", mountpoint).CombinedOutput(); err != nil { + return fmt.Errorf("Error resizing partition: %s\n%s", err, string(out)) + } + if out, err := exec.Command("umount", mountpoint).CombinedOutput(); err != nil { + return fmt.Errorf("Error unmounting partition: %s", string(out)) + } + if out, err := exec.Command("xfs_repair", "-n", partition.Node).CombinedOutput(); err != nil { + return fmt.Errorf("Error checking filesystem: %s", string(out)) + } + + default: + return fmt.Errorf("%s is not a supported filesystem", fsType) + } + + log.Printf("Successfully resized %s", d) + return nil +} + +func createPartition(d string, partition Partition) error { + if err := exec.Command("sfdisk", "-q", "--delete", d).Run(); err != nil { + return fmt.Errorf("Error erasing partition table: %v", err.Error()) + } + + createCmd := exec.Command("sfdisk", "-q", d) + createCmd.Stdin = strings.NewReader(fmt.Sprintf("%d,,83;", partition.Start)) + if err := createCmd.Run(); err != nil { + return fmt.Errorf("Error creating partition table: %v", err) + } + + if err := exec.Command("sfdisk", "-A", d, "1").Run(); err != nil { + return fmt.Errorf("Error making %s bootable: %v", d, err) + } + + // update status + if err := exec.Command("blockdev", "--rereadpt", d).Run(); err != nil { + return fmt.Errorf("Error running blockdev: %v", err) + } + + exec.Command("mdev", "-s").Run() + + // wait for device + var done bool + for i := 0; i < timeout; i++ { + stat, err := os.Stat(partition.Node) + if err == nil { + mode := stat.Sys().(*syscall.Stat_t).Mode + if (mode & syscall.S_IFMT) == syscall.S_IFBLK { + done = true + break + } + } + time.Sleep(100 * time.Millisecond) + exec.Command("mdev", "-s").Run() + } + if !done { + return fmt.Errorf("Error waiting for device %s", partition.Node) + } + // even after the device appears we still have a race + time.Sleep(1 * time.Second) + return nil +} + +func e2fsck(d string, force bool) error { + // preen + args := []string{"-p"} + if force { + args = append(args, "-f") + } + args = append(args, d) + if err := exec.Command("e2fsck", args...).Run(); err != nil { + if exiterr, ok := err.(*exec.ExitError); ok { + status, ok := exiterr.Sys().(syscall.WaitStatus) + if !ok { + return fmt.Errorf("Unable to get status code from e2fsck") + } + switch status.ExitStatus() { + case 1: + return nil + case 2, 3: + return fmt.Errorf("e2fsck fixed errors but requires a reboot") + } + } else { + return fmt.Errorf("Unable to cast err to ExitError") + } + } + + // exit code was > 4. try harder + args[0] = "-y" + if err := exec.Command("/sbin/e2fsck", args...).Run(); err != nil { + if exiterr, ok := err.(*exec.ExitError); ok { + status, ok := exiterr.Sys().(syscall.WaitStatus) + if !ok { + return fmt.Errorf("Unable to get status code from e2fsck") + } + switch status.ExitStatus() { + case 1: + return nil + case 2, 3: + return fmt.Errorf("e2fsck fixed errors but requires a reboot") + default: + return fmt.Errorf("e2fsck exited with fatal error: %v", err) + } + } else { + return fmt.Errorf("Unable to cast err to ExitError") + } + } + return nil +} + +// return a list of all available drives +func findDrives() { + driveKeys = []string{} + ignoreExp := regexp.MustCompile(`^loop.*$|^nbd.*$|^[a-z]+[0-9]+$`) + devs, _ := ioutil.ReadDir("/dev") + for _, d := range devs { + // this probably shouldn't be so hard + // but d.Mode()&os.ModeDevice == 0 doesn't work as expected + mode := d.Sys().(*syscall.Stat_t).Mode + if (mode & syscall.S_IFMT) != syscall.S_IFBLK { + continue + } + // ignore if it matches regexp + if ignoreExp.MatchString(d.Name()) { + continue + } + driveKeys = append(driveKeys, filepath.Join("/dev", d.Name())) + } + sort.Strings(driveKeys) +} + +func init() { + flag.StringVar(&fsTypeVar, "type", "ext4", "Type of filesystem to create") +} + +func main() { + flag.Parse() + findDrives() + if flag.NArg() == 0 { + if err := autoextend(fsTypeVar); err != nil { + log.Fatalf("%v", err) + } + } else { + for _, arg := range flag.Args() { + if err := extend(arg, fsTypeVar); err != nil { + log.Fatalf("%v", err) + } + } + } +} diff --git a/pkg/format/Dockerfile b/pkg/format/Dockerfile index eefa553db..9f44a74cb 100644 --- a/pkg/format/Dockerfile +++ b/pkg/format/Dockerfile @@ -1,4 +1,4 @@ -FROM linuxkit/alpine:9bcf61f605ef0ce36cc94d59b8eac307862de6e1 AS mirror +FROM linuxkit/alpine:488aa6f5dd2d8121a3c5c5c7a1ecf97c424b96ac AS mirror RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ RUN apk add --no-cache --initdb -p /out \ @@ -6,17 +6,27 @@ RUN apk add --no-cache --initdb -p /out \ busybox \ e2fsprogs \ e2fsprogs-extra \ - jq \ + btrfs-progs \ + xfsprogs \ musl \ sfdisk \ + util-linux \ && true RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache +FROM linuxkit/alpine:488aa6f5dd2d8121a3c5c5c7a1ecf97c424b96ac AS build + +RUN apk add --no-cache go musl-dev +ENV GOPATH=/go PATH=$PATH:/go/bin + +COPY format.go /go/src/format/ +RUN go-compile.sh /go/src/format + FROM scratch ENTRYPOINT [] CMD [] WORKDIR / COPY --from=mirror /out/ / -COPY format.sh / -CMD ["/bin/sh", "/format.sh"] +COPY --from=build /go/bin/format usr/bin/format +CMD ["/usr/bin/format"] LABEL org.mobyproject.config='{"binds": ["/dev:/dev"], "capabilities": ["CAP_SYS_ADMIN", "CAP_MKNOD"], "net": "new", "ipc": "new"}' diff --git a/pkg/format/Makefile b/pkg/format/Makefile index b7a136dea..587146eb1 100644 --- a/pkg/format/Makefile +++ b/pkg/format/Makefile @@ -1,4 +1,4 @@ IMAGE=format -DEPS=format.sh +DEPS=format.go include ../package.mk diff --git a/pkg/format/format.go b/pkg/format/format.go new file mode 100644 index 000000000..443f035d8 --- /dev/null +++ b/pkg/format/format.go @@ -0,0 +1,184 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "regexp" + "sort" + "strings" + "syscall" + "time" +) + +const ( + timeout = 60 + ext4opts = "resize_inode,has_journal,extent,huge_file,flex_bg,uninit_bg,64bit,dir_nlink,extra_isize" +) + +var ( + labelVar string + fsTypeVar string + drives map[string]bool + driveKeys []string +) + +func autoformat(label, fsType string) error { + var first string + for _, d := range driveKeys { + err := exec.Command("sfdisk", "-d", d).Run() + if err == nil { + log.Printf("Partition table found on device %s. Skipping.", d) + continue + } + first = d + break + } + + if first == "" { + return fmt.Errorf("No eligible disks found") + } + + if err := format(first, label, fsType); err != nil { + return err + } + + return nil +} + +func format(d, label, fsType string) error { + log.Printf("Creating partition on %s", d) + /* new disks do not have an DOS signature in sector 0 + this makes sfdisk complain. We can workaround this by letting + fdisk create that DOS signature, by just do a "w", a write. + http://bugs.alpinelinux.org/issues/145 + */ + fdiskCmd := exec.Command("fdisk", d) + fdiskCmd.Stdin = strings.NewReader("w") + if out, err := fdiskCmd.CombinedOutput(); err != nil { + return fmt.Errorf("Error running fdisk: %v\n%s", err, out) + } + + // format one large partition + partCmd := exec.Command("sfdisk", "--quiet", d) + partCmd.Stdin = strings.NewReader(";") + if out, err := partCmd.CombinedOutput(); err != nil { + return fmt.Errorf("Error running sfdisk: %v\n%s", err, out) + } + + // update status + if err := exec.Command("blockdev", "--rereadpt", d).Run(); err != nil { + return fmt.Errorf("Error running blockdev: %v", err) + } + + exec.Command("mdev", "-s").Run() + + partition := fmt.Sprintf("%s1", d) + // wait for device + var done bool + for i := 0; i < timeout; i++ { + stat, err := os.Stat(partition) + if err == nil { + mode := stat.Sys().(*syscall.Stat_t).Mode + if (mode & syscall.S_IFMT) == syscall.S_IFBLK { + done = true + break + } + } + time.Sleep(100 * time.Millisecond) + exec.Command("mdev", "-s").Run() + } + if !done { + return fmt.Errorf("Error waiting for device %s", partition) + } + // even after the device appears we still have a race + time.Sleep(1 * time.Second) + + // mkfs + mkfsArgs := []string{"-t", fsType} + + switch fsType { + case "ext4": + ext4Args := []string{"-F", "-O", ext4opts} + if label != "" { + ext4Args = append(ext4Args, []string{"-L", label}...) + } + mkfsArgs = append(mkfsArgs, ext4Args...) + case "btrfs": + btrfsArgs := []string{"-f"} + if label != "" { + btrfsArgs = append(btrfsArgs, []string{"-l", label}...) + } + mkfsArgs = append(mkfsArgs, btrfsArgs...) + case "xfs": + xfsArgs := []string{"-f"} + if label != "" { + xfsArgs = append(xfsArgs, []string{"-L", label}...) + } + mkfsArgs = append(mkfsArgs, xfsArgs...) + default: + log.Println("WARNING: Unsupported filesystem.") + } + + mkfsArgs = append(mkfsArgs, partition) + if out, err := exec.Command("mkfs", mkfsArgs...).CombinedOutput(); err != nil { + return fmt.Errorf("Error running mkfs: %v\n%s", err, string(out)) + } + + log.Printf("Partition %s successfully created!", partition) + return nil +} + +// return a list of all available drives +func findDrives() { + drives = make(map[string]bool) + driveKeys = []string{} + ignoreExp := regexp.MustCompile(`^loop.*$|^nbd.*$|^[a-z]+[0-9]+$`) + devs, _ := ioutil.ReadDir("/dev") + for _, d := range devs { + // this probably shouldn't be so hard + // but d.Mode()&os.ModeDevice == 0 doesn't work as expected + mode := d.Sys().(*syscall.Stat_t).Mode + if (mode & syscall.S_IFMT) != syscall.S_IFBLK { + continue + } + // ignore if it matches regexp + if ignoreExp.MatchString(d.Name()) { + continue + } + driveKeys = append(driveKeys, filepath.Join("/dev", d.Name())) + } + sort.Strings(driveKeys) + for _, d := range driveKeys { + drives[d] = true + } +} + +func init() { + flag.StringVar(&labelVar, "label", "", "Disk label to apply") + flag.StringVar(&fsTypeVar, "type", "ext4", "Type of filesystem to create") +} + +func main() { + flag.Parse() + + findDrives() + + if flag.NArg() > 1 { + log.Fatalf("Too many arguments provided") + } + + if flag.NArg() == 0 { + if err := autoformat(labelVar, fsTypeVar); err != nil { + log.Fatalf("%v", err) + } + } else { + if err := format(flag.Args()[0], labelVar, fsTypeVar); err != nil { + log.Fatalf("%v", err) + } + } +} diff --git a/pkg/format/format.sh b/pkg/format/format.sh deleted file mode 100755 index 6ae912bdb..000000000 --- a/pkg/format/format.sh +++ /dev/null @@ -1,116 +0,0 @@ -#!/bin/sh - -# this script assumes anything on the disk can be removed if corrupted -# other use cases may need different scripts. - -# currently only supports ext4 but should be expanded - -do_fsck() -{ - # preen - /sbin/e2fsck -p $* - EXIT_CODE=$? - # exit code 1 is errors corrected - [ "${EXIT_CODE}" -eq 1 ] && EXIT_CODE=0 - # exit code 2 or 3 means need to reboot - [ "${EXIT_CODE}" -eq 2 -o "${EXIT_CODE}" -eq 3 ] && /sbin/reboot - # exit code 4 or over is fatal - [ "${EXIT_CODE}" -lt 4 ] && return "${EXIT_CODE}" - - # try harder - /sbin/e2fsck -y $* - # exit code 1 is errors corrected - [ "${EXIT_CODE}" -eq 1 ] && EXIT_CODE=0 - # exit code 2 or 3 means need to reboot - [ "${EXIT_CODE}" -eq 2 -o "${EXIT_CODE}" -eq 3 ] && /sbin/reboot - # exit code 4 or over is fatal - [ "${EXIT_CODE}" -ge 4 ] && printf "Filesystem unrecoverably corrupted, will reformat\n" - - return "${EXIT_CODE}" -} - -do_fsck_extend_mount() -{ - DRIVE="$1" - DATA="$2" - - do_fsck "$DATA" || return 1 - - # only try to extend if there is a single partition and free space - PARTITIONS=$(sfdisk -J "$DRIVE" | jq '.partitiontable.partitions | length') - - if [ "$PARTITIONS" -eq 1 ] && \ - sfdisk -F "$DRIVE" | grep -q 'Unpartitioned space' && - ! sfdisk -F "$DRIVE" | grep -q '0 B, 0 bytes, 0 sectors' - then - SPACE=$(sfdisk -F "$DRIVE" | grep 'Unpartitioned space') - printf "Resizing disk partition: $SPACE\n" - - # 83 is Linux partition id - START=$(sfdisk -J "$DRIVE" | jq -e '.partitiontable.partitions | map(select(.type=="83")) | .[0].start') - - sfdisk -q --delete "$DRIVE" 2> /dev/null - echo "${START},,83;" | sfdisk -q "$DRIVE" - - # set bootable flag - sfdisk -A "$DRIVE" 1 - - # update status - blockdev --rereadpt $diskdev 2> /dev/null - mdev -s - - # wait for device - for i in $(seq 1 50); do test -b "$DATA" && break || sleep .1; mdev -s; done - - # resize2fs fails unless we use -f here - do_fsck -f "$DATA" || return 1 - resize2fs "$DATA" - - do_fsck "$DATA" || return 1 - fi -} - -do_mkfs() -{ - diskdev="$1" - - # new disks does not have an DOS signature in sector 0 - # this makes sfdisk complain. We can workaround this by letting - # fdisk create that DOS signature, by just do a "w", a write. - # http://bugs.alpinelinux.org/issues/145 - echo "w" | fdisk $diskdev >/dev/null - - # format one large partition - echo ";" | sfdisk --quiet $diskdev - - # update status - blockdev --rereadpt $diskdev 2> /dev/null - - # wait for device - for i in $(seq 1 50); do test -b "$DATA" && break || sleep .1; mdev -s; done - - FSOPTS="-O resize_inode,has_journal,extent,huge_file,flex_bg,uninit_bg,64bit,dir_nlink,extra_isize" - - mkfs.ext4 -q -F $FSOPTS ${diskdev}1 -} - -# TODO fix for multiple disks, cdroms etc -DEV="$(find /dev -maxdepth 1 -type b ! -name 'loop*' | grep -v '[0-9]$' | sed 's@.*/dev/@@' | sort | head -1 )" - -[ -z "${DEV}" ] && exit 1 - -DRIVE="/dev/${DEV}" - -# see if it has a partition table already -if sfdisk -d "${DRIVE}" >/dev/null 2>/dev/null -then - DATA=$(sfdisk -J "$DRIVE" | jq -e -r '.partitiontable.partitions | map(select(.type=="83")) | .[0].node') - if [ $? -eq 0 ] - then - do_fsck_extend_mount "$DRIVE" "$DATA" || do_mkfs "$DRIVE" - else - do_mkfs "$DRIVE" - fi -else - do_mkfs "$DRIVE" -fi diff --git a/pkg/mount/Dockerfile b/pkg/mount/Dockerfile index caafe8fcc..7c0592239 100644 --- a/pkg/mount/Dockerfile +++ b/pkg/mount/Dockerfile @@ -1,20 +1,27 @@ -FROM linuxkit/alpine:9bcf61f605ef0ce36cc94d59b8eac307862de6e1 AS mirror +FROM linuxkit/alpine:488aa6f5dd2d8121a3c5c5c7a1ecf97c424b96ac AS mirror RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ RUN apk add --no-cache --initdb -p /out \ alpine-baselayout \ busybox \ - jq \ musl \ sfdisk \ && true RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache +FROM linuxkit/alpine:488aa6f5dd2d8121a3c5c5c7a1ecf97c424b96ac AS build + +RUN apk add --no-cache go musl-dev +ENV GOPATH=/go PATH=$PATH:/go/bin + +COPY *.go /go/src/mountie/ +RUN go-compile.sh /go/src/mountie + FROM scratch ENTRYPOINT [] CMD [] WORKDIR / COPY --from=mirror /out/ / -COPY mount.sh / -CMD ["/bin/sh", "/mount.sh"] -LABEL org.mobyproject.config='{"binds": ["/dev:/dev", "/var:/var:rshared,rbind"], "capabilities": ["CAP_SYS_ADMIN"], "rootfsPropagation": "shared", "net": "new", "ipc": "new"}' +COPY --from=build /go/bin/mountie usr/bin/mountie +CMD ["/usr/bin/mountie"] +LABEL org.mobyproject.config='{"binds": ["/dev:/dev", "/var:/var:rshared,rbind", "/:/hostroot"], "capabilities": ["CAP_SYS_ADMIN"], "rootfsPropagation": "shared", "net": "new", "ipc": "new"}' diff --git a/pkg/mount/Makefile b/pkg/mount/Makefile index 2deb1dbf3..6e246442b 100644 --- a/pkg/mount/Makefile +++ b/pkg/mount/Makefile @@ -1,4 +1,4 @@ IMAGE=mount -DEPS=mount.sh +DEPS=mountie.go include ../package.mk diff --git a/pkg/mount/mount.sh b/pkg/mount/mount.sh deleted file mode 100755 index ebf54e8b1..000000000 --- a/pkg/mount/mount.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -MOUNTPOINT="$1" - -[ -z "$MOUNTPOINT" ] && echo "No mountpoint specified" && exit 1 - -mkdir -p "$MOUNTPOINT" - -mount_drive() -{ - # TODO fix for multiple disks, cdroms etc - DEVS="$(find /dev -maxdepth 1 -type b ! -name 'loop*' ! -name 'nbd*' | grep -v '[0-9]$' | sed 's@.*/dev/@@' | sort)" - - for DEV in $DEVS - do - DRIVE="/dev/${DEV}" - - # see if it has a partition table - if sfdisk -d "${DRIVE}" >/dev/null 2>/dev/null - then - # 83 is Linux partition identifier - DATA=$(sfdisk -J "$DRIVE" | jq -e -r '.partitiontable.partitions | map(select(.type=="83")) | .[0].node') - if [ $? -eq 0 ] - then - mount "$DATA" "$MOUNTPOINT" && return - fi - fi - done - - echo "WARNING: Failed to mount a persistent volume (is there one?)" -} - -mount_drive diff --git a/pkg/mount/mountie.go b/pkg/mount/mountie.go new file mode 100644 index 000000000..b304add00 --- /dev/null +++ b/pkg/mount/mountie.go @@ -0,0 +1,192 @@ +package main + +import ( + "bufio" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "regexp" + "sort" + "strings" + "syscall" +) + +var ( + deviceVar, labelVar, uuidVar string +) + +// Fdisk is the JSON output from libfdisk +type Fdisk struct { + PartitionTable struct { + Label string `json:"label"` + ID string `json:"id"` + Device string `json:"device"` + Unit string `json:"unit"` + FirstLBA int `json:"firstlba"` + LastLBA int `json:"lastlba"` + Partitions []struct { + Node string `json:"node"` + Start int `json:"start"` + Size int `json:"size"` + Type string `json:"type"` + UUID string `json:"uuid"` + Name string `json:"name"` + } + } `json:"partitionTable"` +} + +// mount drive/partition to mountpoint +func mount(device, mountpoint string) error { + if out, err := exec.Command("mount", device, mountpoint).CombinedOutput(); err != nil { + return fmt.Errorf("Error mounting %s to %s: %v\n%s", device, mountpoint, err, string(out)) + + } + return nil +} + +func findDevice(pattern string) (string, error) { + out, err := exec.Command("findfs", pattern).Output() + if err != nil { + return "", fmt.Errorf("Error finding device with %s: %v", pattern, err) + } + device := strings.TrimSpace(string(out)) + return device, nil +} + +func findFirst(drives []string) (string, error) { + var first string + + out, err := exec.Command("mount").Output() + if err != nil { + return "", err + } + + mounted := make(map[string]bool) + scanner := bufio.NewScanner(strings.NewReader(string(out))) + for scanner.Scan() { + parts := strings.Split(scanner.Text(), " ") + if _, err := os.Stat(parts[0]); os.IsNotExist(err) { + continue + } + if _, ok := mounted[parts[0]]; !ok { + mounted[parts[0]] = true + } + } + + for _, d := range drives { + err := exec.Command("sfdisk", "-d", d).Run() + if err != nil { + log.Printf("No partition table found on device %s. Skipping.", d) + continue + } + + data, err := exec.Command("sfdisk", "-J", d).Output() + if err != nil { + log.Fatalf("Unable to get drive data for %s from sfdisk: %v", d, err) + } + + f := Fdisk{} + if err := json.Unmarshal(data, &f); err != nil { + return "", fmt.Errorf("Unable to unmarshal partition table from sfdisk: %v", err) + } + + for _, partition := range f.PartitionTable.Partitions { + // ignore anything that isn't a Linux partition + if partition.Type != "83" { + continue + } + if _, ok := mounted[partition.Node]; ok { + log.Printf("%s already mounted. Skipping", partition.Node) + continue + } + first = partition.Node + break + } + } + if first == "" { + return "", fmt.Errorf("No eligible disks found") + } + return first, nil +} + +// return a list of all available drives +func findDrives() []string { + driveKeys := []string{} + ignoreExp := regexp.MustCompile(`^loop.*$|^nbd.*$|^[a-z]+[0-9]+$`) + devs, _ := ioutil.ReadDir("/dev") + for _, d := range devs { + // this probably shouldn't be so hard + // but d.Mode()&os.ModeDevice == 0 doesn't work as expected + mode := d.Sys().(*syscall.Stat_t).Mode + if (mode & syscall.S_IFMT) != syscall.S_IFBLK { + continue + } + // ignore if it matches regexp + if ignoreExp.MatchString(d.Name()) { + continue + } + driveKeys = append(driveKeys, filepath.Join("/dev", d.Name())) + } + sort.Strings(driveKeys) + return driveKeys +} + +func init() { + flag.StringVar(&deviceVar, "device", "", "Name of the device to mount") + flag.StringVar(&labelVar, "label", "", "Label of the device to mount") + flag.StringVar(&uuidVar, "uuid", "", "UUID of the device to mount") +} + +func main() { + flag.Parse() + + var mountpoint string + + switch flag.NArg() { + case 0: + log.Fatal("No mountpoints provided") + case 1: + mountpoint = flag.Args()[0] + case 2: + deviceVar = flag.Args()[0] + mountpoint = flag.Args()[1] + default: + log.Fatalf("Too many arguments") + } + + err := os.MkdirAll(mountpoint, os.ModeDir) + if err != nil { + log.Fatalf("Unable to create mountpoint %s: %v", mountpoint, err) + } + if deviceVar == "" && labelVar != "" { + deviceVar, err = findDevice(fmt.Sprintf("LABEL=%s", labelVar)) + if err != nil { + log.Fatal(err) + } + } + if deviceVar == "" && uuidVar != "" { + deviceVar, err = findDevice(fmt.Sprintf("UUID=%s", uuidVar)) + if err != nil { + log.Fatal(err) + } + } + + if deviceVar == "" { + // find first device + drives := findDrives() + first, err := findFirst(drives) + if err != nil { + log.Fatal(err) + } + deviceVar = first + } + + if err := mount(deviceVar, mountpoint); err != nil { + log.Fatal(err) + } +} diff --git a/projects/compose/compose-dynamic.yml b/projects/compose/compose-dynamic.yml index 828b8cf5d..0f029607a 100644 --- a/projects/compose/compose-dynamic.yml +++ b/projects/compose/compose-dynamic.yml @@ -17,10 +17,10 @@ onboot: - name: binfmt image: linuxkit/binfmt:0bde4ebd422099f45c5ee03217413523ad2223e5 - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib/docker"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] services: - name: rngd image: linuxkit/rngd:1516d5d70683a5d925fe475eb1b6164a2f67ac3b diff --git a/projects/compose/compose-static.yml b/projects/compose/compose-static.yml index 682aaceec..892d32385 100644 --- a/projects/compose/compose-static.yml +++ b/projects/compose/compose-static.yml @@ -17,10 +17,10 @@ onboot: - name: binfmt image: linuxkit/binfmt:0bde4ebd422099f45c5ee03217413523ad2223e5 - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib/docker"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] services: - name: rngd image: linuxkit/rngd:1516d5d70683a5d925fe475eb1b6164a2f67ac3b diff --git a/projects/etcd/etcd.yml b/projects/etcd/etcd.yml index 3fa1a839e..f57e84844 100644 --- a/projects/etcd/etcd.yml +++ b/projects/etcd/etcd.yml @@ -10,10 +10,10 @@ onboot: - name: sysctl image: linuxkit/sysctl:d1a43c7c91e92374766f962dc8534cf9508756b0 - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib/etcd"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/etcd"] - name: dhcpcd image: linuxkit/dhcpcd:17423c1ccced74e3c005fd80486e8177841fe02b command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] diff --git a/projects/kubernetes/kube-master.yml b/projects/kubernetes/kube-master.yml index 8d501668b..3dc9b73d6 100644 --- a/projects/kubernetes/kube-master.yml +++ b/projects/kubernetes/kube-master.yml @@ -16,10 +16,10 @@ onboot: - name: metadata image: linuxkit/metadata:f5d4299909b159db35f72547e4ae70bd76c42c6c - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mounts - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib/"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/"] - name: var image: library/alpine:3.6 command: ["mkdir", "/var/lib/kubeadm"] diff --git a/projects/kubernetes/kube-node.yml b/projects/kubernetes/kube-node.yml index 0eb8dcf09..cf0f65016 100644 --- a/projects/kubernetes/kube-node.yml +++ b/projects/kubernetes/kube-node.yml @@ -16,10 +16,10 @@ onboot: - name: metadata image: linuxkit/metadata:f5d4299909b159db35f72547e4ae70bd76c42c6c - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mounts - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib/"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/"] - name: var image: library/alpine:3.6 command: ["mkdir", "/var/lib/kubeadm"] diff --git a/projects/swarmd/swarmd.yml b/projects/swarmd/swarmd.yml index dc4d8abd0..544279912 100644 --- a/projects/swarmd/swarmd.yml +++ b/projects/swarmd/swarmd.yml @@ -15,10 +15,10 @@ onboot: image: linuxkit/dhcpcd:17423c1ccced74e3c005fd80486e8177841fe02b command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib/swarmd"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/swarmd"] - name: metadata image: linuxkit/metadata:f5d4299909b159db35f72547e4ae70bd76c42c6c services: diff --git a/test/cases/030_security/000_docker-bench/test-docker-bench.yml b/test/cases/030_security/000_docker-bench/test-docker-bench.yml index 6e69decf0..5d01ab816 100644 --- a/test/cases/030_security/000_docker-bench/test-docker-bench.yml +++ b/test/cases/030_security/000_docker-bench/test-docker-bench.yml @@ -14,10 +14,10 @@ onboot: - name: binfmt image: linuxkit/binfmt:0bde4ebd422099f45c5ee03217413523ad2223e5 - name: format - image: linuxkit/format:84a997e69051a1bf05b7c1926ab785bb07932954 + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 - name: mount - image: linuxkit/mount:ac8939c4102f97c084d9ddfd445c1908fce6d768 - command: ["/mount.sh", "/var/lib/docker"] + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] services: - name: rngd image: linuxkit/rngd:1516d5d70683a5d925fe475eb1b6164a2f67ac3b diff --git a/test/cases/040_packages/008_format_mount/000_auto/check.sh b/test/cases/040_packages/008_format_mount/000_auto/check.sh new file mode 100755 index 000000000..7f0b16d2e --- /dev/null +++ b/test/cases/040_packages/008_format_mount/000_auto/check.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function failed { + printf "format_mount test suite FAILED\n" >&1 + exit 1 +} + +touch /var/lib/docker/foo || failed + +printf "format_mount test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/008_format_mount/000_auto/test.sh b/test/cases/040_packages/008_format_mount/000_auto/test.sh new file mode 100644 index 000000000..adcf20390 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/000_auto/test.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SUMMARY: Check that a disk can be formatted and mounted +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-format + +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; +} + +trap clean_up EXIT + +# Test code goes here +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${NAME}1.img,size=512M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/008_format_mount/000_auto/test.yml b/test/cases/040_packages/008_format_mount/000_auto/test.yml new file mode 100644 index 000000000..29f73bcc7 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/000_auto/test.yml @@ -0,0 +1,30 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format"] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/008_format_mount/001_by_label/check.sh b/test/cases/040_packages/008_format_mount/001_by_label/check.sh new file mode 100755 index 000000000..7f0b16d2e --- /dev/null +++ b/test/cases/040_packages/008_format_mount/001_by_label/check.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function failed { + printf "format_mount test suite FAILED\n" >&1 + exit 1 +} + +touch /var/lib/docker/foo || failed + +printf "format_mount test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/008_format_mount/001_by_label/test.sh b/test/cases/040_packages/008_format_mount/001_by_label/test.sh new file mode 100644 index 000000000..47017b995 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/001_by_label/test.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SUMMARY: Check that a formatted disk can be mounted by label +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-format + +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; +} + +trap clean_up EXIT + +# Test code goes here +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${NAME}1.img,size=512M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/008_format_mount/001_by_label/test.yml b/test/cases/040_packages/008_format_mount/001_by_label/test.yml new file mode 100644 index 000000000..fffb9f486 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/001_by_label/test.yml @@ -0,0 +1,30 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format", "-label", "docker"] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "-label", "docker", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/008_format_mount/002_by_name/.gitignore b/test/cases/040_packages/008_format_mount/002_by_name/.gitignore new file mode 100644 index 000000000..e9af030ae --- /dev/null +++ b/test/cases/040_packages/008_format_mount/002_by_name/.gitignore @@ -0,0 +1 @@ +test.yml diff --git a/test/cases/040_packages/008_format_mount/002_by_name/check.sh b/test/cases/040_packages/008_format_mount/002_by_name/check.sh new file mode 100755 index 000000000..7f0b16d2e --- /dev/null +++ b/test/cases/040_packages/008_format_mount/002_by_name/check.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function failed { + printf "format_mount test suite FAILED\n" >&1 + exit 1 +} + +touch /var/lib/docker/foo || failed + +printf "format_mount test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/008_format_mount/002_by_name/test.sh b/test/cases/040_packages/008_format_mount/002_by_name/test.sh new file mode 100644 index 000000000..35ccad89a --- /dev/null +++ b/test/cases/040_packages/008_format_mount/002_by_name/test.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# SUMMARY: Check that a formatted disk can be mounted by name +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-format + +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; + rm -rf test.yml || true +} + +trap clean_up EXIT +# Test code goes here +if [ "${RT_OS}" = "osx" ]; then + DEVICE="/dev/vda" +else + DEVICE="/dev/sda" +fi + +sed -e "s,@DEVICE@,${DEVICE},g" test.yml.orig > test.yml +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${NAME}1.img,size=512M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/008_format_mount/002_by_name/test.yml.orig b/test/cases/040_packages/008_format_mount/002_by_name/test.yml.orig new file mode 100644 index 000000000..829e333ec --- /dev/null +++ b/test/cases/040_packages/008_format_mount/002_by_name/test.yml.orig @@ -0,0 +1,30 @@ +kernel: + image: linuxkit/kernel:4.9.38 + cmdline: "console=ttyS0 page_poison=1" +init: + - linuxkit/init:059b2bb4b6efa5c58cf53fed4d0ea863521959fc + - linuxkit/runc:4a35484aa6f90a1f06cdf1fb36f7056926a084b9 +onboot: + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format", "@DEVICE@"] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "-device", "@DEVICE@1", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/008_format_mount/003_btrfs/check.sh b/test/cases/040_packages/008_format_mount/003_btrfs/check.sh new file mode 100755 index 000000000..7f0b16d2e --- /dev/null +++ b/test/cases/040_packages/008_format_mount/003_btrfs/check.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function failed { + printf "format_mount test suite FAILED\n" >&1 + exit 1 +} + +touch /var/lib/docker/foo || failed + +printf "format_mount test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/008_format_mount/003_btrfs/test.sh b/test/cases/040_packages/008_format_mount/003_btrfs/test.sh new file mode 100644 index 000000000..c102353f9 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/003_btrfs/test.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SUMMARY: Check that a btrfs formatted disk can be mounted +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-format + +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; +} + +trap clean_up EXIT + +# Test code goes here +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${NAME}1.img,size=512M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/008_format_mount/003_btrfs/test.yml b/test/cases/040_packages/008_format_mount/003_btrfs/test.yml new file mode 100644 index 000000000..207b79660 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/003_btrfs/test.yml @@ -0,0 +1,37 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: modprobe + image: alpine:3.6 + capabilities: [all] + binds: + - /lib/modules:/lib/modules + - /sys:/sys + command: ["modprobe", "btrfs"] + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format", "-type", "btrfs" ] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/008_format_mount/004_xfs/check.sh b/test/cases/040_packages/008_format_mount/004_xfs/check.sh new file mode 100755 index 000000000..7f0b16d2e --- /dev/null +++ b/test/cases/040_packages/008_format_mount/004_xfs/check.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function failed { + printf "format_mount test suite FAILED\n" >&1 + exit 1 +} + +touch /var/lib/docker/foo || failed + +printf "format_mount test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/008_format_mount/004_xfs/test.sh b/test/cases/040_packages/008_format_mount/004_xfs/test.sh new file mode 100644 index 000000000..29a4ea81f --- /dev/null +++ b/test/cases/040_packages/008_format_mount/004_xfs/test.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SUMMARY: Check that an XFS formatted disk can be mounted +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-format + +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; +} + +trap clean_up EXIT + +# Test code goes here +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${NAME}1.img,size=512M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/008_format_mount/004_xfs/test.yml b/test/cases/040_packages/008_format_mount/004_xfs/test.yml new file mode 100644 index 000000000..04a746238 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/004_xfs/test.yml @@ -0,0 +1,30 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format", "-type", "xfs" ] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/008_format_mount/010_multiple/check.sh b/test/cases/040_packages/008_format_mount/010_multiple/check.sh new file mode 100755 index 000000000..e630c59ea --- /dev/null +++ b/test/cases/040_packages/008_format_mount/010_multiple/check.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +function failed { + printf "format_mount test suite FAILED\n" >&1 + exit 1 +} + +touch /var/lib/docker/foo || failed +touch /var/foo/bar || failed + +printf "format_mount test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/008_format_mount/010_multiple/test.sh b/test/cases/040_packages/008_format_mount/010_multiple/test.sh new file mode 100644 index 000000000..93d763700 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/010_multiple/test.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SUMMARY: Check that the format and mount packages work +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-format + +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; +} + +trap clean_up EXIT + +# Test code goes here +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${NAME}1.img,size=512M -disk file=${NAME}2.img,size=512M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/008_format_mount/010_multiple/test.yml b/test/cases/040_packages/008_format_mount/010_multiple/test.yml new file mode 100644 index 000000000..b668db2d7 --- /dev/null +++ b/test/cases/040_packages/008_format_mount/010_multiple/test.yml @@ -0,0 +1,37 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format", "-label", "docker"] + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format", "-label", "foo"] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "-label", "docker", "/var/lib/docker"] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "-label", "foo", "/var/foo"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /var/foo:/var/foo + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/009_extend/000_ext4/Dockerfile b/test/cases/040_packages/009_extend/000_ext4/Dockerfile new file mode 100644 index 000000000..7d65b7bf1 --- /dev/null +++ b/test/cases/040_packages/009_extend/000_ext4/Dockerfile @@ -0,0 +1,2 @@ +FROM alpine:3.6 +RUN apk add --no-cache qemu-img sfdisk e2fsprogs util-linux diff --git a/test/cases/040_packages/009_extend/000_ext4/check.sh b/test/cases/040_packages/009_extend/000_ext4/check.sh new file mode 100755 index 000000000..c14eef3c5 --- /dev/null +++ b/test/cases/040_packages/009_extend/000_ext4/check.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -x + +function failed { + printf "extend test suite FAILED\n" >&1 + exit 1 +} + +[ -f /var/lib/docker/bar ] || failed +touch /var/lib/docker/foo || failed +df -h | grep -q "490.9M" || failed +printf "extend test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/009_extend/000_ext4/extend.sh b/test/cases/040_packages/009_extend/000_ext4/extend.sh new file mode 100755 index 000000000..f7f9e5788 --- /dev/null +++ b/test/cases/040_packages/009_extend/000_ext4/extend.sh @@ -0,0 +1,3 @@ +#!/bin/sh +set -ex +qemu-img resize -f qcow2 "$1" +256M diff --git a/test/cases/040_packages/009_extend/000_ext4/test-create.yml b/test/cases/040_packages/009_extend/000_ext4/test-create.yml new file mode 100644 index 000000000..4d0f6e533 --- /dev/null +++ b/test/cases/040_packages/009_extend/000_ext4/test-create.yml @@ -0,0 +1,25 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + command: ["touch", "/var/lib/docker/bar"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/009_extend/000_ext4/test.sh b/test/cases/040_packages/009_extend/000_ext4/test.sh new file mode 100644 index 000000000..91b8e86a2 --- /dev/null +++ b/test/cases/040_packages/009_extend/000_ext4/test.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# SUMMARY: Check that an ext4 partition can be extended +# LABELS: +# REPEAT: + +set -ex + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-extend +DISK=disk0.img +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; + rm -rf ${DISK} || true + docker rmi ${NAME} || true +} + +trap clean_up EXIT + +# Test code goes here +rm -rf ${DISK} || true +docker build -t ${NAME} . +moby build --name create -output kernel+initrd test-create.yml +linuxkit run -disk file=${DISK},size=256M create +rm -rf "create*" +[ -f ${DISK} ] || exit 1 +docker run -i --rm --privileged -v "$PWD:/tmp" -w /tmp ${NAME} ./extend.sh ${DISK} +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${DISK} ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/009_extend/000_ext4/test.yml b/test/cases/040_packages/009_extend/000_ext4/test.yml new file mode 100644 index 000000000..431743f30 --- /dev/null +++ b/test/cases/040_packages/009_extend/000_ext4/test.yml @@ -0,0 +1,29 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: extend + image: linuxkit/extend:1e81ffe40ad63887d6210228c2a791f28375ee0f + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/009_extend/001_btrfs/Dockerfile b/test/cases/040_packages/009_extend/001_btrfs/Dockerfile new file mode 100644 index 000000000..7d65b7bf1 --- /dev/null +++ b/test/cases/040_packages/009_extend/001_btrfs/Dockerfile @@ -0,0 +1,2 @@ +FROM alpine:3.6 +RUN apk add --no-cache qemu-img sfdisk e2fsprogs util-linux diff --git a/test/cases/040_packages/009_extend/001_btrfs/check.sh b/test/cases/040_packages/009_extend/001_btrfs/check.sh new file mode 100755 index 000000000..905634e7d --- /dev/null +++ b/test/cases/040_packages/009_extend/001_btrfs/check.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -x + +function failed { + printf "extend test suite FAILED\n" >&1 + exit 1 +} + +[ -f /var/lib/docker/bar ] || failed +touch /var/lib/docker/foo || failed +df -h | grep -q "511.0M" || failed +printf "extend test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/009_extend/001_btrfs/extend.sh b/test/cases/040_packages/009_extend/001_btrfs/extend.sh new file mode 100755 index 000000000..f7f9e5788 --- /dev/null +++ b/test/cases/040_packages/009_extend/001_btrfs/extend.sh @@ -0,0 +1,3 @@ +#!/bin/sh +set -ex +qemu-img resize -f qcow2 "$1" +256M diff --git a/test/cases/040_packages/009_extend/001_btrfs/test-create.yml b/test/cases/040_packages/009_extend/001_btrfs/test-create.yml new file mode 100644 index 000000000..cc0f430fe --- /dev/null +++ b/test/cases/040_packages/009_extend/001_btrfs/test-create.yml @@ -0,0 +1,33 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: modprobe + image: alpine:3.6 + capabilities: [all] + binds: + - /lib/modules:/lib/modules + - /sys:/sys + command: ["modprobe", "btrfs"] + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format", "-type", "btrfs" ] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + command: ["touch", "/var/lib/docker/bar"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/009_extend/001_btrfs/test.sh b/test/cases/040_packages/009_extend/001_btrfs/test.sh new file mode 100644 index 000000000..9649bc8f6 --- /dev/null +++ b/test/cases/040_packages/009_extend/001_btrfs/test.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# SUMMARY: Check that a btrfs partition can be extended +# LABELS: +# REPEAT: + +set -ex + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-extend +DISK=disk0.img +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; + rm -rf ${DISK} || true + docker rmi ${NAME} || true +} + +trap clean_up EXIT + +# Test code goes here +rm -rf disk0.img || true +docker build -t ${NAME} . +moby build --name create -output kernel+initrd test-create.yml +linuxkit run -disk file=${DISK},size=256M create +rm -rf "create*" +[ -f ${DISK} ] || exit 1 +docker run -i --rm --privileged -v "$PWD:/tmp" -w /tmp ${NAME} ./extend.sh ${DISK} +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${DISK} ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/009_extend/001_btrfs/test.yml b/test/cases/040_packages/009_extend/001_btrfs/test.yml new file mode 100644 index 000000000..6cc722d6a --- /dev/null +++ b/test/cases/040_packages/009_extend/001_btrfs/test.yml @@ -0,0 +1,37 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: modprobe + image: alpine:3.6 + capabilities: [all] + binds: + - /lib/modules:/lib/modules + - /sys:/sys + command: ["modprobe", "btrfs"] + - name: extend + image: linuxkit/extend:1e81ffe40ad63887d6210228c2a791f28375ee0f + command: ["/usr/bin/extend", "-type", "btrfs"] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/009_extend/002_xfs/Dockerfile b/test/cases/040_packages/009_extend/002_xfs/Dockerfile new file mode 100644 index 000000000..7d65b7bf1 --- /dev/null +++ b/test/cases/040_packages/009_extend/002_xfs/Dockerfile @@ -0,0 +1,2 @@ +FROM alpine:3.6 +RUN apk add --no-cache qemu-img sfdisk e2fsprogs util-linux diff --git a/test/cases/040_packages/009_extend/002_xfs/check.sh b/test/cases/040_packages/009_extend/002_xfs/check.sh new file mode 100755 index 000000000..4523db10d --- /dev/null +++ b/test/cases/040_packages/009_extend/002_xfs/check.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -x + +function failed { + printf "extend test suite FAILED\n" >&1 + exit 1 +} + +[ -f /var/lib/docker/bar ] || failed +touch /var/lib/docker/foo || failed +df -h | grep -q "507.7M" || failed +printf "extend test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/009_extend/002_xfs/extend.sh b/test/cases/040_packages/009_extend/002_xfs/extend.sh new file mode 100755 index 000000000..f7f9e5788 --- /dev/null +++ b/test/cases/040_packages/009_extend/002_xfs/extend.sh @@ -0,0 +1,3 @@ +#!/bin/sh +set -ex +qemu-img resize -f qcow2 "$1" +256M diff --git a/test/cases/040_packages/009_extend/002_xfs/test-create.yml b/test/cases/040_packages/009_extend/002_xfs/test-create.yml new file mode 100644 index 000000000..c97b2a616 --- /dev/null +++ b/test/cases/040_packages/009_extend/002_xfs/test-create.yml @@ -0,0 +1,26 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: format + image: linuxkit/format:efafddf9bc6165b5efaf09c532c15a1100a10e61 + command: ["/usr/bin/format", "-type", "xfs"] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + command: ["touch", "/var/lib/docker/bar"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +trust: + org: + - linuxkit + - library diff --git a/test/cases/040_packages/009_extend/002_xfs/test.sh b/test/cases/040_packages/009_extend/002_xfs/test.sh new file mode 100644 index 000000000..cc05a834f --- /dev/null +++ b/test/cases/040_packages/009_extend/002_xfs/test.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# SUMMARY: Check that an XFS partition can be extended +# LABELS: +# REPEAT: + +set -ex + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=test-extend +DISK=disk0.img +clean_up() { + find . -depth -iname "${NAME}*" -not -iname "*.yml" -exec rm -rf {} \; + rm -rf ${DISK} || true + docker rmi ${NAME} || true +} + +trap clean_up EXIT + +# Test code goes here +rm -rf disk0.img || true +docker build -t ${NAME} . +moby build --name create -output kernel+initrd test-create.yml +linuxkit run -disk file=${DISK},size=256M create +rm -rf "create*" +[ -f ${DISK} ] || exit 1 +docker run -i --rm --privileged -v "$PWD:/tmp" -w /tmp ${NAME} ./extend.sh ${DISK} +moby build -name ${NAME} -output kernel+initrd test.yml +RESULT="$(linuxkit run -disk file=${DISK} ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/009_extend/002_xfs/test.yml b/test/cases/040_packages/009_extend/002_xfs/test.yml new file mode 100644 index 000000000..535764a6e --- /dev/null +++ b/test/cases/040_packages/009_extend/002_xfs/test.yml @@ -0,0 +1,30 @@ +kernel: + image: linuxkit/kernel:4.9.39 + cmdline: "console=ttyS0" +init: + - linuxkit/init:838b772355a8690143b37de1cdd4ac5db725271f + - linuxkit/runc:d5cbeb95bdafedb82ad2cf11cff1a5da7fcae630 +onboot: + - name: extend + image: linuxkit/extend:1e81ffe40ad63887d6210228c2a791f28375ee0f + command: ["/usr/bin/extend", "-type", "xfs"] + - name: mount + image: linuxkit/mount:54990a6a69cb3ead4da8a9c1f0b651e27aea8d3f + command: ["/usr/bin/mountie", "/var/lib/docker"] + - name: test + image: alpine:3.6 + readonly: true + binds: + - /var/lib/docker:/var/lib/docker + - /check.sh:/check.sh + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:bce51402e293da0b653923a43c3c7be6e0effa05 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + - library