Merge lp:~ltrager/maas-images/read_stream_data into lp:maas-images

Proposed by Lee Trager
Status: Merged
Merged at revision: 238
Proposed branch: lp:~ltrager/maas-images/read_stream_data
Merge into: lp:maas-images
Diff against target: 118 lines (+65/-15)
1 file modified
meph2/commands/meph2_util.py (+65/-15)
To merge this branch: bzr merge lp:~ltrager/maas-images/read_stream_data
Reviewer Review Type Date Requested Status
maintainers of maas images Pending
Review via email: mp+272195@code.launchpad.net

Commit message

Parse existing stream data to prevent images from being regenerated

Description of the change

Parse existing simplestream data during the import and merge process. During the import process this allows us to prevent existing images from being regenerated. During the merge process this allows us to verify that existing images have the same SHA256 sum on both the source and target.

Currently this only supports reading simplestream data from the local filesystem.

To post a comment you must log in.
239. By Lee Trager

Add sys.exit when an error is detected

240. By Lee Trager

If the image exists during merge don't copy it

241. By Lee Trager

Output error to stderr and return 1

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'meph2/commands/meph2_util.py'
2--- meph2/commands/meph2_util.py 2015-09-11 18:31:22 +0000
3+++ meph2/commands/meph2_util.py 2015-09-24 17:14:55 +0000
4@@ -14,10 +14,12 @@
5 from meph2 import util
6 from meph2.url_helper import geturl_text
7
8-from simplestreams import filters
9-from simplestreams import mirrors
10-from simplestreams import util as sutil
11-from simplestreams import objectstores
12+from simplestreams import (
13+ contentsource,
14+ filters,
15+ mirrors,
16+ util as sutil,
17+ objectstores)
18
19 DEF_KEYRING = "/usr/share/keyrings/ubuntu-cloudimage-keyring.gpg"
20
21@@ -362,6 +364,25 @@
22 return sha256.hexdigest()
23
24
25+def load_product_streams(src):
26+ index_path = os.path.join(src, STREAMS_D, "index.json")
27+ if not os.path.exists(index_path):
28+ return []
29+ with contentsource.UrlContentSource(index_path) as tcs:
30+ index = sutil.load_content(tcs.read())
31+ return [product['path'] for product in index['index'].values()]
32+
33+
34+def load_products(path, product_streams):
35+ products = {}
36+ for product_stream in product_streams:
37+ with contentsource.UrlContentSource(
38+ os.path.join(path, product_stream)) as tcs:
39+ product_listing = sutil.load_content(tcs.read())
40+ products.update(product_listing['products'])
41+ return products
42+
43+
44 def main_insert(args):
45 (src_url, src_path) = sutil.path_from_mirror_url(args.src, None)
46 filter_list = filters.get_filters(args.filters)
47@@ -409,6 +430,9 @@
48 print("Error: Unable to find config file %s" % args.import_cfg)
49 os.exit(1)
50
51+ target_product_streams = load_product_streams(args.target)
52+ target_products = load_products(args.target, target_product_streams)
53+
54 with open(cfg_path) as fp:
55 cfgdata = yaml.load(fp)
56
57@@ -427,6 +451,13 @@
58
59 product_id = cfgdata['product_id'].format(
60 version=release_info['version'], arch=arch)
61+
62+ # If the product already exists don't regenerate the image, just copy
63+ # its metadata
64+ if product_id in target_products:
65+ product_tree['products'][product_id] = target_products[product_id]
66+ continue
67+
68 product_tree['products'][product_id] = {
69 'subarches': 'generic',
70 'label': 'release',
71@@ -479,17 +510,36 @@
72
73
74 def main_merge(args):
75- for (dir, subdirs, files) in os.walk(args.src):
76- for file in files:
77- if file.endswith(".sjson"):
78- continue
79- src_path = os.path.join(dir, file)
80- dest_path = os.path.join(
81- args.target, '/'.join(src_path.split('/')[1:]))
82- dest_dir = os.path.dirname(dest_path)
83- if not os.path.exists(dest_dir):
84- os.makedirs(dest_dir)
85- shutil.copy2(src_path, dest_path)
86+ src_product_streams = load_product_streams(args.src)
87+ target_product_streams = load_product_streams(args.target)
88+ src_products = load_products(args.src, src_product_streams)
89+ target_products = load_products(args.target, target_product_streams)
90+
91+ for (product_name, product_info) in src_products.items():
92+ for (version, version_info) in product_info['versions'].items():
93+ for (item, item_info) in version_info['items'].items():
94+ if product_name in target_products:
95+ target_product = target_products[product_name]
96+ target_version = target_product['versions'][version]
97+ target_item = target_version['items'][item]
98+ if item_info['sha256'] != target_item['sha256']:
99+ print(
100+ "Error: SHA256 of %s and %s do not match!" %
101+ (item['path'], target_item['path']),
102+ file=sys.stderr)
103+ sys.exit(1)
104+ else:
105+ continue
106+ file_src = os.path.join(args.src, item_info['path'])
107+ file_target = os.path.join(args.target, item_info['path'])
108+ target_dir = os.path.dirname(file_target)
109+ if not os.path.exists(target_dir):
110+ os.makedirs(target_dir)
111+ shutil.copy2(file_src, file_target)
112+ for product_stream in src_product_streams:
113+ shutil.copy2(
114+ os.path.join(args.src, product_stream),
115+ os.path.join(args.target, product_stream))
116
117 md_d = os.path.join(args.target, 'streams', 'v1')
118 if not os.path.exists(md_d):

Subscribers

People subscribed via source and target branches