Merge ~harlowja/cloud-init:config-entrypoints into cloud-init:master

Proposed by Joshua Harlow
Status: Rejected
Rejected by: Scott Moser
Proposed branch: ~harlowja/cloud-init:config-entrypoints
Merge into: cloud-init:master
Diff against target: 135 lines (+57/-13)
4 files modified
cloudinit/config/__init__.py (+0/-2)
cloudinit/importer.py (+11/-0)
cloudinit/stages.py (+30/-11)
setup.py (+16/-0)
Reviewer Review Type Date Requested Status
Scott Moser Disapprove
Review via email: mp+302609@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

We discussed this MP in #cloud-init. logs available at
https://irclogs.ubuntu.com/2016/08/16/%23cloud-init.html#t18:02

I don't like entry points usage because it is so very heavy on filesystem.
Example is here http://paste.ubuntu.com/23062607/ .

Basically that just calls the suggested 'iter_entry_points' and shows the cost of doing so.

It is *very* heavy to do this, and i'm dis-interested right now in slowing down cloud-init.

review: Disapprove

Unmerged commits

8ad0b3d... by Joshua Harlow

Use entrypoints for cloudinit.config

Instead of looking in a very specific location for
cloudinit config modules; which for those adding there
own modules makes it hard to do without patching that
location instead use entrypoints and register all
current cloudinit config modules by default with that
new entrypoint (and use that same entrypoint namespace
for later finding needed modules).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cloudinit/config/__init__.py b/cloudinit/config/__init__.py
2index d57453b..948ce5f 100644
3--- a/cloudinit/config/__init__.py
4+++ b/cloudinit/config/__init__.py
5@@ -39,8 +39,6 @@ def form_module_name(name):
6 canon_name = canon_name.strip()
7 if not canon_name:
8 return None
9- if not canon_name.startswith(MOD_PREFIX):
10- canon_name = '%s%s' % (MOD_PREFIX, canon_name)
11 return canon_name
12
13
14diff --git a/cloudinit/importer.py b/cloudinit/importer.py
15index fb57253..fb68d99 100644
16--- a/cloudinit/importer.py
17+++ b/cloudinit/importer.py
18@@ -20,6 +20,7 @@
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22+import pkg_resources
23 import sys
24
25
26@@ -56,3 +57,13 @@ def find_module(base_name, search_paths, required_attrs=None):
27 if found_attrs == len(required_attrs):
28 found_paths.append(full_path)
29 return (found_paths, lookup_paths)
30+
31+
32+def iter_entry_points(namespace, loader=None, name=None):
33+ for e in pkg_resources.iter_entry_points(namespace, name=name):
34+ if loader is None:
35+ thing = e.load()
36+ else:
37+ thing = loader(e)
38+ if thing is not None:
39+ yield (e.name, thing)
40diff --git a/cloudinit/stages.py b/cloudinit/stages.py
41index 47deac6..beb3cba 100644
42--- a/cloudinit/stages.py
43+++ b/cloudinit/stages.py
44@@ -54,6 +54,7 @@ LOG = logging.getLogger(__name__)
45
46 NULL_DATA_SOURCE = None
47 NO_PREVIOUS_INSTANCE_ID = "NO_PREVIOUS_INSTANCE_ID"
48+EP_CONFIG_NAMESPACE = 'cloudinit.config'
49
50
51 class Init(object):
52@@ -731,21 +732,39 @@ class Modules(object):
53 raw_name = raw_mod['mod']
54 freq = raw_mod.get('freq')
55 run_args = raw_mod.get('args') or []
56- mod_name = config.form_module_name(raw_name)
57- if not mod_name:
58+ canon_name = config.form_module_name(raw_name)
59+ if not canon_name:
60 continue
61+ ep_locs = list(
62+ importer.iter_entry_points(EP_CONFIG_NAMESPACE,
63+ name=canon_name))
64+ if not ep_locs:
65+ LOG.warn("Could not find entrypoint matching name '%s'"
66+ " (which is the canonicalized form of '%s')"
67+ " registered under namespace '%s'",
68+ canon_name, raw_name, EP_CONFIG_NAMESPACE)
69+ continue
70+ ep_names = [mod_name for (mod_name, _mod) in ep_locs]
71+ if len(ep_names) > 1:
72+ LOG.warn("Selecting '%s' entrypoint for configuration"
73+ " module '%s' (which is the canonicalized form"
74+ " of '%s') even though %s other entrypoints were"
75+ " found", ep_names[0], canon_name, raw_name,
76+ ep_names)
77+ else:
78+ LOG.debug("Selecting '%s' entrypoint for configuration"
79+ " module '%s' (which is the canonicalized"
80+ " form of '%s')", ep_names[0], canon_name, raw_name)
81+ # Entry points are yielded from the active distributions in
82+ # the order that the distributions appear on sys.path
83+ ep_name, mod = ep_locs[0]
84+ mod = config.fixup_module(mod)
85 if freq and freq not in FREQUENCIES:
86- LOG.warn(("Config specified module %s"
87- " has an unknown frequency %s"), raw_name, freq)
88+ LOG.warn("Config specified module '%s' (found at entrypoint"
89+ " '%s') has an unknown frequency %s",
90+ raw_name, ep_name, freq)
91 # Reset it so when ran it will get set to a known value
92 freq = None
93- mod_locs, looked_locs = importer.find_module(
94- mod_name, ['', type_utils.obj_name(config)], ['handle'])
95- if not mod_locs:
96- LOG.warn("Could not find module named %s (searched %s)",
97- mod_name, looked_locs)
98- continue
99- mod = config.fixup_module(importer.import_module(mod_locs[0]))
100 mostly_mods.append([mod, raw_name, freq, run_args])
101 return mostly_mods
102
103diff --git a/setup.py b/setup.py
104index 4abbb67..1949dd1 100755
105--- a/setup.py
106+++ b/setup.py
107@@ -196,6 +196,21 @@ requirements = read_requires()
108 if sys.version_info < (3,):
109 requirements.append('cheetah')
110
111+config_eps = []
112+for filename in os.listdir(os.path.join(os.getcwd(), "cloudinit", "config")):
113+ if filename.startswith("_"):
114+ continue
115+ else:
116+ if filename.endswith(".py"):
117+ realname = filename[0:-3]
118+ if realname.startswith("cc_"):
119+ basename = realname[3:]
120+ else:
121+ basename = realname
122+ config_eps.append(
123+ "%s = cloudinit.config.%s" % (basename, realname))
124+
125+
126 setuptools.setup(
127 name='cloud-init',
128 version=get_version(),
129@@ -213,5 +228,6 @@ setuptools.setup(
130 'console_scripts': [
131 'cloud-init = cloudinit.cmd.main:main'
132 ],
133+ 'cloudinit.config': config_eps,
134 }
135 )

Subscribers

People subscribed via source and target branches