Merge lp:~terceiro/lava-dispatcher/expose-config-dirs into lp:lava-dispatcher

Proposed by Antonio Terceiro
Status: Merged
Approved by: Neil Williams
Approved revision: 624
Merged at revision: 626
Proposed branch: lp:~terceiro/lava-dispatcher/expose-config-dirs
Merge into: lp:lava-dispatcher
Diff against target: 254 lines (+67/-49)
4 files modified
lava/dispatcher/commands.py (+12/-13)
lava_dispatcher/config.py (+51/-32)
lava_dispatcher/context.py (+1/-2)
lava_dispatcher/downloader.py (+3/-2)
To merge this branch: bzr merge lp:~terceiro/lava-dispatcher/expose-config-dirs
Reviewer Review Type Date Requested Status
Neil Williams Approve
Review via email: mp+168807@code.launchpad.net

Description of the change

Refactor handling of configuration directories

The configuration search path is now unconditionally set to:

$HOME/.config/lava-dispatcher
${VIRTUAL_ENV}/etc/lava-dispatcher
${lava_dispatcher_root}/lava_dispatcher/default-config/lava-dispatcher

If the VIRTUAL_ENV environment variable is not set, then it will read
configuration from /etc/lava-dispatcher (as expected).

- The search path is now exposed to client code by the
  lava_dispatcher.config.search_path() function

- Each individual directory in the search path can be accessed by the variables
  user_config_path, system_config_path and default_config_path.

- Switched from /etc/xdg/lava-dispatcher to /etc/lava-dispatcher. Because of
  the previous state of the code, where a specific config_dir was always passed
  in and there was no way of overriding it, /etc/xdg/lava-dispatcher was never
  actually used by anybody, so the risk of this change is zero.

- Removed passing around of configuration directory.

- --config-dir switch in command line tools was kept and has the same behaviour
  as before. If a custom config dir is passed, both user and system-wide
  directories are ignored, and only the custom directory and the hardcoded
  defaults are used.

To post a comment you must log in.
Revision history for this message
Milo Casagrande (milo) wrote :

Thanks Antonio for working on this!
FWIW, +1 from me, it looks good.

One note only: it might be good to update documentation with the new behavior. There are references in doc/QUICKSTART (that is "linked" from the README), plus I guess the docs that will appear on lava.readthedocs.org. I can manage to do that in case, so I'll start to take a look around this code base.

Revision history for this message
Antonio Terceiro (terceiro) wrote :

On Wed, Jun 12, 2013 at 09:30:17AM -0000, Milo Casagrande wrote:
> Thanks Antonio for working on this!
> FWIW, +1 from me, it looks good.
>
> One note only: it might be good to update documentation with the new
> behavior. There are references in doc/QUICKSTART (that is "linked"
> from the README), plus I guess the docs that will appear on
> lava.readthedocs.org. I can manage to do that in case, so I'll start
> to take a look around this code base.

Thanks - I just updated doc/QUICKSTART. I couldn't find any other
reference to /etc/xdg elsewhere.

--
Antonio Terceiro
Software Engineer - Linaro
http://www.linaro.org

Revision history for this message
Neil Williams (codehelp) wrote :

I've tested this with my git packaging branch which relies on the settings in /etc/lava-dispatcher/lava-dispatcher.conf and it fixes the problem and correctly uses the values in /etc/ in preference to those in /usr/share/lava_dispatcher/default-config/.

git://git.linaro.org/people/neilwilliams/lava-dispatcher.git
(multinode branch)

Thanks for the fix, Antonio.

