github.com/coreos/mantle@v0.13.0/kola/tests/update/update.go (about) 1 // Copyright 2018 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 update 16 17 import ( 18 "bufio" 19 "fmt" 20 "os" 21 "strings" 22 "time" 23 24 "github.com/coreos/go-omaha/omaha" 25 26 "github.com/coreos/mantle/kola" 27 "github.com/coreos/mantle/kola/cluster" 28 "github.com/coreos/mantle/kola/register" 29 tutil "github.com/coreos/mantle/kola/tests/util" 30 "github.com/coreos/mantle/platform" 31 "github.com/coreos/mantle/platform/local" 32 "github.com/coreos/mantle/util" 33 ) 34 35 func init() { 36 register.Register(®ister.Test{ 37 Name: "cl.update.payload", 38 Run: payload, 39 ClusterSize: 1, 40 NativeFuncs: map[string]func() error{ 41 "Omaha": Serve, 42 }, 43 Distros: []string{"cl"}, 44 }) 45 } 46 47 func Serve() error { 48 omahaserver, err := omaha.NewTrivialServer(":34567") 49 if err != nil { 50 return fmt.Errorf("creating trivial omaha server: %v\n", err) 51 } 52 53 omahawrapper := local.OmahaWrapper{TrivialServer: omahaserver} 54 55 if err = omahawrapper.AddPackage("/updates/update.gz", "update.gz"); err != nil { 56 return fmt.Errorf("bad payload: %v", err) 57 } 58 59 return omahawrapper.Serve() 60 } 61 62 func payload(c cluster.TestCluster) { 63 addr := configureOmahaServer(c, c.Machines()[0]) 64 65 // create the actual test machine, the machine 66 // that is created by the test registration is 67 // used to host the omaha server 68 m, err := c.NewMachine(nil) 69 if err != nil { 70 c.Fatalf("creating test machine: %v", err) 71 } 72 73 // Machines are intentionally configured post-boot 74 // via SSH to allow for testing versions which predate 75 // Ignition 76 configureMachineForUpdate(c, m, addr) 77 78 tutil.AssertBootedUsr(c, m, "USR-A") 79 80 updateMachine(c, m) 81 82 tutil.AssertBootedUsr(c, m, "USR-B") 83 84 tutil.InvalidateUsrPartition(c, m, "USR-A") 85 86 updateMachine(c, m) 87 88 tutil.AssertBootedUsr(c, m, "USR-A") 89 } 90 91 func configureOmahaServer(c cluster.TestCluster, srv platform.Machine) string { 92 if kola.UpdatePayloadFile == "" { 93 c.Skip("no update payload provided") 94 } 95 96 in, err := os.Open(kola.UpdatePayloadFile) 97 if err != nil { 98 c.Fatalf("opening update payload: %v", err) 99 } 100 defer in.Close() 101 if err := platform.InstallFile(in, srv, "/updates/update.gz"); err != nil { 102 c.Fatalf("copying update payload to omaha server: %v", err) 103 } 104 105 c.MustSSH(srv, fmt.Sprintf("sudo systemd-run --quiet ./kolet run %s Omaha", c.H.Name())) 106 107 err = util.WaitUntilReady(60*time.Second, 5*time.Second, func() (bool, error) { 108 _, _, err := srv.SSH(fmt.Sprintf("curl %s:34567", srv.PrivateIP())) 109 return err == nil, nil 110 }) 111 if err != nil { 112 c.Fatal("timed out waiting for omaha server to become active") 113 } 114 115 return fmt.Sprintf("%s:34567", srv.PrivateIP()) 116 } 117 118 func configureMachineForUpdate(c cluster.TestCluster, m platform.Machine, addr string) { 119 // update atomicly so nothing reading update.conf fails 120 c.MustSSH(m, fmt.Sprintf(`sudo bash -c "cat >/etc/coreos/update.conf.new <<EOF 121 GROUP=developer 122 SERVER=http://%s/v1/update 123 EOF"`, addr)) 124 c.MustSSH(m, "sudo mv /etc/coreos/update.conf{.new,}") 125 126 // inject dev key 127 c.MustSSH(m, `sudo bash -c "cat >/etc/coreos/update-payload-key.pub.pem <<EOF 128 -----BEGIN PUBLIC KEY----- 129 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzFS5uVJ+pgibcFLD3kbY 130 k02Edj0HXq31ZT/Bva1sLp3Ysv+QTv/ezjf0gGFfASdgpz6G+zTipS9AIrQr0yFR 131 +tdp1ZsHLGxVwvUoXFftdapqlyj8uQcWjjbN7qJsZu0Ett/qo93hQ5nHW7Sv5dRm 132 /ZsDFqk2Uvyaoef4bF9r03wYpZq7K3oALZ2smETv+A5600mj1Xg5M52QFU67UHls 133 EFkZphrGjiqiCdp9AAbAvE7a5rFcJf86YR73QX08K8BX7OMzkn3DsqdnWvLB3l3W 134 6kvIuP+75SrMNeYAcU8PI1+bzLcAG3VN3jA78zeKALgynUNH50mxuiiU3DO4DZ+p 135 5QIDAQAB 136 -----END PUBLIC KEY----- 137 EOF"`) 138 139 c.MustSSH(m, "sudo mount --bind /etc/coreos/update-payload-key.pub.pem /usr/share/update_engine/update-payload-key.pub.pem") 140 141 // disable reboot so the test has explicit control 142 c.MustSSH(m, "sudo systemctl mask --now locksmithd.service") 143 c.MustSSH(m, "sudo systemctl reset-failed locksmithd.service") 144 145 c.MustSSH(m, "sudo systemctl restart update-engine.service") 146 } 147 148 func updateMachine(c cluster.TestCluster, m platform.Machine) { 149 c.Logf("Triggering update_engine") 150 151 out, stderr, err := m.SSH("update_engine_client -check_for_update") 152 if err != nil { 153 c.Fatalf("Executing update_engine_client failed: %v: %v: %s", out, err, stderr) 154 } 155 156 err = util.WaitUntilReady(120*time.Second, 10*time.Second, func() (bool, error) { 157 envs, stderr, err := m.SSH("update_engine_client -status 2>/dev/null") 158 if err != nil { 159 return false, fmt.Errorf("checking status failed: %v: %s", err, stderr) 160 } 161 162 return splitNewlineEnv(string(envs))["CURRENT_OP"] == "UPDATE_STATUS_UPDATED_NEED_REBOOT", nil 163 }) 164 if err != nil { 165 c.Fatalf("waiting for UPDATE_STATUS_UPDATED_NEED_REBOOT: %v", err) 166 } 167 168 c.Logf("Rebooting test machine") 169 170 if err = m.Reboot(); err != nil { 171 c.Fatalf("reboot failed: %v", err) 172 } 173 } 174 175 // splits newline-delimited KEY=VAL pairs into a map 176 func splitNewlineEnv(envs string) map[string]string { 177 m := make(map[string]string) 178 sc := bufio.NewScanner(strings.NewReader(envs)) 179 for sc.Scan() { 180 spl := strings.SplitN(sc.Text(), "=", 2) 181 m[spl[0]] = spl[1] 182 } 183 return m 184 }