Skip to content

Commit d90ae2e

Browse files
authored
Added env variable support for himl (#55)
* Added env variable support for himl
1 parent fd2078d commit d90ae2e

File tree

5 files changed

+80
-1
lines changed

5 files changed

+80
-1
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ remote_states:
267267
endpoint: "{{outputs.cluster_composition.output.value.redis_endpoint}}"
268268
```
269269

270+
### Merge with env variables
271+
```yaml
272+
kubeconfig_location: {{env(KUBECONFIG)}}
273+
```
274+
270275

271276
## himl config merger
272277

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
cluster: cluster1
2+
home: {{env(HOME)}}

himl/config_generator.py

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

20-
from .interpolation import InterpolationResolver, EscapingResolver, InterpolationValidator, SecretResolver, DictIterator, replace_parent_working_directory
20+
from .interpolation import InterpolationResolver, EscapingResolver, InterpolationValidator, SecretResolver, \
21+
DictIterator, replace_parent_working_directory, EnvVarResolver
2122
from .python_compat import iteritems, primitive_types, PY3
2223
from .remote_state import S3TerraformRemoteStateRetriever
2324

@@ -68,6 +69,9 @@ def process(self, cwd=None, path=None, filters=(), exclude_keys=(), enclosing_ke
6869
# value2: "something-{{value1}} <--- this will be resolved at this step
6970
generator.resolve_interpolations()
7071

72+
generator.resolve_env()
73+
generator.resolve_interpolations()
74+
7175
if len(filters) > 0:
7276
generator.filter_data(filters)
7377

@@ -279,6 +283,10 @@ def resolve_secrets(self, default_aws_profile):
279283
resolver = SecretResolver()
280284
self.generated_data = resolver.resolve_secrets(self.generated_data, default_aws_profile)
281285

286+
def resolve_env(self):
287+
resolver = EnvVarResolver()
288+
self.generated_data = resolver.resolve_env_vars(self.generated_data)
289+
282290
def validate_interpolations(self):
283291
self.interpolation_validator.check_all_interpolations_resolved(self.generated_data)
284292

himl/inject_env.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright 2021 Adobe. All rights reserved.
2+
# This file is licensed to you under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License. You may obtain a copy
4+
# of the License at http://www.apache.org/licenses/LICENSE-2.0
5+
6+
# Unless required by applicable law or agreed to in writing, software distributed under
7+
# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
8+
# OF ANY KIND, either express or implied. See the License for the specific language
9+
# governing permissions and limitations under the License.
10+
11+
from os import getenv
12+
13+
14+
class EnvVarInjector(object):
15+
"""
16+
Resolve variables in the form:
17+
{{env(HOME)}}
18+
"""
19+
20+
def __init__(self):
21+
return
22+
23+
def is_interpolation(self, value):
24+
return value.startswith('{{') and value.endswith('}}')
25+
26+
def inject_env_var(self, line):
27+
"""
28+
Check if value is an interpolation and try to resolve it.
29+
"""
30+
if not self.is_interpolation(line):
31+
return line
32+
33+
# remove {{ and }}
34+
updated_line = line[2:-2]
35+
36+
# check supported function to ensure the proper format is used
37+
if not self.is_env_interpolation(updated_line):
38+
return line
39+
40+
# remove env( and ) to extract the env Variable
41+
updated_line = updated_line[4:-1]
42+
43+
# If env variable is missing or not set, the output will be None
44+
return getenv(updated_line)
45+
46+
def is_env_interpolation(self, value):
47+
return value.startswith('env(') and value.endswith(')')

himl/interpolation.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import re
1212

13+
from .inject_env import EnvVarInjector
1314
from .inject_secrets import SecretInjector
1415
from .python_compat import iteritems, string_types, primitive_types
1516

@@ -83,6 +84,14 @@ def resolve_secrets(self, data, default_aws_profile):
8384
return data
8485

8586

87+
class EnvVarResolver(object):
88+
def resolve_env_vars(self, data):
89+
injector = EnvVarInjector()
90+
env_resolver = EnvVarInterpolationsResolver(injector)
91+
env_resolver.resolve_interpolations(data)
92+
return data
93+
94+
8695
class DictIterator(object):
8796

8897
def loop_all_items(self, data, process_func):
@@ -168,6 +177,15 @@ def do_resolve_interpolation(self, line):
168177
return self.secrets_injector.inject_secret(line)
169178

170179

180+
class EnvVarInterpolationsResolver(AbstractInterpolationResolver):
181+
def __init__(self, env_vars_injector):
182+
AbstractInterpolationResolver.__init__(self)
183+
self.env_vars_injector = env_vars_injector
184+
185+
def do_resolve_interpolation(self, line):
186+
return self.env_vars_injector.inject_env_var(line)
187+
188+
171189
class InterpolationValidator(DictIterator):
172190

173191
def check_all_interpolations_resolved(self, data):

0 commit comments

Comments
 (0)