def test_stemplate_miss(self): # test that a non-existant param raises a TemplateError test_variables = {"user-names": {"value": "Tom Jaxon"}} string_w_variables = "Try and render {{yac-ref:user-name}} into this file" # run test error_raised = False try: apply_stemplate(string_w_variables, Params(test_variables)) except TemplateError as e: error_raised = True print(e) self.assertTrue(error_raised)
def test_stemplate(self): test_file = 'yac/tests/template/vectors/sample_map_file.txt' test_variables = { "user-name": { "value": "henry-grantham" }, "neighborhood-map": { "lookup": "user-name", "value": { "tom-jackson": "phinney", "henry-grantham": "capital-hill" } } } # read file into string file_contents = get_file_contents(test_file) # run test updated_file_contents = apply_stemplate(file_contents, Params(test_variables)) # test that the correct neighborhood got rendered into the file contents render_check = "capital-hill" in updated_file_contents self.assertTrue(render_check)
def do_calc(calc_arg, params): # Return a list of boot script lines, one per script line provided in params. # List is intended to be incorporated into the UserData portion of an EC2 or LaunchConfiguration # template. # args: # calc_arg: array containing single element: a string holding path to boot script file boot_script_list = [] err = "" servicefile_path = params.get("servicefile-path") boot_file = calc_arg[0] if len(calc_arg) == 1 else "" if boot_file: boot_script_contents = get_file_contents(boot_file, servicefile_path) if boot_script_contents: # render template variables into the file contents boot_script_contents = apply_stemplate(boot_script_contents, params) # split script into lines boot_script_lines_list = boot_script_contents.split('\n') for i, line in enumerate(boot_script_lines_list): if ("{" in line and "}" in line and "Ref" in line): # this line contains a cloud formation reference which needs to be broken out # i.e. something like ... # CLUSTER_NAME={"Ref": "ECS"} prefix = line[:line.index('{')] reference = line[line.index('{'):line.index('}') + 1] reference_dict = json.loads(reference) boot_script_list = boot_script_list + [ prefix, { "Ref": reference_dict["Ref"] } ] + ["\n"] else: boot_script_list = boot_script_list + [line] + ["\n"] else: err = "boot file %s does not exist or has no content" % boot_file else: err = "No boot script provided" return boot_script_list, err
def test_stranger(self): string_w_variables = 'Simons says {{yac-calc:["yac/tests/template/vectors/say_hello.py"]}}' # run test string_w_variables = apply_stemplate(string_w_variables, Params({})) # test that "Hello stranger" got rendered into the string contents render_check = "hello stranger" in string_w_variables self.assertTrue(render_check)
def test_bad_calculator(self): string_w_variables = 'Simons says {{yac-calc: ["nonexistent.py"]}}' err = "" try: string_w_variables = apply_stemplate(string_w_variables, Params({})) except TemplateError as e: err = e self.assertTrue(err)
def do_calc(arg_array, params): # this calc should only be called via the calcs module, so we can be # less defensive with input checking boot_file = arg_array[0] boot_script_list = [] servicefile_path = params.get("servicefile-path") # get the boot script from the user params if boot_file: boot_script_contents = get_file_contents(boot_file, servicefile_path) if boot_script_contents: # render template variables into the file contents boot_script_contents = apply_stemplate(boot_script_contents, params) # split script into lines boot_script_lines_list = boot_script_contents.split('\n') for i, line in enumerate(boot_script_lines_list): if ("{" in line and "}" in line and "Ref" in line): # this line contains a cloud formation reference which needs to be broken out # i.e. something like ... # CLUSTER_NAME={"Ref": "ECS"} prefix = line[:line.index('{')] reference = line[line.index('{'):line.index('}') + 1] reference_dict = json.loads(reference) boot_script_list = boot_script_list + [ prefix, { "Ref": reference_dict["Ref"] } ] + ["\n"] else: boot_script_list = boot_script_list + [line] + ["\n"] else: boot_script_list = boot_script_list + [ "# No boot script provided. See yac docs for more info.\n" ] return boot_script_list
def test_stemplate(self): # test rendering templates in a string test_variables = {"user-name": {"value": "Tom Jaxon"}} string_w_variables = "Try and render {{yac-ref:user-name}} into this file" # run test string_w_variables = apply_stemplate(string_w_variables, Params(test_variables)) # test that user name got rendered into the file contents render_check = "Tom Jaxon" in string_w_variables self.assertTrue(render_check)
def render_body_elements(self, secrets_array): # render template variables in the body elements for secret in secrets_array: if 'data' in secret: data_keys = list(secret['data'].keys()) for data_key in data_keys: try: # render template variables in this data element secret['data'][data_key] = apply_stemplate(secret['data'][data_key], self.params) except TemplateError as e: print("secret '%s' errors need fixing. exiting ..."%secret['metadata']['name']) print(e) exit(1)
def render_body_elements(self, configmaps_array): # render template variables in the body elements for configmap in configmaps_array: if 'data' in configmap: data_keys = list(configmap['data'].keys()) for data_key in data_keys: try: # render template variables in this data element configmap['data'][data_key] = apply_stemplate( configmap['data'][data_key], self.params) except TemplateError as e: print( "configmap '%s' errors need fixing. exiting ..." % configmap['metadata']['name']) print(e) exit(1)
def install_kube_config(self, params): # use .kubeconfig.yaml as a template with open(os.path.join(get_root_path(), "lib/stacks/k8s/configs/.kubeconfig.yaml"), 'r') as config_file: file_contents = config_file.read() # render mustaches in the file ... # first worry about how to render the 'token' token in the # file # use placeholder values (o.w. apply_stemplate will raise TemplateError). # the user will need to use kubelogin to overwrite stock_tokens = ["via kubelogin", "via kubelogin", "via kubelogin"] if not self.tokens: # no tokens are provided via servicefile. this is a typical pattern # for servicefiles that are meant to be run from a developer desktop. tokens = stock_tokens else: tmp_tokens = stock_tokens # make sure there is one token per cluster tmp_tokens[0:len(self.tokens)] = self.tokens # tokens were specified in the servicefile # these will typically include secrets that are referenced # via a yac-ref intrinstric, so render intrinsics in the tokens tokens = apply_intrinsics(tmp_tokens, params) # build the params for each variable in the file local_params = Params({}) # set variables for each of the cluster tokens cluster_keys = ["nonprod-token","prod1-token","prod2-token"] for i,token in enumerate(tokens): local_params.set(cluster_keys[i],token) # the namespace params supports intrinsics (so that it can be set via an input) namespace = apply_intrinsics(self.namespace, params) # set namespace variable for template rendering local_params.set("namespace", namespace) if self.is_desktop: # use the private api to avoid the limitations of the public # api endpoint, per: # * https://gitlab.nordstrom.com/k8s/platform-bootstrap/wikis/Onboard-to-AWS-Kubernetes-Clusters local_params.set("nonprod-api-url",NONPROD_PRIVATE_API) else: # pipelines must use the public to avoid v2 account peering # contraints local_params.set("nonprod-api-url",NONPROD_PUBLIC_API) # do the actual mustache rendering rendered_file_contents = apply_stemplate(file_contents,local_params) # take backup of any existing .kube/config files self.backup_existing(".kube/config") # write file self.write_home_file(rendered_file_contents,".kube/config")