Merge lp:~harlowja/cloud-init/query-back-duo into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Joshua Harlow
Status: Rejected
Rejected by: Chad Smith
Proposed branch: lp:~harlowja/cloud-init/query-back-duo
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 182 lines (+75/-21)
3 files modified
bin/cloud-init (+70/-13)
cloudinit/sources/__init__.py (+0/-4)
cloudinit/stages.py (+5/-4)
To merge this branch: bzr merge lp:~harlowja/cloud-init/query-back-duo
Reviewer Review Type Date Requested Status
Chad Smith Needs Fixing
Server Team CI bot continuous-integration Needs Fixing
Review via email: mp+141198@code.launchpad.net

Description of the change

Reworking the query tool back to life addition. This method is a little less intrusive.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) wrote :

Hello,
Thank you for taking the time to contribute to cloud-init. Cloud-init has moved its revision control system to git. We are cleaning up old reviews that no longer apply to the current codebase. As a result, we are marking all bzr merge proposals as 'rejected'. If you would like to re-submit this proposal for review, please do so by following the current HACKING documentation at http://cloudinit.readthedocs.io/en/latest/topics/hacking.html.

Also, as you know= cloud-init cmdline util has now moved to cloudinit/cmd/main.py

review: Needs Fixing

Unmerged revisions

755. By Joshua Harlow

