Skip to content

Commit 009504a

Browse files
authored
Merge pull request #22 from ecojan/himl/values-escaping
Support exclude key on interpolation for himl with escape cleaning
2 parents 290191d + 8acc1e8 commit 009504a

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,21 @@
11
cluster:
22
name: cluster1
3+
testkey: |-
4+
# Set to true to log user information returned from LDAP
5+
verbose_logging = true
6+
7+
[[servers]]
8+
# Ldap server host
9+
host = "someaddress"
10+
11+
# Default port is 389 or 636 if use_ssl = true
12+
port = 389
13+
14+
start_tls = true
15+
16+
skipInterpolation_key: "{{`this is a {{ value }} that should not be interpolated`}}"
17+
skipInterpolation_dict:
18+
skipInterpolation_key: "{{`this is a {{ value }} that should not be interpolated`}}"
19+
skipInterpolation_list:
20+
- "{{`this is a {{ value }} that should not be interpolated`}}"
21+

himl/config_generator.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
import yaml
1818
from deepmerge import Merger
1919

20-
from .interpolation import InterpolationResolver, InterpolationValidator, SecretResolver, DictIterator, replace_parent_working_directory
20+
from .interpolation import InterpolationResolver, EscapingResolver, InterpolationValidator, SecretResolver, DictIterator, replace_parent_working_directory
2121
from .python_compat import iteritems, primitive_types, PY3
2222
from .remote_state import S3TerraformRemoteStateRetriever
2323

2424
logger = logging.getLogger(__name__)
2525

26+
2627
class ConfigProcessor(object):
2728

2829
def process(self, cwd=None, path=None, filters=(), exclude_keys=(), enclosing_key=None, remove_enclosing_key=None, output_format="yaml",
@@ -82,6 +83,8 @@ def process(self, cwd=None, path=None, filters=(), exclude_keys=(), enclosing_ke
8283
else:
8384
data = generator.generated_data
8485

86+
generator.clean_escape_characters()
87+
8588
formatted_data = generator.output_data(data, output_format)
8689

8790
if print_data:
@@ -271,6 +274,13 @@ def resolve_secrets(self, default_aws_profile):
271274
def validate_interpolations(self):
272275
self.interpolation_validator.check_all_interpolations_resolved(self.generated_data)
273276

277+
def clean_escape_characters(self):
278+
"""
279+
Method should clean the escaping characters {{` and `}} from all escaped values
280+
"""
281+
resolver = EscapingResolver()
282+
self.generated_data = resolver.resolve_escaping(self.generated_data)
283+
274284
@staticmethod
275285
def should_use_block(value):
276286
"""

himl/interpolation.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616

1717
def is_interpolation(value):
1818
return isinstance(value, string_types) and '{{' in value and '}}' in value \
19-
and '{{`' not in value and '`}}' not in value
19+
and not is_escaped_interpolation(value)
20+
21+
22+
def is_escaped_interpolation(value):
23+
return isinstance(value, string_types) and value.startswith('{{`') and value.endswith('`}}')
2024

2125

2226
def is_full_interpolation(value):
@@ -48,6 +52,19 @@ def resolve_interpolations(self, data):
4852
return data
4953

5054

55+
class EscapingResolver(object):
56+
57+
def resolve_escaping(self, data):
58+
"""
59+
Should do one last check through all values to ensure the ones that were escaped are cleaned of the escape
60+
sequence
61+
"""
62+
from_dict_injector = DictEscapingResolver(data, FromDictInjector())
63+
from_dict_injector.clean_escapes(data)
64+
65+
return data
66+
67+
5168
class SecretResolver(object):
5269

5370
def resolve_secrets(self, data, default_aws_profile):
@@ -82,6 +99,21 @@ def loop_all_items(self, data, process_func):
8299
return data
83100

84101

102+
class AbstractEscapingResolver(DictIterator):
103+
104+
def clean_escapes(self, data):
105+
return self.loop_all_items(data, self.clean_escape)
106+
107+
def clean_escape(self, line):
108+
# Check if line is escaped
109+
if not is_escaped_interpolation(line):
110+
return line
111+
return self.do_clean_escapes(line)
112+
113+
def do_clean_escapes(self, line):
114+
pass
115+
116+
85117
class AbstractInterpolationResolver(DictIterator):
86118

87119
def resolve_interpolations(self, data):
@@ -98,6 +130,18 @@ def do_resolve_interpolation(self, line):
98130
pass
99131

100132

133+
class DictEscapingResolver(AbstractEscapingResolver):
134+
def __init__(self, data, from_dict_injector):
135+
AbstractEscapingResolver.__init__(self)
136+
self.data = data
137+
self.from_dict_injector = from_dict_injector
138+
self.full_blob_injector = FullBlobInjector()
139+
140+
def do_clean_escapes(self, line):
141+
updated_line = self.from_dict_injector.resolve(line, self.data)
142+
return self.full_blob_injector.clean(updated_line)
143+
144+
101145
class DictInterpolationResolver(AbstractInterpolationResolver):
102146
def __init__(self, data, from_dict_injector):
103147
AbstractInterpolationResolver.__init__(self)
@@ -179,6 +223,15 @@ def resolve(self, line, data):
179223

180224
return resolved_value if is_valid_value else line
181225

226+
def clean(self, line):
227+
if not is_escaped_interpolation(line):
228+
return line
229+
230+
resolved_value = self.get_value_from_escaping(line)
231+
is_valid_value = resolved_value is not None
232+
233+
return resolved_value if is_valid_value else line
234+
182235
@staticmethod
183236
def get_inner_value(keys, data):
184237
for key in keys:
@@ -195,3 +248,10 @@ def get_keys_from_interpolation(line):
195248
line = line[2:-2]
196249

197250
return line.split('.')
251+
252+
@staticmethod
253+
def get_value_from_escaping(line):
254+
# remove {{` and `}}
255+
line = line[3:-3]
256+
257+
return line

0 commit comments

Comments
 (0)