~ubuntu-core-dev/ubuntu/xenial/ubuntu-release-upgrader/xenial

« back to all changes in this revision

Viewing changes to AutoUpgradeTester/UpgradeTestBackendSSH.py

  • Committer: Michael Terry
  • Date: 2012-06-06 21:23:35 UTC
  • mto: This revision was merged to the branch mainline in revision 2509.
  • Revision ID: michael.terry@canonical.com-20120606212335-dt5xyu2v3ct5hcey
first pass at converting update-manager source into ubuntu-release-upgrader

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# abstract backend that is based around ssh login
2
 
 
3
 
from __future__ import absolute_import, print_function
4
 
 
5
 
from .UpgradeTestBackend import UpgradeTestBackend
6
 
 
7
 
import glob
8
 
import logging
9
 
import os
10
 
import subprocess
11
 
import time
12
 
 
13
 
 
14
 
class UpgradeTestBackendSSH(UpgradeTestBackend):
15
 
    " abstract backend that works with ssh "
16
 
 
17
 
    def __init__(self, profile):
18
 
        UpgradeTestBackend.__init__(self, profile)
19
 
        self.profiledir = os.path.dirname(profile)
20
 
        # get ssh key name
21
 
        self.ssh_key = os.path.abspath(
22
 
            self.config.getWithDefault(
23
 
                "NonInteractive",
24
 
                "SSHKey",
25
 
                "/var/cache/auto-upgrade-tester/ssh-key")
26
 
            )
27
 
        if not os.path.exists(self.ssh_key):
28
 
            print("Creating key: %s" % self.ssh_key)
29
 
            subprocess.call(["ssh-keygen","-N","","-f",self.ssh_key])
30
 
 
31
 
    def login(self):
32
 
        " run a shell in the image "
33
 
        print("login")
34
 
        self.start()
35
 
        ret = self._runInImage(["/bin/sh"])
36
 
        if ret != 0:
37
 
            logging.warn("_runInImage returned: %s" % ret)
38
 
        self.stop()
39
 
 
40
 
    def ping(self, user="root"):
41
 
        " check if the instance is ready "
42
 
        ret = self._runInImageAsUser(user, ["/bin/true"])
43
 
        return (ret == 0)
44
 
 
45
 
    def _copyToImage(self, fromF, toF, recursive=False):
46
 
        "copy a file (or a list of files) to the given toF image location"
47
 
        cmd = ["scp",
48
 
               "-P", self.ssh_port,
49
 
               "-q","-q", # shut it up
50
 
               "-i",self.ssh_key,
51
 
               "-o", "StrictHostKeyChecking=no",
52
 
               "-o", "UserKnownHostsFile=%s" % os.path.dirname(
53
 
                self.profile)+"/known_hosts"
54
 
               ]
55
 
        if recursive:
56
 
            cmd.append("-r")
57
 
        # we support both single files and lists of files
58
 
        if isinstance(fromF,list):
59
 
            cmd += fromF
60
 
        else:
61
 
            cmd.append(fromF)
62
 
        cmd.append("root@%s:%s" %  (self.ssh_hostname, toF))
63
 
        #print(cmd)
64
 
        ret = subprocess.call(cmd)
65
 
        return ret
66
 
 
67
 
    def _copyFromImage(self, fromF, toF):
68
 
        "copy a file from the given fromF image location"
69
 
        cmd = ["scp",
70
 
               "-P",self.ssh_port,
71
 
               "-q","-q", # shut it up
72
 
               "-i",self.ssh_key,
73
 
               "-o", "StrictHostKeyChecking=no",
74
 
               "-o", "UserKnownHostsFile=%s" % os.path.dirname(self.profile)+"/known_hosts",
75
 
               "root@%s:%s" %  (self.ssh_hostname, fromF),
76
 
               toF
77
 
               ]
78
 
        #print(cmd)
79
 
        ret = subprocess.call(cmd)
80
 
        return ret
81
 
 
82
 
 
83
 
    def _runInImage(self, command, **kwargs):
84
 
        ret = self._runInImageAsUser("root", command, **kwargs)
85
 
        return ret
86
 
 
87
 
    def _runInImageAsUser(self, user, command, **kwargs):
88
 
        "run a given command in the image"
89
 
        # ssh -l root -p 54321 localhost -i profile/server/ssh_key
90
 
        #     -o StrictHostKeyChecking=no
91
 
        ret = subprocess.call(["ssh",
92
 
                               "-tt",
93
 
                               "-l", user,
94
 
                               "-p",self.ssh_port,
95
 
                               self.ssh_hostname,
96
 
                               "-q","-q", # shut it up
97
 
                               "-i",self.ssh_key,
98
 
                               "-o", "StrictHostKeyChecking=no",
99
 
                               "-o", "BatchMode=yes",
100
 
                               "-o", "UserKnownHostsFile=%s" % os.path.dirname(self.profile)+"/known_hosts",
101
 
                               ]+command, **kwargs)
102
 
        return ret
103
 
 
104
 
 
105
 
    def installPackages(self, pkgs):
106
 
        " install additional pkgs (list) into the vm before the upgrade "
107
 
        if not pkgs:
108
 
            return True
109
 
        self.start()
110
 
        self._runInImage(["apt-get","update"])
111
 
        ret = self._runInImage(["DEBIAN_FRONTEND=noninteractive","apt-get","install", "--reinstall", "-y"]+pkgs)
112
 
        self.stop()
113
 
        return (ret == 0)
114
 
 
115
 
 
116
 
    def _copyUpgraderFilesFromBzrCheckout(self):
117
 
        " copy upgrader files from a bzr checkout "
118
 
        print("copy upgrader into image")