Revision history for this message
Neil Williams (codehelp) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lava/dispatcher/commands.py'
2--- lava/dispatcher/commands.py 2013-01-23 22:28:49 +0000
3+++ lava/dispatcher/commands.py 2013-06-11 20:55:28 +0000
4@@ -1,3 +1,4 @@
5+import argparse
6 import json
7 import logging
8 import os
9@@ -7,26 +8,24 @@
10 from lava.tool.command import Command
11 from lava.tool.errors import CommandError
12
13+import lava_dispatcher.config
14 from lava_dispatcher.config import get_config, get_device_config, get_devices
15 from lava_dispatcher.job import LavaTestJob, validate_job_data
16
17
18+class SetUserConfigDirAction(argparse.Action):
19+ def __call__(self, parser, namespace, value, option_string=None):
20+ lava_dispatcher.config.custom_config_path = value
21+
22+
23 class DispatcherCommand(Command):
24 @classmethod
25 def register_arguments(cls, parser):
26 super(DispatcherCommand, cls).register_arguments(parser)
27- # When we're working inside a virtual environment use venv-relative
28- # configuration directory. This works well with lava-deployment-tool
29- # and the directory layout it currently provides but will need to be
30- # changed for codeline support.
31- if "VIRTUAL_ENV" in os.environ:
32- default_config_dir = os.path.join(
33- os.environ["VIRTUAL_ENV"], "etc", "lava-dispatcher")
34- else:
35- default_config_dir = None
36 parser.add_argument(
37 "--config-dir",
38- default=default_config_dir,
39+ default=None,
40+ action=SetUserConfigDirAction,
41 help="Configuration directory override (currently %(default)s")
42
43
44@@ -35,7 +34,7 @@
45 Lists all the configured devices in this LAVA instance.
46 """
47 def invoke(self):
48- for d in get_devices(self.args.config_dir):
49+ for d in get_devices():
50 print d.hostname
51
52
53@@ -88,7 +87,7 @@
54 FORMAT = '<LAVA_DISPATCHER>%(asctime)s %(levelname)s: %(message)s'
55 DATEFMT = '%Y-%m-%d %I:%M:%S %p'
56 logging.basicConfig(format=FORMAT, datefmt=DATEFMT)
57- config = get_config(self.args.config_dir)
58+ config = get_config()
59 logging.root.setLevel(config.logging_level)
60
61 # Set process id if job-id was passed to dispatcher
62@@ -139,7 +138,7 @@
63 @property
64 def device_config(self):
65 try:
66- return get_device_config(self.args.device, self.args.config_dir)
67+ return get_device_config(self.args.device)
68 except Exception:
69 raise CommandError("no such device: %s" % self.args.device)
70
71
72=== modified file 'lava_dispatcher/config.py'
73--- lava_dispatcher/config.py 2013-06-05 21:43:24 +0000
74+++ lava_dispatcher/config.py 2013-06-11 20:55:28 +0000
75@@ -152,30 +152,40 @@
76
77 class DispatcherConfig(object):
78
79- def __init__(self, cp, config_dir):
80+ def __init__(self, cp):
81 self.cp = cp
82- self.config_dir = config_dir
83
84 for option in DispatcherSchema().options():
85 locals()[option.name] = OptionDescriptor(option.name)
86
87
88-default_config_path = os.path.join(
89- os.path.dirname(__file__), 'default-config')
90-
91-
92-def load_config_paths(name, config_dir):
93- if config_dir is None:
94- paths = [
95- os.path.join(path, name) for path in [
96- os.path.expanduser("~/.config"),
97- "/etc/xdg",
98- default_config_path]]
99+user_config_path = os.path.expanduser("~/.config/lava-dispatcher")
100+
101+if "VIRTUAL_ENV" in os.environ:
102+ system_config_path = os.path.join(os.environ["VIRTUAL_ENV"],
103+ "etc/lava-dispatcher")
104+else:
105+ system_config_path = "/etc/lava-dispatcher"
106+
107+deprecated_system_config_path = "/etc/xdg/lava-dispatcher"
108+
109+default_config_path = os.path.join(os.path.dirname(__file__),
110+ 'default-config/lava-dispatcher')
111+
112+custom_config_path = None
113+
114+def search_path():
115+ if custom_config_path:
116+ return [
117+ custom_config_path,
118+ default_config_path,
119+ ]
120 else:
121- paths = [config_dir, os.path.join(default_config_path, name)]
122- for path in paths:
123- if os.path.isdir(path):
124- yield path
125+ return [
126+ user_config_path,
127+ system_config_path,
128+ default_config_path,
129+ ]
130
131
132 def _read_into(path, cp):
133@@ -186,7 +196,7 @@
134 cp.readfp(s)
135
136
137-def _get_config(name, config_dir, cp):
138+def _get_config(name, cp):
139 """Read a config file named name + '.conf'.
140
141 This checks and loads files from the source tree, site wide location and
142@@ -194,7 +204,7 @@
143 settings which override source settings.
144 """
145 config_files = []
146- for directory in load_config_paths('lava-dispatcher', config_dir):
147+ for directory in search_path():
148 path = os.path.join(directory, '%s.conf' % name)
149 if os.path.exists(path):
150 config_files.append(path)
151@@ -207,13 +217,13 @@
152 return cp
153
154
155-def get_config(config_dir):
156+def get_config():
157 cp = parser.SchemaConfigParser(DispatcherSchema())
158- _get_config("lava-dispatcher", config_dir, cp)
159+ _get_config("lava-dispatcher", cp)
160 valid, report = cp.is_valid(report=True)
161 if not valid:
162 logging.warning("dispatcher config is not valid:\n %s", '\n '.join(report))
163- return DispatcherConfig(cp, config_dir)
164+ return DispatcherConfig(cp)
165
166
167 def _hack_boot_options(scp):
168@@ -243,19 +253,19 @@
169 return scrubbed
170
171
172-def get_device_config(name, config_dir):
173+def get_device_config(name):
174 # We read the device config once to get the device type, then we start
175 # again and read device-defaults, device-types/$device-type and
176 # devices/$device in that order.
177 initial_config = ConfigParser()
178- _get_config("devices/%s" % name, config_dir, initial_config)
179+ _get_config("devices/%s" % name, initial_config)
180
181 real_device_config = parser.SchemaConfigParser(DeviceSchema())
182- _get_config("device-defaults", config_dir, real_device_config)
183+ _get_config("device-defaults", real_device_config)
184 _get_config(
185 "device-types/%s" % initial_config.get('__main__', 'device_type'),
186- config_dir, real_device_config)
187- _get_config("devices/%s" % name, config_dir, real_device_config)
188+ real_device_config)
189+ _get_config("devices/%s" % name, real_device_config)
190 real_device_config.set("__main__", "hostname", name)
191 _hack_boot_options(real_device_config)
192 valid, report = real_device_config.is_valid(report=True)
193@@ -269,10 +279,19 @@
194 return DeviceConfig(real_device_config)
195
196
197-def get_devices(config_dir):
198+def get_devices():
199 devices = []
200- devices_dir = os.path.join(config_dir, 'devices')
201- for d in os.listdir(devices_dir):
202- d = os.path.splitext(d)[0]
203- devices.append(get_device_config(d, config_dir))
204+ for config_dir in search_path():
205+ devices_dir = os.path.join(config_dir, 'devices')
206+ if os.path.isdir(devices_dir):
207+ for d in os.listdir(devices_dir):
208+ d = os.path.splitext(d)[0]
209+ devices.append(get_device_config(d))
210 return devices
211+
212+def get_config_file(config_file):
213+ for config_dir in search_path():
214+ config_file_path = os.path.join(config_dir, config_file)
215+ if os.path.exists(config_file_path):
216+ return config_file_path
217+ return None
218
219=== modified file 'lava_dispatcher/context.py'
220--- lava_dispatcher/context.py 2013-04-02 16:16:18 +0000
221+++ lava_dispatcher/context.py 2013-06-11 20:55:28 +0000
222@@ -94,8 +94,7 @@
223 self.job_data = job_data
224 self.output = Outputter(output_dir)
225 self.logfile_read = self.output.logfile_read
226- self.device_config = get_device_config(
227- target, dispatcher_config.config_dir)
228+ self.device_config = get_device_config(target)
229 self._client = TargetBasedClient(self, self.device_config)
230 self.test_data = LavaTestData()
231 self.oob_file = oob_file
232
233=== modified file 'lava_dispatcher/downloader.py'
234--- lava_dispatcher/downloader.py 2012-12-18 19:50:48 +0000
235+++ lava_dispatcher/downloader.py 2013-06-11 20:55:28 +0000
236@@ -33,6 +33,7 @@
237 import zlib
238
239 from tempfile import mkdtemp
240+from lava_dispatcher.config import get_config_file
241 from lava_dispatcher.utils import rmtree
242
243
244@@ -122,8 +123,8 @@
245 '''allows the downloader to override a URL so that something like:
246 http://blah/ becomes file://localhost/blah
247 '''
248- mappings = '%s/urlmappings.txt' % context.config.config_dir
249- if os.path.exists(mappings):
250+ mappings = get_config_file('urlmappings.txt')
251+ if mappings:
252 newurl = url
253 with open(mappings, 'r') as f:
254 for line in f.readlines():

Subscribers

People subscribed via source and target branches