OLD | NEW |
| 1 import json |
1 import logging | 2 import logging |
2 import os | 3 import os |
3 import pipes | 4 import pipes |
4 import re | 5 import re |
5 import sys | 6 import sys |
6 | 7 |
7 from twisted.internet.defer import inlineCallbacks, returnValue | 8 from twisted.internet.defer import inlineCallbacks, returnValue |
8 | 9 |
9 from juju.hooks.cli import ( | 10 from juju.hooks.cli import ( |
10 CommandLineClient, parse_log_level, parse_port_protocol) | 11 CommandLineClient, parse_log_level, parse_port_protocol) |
11 from juju.hooks.protocol import MustSpecifyRelationName | 12 from juju.hooks.protocol import MustSpecifyRelationName |
12 | 13 |
13 | 14 |
14 BAD_CHARS = re.compile("[\-\./:()<>|?*]|(\\\)") | 15 BAD_CHARS = re.compile("[\-\./:()<>|?*]|(\\\)") |
15 | 16 |
16 | 17 |
17 class RelationGetCli(CommandLineClient): | 18 class TestOptionMixin(object): |
| 19 def customize_parser(self): |
| 20 self.parser.add_argument("--test", |
| 21 action="store_true", |
| 22 default=False, |
| 23 help="Exit code indicates if the value " |
| 24 "is present and not empty") |
| 25 |
| 26 def tests_true(self, result): |
| 27 return 0 if bool(result) else 1 |
| 28 |
| 29 def handle_test(self, result): |
| 30 self.exit_code = self.tests_true(result) |
| 31 |
| 32 def render(self, result): |
| 33 if self.options.test is True: |
| 34 self.handle_test(result) |
| 35 else: |
| 36 super(TestOptionMixin, self).render(result) |
| 37 |
| 38 |
| 39 class RelationGetCli(TestOptionMixin, CommandLineClient): |
18 keyvalue_pairs = False | 40 keyvalue_pairs = False |
19 | 41 |
20 def customize_parser(self): | 42 def customize_parser(self): |
21 remote_unit = os.environ.get("JUJU_REMOTE_UNIT") | 43 remote_unit = os.environ.get("JUJU_REMOTE_UNIT") |
22 | 44 |
23 self.parser.add_argument( | 45 self.parser.add_argument( |
24 "-r", dest="relation_id", default="", metavar="RELATION ID") | 46 "-r", dest="relation_id", default="", metavar="RELATION ID") |
25 self.parser.add_argument("settings_name", default="", nargs="?") | 47 self.parser.add_argument("settings_name", default="", nargs="?") |
26 self.parser.add_argument("unit_name", default=remote_unit, nargs="?") | 48 self.parser.add_argument("unit_name", default=remote_unit, nargs="?") |
| 49 super(RelationGetCli, self).customize_parser() |
27 | 50 |
28 @inlineCallbacks | 51 @inlineCallbacks |
29 def run(self): | 52 def run(self): |
30 # handle settings_name being explictly skipped on the cli | 53 # handle settings_name being explictly skipped on the cli |
31 if self.options.settings_name == "-": | 54 if self.options.settings_name == "-": |
32 self.options.settings_name = "" | 55 self.options.settings_name = "" |
33 result = yield self.client.relation_get(self.options.client_id, | 56 result = yield self.client.relation_get(self.options.client_id, |
34 self.options.relation_id, | 57 self.options.relation_id, |
35 self.options.unit_name, | 58 self.options.unit_name, |
36 self.options.settings_name) | 59 self.options.settings_name) |
37 returnValue(result) | 60 returnValue(result) |
38 | 61 |
39 def format_shell(self, result, stream): | 62 def format_shell(self, result, stream): |
40 options = self.options | 63 options = self.options |
41 settings_name = options.settings_name | 64 settings_name = options.settings_name |
42 | 65 |
43 if settings_name and settings_name != "-": | 66 if settings_name and settings_name != "-": |
44 # result should be a single value | 67 # result should be a single value |
45 result = {settings_name.upper(): result} | 68 result = {settings_name.upper(): result} |
46 | 69 |
47 if result: | 70 if result: |
48 errs = [] | 71 errs = [] |
49 for k, v in sorted(os.environ.items()): | 72 for k, v in sorted(os.environ.items()): |
50 if k.startswith("VAR_"): | 73 if k.startswith("VAR_"): |
51 print >>stream, "%s=" % (k.upper(), ) | 74 print >>stream, "%s=" % k.upper() |
52 errs.append(k) | 75 errs.append(k) |
53 | 76 |
54 for k, v in sorted(result.items()): | 77 for k, v in sorted(result.items()): |
55 k = BAD_CHARS.sub("_", k.upper()) | 78 k = BAD_CHARS.sub("_", k.upper()) |
56 v = pipes.quote(v) | 79 if not isinstance(v, basestring): |
| 80 v = json.dumps(v) |
| 81 else: |
| 82 v = pipes.quote(v) |
57 print >>stream, "VAR_%s=%s" % (k.upper(), v) | 83 print >>stream, "VAR_%s=%s" % (k.upper(), v) |
58 | 84 |
59 # Order of output within streams is assured, but we output | 85 # Order of output within streams is assured, but we output |
60 # on (commonly) two streams here and the ordering of those | 86 # on (commonly) two streams here and the ordering of those |
61 # messages is significant to the user. Make a best | 87 # messages is significant to the user. Make a best |
62 # effort. However, this cannot be guaranteed when these | 88 # effort. However, this cannot be guaranteed when these |
63 # streams are collected by `HookProtocol`. | 89 # streams are collected by `HookProtocol`. |
64 stream.flush() | 90 stream.flush() |
65 | 91 |
66 if errs: | 92 if errs: |
(...skipping 14 matching lines...) Expand all Loading... |
81 | 107 |
82 def customize_parser(self): | 108 def customize_parser(self): |
83 self.parser.add_argument( | 109 self.parser.add_argument( |
84 "-r", dest="relation_id", default="", metavar="RELATION ID") | 110 "-r", dest="relation_id", default="", metavar="RELATION ID") |
85 | 111 |
86 def run(self): | 112 def run(self): |
87 return self.client.relation_set(self.options.client_id, | 113 return self.client.relation_set(self.options.client_id, |
88 self.options.relation_id, | 114 self.options.relation_id, |
89 self.options.keyvalue_pairs) | 115 self.options.keyvalue_pairs) |
90 | 116 |
| 117 def render(self, result): |
| 118 return None |
| 119 |
91 | 120 |
92 def relation_set(): | 121 def relation_set(): |
93 """Entry point for relation-set.""" | 122 """Entry point for relation-set.""" |
94 client = RelationSetCli() | 123 client = RelationSetCli() |
95 sys.exit(client()) | 124 sys.exit(client()) |
96 | 125 |
97 | 126 |
98 class RelationIdsCli(CommandLineClient): | 127 class RelationIdsCli(CommandLineClient): |
99 keyvalue_pairs = False | 128 keyvalue_pairs = False |
100 | 129 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 def render(self, result): | 201 def render(self, result): |
173 return None | 202 return None |
174 | 203 |
175 | 204 |
176 def log(): | 205 def log(): |
177 """Entry point for juju-log.""" | 206 """Entry point for juju-log.""" |
178 client = LoggingCli() | 207 client = LoggingCli() |
179 sys.exit(client()) | 208 sys.exit(client()) |
180 | 209 |
181 | 210 |
182 class ConfigGetCli(CommandLineClient): | 211 class ConfigGetCli(TestOptionMixin, CommandLineClient): |
183 keyvalue_pairs = False | 212 keyvalue_pairs = False |
184 | 213 |
185 def customize_parser(self): | 214 def customize_parser(self): |
186 self.parser.add_argument("option_name", default="", nargs="?") | 215 self.parser.add_argument("option_name", default="", nargs="?") |
| 216 super(ConfigGetCli, self).customize_parser() |
187 | 217 |
188 @inlineCallbacks | 218 @inlineCallbacks |
189 def run(self): | 219 def run(self): |
190 # handle settings_name being explictly skipped on the cli | 220 # handle settings_name being explictly skipped on the cli |
191 result = yield self.client.config_get(self.options.client_id, | 221 result = yield self.client.config_get(self.options.client_id, |
192 self.options.option_name) | 222 self.options.option_name) |
193 returnValue(result) | 223 returnValue(result) |
194 | 224 |
195 | 225 |
196 def config_get(): | 226 def config_get(): |
197 """Entry point for config-get""" | 227 """Entry point for config-get""" |
198 client = ConfigGetCli() | 228 client = ConfigGetCli() |
199 sys.exit(client()) | 229 sys.exit(client()) |
200 | 230 |
201 | 231 |
202 class OpenPortCli(CommandLineClient): | 232 class OpenPortCli(CommandLineClient): |
203 keyvalue_pairs = False | 233 keyvalue_pairs = False |
204 | 234 |
205 def customize_parser(self): | 235 def customize_parser(self): |
206 self.parser.add_argument( | 236 self.parser.add_argument( |
207 "port_protocol", | 237 "port_protocol", |
208 metavar="PORT[/PROTOCOL]", | 238 metavar="PORT[/PROTOCOL]", |
209 help="The port to open. The protocol defaults to TCP.", | 239 help="The port to open. The protocol defaults to TCP.", |
210 type=parse_port_protocol) | 240 type=parse_port_protocol) |
211 | 241 |
212 def run(self): | 242 def run(self): |
213 return self.client.open_port( | 243 return self.client.open_port( |
214 self.options.client_id, *self.options.port_protocol) | 244 self.options.client_id, *self.options.port_protocol) |
215 | 245 |
| 246 def render(self, result): |
| 247 return None |
| 248 |
216 | 249 |
217 def open_port(): | 250 def open_port(): |
218 """Entry point for open-port.""" | 251 """Entry point for open-port.""" |
219 client = OpenPortCli() | 252 client = OpenPortCli() |
220 sys.exit(client()) | 253 sys.exit(client()) |
221 | 254 |
222 | 255 |
223 class ClosePortCli(CommandLineClient): | 256 class ClosePortCli(CommandLineClient): |
224 keyvalue_pairs = False | 257 keyvalue_pairs = False |
225 | 258 |
226 def customize_parser(self): | 259 def customize_parser(self): |
227 self.parser.add_argument( | 260 self.parser.add_argument( |
228 "port_protocol", | 261 "port_protocol", |
229 metavar="PORT[/PROTOCOL]", | 262 metavar="PORT[/PROTOCOL]", |
230 help="The port to close. The protocol defaults to TCP.", | 263 help="The port to close. The protocol defaults to TCP.", |
231 type=parse_port_protocol) | 264 type=parse_port_protocol) |
232 | 265 |
233 def run(self): | 266 def run(self): |
234 return self.client.close_port( | 267 return self.client.close_port( |
235 self.options.client_id, *self.options.port_protocol) | 268 self.options.client_id, *self.options.port_protocol) |
236 | 269 |
| 270 def render(self, result): |
| 271 return None |
| 272 |
237 | 273 |
238 def close_port(): | 274 def close_port(): |
239 """Entry point for close-port.""" | 275 """Entry point for close-port.""" |
240 client = ClosePortCli() | 276 client = ClosePortCli() |
241 sys.exit(client()) | 277 sys.exit(client()) |
242 | 278 |
243 | 279 |
244 class UnitGetCli(CommandLineClient): | 280 class UnitGetCli(TestOptionMixin, CommandLineClient): |
245 keyvalue_pairs = False | 281 keyvalue_pairs = False |
246 | 282 |
247 def customize_parser(self): | 283 def customize_parser(self): |
248 self.parser.add_argument("setting_name") | 284 self.parser.add_argument("setting_name") |
| 285 super(UnitGetCli, self).customize_parser() |
249 | 286 |
250 @inlineCallbacks | 287 @inlineCallbacks |
251 def run(self): | 288 def run(self): |
252 result = yield self.client.get_unit_info(self.options.client_id, | 289 result = yield self.client.get_unit_info(self.options.client_id, |
253 self.options.setting_name) | 290 self.options.setting_name) |
254 returnValue(result["data"]) | 291 returnValue(result["data"]) |
255 | 292 |
256 | 293 |
257 def unit_get(): | 294 def unit_get(): |
258 """Entry point for config-get""" | 295 """Entry point for config-get""" |
259 client = UnitGetCli() | 296 client = UnitGetCli() |
260 sys.exit(client()) | 297 sys.exit(client()) |
OLD | NEW |