blob: 00506735a8df141431378ccc7e69c2c1828bd20e [file] [log] [blame]
Adam Israeldcdf82b2017-08-15 15:26:43 -04001#
2# Module that parses constraints
3#
4# The current version of juju core expects the client to take
5# constraints given in the form "mem=10G foo=bar" and parse them into
6# json that looks like {"mem": 10240, "foo": "bar"}. This module helps us
7# accomplish that task.
8#
9# We do not attempt to duplicate the checking done in
10# client/_client.py:Value here. That class will verify that the
11# constraints keys are valid, and that we can successfully dump the
12# constraints dict to json.
13#
14# Once https://bugs.launchpad.net/juju/+bug/1645402 is addressed, this
15# module should be deprecated.
16#
17
18import re
19
20# Matches on a string specifying memory size
21MEM = re.compile('^[1-9][0-9]*[MGTP]$')
22
23# Multiplication factors to get Megabytes
24# https://github.com/juju/juju/blob/master/constraints/constraints.go#L666
25FACTORS = {
26 "M": 1,
27 "G": 1024,
28 "T": 1024 * 1024,
29 "P": 1024 * 1024 * 1024
30}
31
Adam Israelb0943662018-08-02 15:32:00 -040032LIST_KEYS = {'tags', 'spaces'}
33
Adam Israeldcdf82b2017-08-15 15:26:43 -040034SNAKE1 = re.compile(r'(.)([A-Z][a-z]+)')
35SNAKE2 = re.compile('([a-z0-9])([A-Z])')
36
37
38def parse(constraints):
39 """
40 Constraints must be expressed as a string containing only spaces
41 and key value pairs joined by an '='.
42
43 """
44 if not constraints:
45 return None
46
47 if type(constraints) is dict:
48 # Fowards compatibilty: already parsed
49 return constraints
50
51 constraints = {
Adam Israelb0943662018-08-02 15:32:00 -040052 normalize_key(k): (
53 normalize_list_value(v) if k in LIST_KEYS else
54 normalize_value(v)
55 ) for k, v in [s.split("=") for s in constraints.split(" ")]}
Adam Israeldcdf82b2017-08-15 15:26:43 -040056
57 return constraints
58
59
60def normalize_key(key):
61 key = key.strip()
62
63 key = key.replace("-", "_") # Our _client lib wants "_" in place of "-"
64
65 # Convert camelCase to snake_case
66 key = SNAKE1.sub(r'\1_\2', key)
67 key = SNAKE2.sub(r'\1_\2', key).lower()
68
69 return key
70
71
72def normalize_value(value):
73 value = value.strip()
74
75 if MEM.match(value):
76 # Translate aliases to Megabytes. e.g. 1G = 10240
77 return int(value[:-1]) * FACTORS[value[-1:]]
78
Adam Israeldcdf82b2017-08-15 15:26:43 -040079 if value.isdigit():
80 return int(value)
81
82 return value
Adam Israelb0943662018-08-02 15:32:00 -040083
84
85def normalize_list_value(value):
86 values = value.strip().split(',')
87 return [normalize_value(value) for value in values]