967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
1 |
#!/usr/bin/python
|
967.1.16
by Curtis Hovey
Added some docstrings. |
2 |
"""Update the lxc 'download' template cache for hosts on closed networks."""
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
3 |
|
4 |
from __future__ import print_function |
|
5 |
||
6 |
from argparse import ArgumentParser |
|
7 |
from collections import namedtuple |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
8 |
import errno |
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
9 |
import os |
10 |
import sys |
|
11 |
import traceback |
|
12 |
import shutil |
|
13 |
import subprocess |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
14 |
import urllib2 |
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
15 |
|
16 |
||
17 |
SITE = 'https://images.linuxcontainers.org' |
|
18 |
INDEX_PATH = 'meta/1.0' |
|
19 |
INDEX = 'index-system' |
|
20 |
ROOTFS = 'rootfs.tar.xz' |
|
21 |
META = 'meta.tar.xz' |
|
22 |
LXC_CACHE = '/var/cache/lxc/download' |
|
23 |
||
24 |
||
25 |
System = namedtuple( |
|
26 |
'System', ['dist', 'release', 'arch', 'variant', 'version', 'path']) |
|
27 |
||
28 |
||
29 |
PUT_SCRIPT = """\ |
|
30 |
scp {rootfs_path} {meta_path} {user_host}:~/ |
|
31 |
"""
|
|
32 |
||
33 |
INSTALL_SCRIPT = """\ |
|
34 |
ssh {user_host} bash <<"EOT" |
|
35 |
sudo mkdir -p {lxc_cache} |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
36 |
sudo mv ~/{rootfs} ~/{meta} {lxc_cache} |
37 |
sudo chown -R root:root {lxc_cache} |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
38 |
sudo tar -C {lxc_cache} -xf {lxc_cache}/meta.tar.xz |
39 |
EOT
|
|
40 |
"""
|
|
41 |
||
42 |
||
43 |
class LxcCache: |
|
44 |
"""Manage the LXC download template cache."""
|
|
45 |
||
46 |
def __init__(self, workspace, verbose=False, dry_run=False): |
|
967.1.16
by Curtis Hovey
Added some docstrings. |
47 |
"""Set the workspace for the local cache."""
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
48 |
self.workspace = os.path.abspath(workspace) |
49 |
self.verbose = verbose |
|
50 |
self.dry_run = dry_run |
|
51 |
local_path = os.path.join(self.workspace, INDEX_PATH, INDEX) |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
52 |
self.systems, ignore = self.init_systems(local_path) |
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
53 |
|
54 |
def init_systems(self, location): |
|
967.1.16
by Curtis Hovey
Added some docstrings. |
55 |
"""Return a tuple of the dict of lxc Systems and the source data.
|
56 |
||
57 |
A System has these attributes: 'dist', 'release', 'arch', 'variant',
|
|
58 |
'version', and 'path'. The dict keys are a tuple of
|
|
59 |
(dist, release, arch, variant).
|
|
60 |
"""
|
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
61 |
systems = {} |
62 |
if location.startswith('http'): |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
63 |
request = urllib2.Request(location) |
64 |
response = urllib2.urlopen(request) |
|
65 |
data = response.read() |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
66 |
else: |
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
67 |
try: |
68 |
with open(location) as f: |
|
69 |
data = f.read() |
|
70 |
except IOError as e: |
|
71 |
if e.errno == errno.ENOENT: |
|
72 |
if self.verbose: |
|
73 |
print('Local cache is empty.') |
|
74 |
return systems, None |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
75 |
for line in data.splitlines(): |
76 |
system = System(*line.split(';')) |
|
77 |
key = (system.dist, system.release, system.arch, system.variant) |
|
78 |
systems[key] = system |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
79 |
return systems, data |
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
80 |
|
81 |
def get_updates(self, dist, release, arch, variant): |
|
967.1.16
by Curtis Hovey
Added some docstrings. |
82 |
"""Return a tuple of the new system and the source data that match.
|
83 |
||
967.1.17
by Curtis Hovey
Fix grammar and remove gremlin. |
84 |
The new system and source data will be None when there are
|
967.1.16
by Curtis Hovey
Added some docstrings. |
85 |
no updates. The dist, release, arch, and variant args identify the
|
967.1.17
by Curtis Hovey
Fix grammar and remove gremlin. |
86 |
system to return.
|
967.1.16
by Curtis Hovey
Added some docstrings. |
87 |
"""
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
88 |
key = (dist, release, arch, variant) |
89 |
old_system = self.systems.get(key) |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
90 |
url = '%s/%s/%s' % (SITE, INDEX_PATH, INDEX) |
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
91 |
new_systems, data = self.init_systems(url) |
92 |
new_system = new_systems[key] |
|
93 |
if not old_system or new_system.version > old_system.version: |
|
94 |
if self.verbose: |
|
95 |
print('Found new version for %s' % str(key)) |
|
96 |
print(new_system.version) |
|
97 |
return new_system, data |
|
98 |
if self.verbose: |
|
99 |
print('Version is current for %s' % str(key)) |
|
100 |
print(old_system.version) |
|
101 |
return None, None |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
102 |
|
103 |
def get_lxc_data(self, system): |
|
967.1.16
by Curtis Hovey
Added some docstrings. |
104 |
"""Download the system image and meta data.
|
105 |
||
106 |
Return a tuple of the image and meta data paths.
|
|
107 |
"""
|
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
108 |
image_path = os.path.join(self.workspace, system.path[1:]) |
109 |
if not self.dry_run: |
|
110 |
if self.verbose: |
|
111 |
print('creating %s' % image_path) |
|
112 |
if not os.path.isdir(image_path): |
|
967.1.12
by Curtis Hovey
Added test_get_lxc_data. |
113 |
os.makedirs(image_path) |
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
114 |
rootfs_path = os.path.join(image_path, ROOTFS) |
115 |
rootfs_url = '%s%s%s' % (SITE, system.path, ROOTFS) |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
116 |
self.download(rootfs_url, rootfs_path) |
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
117 |
meta_path = os.path.join(image_path, META) |
118 |
meta_url = '%s%s%s' % (SITE, system.path, META) |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
119 |
self.download(meta_url, meta_path) |
120 |
return rootfs_path, meta_path |
|
121 |
||
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
122 |
def download(self, location, path): |
967.1.16
by Curtis Hovey
Added some docstrings. |
123 |
"""Download a large binary from location to the specified path."""
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
124 |
chunk = 16 * 1024 |
125 |
if not self.dry_run: |
|
126 |
request = urllib2.Request(location) |
|
127 |
response = urllib2.urlopen(request) |
|
128 |
if response.getcode() == 200: |
|
129 |
with open(path, 'wb') as f: |
|
130 |
shutil.copyfileobj(response, f, chunk) |
|
131 |
if self.verbose: |
|
132 |
print('Downloaded %s' % location) |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
133 |
|
134 |
def put_lxc_data(self, user_host, system, rootfs_path, meta_path): |
|
967.1.16
by Curtis Hovey
Added some docstrings. |
135 |
"""Install the lxc image and meta data on the host.
|
136 |
||
137 |
The user on the host must have password-less sudo.
|
|
138 |
"""
|
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
139 |
lxc_cache = os.path.join( |
140 |
LXC_CACHE, system.dist, system.release, system.arch, |
|
141 |
system.variant) |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
142 |
put_script = PUT_SCRIPT.format( |
143 |
user_host=user_host, rootfs_path=rootfs_path, meta_path=meta_path) |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
144 |
if not self.dry_run: |
145 |
subprocess.check_call([put_script], shell=True) |
|
146 |
if self.verbose: |
|
147 |
print("Uploaded %s and %s" % (ROOTFS, META)) |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
148 |
install_script = INSTALL_SCRIPT.format( |
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
149 |
user_host=user_host, lxc_cache=lxc_cache, rootfs=ROOTFS, meta=META) |
150 |
if not self.dry_run: |
|
151 |
subprocess.check_call([install_script], shell=True) |
|
152 |
if self.verbose: |
|
153 |
print("Installed %s and %s" % (ROOTFS, META)) |
|
154 |
||
155 |
def save_index(self, data): |
|
967.1.16
by Curtis Hovey
Added some docstrings. |
156 |
"Save the (current) index data for future calls to get_updates()."
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
157 |
index_dir = os.path.join(self.workspace, INDEX_PATH) |
158 |
if not os.path.isdir(index_dir): |
|
159 |
os.makedirs(index_dir) |
|
160 |
index_path = os.path.join(self.workspace, INDEX_PATH, INDEX) |
|
161 |
with open(index_path, 'w') as f: |
|
162 |
f.write(data) |
|
163 |
if self.verbose: |
|
164 |
print('saved index: %s' % INDEX) |
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
165 |
|
166 |
||
167 |
def parse_args(argv=None): |
|
168 |
"""Return the argument parser for this program."""
|
|
169 |
parser = ArgumentParser( |
|
170 |
"Update a remote host's download lxc template cache.") |
|
171 |
parser.add_argument( |
|
172 |
'-d', '--dry-run', action='store_true', default=False, |
|
173 |
help='Do not make changes.') |
|
174 |
parser.add_argument( |
|
175 |
'-v', '--verbose', action='store_true', default=False, |
|
176 |
help='Increase verbosity.') |
|
177 |
parser.add_argument( |
|
178 |
'--dist', default="ubuntu", help="The distribution to update.") |
|
179 |
parser.add_argument( |
|
180 |
'--variant', default="default", help="The variant to update.") |
|
181 |
parser.add_argument( |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
182 |
'user_host', help='The user@host to update.') |
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
183 |
parser.add_argument( |
184 |
'release', help='The release to update.') |
|
185 |
parser.add_argument( |
|
967.1.16
by Curtis Hovey
Added some docstrings. |
186 |
'arch', help='The architecture of the remote host') |
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
187 |
parser.add_argument( |
188 |
'workspace', help='The path to the local dir to stage the update.') |
|
189 |
args = parser.parse_args(argv) |
|
190 |
return args |
|
191 |
||
192 |
||
193 |
def main(argv): |
|
967.1.16
by Curtis Hovey
Added some docstrings. |
194 |
"""Update the lxc download template cache for hosts on closed networks."""
|
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
195 |
args = parse_args(argv) |
196 |
try: |
|
197 |
lxc_cache = LxcCache( |
|
198 |
args.workspace, verbose=args.verbose, dry_run=args.dry_run) |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
199 |
new_system, data = lxc_cache.get_updates( |
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
200 |
args.dist, args.release, args.arch, args.variant) |
201 |
if new_system: |
|
202 |
rootfs_path, meta_path = lxc_cache.get_lxc_data(new_system) |
|
203 |
lxc_cache.put_lxc_data( |
|
204 |
args.user_host, new_system, rootfs_path, meta_path) |
|
967.1.2
by Curtis Hovey
Added a working script to keep ppc64-slave's lxc cache current. |
205 |
lxc_cache.save_index(data) |
967.1.1
by Curtis Hovey
Added spike to manage the lxc cache for hosts on private networks. |
206 |
except Exception as e: |
207 |
print(e) |
|
208 |
print(getattr(e, 'output', '')) |
|
209 |
if args.verbose: |
|
210 |
traceback.print_tb(sys.exc_info()[2]) |
|
211 |
return 2 |
|
212 |
if args.verbose: |
|
213 |
print("Done.") |
|
214 |
return 0 |
|
215 |
||
216 |
||
217 |
if __name__ == '__main__': |
|
218 |
sys.exit(main(sys.argv[1:])) |