119
 
        # copy the upgrade into target+/upgrader-tester/
120
 
        files = []
121
 
        self._runInImage(["mkdir","-p","/upgrade-tester","/etc/update-manager/release-upgrades.d"])
122
 
        for f in glob.glob("%s/*" % self.upgradefilesdir):
123
 
            if not os.path.isdir(f):
124
 
                files.append(f)
125
 
            elif os.path.islink(f):
126
 
                print("Copying link '%s' to image " % f)
127
 
                self._copyToImage(f, "/upgrade-tester", recursive=True)
128
 
        self._copyToImage(files, "/upgrade-tester")
129
 
        # and any other cfg files
130
 
        for f in glob.glob(os.path.dirname(self.profile)+"/*.cfg"):
131
 
            if (os.path.isfile(f) and
132
 
                not os.path.basename(f).startswith("DistUpgrade.cfg")):
133
 
                print("Copying '%s' to image " % f)
134
 
                self._copyToImage(f, "/upgrade-tester")
135
 
        # base-installer
136
 
        bi="%s/base-installer" %  self.upgradefilesdir
137
 
        print("Copying '%s' to image" % bi)
138
 
        self._copyToImage(bi, "/upgrade-tester/", recursive=True)
139
 
        # copy the patches
140
 
        pd="%s/patches" %  self.upgradefilesdir
141
 
        print("Copying '%s' to image" % pd)
142
 
        self._copyToImage(pd, "/upgrade-tester/", recursive=True)
143
 
        # and prereq lists
144
 
        prereq = self.config.getWithDefault("PreRequists","SourcesList",None)
145
 
        if prereq is not None:
146
 
            prereq = os.path.join(os.path.dirname(self.profile),prereq)
147
 
            print("Copying '%s' to image" % prereq)
148
 
            self._copyToImage(prereq, "/upgrade-tester")
149
 
 
150
 
    def _runBzrCheckoutUpgrade(self, cmd_prefix):
151
 
        # start the upgrader
152
 
        print("running the upgrader now")
153
 
 
154
 
        # this is to support direct copying of backport udebs into the 
155
 
        # qemu image - useful for testing backports without having to
156
 
        # push them into the archive
157
 
        upgrader_args = ""
158
 
        upgrader_env = ""
159
 
 
160
 
        backports = self.config.getlist("NonInteractive", "PreRequistsFiles")
161
 
        if backports:
162
 
            self._runInImage(["mkdir -p /upgrade-tester/backports"])
163
 
            for f in backports:
164
 
                print("Copying %s" % os.path.basename(f))
165
 
                self._copyToImage(f, "/upgrade-tester/backports/")
166
 
                self._runInImage(["(cd /upgrade-tester/backports ; dpkg-deb -x %s . )" % os.path.basename(f)])
167
 
            upgrader_args = " --have-prerequists"
168
 
            upgrader_env = "LD_LIBRARY_PATH=/upgrade-tester/backports/usr/lib PATH=/upgrade-tester/backports/usr/bin:$PATH PYTHONPATH=/upgrade-tester/backports//usr/lib/python$(python -c 'import sys; print(\"%s.%s\" % (sys.version_info[0], sys.version_info[1]))')/site-packages/ "
169
 
 
170
 
        ret = self._runInImage(cmd_prefix+["(cd /upgrade-tester/ ; "
171
 
                                "%s./dist-upgrade.py %s)" % (upgrader_env,
172
 
                                                             upgrader_args)])
173
 
        return ret
174
 
 
175
 
    def test(self):
176
 
        # - generate diff of upgrade vs fresh install
177
 
        # ...
178
 
        #self.genDiff()
179
 
        self.start()
180
 
        # check for crashes
181
 
        self._copyFromImage("/var/crash/*.crash", self.resultdir)
182
 
        crashfiles = glob.glob(self.resultdir+"/*.crash")
183
 
        # run stuff in post_upgrade_tests dir
184
 
        ok = True
185
 
        results = []
186
 
        for script in glob.glob(self.post_upgrade_tests_dir+"*"):
187
 
            if not os.access(script, os.X_OK):
188
 
                continue
189
 
            result = {'name':os.path.basename(script),
190
 
                      'result':'pass',
191
 
                      'time':0,
192
 
                      'message':''
193
 
                     }
194
 
            start_time = time.time()
195
 
            logging.info("running '%s' post_upgrade_test" % script)
196
 
            self._copyToImage(script, "/tmp/")
197
 
            ret = self._runInImage(["/tmp/%s" % os.path.basename(script)])
198
 
            if ret != 0:
199
 
                print("WARNING: post_upgrade_test '%s' failed" % script)
200
 
                ok = False
201
 
                log=open(self.resultdir+"/test-%s.FAIL" % os.path.basename(script), "w")
202
 
                log.write("FAIL")
203
 
                result['result'] = 'fail'
204
 
                result['message'] = "post_upgrade_test '%s' failed" % script
205
 
            result['time'] = time.time() - start_time
206
 
            results.append(result)
207
 
 
208
 
        # check for conffiles (the copy is done via a post upgrade script)
209
 
        self._copyFromImage("/tmp/*.dpkg-dist", self.resultdir)
210
 
        # Collect debconf prompts generated by debconf_test.py script
211
 
        self._copyFromImage("/tmp/debconf_*.log", self.resultdir)
212
 
        self.resultsToJunitXML(results, os.path.join(self.resultdir, 'results.xml'))
213
 
 
214
 
        self.stop()
215
 
        if len(crashfiles) > 0:
216
 
            print("WARNING: crash files detected on the upgrade")
217
 
            print(crashfiles)
218
 
            return False
219
 
        return ok