Merge lp:~pjdc/glance-simplestreams-sync-charm/image-modifier-hook into lp:glance-simplestreams-sync-charm

Proposed by Paul Collins
Status: Merged
Merge reported by: Paul Collins
Merged at revision: not available
Proposed branch: lp:~pjdc/glance-simplestreams-sync-charm/image-modifier-hook
Merge into: lp:glance-simplestreams-sync-charm
Diff against target: 210 lines (+95/-9)
5 files modified
config.yaml (+25/-0)
hooks/hooks.py (+34/-3)
metadata.yaml (+3/-0)
scripts/glance-simplestreams-sync.py (+29/-6)
templates/mirrors.yaml (+4/-0)
To merge this branch: bzr merge lp:~pjdc/glance-simplestreams-sync-charm/image-modifier-hook
Reviewer Review Type Date Requested Status
Mike McCracken (community) Needs Fixing
Review via email: mp+226242@code.launchpad.net

Description of the change

Canonical IS uses glance-simplestreams-sync for an internal project.

We have made some changes to g-s-s support this project, as follows:

 * add a new hook, image-modifier, using a new interface, script-provider

   We use this hook to relate a subordinate charm that contains
   scripts used to pre-process images as they are synced to support
   our use cases. (One of these use cases involves spawning
   single-use instances to perform jobs that may take less than a
   minute, so we pre-install daemon packages, etc. to avoid losing too
   much time to things that be done to the image ahead of time.)

 * add a subclass of GlanceMirror, FilteredGlanceMirror, and use it

   GlanceMirror's filtering logic is hardcoded to a value that does
   not cover all of our anticipated use cases.

 * add two new config items, name_prefix and content_id_template

   name_prefix is used by our image-selection logic, and
   content_id_template is used so that multiple disjoint sets of
   images can be mirrored from the same source without interfering
   with each other. For example, one set of images via a g-s-s
   deployed with an image-modifier subordinate charm (see above) and a
   second g-s-s mirroring unmodified vanilla images.

 * run exec.d/*/charm-pre-install at the appropriate times

Please let me know what you think.

To post a comment you must log in.
Revision history for this message
Mike McCracken (mikemc) wrote :

Hi Paul, thanks for the work on this, I'm glad it's proving useful for you in IS.
Sorry for the slow response, this MP got buried in email at first.

The LP repo is a mirror - the main development of the sync charm is on github here:
https://github.com/Ubuntu-Solutions-Engineering/glance-simplestreams-sync-charm
If you're comfortable using git/github, it'd be easiest to merge things via PR's there.
If you'd prefer to use bzr&lp, I have no problems with reviewing
branches here and doing the patches myself in git.

As a general comment, I'd prefer to review separate branches for
separate changes: eg, one for adding the image-modifier relation and
one for adding filter config, etc. It makes it easier to approve one
change and get it merged while asking for feedback or changes on the others.

 - The image modifier script subordinate charm is a nice approach, we
   were thinking about how to support modify_hook here, and did not
   like the possibility of writing scripts quoted inside the yaml
   config.

 - As for the item filter, that subclass is a solid workaround for
   simplestreams not supporting it, but we probably don't need it - I
   fixed it in simplestreams upstream, so GlanceMirror in
   simplestreams in utopic now does pay attention to the item_filter
   args, while I'm pushing an SRU through to trusty to get it added
   there: https://bugs.launchpad.net/simplestreams/+bug/1339842 (Your
   adding a comment there might be useful to help push it, I'm not
   familiar with the process) If you need it on any other series,
   let's discuss.

   I also have a trusty build with that change (and one other, to
   support per-file download progress updates in glancemirror) in this
   PPA:
   https://launchpad.net/~cloud-installer/+archive/ubuntu/simplestreams-testing

 - It's nice to have the prefix and content-id settings fixed by
   someone who knows what they need there. Thanks!

 - Thanks for adding the execd support, too. I wasn't aware of its
   existence.

review: Needs Fixing
Revision history for this message
Mike McCracken (mikemc) wrote :

I'm currently breaking this branch into separate branches on the github repo, and will post the links here when I'm done.

Revision history for this message
Mike McCracken (mikemc) wrote :
Revision history for this message
Tom Haddon (mthaddon) wrote :

Hi Mike,

Thanks for doing those. Is there anything we/Paul should be doing on this end of things, or should we just monitor these pull requests and see as updates get applied or otherwise in github and then pulled back into LP?

Thanks, Tom

Revision history for this message
Mike McCracken (mikemc) wrote :

Hi Tom, I'd appreciate if someone (I guess Paul, or anyone else who's familiar with these changes) took a quick look at the pull requests and gave a +1.
There were a couple of minor changes, so I'd like to get a sanity check.

Also, just one clarification question:

Are you OK with waiting for a simplestreams SRU to get filtering on trusty or do you need a version of this charm that does its own filtering?

Revision history for this message
Paul Collins (pjdc) wrote :

Hi Mike,

I've eyeballed a diff between a Hulk-smash of your three PR branches and our version of the charm and the result looks reasonable to me.

Re glance filtering, we're happy to maintain GlanceFilteredMirror in our branch of the charm until the SRU is approved.

Cheers,
Paul

Revision history for this message
Paul Collins (pjdc) wrote :

These substance of these changes was upstreamed some time ago, so I'll mark this MP as merged.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'config.yaml'
2--- config.yaml 2014-07-08 22:49:07 +0000
3+++ config.yaml 2014-07-10 04:09:22 +0000
4@@ -29,3 +29,28 @@
5 type: string
6 default: "glance-simplestreams-sync-openstack"
7 description: "Cloud name to be used in simplestreams index file"
8+ name_prefix:
9+ type: string
10+ default: "auto-sync/"
11+ description: "This is prefixed to the object name when uploading to glance."
12+ content_id_template:
13+ type: string
14+ default: "auto.sync"
15+ description: >
16+ A Python-style .format() template to use when generating
17+ content_id properties for images uploaded to glance.
18+
19+ The content_id is considered when matching images between the
20+ source and destination to decide which images to mirror. By
21+ varying this value you can mirror disjoint sets of images from
22+ the same source into a single glance, either by using multiple
23+ deployments of this charm, or by using a tool such as
24+ sstream-mirror-glance, and they will not interfere with each
25+ other.
26+
27+ Here is a more interesting example value:
28+
29+ com.example.customstack.{region}:ubuntu:celery-worker
30+
31+ Currently the only available substitution is "region". Any
32+ other attempted substitutions will break the sync script.
33
34=== added directory 'exec.d'
35=== modified file 'hooks/hooks.py'
36--- hooks/hooks.py 2014-07-02 18:49:19 +0000
37+++ hooks/hooks.py 2014-07-10 04:09:22 +0000
38@@ -26,8 +26,9 @@
39 import sys
40 import shutil
41
42+from charmhelpers.core import hookenv
43 from charmhelpers.fetch import apt_install
44-from charmhelpers.core import hookenv
45+from charmhelpers.payload.execd import execd_preinstall
46
47 from charmhelpers.contrib.openstack.context import (IdentityServiceContext,
48 OSContextGenerator)
49@@ -49,15 +50,42 @@
50 hooks = hookenv.Hooks()
51
52
53+class MultipleImageModifierSubordinatesIsNotSupported(Exception):
54+ """Raise this if multiple image-modifier subordinates are related to this charm."""
55+ pass
56+
57+
58 class MirrorsConfigServiceContext(OSContextGenerator):
59- """Context for mirrors.yaml template - does not use relation info.
60+ """Context for mirrors.yaml template.
61 """
62 interfaces = ['simplestreams-image-service']
63
64 def __call__(self):
65 hookenv.log("Generating template ctxt for simplestreams-image-service")
66 config = hookenv.config()
67+
68+ modify_hook_scripts = []
69+ image_modifiers = hookenv.relations_of_type('image-modifier')
70+ if len(image_modifiers) > 1:
71+ raise MultipleImageModifierSubordinatesIsNotSupported()
72+
73+ try:
74+ modify_hook_scripts.append(image_modifiers[0]['script-path'])
75+ except IndexError: # no subordinate
76+ pass
77+ except KeyError as ke:
78+ print 'relation {} yielded exception {} - forging ahead'.format(
79+ repr(relation), repr(ke))
80+
81+ # default no-op so that None still means "missing" for config
82+ # validation (see elsewhere)
83+ if len(modify_hook_scripts) == 0:
84+ modify_hook_scripts.append('/bin/true')
85+
86 return dict(mirror_list=config['mirror_list'],
87+ modify_hook_scripts=', '.join(modify_hook_scripts),
88+ name_prefix=config['name_prefix'],
89+ content_id_template=config['content_id_template'],
90 use_swift=config['use_swift'],
91 region=config['region'],
92 cloud_name=config['cloud_name'])
93@@ -135,6 +163,7 @@
94
95 @hooks.hook('install')
96 def install():
97+ execd_preinstall()
98 for directory in [CONF_FILE_DIR, USR_SHARE_DIR]:
99 hookenv.log("creating config dir at {}".format(directory))
100 if not os.path.isdir(directory):
101@@ -151,7 +180,9 @@
102 hookenv.log('end install hook.')
103
104
105-@hooks.hook('config-changed')
106+@hooks.hook('config-changed',
107+ 'image-modifier-relation-changed',
108+ 'image-modifier-relation-joined')
109 def config_changed():
110 hookenv.log('begin config-changed hook.')
111
112
113=== added symlink 'hooks/image-modifier-relation-changed'
114=== target is u'hooks.py'
115=== added symlink 'hooks/image-modifier-relation-joined'
116=== target is u'hooks.py'
117=== modified file 'metadata.yaml'
118--- metadata.yaml 2014-05-27 13:36:53 +0000
119+++ metadata.yaml 2014-07-10 04:09:22 +0000
120@@ -10,6 +10,9 @@
121 provides:
122 simplestreams-image-service:
123 interface: glance-simplestreams-sync
124+ image-modifier:
125+ scope: container
126+ interface: script-provider
127 requires:
128 identity-service:
129 interface: keystone
130
131=== modified file 'scripts/glance-simplestreams-sync.py'
132--- scripts/glance-simplestreams-sync.py 2014-06-18 18:15:29 +0000
133+++ scripts/glance-simplestreams-sync.py 2014-07-10 04:09:22 +0000
134@@ -46,6 +46,7 @@
135 import atexit
136 from keystoneclient.v2_0 import client as keystone_client
137 import os
138+from simplestreams import filters
139 from simplestreams.mirrors import glance, UrlMirrorReader
140 from simplestreams.objectstores.swift import SwiftObjectStore
141 from simplestreams.util import read_signed, path_from_mirror_url
142@@ -71,13 +72,30 @@
143
144 CRON_POLL_FILENAME = '/etc/cron.d/glance_simplestreams_sync_fastpoll'
145
146+# As hardcoded in GlanceMirror:
147+DEFAULT_GLANCE_FILTERS = ['arch~(x86_64|amd64|i386)',
148+ 'ftype~(disk1.img|disk.img)']
149+
150+class FilteredGlanceMirror(glance.GlanceMirror):
151+ def __init__(self, config, objectstore=None, region=None, name_prefix=None):
152+ super(FilteredGlanceMirror, self).__init__(config=config,
153+ objectstore=objectstore,
154+ region=region,
155+ name_prefix=name_prefix)
156+ try:
157+ self.filters = filters.get_filters(config['filters'])
158+ except:
159+ self.filters = filters.get_filters(DEFAULT_GLANCE_FILTERS)
160+
161+ def filter_item(self, data, src, target, pedigree):
162+ return filters.filter_item(self.filters, data, src, pedigree)
163+
164+
165 # TODOs:
166 # - allow people to specify their own policy, since they can specify
167 # their own mirrors.
168 # - potentially allow people to specify backup mirrors?
169 # - debug keyring support
170-# - figure out what content_id is and whether we should allow users to
171-# set it
172
173
174 def policy(content, path):
175@@ -142,13 +160,18 @@
176 store = None
177
178 config = {'max_items': mirror_info['max'],
179+ 'modify_hook': charm_conf['modify_hook_scripts'],
180 'keep_items': False,
181- 'content_id': 'auto.sync',
182+ 'content_id': charm_conf['content_id_template'].format(
183+ region=charm_conf['region'],
184+ ),
185 'cloud_name': charm_conf['cloud_name'],
186- 'item_filters': mirror_info['item_filters']}
187+ 'filters': mirror_info['item_filters']}
188
189- tmirror = glance.GlanceMirror(config=config, objectstore=store)
190- log.info("calling GlanceMirror.sync")
191+ tmirror = FilteredGlanceMirror(config=config,
192+ objectstore=store,
193+ name_prefix=charm_conf['name_prefix'])
194+ log.info("calling FilteredGlanceMirror.sync")
195 tmirror.sync(smirror, path=initial_path)
196
197
198
199=== modified file 'templates/mirrors.yaml'
200--- templates/mirrors.yaml 2014-06-18 17:48:54 +0000
201+++ templates/mirrors.yaml 2014-07-10 04:09:22 +0000
202@@ -1,4 +1,8 @@
203 mirror_list: {{ mirror_list }}
204+modify_hook_scripts: {{ modify_hook_scripts }}
205+name_prefix: {{ name_prefix }}
206 use_swift: {{ use_swift }}
207 region: {{ region }}
208 cloud_name: {{ cloud_name }}
209+content_id_template: {{ content_id_template }}
210+

Subscribers

People subscribed via source and target branches