Integrate a slightly cleaner query tool, bring it back to life!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/cloud-init'
2--- bin/cloud-init 2012-09-20 01:19:43 +0000
3+++ bin/cloud-init 2012-12-24 04:32:20 +0000
4@@ -26,6 +26,8 @@
5 import sys
6 import traceback
7
8+import cPickle as pickle
9+
10 # This is more just for running from the bin folder so that
11 # cloud-init binary can find the cloudinit module
12 possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
13@@ -45,6 +47,8 @@
14 from cloudinit import util
15 from cloudinit import version
16
17+from cloudinit.sources import DataSource
18+
19 from cloudinit.settings import (PER_INSTANCE, PER_ALWAYS, PER_ONCE,
20 CLOUD_CONFIG)
21
22@@ -56,12 +60,18 @@
23 # Module section template
24 MOD_SECTION_TPL = "cloud_%s_modules"
25
26-# Things u can query on
27-QUERY_DATA_TYPES = [
28- 'data',
29- 'data_raw',
30- 'instance_id',
31-]
32+# Things u can query on and the lambda to fetch that
33+# item when given a datasource to apply on
34+QUERY_DATA_TYPES = {
35+ 'metadata': lambda ds: ds.metadata,
36+ 'userdata': lambda ds: ds.userdata,
37+ 'iid': lambda ds: ds.get_instance_id(),
38+ 'hostname': lambda ds: ds.get_hostname(),
39+ 'locale': lambda ds: ds.get_locale(),
40+ 'az': lambda ds: ds.availability_zone,
41+ 'launch_index': lambda ds: ds.launch_index,
42+ 'public_keys': lambda ds: ds.get_public_ssh_keys(),
43+}
44
45 # Frequency shortname to full name
46 # (so users don't have to remember the full name...)
47@@ -86,6 +96,10 @@
48 sys.stderr.write("\n")
49
50
51+def is_root():
52+ return os.geteuid() == 0
53+
54+
55 def welcome(action, msg=None):
56 if not msg:
57 msg = welcome_format(action)
58@@ -346,9 +360,48 @@
59 return run_module_section(mods, name, name)
60
61
62-def main_query(name, _args):
63- raise NotImplementedError(("Action '%s' is not"
64- " currently implemented") % (name))
65+def main_query(name, args):
66+ # TODO(harlowja) refactor init so that
67+ # it is not the sole entrypoint for so many operations
68+ # perhaps split into
69+ init = stages.Init(ds_deps=[])
70+ safe_ds_where = init.paths.get_ipath_cur("obj_pkl_safe")
71+ if not os.path.isfile(safe_ds_where):
72+ if is_root() and args.populate:
73+ # At this point we can make a safe datasource from whatever
74+ # may exist locally (if anything)
75+ ds = init.fetch(True)
76+ if not ds:
77+ raise NotImplementedError(("No datasource found to "
78+ "convert into a 'safe' datasource"))
79+ else:
80+ # Keep only the basics, ignoring the userdata since typically
81+ # said userdata contains contents and data that users should
82+ # not always be able to see.
83+ safe_ds = DataSource(ds.sys_cfg, ds.distro, ds.paths)
84+ safe_ds.metadata = ds.metadata
85+ pk_contents = pickle.dumps(safe_ds)
86+ util.write_file(safe_ds_where, pk_contents, mode=0644)
87+ if args.what:
88+ ds = None
89+ if is_root():
90+ # Use a full datasource if running as root
91+ ds = init.fetch(True)
92+ if not ds:
93+ try:
94+ pk_contents = util.load_file(safe_ds_where)
95+ ds = pickle.loads(pk_contents)
96+ except:
97+ pass
98+ if not ds:
99+ raise NotImplementedError("No datasource found for querying.")
100+ for i in args.what:
101+ i_canon = i.lower().strip()
102+ if i_canon not in QUERY_DATA_TYPES:
103+ print("Unknown how to query on %s!" % (i))
104+ else:
105+ func = QUERY_DATA_TYPES[i_canon]
106+ print("%s: %s" % (i, func(ds)))
107
108
109 def main_single(name, args):
110@@ -468,10 +521,14 @@
111 parser_query = subparsers.add_parser('query',
112 help=('query information stored '
113 'in cloud-init'))
114- parser_query.add_argument("--name", '-n', action="store",
115- help="item name to query on",
116- required=True,
117- choices=QUERY_DATA_TYPES)
118+ if is_root():
119+ parser_query.add_argument("--populate", '-p', action="store_true",
120+ help=("populate the 'safe' "
121+ "datasource that users can query"),
122+ default=False)
123+ query_help = "query the given datasource field (%s)"
124+ query_help = query_help % (", ".join(sorted(QUERY_DATA_TYPES.keys())))
125+ parser_query.add_argument('what', nargs='*', help=query_help)
126 parser_query.set_defaults(action=('query', main_query))
127
128 # This subcommand allows you to run a single module
129
130=== modified file 'cloudinit/sources/__init__.py'
131--- cloudinit/sources/__init__.py 2012-11-12 17:26:49 +0000
132+++ cloudinit/sources/__init__.py 2012-12-24 04:32:20 +0000
133@@ -20,7 +20,6 @@
134 # You should have received a copy of the GNU General Public License
135 # along with this program. If not, see <http://www.gnu.org/licenses/>.
136
137-import abc
138 import os
139
140 from cloudinit import importer
141@@ -42,9 +41,6 @@
142
143
144 class DataSource(object):
145-
146- __metaclass__ = abc.ABCMeta
147-
148 def __init__(self, sys_cfg, distro, paths, ud_proc=None):
149 self.sys_cfg = sys_cfg
150 self.distro = distro
151
152=== modified file 'cloudinit/stages.py'
153--- cloudinit/stages.py 2012-12-17 13:41:11 +0000
154+++ cloudinit/stages.py 2012-12-24 04:32:20 +0000
155@@ -217,13 +217,14 @@
156 cfg_list = self.cfg.get('datasource_list') or []
157 return (cfg_list, pkg_list)
158
159- def _get_data_source(self):
160+ def _get_data_source(self, local_only):
161 if self.datasource is not NULL_DATA_SOURCE:
162 return self.datasource
163 ds = self._restore_from_cache()
164 if ds:
165 LOG.debug("Restored from cache, datasource: %s", ds)
166- if not ds:
167+ # Try to find one that will work
168+ if not ds and not local_only:
169 (cfg_list, pkg_list) = self._get_datasources()
170 # Deep copy so that user-data handlers can not modify
171 # (which will affect user-data handlers down the line...)
172@@ -303,8 +304,8 @@
173 self._reset()
174 return iid
175
176- def fetch(self):
177- return self._get_data_source()
178+ def fetch(self, local_only=False):
179+ return self._get_data_source(local_only)
180
181 def instancify(self):
182 return self._reflect_cur_instance()