Commit | Line | Data |
---|---|---|
92150710 MJ |
1 | #!/usr/bin/python |
2 | # -*- coding: utf-8 -*- | |
3 | # | |
4 | # Copyright (C) 2015 - Michael Jeanson <mjeanson@efficios.com> | |
5 | # | |
6 | # This program is free software: you can redistribute it and/or modify | |
7 | # it under the terms of the GNU General Public License as published by | |
8 | # the Free Software Foundation, either version 3 of the License, or | |
9 | # (at your option) any later version. | |
10 | # | |
11 | # This program is distributed in the hope that it will be useful, | |
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | # GNU General Public License for more details. | |
15 | # | |
16 | # You should have received a copy of the GNU General Public License | |
17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | ||
19 | """ This script is used to upgrade the base snapshot of standalone ci slaves """ | |
20 | ||
21 | USERNAME = '' | |
85edba54 | 22 | APIKEY = '' |
92150710 MJ |
23 | JENKINS_URL = 'https://ci.lttng.org' |
24 | ||
25 | DISTRO_LIST = ['el', 'sles', 'ubuntu'] | |
26 | DEFAULT_DISTRO = 'ubuntu' | |
27 | DISTRO_COMMAND = { | |
d6fb1365 | 28 | 'el': 'yum update -y && package-cleanup -y --oldkernels --count=2 && yum clean all', |
92150710 MJ |
29 | 'sles': 'zypper --non-interactive refresh && zypper --non-interactive patch --auto-agree-with-licenses --with-interactive', |
30 | 'ubuntu': 'apt-get update && apt-get dist-upgrade -V -y && apt-get clean && apt-get --purge autoremove -y', | |
31 | } | |
32 | ||
33 | BASESNAP = 'base-configuration' | |
34 | ||
35 | SNAPSHOTXML = """ | |
36 | <domainsnapshot> | |
37 | <name>%s</name> | |
38 | <description>Snapshot of OS install and updates</description> | |
39 | <memory snapshot='no'/> | |
40 | </domainsnapshot> | |
41 | """ % BASESNAP | |
42 | ||
43 | import argparse | |
44 | import sys | |
45 | import libvirt | |
85edba54 | 46 | from jenkinsapi.jenkins import Jenkins |
92150710 MJ |
47 | from time import sleep |
48 | import paramiko | |
49 | import select | |
50 | ||
51 | ||
52 | def main(): | |
53 | """ Main """ | |
54 | ||
55 | parser = argparse.ArgumentParser(description='Update base snapshot.') | |
56 | parser.add_argument('instance_name', metavar='INSTANCE', type=str, | |
57 | help='the shortname of the instance to update') | |
58 | parser.add_argument('vmhost_name', metavar='VMHOST', type=str, | |
59 | help='the hostname of the VM host') | |
60 | parser.add_argument('--distro', choices=DISTRO_LIST, | |
61 | default=DEFAULT_DISTRO, type=str, | |
62 | help='the distro of the target instance') | |
63 | ||
64 | args = parser.parse_args() | |
65 | ||
66 | instance_name = args.instance_name | |
67 | vmhost_name = args.vmhost_name | |
68 | distro = args.distro | |
69 | ||
70 | ||
71 | # Get jenkibs connexion | |
85edba54 | 72 | jenkins = Jenkins(JENKINS_URL, username=USERNAME, password=APIKEY) |
92150710 MJ |
73 | |
74 | # Get jenkins node | |
85edba54 MJ |
75 | print("Getting node %s from Jenkins..." % instance_name) |
76 | node = jenkins.get_node(instance_name) | |
77 | ||
78 | if not node: | |
79 | print("Could not get node %s on %s" % (instance_name, JENKINS_URL)) | |
80 | sys.exit(1) | |
81 | ||
82 | # Check if node is idle | |
83 | if not node.is_idle: | |
84 | print("Node %s is not idle" % instance_name) | |
85 | sys.exit(1) | |
86 | ||
92150710 MJ |
87 | |
88 | # Set node temporarily offline | |
85edba54 MJ |
89 | if not node.is_temporarily_offline(): |
90 | node.toggle_temporarily_offline('Down for upgrade to base snapshot') | |
92150710 MJ |
91 | |
92 | # Get libvirt connexion | |
93 | print("Opening libvirt connexion to %s..." % vmhost_name) | |
94 | vmhost = libvirt.open("qemu+ssh://root@%s/system" % vmhost_name) | |
95 | ||
96 | if not vmhost: | |
97 | print("Could not connect to libvirt on %s" % vmhost_name) | |
98 | sys.exit(1) | |
99 | ||
100 | # Get instance | |
101 | print("Getting instance %s from libvirt..." % instance_name) | |
102 | vminstance = vmhost.lookupByName(instance_name) | |
103 | ||
104 | if not vminstance: | |
105 | print("Could not get instance %s on %s" % (instance_name, vmhost_name)) | |
106 | sys.exit(1) | |
107 | ||
108 | # If instance is running, shutdown | |
109 | print("Checking if instance %s is running..." % instance_name) | |
110 | if vminstance.isActive(): | |
111 | try: | |
112 | print("Shutting down instance %s" % instance_name) | |
113 | vminstance.destroy() | |
114 | except: | |
115 | print("Failed to shutdown %s", instance_name) | |
116 | sys.exit(1) | |
117 | ||
118 | ||
119 | # Revert to base snapshot | |
120 | print("Getting base snapshot...") | |
121 | basesnap = vminstance.snapshotLookupByName(BASESNAP) | |
122 | if not basesnap: | |
123 | print("Could not find base snapshot %s" % BASESNAP) | |
124 | sys.exit(1) | |
125 | ||
126 | #if not basesnap.isCurrent(): | |
127 | # print("Not current snapshot") | |
128 | ||
129 | print("Reverting to base snapshot...") | |
130 | try: | |
131 | vminstance.revertToSnapshot(basesnap) | |
132 | except: | |
133 | print("Failed to revert to base snapshot %s" % basesnap.getName()) | |
134 | sys.exit(1) | |
135 | ||
136 | # Launch instance | |
137 | try: | |
138 | print("Starting instance %s.." % instance_name) | |
139 | vminstance.create() | |
140 | except: | |
141 | print("Failed to start instance %s" % instance_name) | |
142 | sys.exit(1) | |
143 | ||
144 | ||
145 | # Wait for instance to boot | |
146 | print("Waiting for instance to boot...") | |
147 | sleep(10) | |
148 | ||
149 | # Run dist-upgrade | |
150 | print("Running upgrade command...") | |
151 | client = paramiko.SSHClient() | |
152 | client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |
153 | client.load_system_host_keys() | |
154 | client.connect(instance_name, username="root") | |
155 | stdin, stdout, stderr = client.exec_command(DISTRO_COMMAND[distro]) | |
156 | while not stdout.channel.exit_status_ready(): | |
157 | if stdout.channel.recv_ready(): | |
158 | rl, wl, xl = select.select([stdout.channel], [], [], 0.0) | |
159 | if len(rl) > 0: | |
160 | print(stdout.channel.recv(1024)), | |
161 | ||
162 | if stdout.channel.recv_exit_status() != 0: | |
163 | print("Update command failed!") | |
164 | sys.exit(1) | |
165 | ||
166 | # Close ssh connexion | |
167 | client.close() | |
168 | ||
169 | # Shutdown VM | |
170 | print("Shutting down instance...") | |
171 | try: | |
172 | vminstance.shutdown() | |
173 | except: | |
174 | print("Failed to shutdown instance %s" % instance_name) | |
175 | sys.exit(1) | |
176 | ||
177 | while vminstance.isActive(): | |
178 | sleep(1) | |
179 | print("Waiting for instance to shutdown...") | |
180 | ||
181 | # Delete original base snapshot | |
182 | print("Deleting current base snapshot...") | |
183 | try: | |
184 | basesnap.delete() | |
185 | except: | |
186 | print("Failed to delete base snapshot %s" % basesnap.getName()) | |
187 | sys.exit(1) | |
188 | ||
189 | # Create new base snapshot | |
190 | print("Creating new base snapshot...") | |
191 | try: | |
192 | vminstance.snapshotCreateXML(SNAPSHOTXML) | |
193 | except: | |
194 | print("Failed to create new snapshot.") | |
195 | sys.exit(1) | |
196 | ||
85edba54 MJ |
197 | # Set node online in jenkins |
198 | if node.is_temporarily_offline(): | |
199 | node.toggle_temporarily_offline() | |
200 | ||
92150710 MJ |
201 | # And we're done! |
202 | print("All done!") | |
203 | ||
204 | ||
205 | if __name__ == "__main__": | |
206 | main() | |
207 | ||
208 | # EOF |