github.com/coreos/mantle@v0.13.0/kola/tests/rkt/rkt.go (about) 1 // Copyright 2016 CoreOS, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package rkt 16 17 import ( 18 "bytes" 19 "fmt" 20 "strings" 21 "time" 22 23 "github.com/coreos/mantle/kola/cluster" 24 "github.com/coreos/mantle/kola/register" 25 "github.com/coreos/mantle/platform" 26 "github.com/coreos/mantle/platform/conf" 27 "github.com/coreos/mantle/util" 28 ) 29 30 var config = conf.Ignition(`{ 31 "ignition": { 32 "version": "2.0.0" 33 }, 34 "systemd": { 35 "units": [{ 36 "name": "etcd-member.service", 37 "enable": true 38 }] 39 } 40 }`) 41 42 func init() { 43 register.Register(®ister.Test{ 44 Name: "cl.rkt.etcd3", 45 Run: rktEtcd, 46 ClusterSize: 1, 47 Flags: []register.Flag{register.RequiresInternetAccess}, // etcdctl health-check requires networking 48 Distros: []string{"cl"}, 49 UserData: config, 50 }) 51 52 register.Register(®ister.Test{ 53 Name: "rkt.base", 54 ClusterSize: 1, 55 Run: rktBase, 56 Distros: []string{"cl"}, 57 }) 58 59 } 60 61 func rktEtcd(c cluster.TestCluster) { 62 m := c.Machines()[0] 63 64 etcdCmd := "etcdctl cluster-health" 65 etcdCheck := func() error { 66 output, err := c.SSH(m, etcdCmd) 67 if err != nil { 68 return fmt.Errorf("failed to run %q: output: %q status: %q", etcdCmd, output, err) 69 } 70 71 return nil 72 } 73 74 if err := util.Retry(60, 3*time.Second, etcdCheck); err != nil { 75 c.Fatalf("etcd in rkt failed health check: %v", err) 76 } 77 } 78 79 // we use subtests to improve testing performance here. Creating the aci is 80 // more expensive than actually running most of these tests. 81 func rktBase(c cluster.TestCluster) { 82 m := c.Machines()[0] 83 84 // TODO this should not be necessary, but is at the time of writing 85 c.MustSSH(m, "sudo setenforce 0") 86 87 createTestAci(c, m, "test.rkt.aci", []string{"echo", "sleep", "sh"}) 88 89 journalForPodContains := func(c cluster.TestCluster, uuidFile string, contains string) { 90 output := c.MustSSH(m, fmt.Sprintf("journalctl --dir /var/log/journal/$(cat %s | sed 's/-//g')", uuidFile)) 91 if !bytes.Contains(output, []byte(contains)) { 92 c.Fatalf("expected journal logs from machine dir to include app output %q; was %s", contains, output) 93 } 94 } 95 96 c.Run("cli", func(c cluster.TestCluster) { 97 uuidFile := "/tmp/run-test.uuid" 98 99 output := c.MustSSH(m, fmt.Sprintf("sudo rkt run --uuid-file-save=%s test.rkt.aci:latest --exec=sh -- -c 'echo success'", uuidFile)) 100 defer c.SSH(m, fmt.Sprintf("sudo rkt rm --uuid-file=%s", uuidFile)) 101 102 if !bytes.Contains(output, []byte("success")) { 103 c.Fatalf("expected rkt stdout to include app output ('success'); was %s", output) 104 } 105 106 journalForPodContains(c, uuidFile, "success") 107 }) 108 109 c.Run("unit", func(c cluster.TestCluster) { 110 uuidFile := "/tmp/run-as-unit-test.uuid" 111 112 c.MustSSH(m, fmt.Sprintf("sudo systemd-run --quiet --unit run-as-unit.service -- rkt run --uuid-file-save=%s test.rkt.aci:latest --exec=sh -- -c 'echo success'", uuidFile)) 113 defer c.SSH(m, fmt.Sprintf("sudo rkt rm --uuid-file=%s", uuidFile)) 114 115 c.MustSSH(m, fmt.Sprintf("while ! [ -s %s ]; do sleep 0.1; done; rkt status --wait $(cat %s)", uuidFile, uuidFile)) 116 117 journalForPodContains(c, uuidFile, "success") 118 }) 119 120 c.Run("machinectl-integration", func(c cluster.TestCluster) { 121 uuidFile := "/tmp/run-machinectl.uuid" 122 123 c.MustSSH(m, fmt.Sprintf("sudo systemd-run --quiet --unit run-machinectl -- rkt run --uuid-file-save=%s test.rkt.aci:latest --exec=sleep -- inf", uuidFile)) 124 defer c.SSH(m, fmt.Sprintf("sudo rkt rm --uuid-file=%s", uuidFile)) 125 126 c.MustSSH(m, fmt.Sprintf("while ! [ -s %s ]; do sleep 0.1; done; rkt status --wait-ready $(cat %s)", uuidFile, uuidFile)) 127 128 machinectlOutput := c.MustSSH(m, fmt.Sprintf("machinectl show rkt-$(cat %s)", uuidFile)) 129 130 for _, line := range []string{"State=running", "Class=container", "Service=rkt"} { 131 if !bytes.Contains(machinectlOutput, []byte(line)) { 132 c.Fatalf("expected machinectl to include %q: was %s", line, machinectlOutput) 133 } 134 } 135 136 c.MustSSH(m, fmt.Sprintf("sudo rkt stop --uuid-file=%s", uuidFile)) 137 c.MustSSH(m, fmt.Sprintf("rkt status --wait $(cat %s)", uuidFile)) 138 }) 139 } 140 141 // TODO: once rkt can fetch a local 'docker' image, using `genDockerContainer` 142 // from the docker test file could be a better solution. 143 func createTestAci(c cluster.TestCluster, m platform.Machine, name string, bins []string) { 144 // Has format strings for: 145 // 1) aci name 146 // 2) arch 147 testAciManifest := `{ 148 "acKind": "ImageManifest", 149 "acVersion": "0.8.9", 150 "name": "%s", 151 "labels": [{"name": "os","value": "linux"},{"name": "arch","value": "amd64"},{"name": "version","value": "latest"}] 152 }` 153 154 c.MustSSH(m, `set -e 155 tmpdir=$(mktemp -d) 156 cd $tmpdir 157 cat > manifest <<EOF 158 `+fmt.Sprintf(testAciManifest, name)+` 159 EOF 160 161 mkdir rootfs 162 bins=$(which `+strings.Join(bins, " ")+`) 163 libs=$(sudo ldd $bins | grep -o /lib'[^ ]*' | sort -u) 164 sudo rsync -av --relative --copy-links $bins $libs ./rootfs/ 165 166 sudo tar cf /tmp/test-aci.aci . 167 sudo rkt image fetch --insecure-options=image /tmp/test-aci.aci 168 cd 169 sudo rm -rf /tmp/test-aci.aci $tmpdir`) 170 }