def render_credential_template(cls): global CRED_VAR_NAME_MAP, CRED_FILES LOG.debug("Rendering {} credential template".format(cls.__name__)) if not isinstance(cls, CredentialType): raise TypeError("{} is not of type {}".format(cls, CredentialType)) user_attrs = cls.get_user_attrs() user_attrs["description"] = cls.__doc__ var_name = "BP_CRED_{}".format(get_valid_identifier(cls.__name__)) file_name = "{}_{}".format(var_name, user_attrs["type"]) file_loc = os.path.join(get_local_dir(), file_name) # Storing empty value in the file with open(file_loc, "w+") as fd: fd.write("") user_attrs["var_name"] = var_name user_attrs["value"] = file_name if user_attrs.get("editables", {}): user_attrs["editables"] = user_attrs["editables"].get_dict() # update the map CRED_VAR_NAME_MAP[user_attrs["name"]] = var_name CRED_FILES.append(file_name) text = render_template("credential.py.jinja2", obj=user_attrs) return text.strip()
def render_ahv_vm_gpu(cls): gpu_vendor_key_map = {"AMD": "Amd", "INTEL": "Intel", "NVIDIA": "Nvidia"} gpu_mode_key_map = { "PASSTHROUGH_GRAPHICS": "passThroughGraphic", "PASSTHROUGH_COMPUTE": "passThroughCompute", "VIRTUAL": "virtual", } gpu_data = cls.get_dict() user_attrs = {} gpu_vendor = gpu_data["vendor"] if gpu_vendor_key_map.get(gpu_vendor, None): user_attrs["vendor_key"] = gpu_vendor_key_map[gpu_vendor] else: LOG.error("Unknown GPU vendor '{}'".format(gpu_vendor)) sys.exit(-1) gpu_mode = gpu_data["mode"] if gpu_mode_key_map.get(gpu_mode, None): user_attrs["mode_key"] = gpu_mode_key_map[gpu_mode] else: LOG.error("Unknown GPU mode '{}'".format(gpu_mode)) sys.exit(-1) user_attrs["device_id"] = gpu_data.get("device_id", 0) text = render_template(schema_file="ahv_vm_gpu.py.jinja2", obj=user_attrs) return text.strip()
def render_metadata_template(cls): if not cls: return if not isinstance(cls, MetadataType): raise TypeError("{} is not of type {}".format(cls, MetadataType)) cls_data = cls.get_dict() user_attrs = {} if cls_data.get("categories"): user_attrs["categories"] = cls_data["categories"] # NOTE: Project and Owner info is not provided by calm export_file api yet. # When available add their rendered_text to user_attrs and modify jinja template accordingly # NOTE: Name of class is constant i.e. BpMetadata # If metadata is not available, return empty string if not user_attrs: return "" text = render_template("metadata.py.jinja2", obj=user_attrs) return text.strip()
def render_ahv_vm_nic(cls): nic_data = cls.get_dict() subnet_ref = nic_data["subnet_reference"] nic_type = nic_data["nic_type"] network_function_nic_type = nic_data["network_function_nic_type"] subnet_uuid = subnet_ref["uuid"] subnet_cache_data = Cache.get_entity_data_using_uuid( entity_type="ahv_subnet", uuid=subnet_uuid) user_attrs = {} if not subnet_cache_data: LOG.error("Subnet with uuid '{}' not found".format(subnet_uuid)) sys.exit(-1) user_attrs["subnet_name"] = subnet_cache_data["name"] user_attrs["cluster_name"] = subnet_cache_data["cluster"] schema_file = "" if nic_type == "NORMAL_NIC": if network_function_nic_type == "INGRESS": schema_file = "ahv_normal_ingress_nic.py.jinja2" elif network_function_nic_type == "EGRESS": schema_file = "ahv_normal_egress_nic.py.jinja2" elif network_function_nic_type == "TAP": schema_file = "ahv_normal_tap_nic.py.jinja2" else: LOG.error("Unknown network function nic type '{}'".format( network_function_nic_type)) sys.exit(-1) elif nic_type == "DIRECT_NIC": if network_function_nic_type == "INGRESS": schema_file = "ahv_direct_ingress_nic.py.jinja2" elif network_function_nic_type == "EGRESS": schema_file = "ahv_direct_egress_nic.py.jinja2" elif network_function_nic_type == "TAP": schema_file = "ahv_direct_tap_nic.py.jinja2" else: LOG.error("Unknown network function nic type '{}'".format( network_function_nic_type)) sys.exit(-1) else: LOG.error("Unknown nic type '{}'".format(nic_type)) sys.exit(-1) text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()
def render_action_template(cls, entity_context=""): global RUNBOOK_ACTION_MAP LOG.debug("Rendering {} action template".format(cls.__name__)) if not isinstance(cls, ActionType): raise TypeError("{} is not of type {}".format(cls, action)) # Update entity context # TODO for now, not adding runbook to context as current mapping -is 1:1 entity_context = entity_context + "_Action_" + cls.__name__ runbook = cls.runbook runbook_name = getattr(runbook, "name", "") or runbook.__name__ # Note cls.__name__ should be used for call_runbook tasks RUNBOOK_ACTION_MAP[runbook_name] = cls.__name__ # NOTE Not using main_task_local_reference for now, # bcz type of main task is "DAG" levelled_tasks = get_task_order(runbook.tasks) tasks = [] for task_list in levelled_tasks: if len(task_list) != 1: tasks.append( render_parallel_task_template( task_list, entity_context, RUNBOOK_ACTION_MAP ) ) else: tasks.append( render_task_template(task_list[0], entity_context, RUNBOOK_ACTION_MAP) ) variables = [] for variable in runbook.variables: variables.append(render_variable_template(variable, entity_context)) if not (variables or tasks): return "" user_attrs = { "name": cls.__name__, "description": cls.__doc__ or "", "tasks": tasks, "variables": variables, } gui_display_name = getattr(cls, "name", "") or cls.__name__ if gui_display_name != cls.__name__: user_attrs["gui_display_name"] = gui_display_name text = render_template(schema_file="action.py.jinja2", obj=user_attrs) return text.strip()
def render_service_template(cls): LOG.debug("Rendering {} service template".format(cls.__name__)) if not isinstance(cls, ServiceType): raise TypeError("{} is not of type {}".format(cls, ServiceType)) # Entity context entity_context = "Service_" + cls.__name__ user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.__name__ user_attrs["description"] = cls.__doc__ or "" # Update service name map and gui name gui_display_name = getattr(cls, "name", "") or cls.__name__ if gui_display_name != cls.__name__: user_attrs["gui_display_name"] = gui_display_name # updating ui and dsl name mapping update_service_name(gui_display_name, cls.__name__) depends_on_list = [] for entity in user_attrs.get("dependencies", []): depends_on_list.append(render_ref_template(entity)) variable_list = [] for entity in user_attrs.get("variables", []): variable_list.append(render_variable_template(entity, entity_context)) action_list = [] system_actions = { v: k for k, v in ServiceType.ALLOWED_SYSTEM_ACTIONS.items() } for entity in user_attrs.get("actions", []): if entity.__name__ in list(system_actions.keys()): entity.name = system_actions[entity.__name__] entity.__name__ = system_actions[entity.__name__] rendered_txt = render_action_template(entity, entity_context) if rendered_txt: action_list.append(rendered_txt) user_attrs["dependencies"] = ",".join(depends_on_list) user_attrs["variables"] = variable_list user_attrs["actions"] = action_list # TODO add ports, ..etc. text = render_template("service.py.jinja2", obj=user_attrs) return text.strip()
def render_parallel_task_template(task_list, entity_context, RUNBOOK_ACTION_MAP): """render parallel tasks template""" rendered_tasks = [] for task in task_list: rendered_tasks.append( render_task_template(task, entity_context, RUNBOOK_ACTION_MAP)) user_attrs = {"tasks": rendered_tasks} text = render_template(schema_file="parallel_task.py.jinja2", obj=user_attrs) return text.strip()
def render_restore_config_template(cls, entity_context): LOG.debug("Rendering {} restore config template".format(cls.__name__)) if not isinstance(cls, ConfigSpecType): raise TypeError("{} is not of type {}".format(cls, ConfigSpecType)) _user_attrs = cls.get_user_attrs() user_attrs = dict() user_attrs["name"] = _user_attrs["name"] or cls.__name__ attrs = _user_attrs["attrs_list"][0] user_attrs["target"] = get_valid_identifier( attrs["target_any_local_reference"]["name"] ) user_attrs["delete_vm_post_restore"] = attrs["delete_vm_post_restore"] text = render_template(schema_file="restore_config.py.jinja2", obj=user_attrs) return text.strip()
def render_package_template(cls): LOG.debug("Rendering {} package template".format(cls.__name__)) if not isinstance(cls, PackageType): raise TypeError("{} is not of type {}".format(cls, PackageType)) # Entity context entity_context = "Package_" + cls.__name__ user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.__name__ user_attrs["description"] = cls.__doc__ or "" # Update package name map gui_display_name = getattr(cls, "name", "") or cls.__name__ if gui_display_name != cls.__name__: user_attrs["gui_display_name"] = gui_display_name # updating ui and dsl name mapping update_package_name(gui_display_name, cls.__name__) service_list = [] for entity in user_attrs.get("services", []): service_list.append(render_ref_template(entity)) variable_list = [] for entity in user_attrs.get("variables", []): variable_list.append(render_variable_template(entity, entity_context)) action_list = [] if hasattr(cls, "__install__"): cls.__install__.__name__ = "__install__" cls.__install__.name = "__install__" action_list.append(render_action_template(cls.__install__, entity_context)) if hasattr(cls, "__uninstall__"): cls.__uninstall__.__name__ = "__uninstall__" cls.__uninstall__.name = "__uninstall__" action_list.append(render_action_template(cls.__uninstall__, entity_context)) user_attrs["services"] = ",".join(service_list) user_attrs["variables"] = variable_list user_attrs["actions"] = action_list text = render_template("package.py.jinja2", obj=user_attrs) return text.strip()
def render_vm_disk_package_template(cls): if not isinstance(cls, VmDiskPackageType): raise TypeError("{} is not of type {}".format(cls, VmDiskPackageType)) disk_data = cls.get_dict() user_attrs = { "name": disk_data.pop("name"), "description": disk_data.pop("description"), "config": disk_data, } # Escape new line character. As it is inline parameter for vm_disk_package helper user_attrs["description"] = user_attrs["description"].replace("\n", "\\n") text = render_template("vm_disk_package.py.jinja2", obj=user_attrs) return text.strip()
def render_readiness_probe_template(cls): LOG.debug("Rendering {} readiness probe template".format(cls.__name__)) if not isinstance(cls, ReadinessProbeType): raise TypeError("{} is not of type {}".format(cls, ReadinessProbeType)) user_attrs = cls.get_user_attrs() # deal with cred cred = user_attrs["credential"] if cred: user_attrs["credential"] = "ref({})".format( get_cred_var_name(cred.__name__)) schema_file = "readiness_probe.py.jinja2" text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()
def render_blueprint_template(cls): LOG.debug("Rendering {} blueprint template".format(cls.__name__)) if not isinstance(cls, BlueprintType): raise TypeError("{} is not of type {}".format(cls, BlueprintType)) user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.__name__ user_attrs["description"] = cls.__doc__ or "" credential_list = [] for cred in cls.credentials: credential_list.append( get_cred_var_name(getattr(cred, "name", "") or cred.__name__)) service_list = [] for service in cls.services: service_list.append(service.__name__) package_list = [] for package in cls.packages: package_list.append(package.__name__) substrate_list = [] for substrate in cls.substrates: substrate_list.append(substrate.__name__) profile_list = [] for profile in cls.profiles: profile_list.append(profile.__name__) user_attrs.update({ "services": ", ".join(service_list), "packages": ", ".join(package_list), "substrates": ", ".join(substrate_list), "profiles": ", ".join(profile_list), "credentials": ", ".join(credential_list), }) text = render_template("blueprint.py.jinja2", obj=user_attrs) return text.strip()
def render_vm_disk_package_template(cls): if not isinstance(cls, VmDiskPackageType): raise TypeError("{} is not of type {}".format(cls, VmDiskPackageType)) # It will be used for image reference in ahv vm disks gui_display_name = getattr(cls, "name", "") or cls.__name__ update_package_name(gui_display_name, cls.__name__) disk_data = cls.get_dict() user_attrs = { "name": cls.__name__, "description": disk_data.pop("description"), "config": disk_data, } # Escape new line character. As it is inline parameter for vm_disk_package helper user_attrs["description"] = user_attrs["description"].replace("\n", "\\n") text = render_template("vm_disk_package.py.jinja2", obj=user_attrs) return text.strip()
def render_snapshot_config_template(cls, entity_context, CONFIG_SPEC_MAP): LOG.debug("Rendering {} snapshot config template".format(cls.__name__)) if not isinstance(cls, ConfigSpecType): raise TypeError("{} is not of type {}".format(cls, ConfigSpecType)) _user_attrs = cls.get_user_attrs() user_attrs = dict() user_attrs["name"] = _user_attrs["name"] or cls.__name__ user_attrs["restore_config"] = CONFIG_SPEC_MAP[ _user_attrs["config_references"][0].name ]["local_name"] attrs = _user_attrs["attrs_list"][0] user_attrs["target"] = get_valid_identifier( attrs["target_any_local_reference"]["name"] ) user_attrs["num_of_replicas"] = attrs["num_of_replicas"] if attrs.get("app_protection_policy_reference", None): user_attrs["policy"] = attrs["app_protection_policy_reference"]["name"] if attrs.get("app_protection_rule_reference", None): user_attrs["rule"] = attrs["app_protection_rule_reference"]["name"] text = render_template(schema_file="snapshot_config.py.jinja2", obj=user_attrs) return text.strip()
def render_ref_template(cls): LOG.debug("Rendering {} ref template".format(cls.__name__)) if not isinstance(cls, RefType): raise TypeError("{} is not of type {}".format(cls, RefType)) user_attrs = cls.get_user_attrs() user_attrs["name"] = getattr(cls, "name") if not user_attrs["name"]: user_attrs["name"] = cls.__name__ schema_file = "ref.py.jinja2" kind = cls.kind if kind == "app_service": cls_name = get_service_name(user_attrs["name"]) if cls_name: user_attrs["name"] = cls_name elif kind == "app_package": cls_name = get_package_name(user_attrs["name"]) if cls_name: user_attrs["name"] = cls_name elif kind == "app_substrate": cls_name = get_substrate_name(user_attrs["name"]) if cls_name: user_attrs["name"] = cls_name elif kind == "app_blueprint_deployment": cls_name = get_deployment_name(user_attrs["name"]) if cls_name: user_attrs["name"] = cls_name elif kind == "app_profile": cls_name = get_profile_name(user_attrs["name"]) if cls_name: user_attrs["name"] = cls_name # Updating name attribute of class cls.name = user_attrs["name"] text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()
def render_profile_template(cls): LOG.debug("Rendering {} profile template".format(cls.__name__)) if not isinstance(cls, ProfileType): raise TypeError("{} is not of type {}".format(cls, ProfileType)) # Entity context entity_context = "Profile_" + cls.__name__ user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.__name__ user_attrs["description"] = cls.__doc__ or "" # Update profile name map and gui name gui_display_name = getattr(cls, "name", "") or cls.__name__ if gui_display_name != cls.__name__: user_attrs["gui_display_name"] = gui_display_name # updating ui and dsl name mapping update_profile_name(gui_display_name, cls.__name__) action_list = [] for action in user_attrs.get("actions", []): action_list.append(render_action_template(action, entity_context)) deployment_list = [] for deployment in user_attrs.get("deployments", []): deployment_list.append(deployment.__name__) variable_list = [] for entity in user_attrs.get("variables", []): variable_list.append(render_variable_template(entity, entity_context)) user_attrs["variables"] = variable_list user_attrs["deployments"] = ", ".join(deployment_list) user_attrs["actions"] = action_list text = render_template("profile.py.jinja2", obj=user_attrs) return text.strip()
def render_ahv_vm(cls, boot_config): LOG.debug("Rendering {} ahv_vm template".format(cls.__name__)) if not isinstance(cls, AhvVmType): raise TypeError("{} is not of type {}".format(cls, AhvVmType)) user_attrs = cls.get_user_attrs() vm_name = cls.__name__ user_attrs["name"] = vm_name # Update service name map and gui name gui_display_name = getattr(cls, "name", "") or vm_name if gui_display_name != vm_name: user_attrs["gui_display_name"] = gui_display_name # render resources template user_attrs["resources_cls_name"] = "{}Resources".format(vm_name) cls.resources.__name__ = user_attrs["resources_cls_name"] user_attrs["resources"] = render_ahv_vm_resources( cls.resources, boot_config=boot_config, vm_name_prefix=vm_name ) text = render_template(schema_file="ahv_vm.py.jinja2", obj=user_attrs) return text.strip()
def render_ahv_vm_resources(cls, boot_config, vm_name_prefix=""): LOG.debug("Rendering {} ahv_vm_resources template".format(cls.__name__)) if not isinstance(cls, AhvVmResourcesType): raise TypeError("{} is not of type {}".format(cls, AhvVmResourcesType)) user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.__name__ # Memory to GiB user_attrs["memory"] = int(user_attrs["memory"]) // 1024 disk_list = [] for disk in cls.disks: disk_list.append(render_ahv_vm_disk(disk, boot_config)) nic_list = [] for nic in cls.nics: nic_list.append(render_ahv_vm_nic(nic)) gpu_list = [] for gpu in cls.gpus: gpu_list.append(render_ahv_vm_gpu(gpu)) user_attrs.update({ "disks": ", ".join(disk_list), "nics": ", ".join(nic_list), "gpus": ", ".join(gpu_list), }) if getattr(cls, "guest_customization", None): user_attrs["guest_customization"] = render_ahv_vm_gc( cls.guest_customization, vm_name_prefix=vm_name_prefix) text = render_template(schema_file="ahv_vm_resources.py.jinja2", obj=user_attrs) return text.strip()
def render_task_template(cls, entity_context="", RUNBOOK_ACTION_MAP={}): LOG.debug("Rendering {} task template".format(cls.name)) if not isinstance(cls, TaskType): raise TypeError("{} is not of type {}".format(cls, TaskType)) # update entity_context entity_context = entity_context + "_Task_" + cls.__name__ user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.name target = getattr(cls, "target_any_local_reference", None) if target: user_attrs["target"] = render_ref_template(target) cred = cls.attrs.get("login_credential_local_reference", None) if cred: # TODO make it as task decompile functionality cred = RefType.decompile(cred) user_attrs["cred"] = "ref({})".format(get_cred_var_name(cred.__name__)) if cls.type == "EXEC": script_type = cls.attrs["script_type"] cls.attrs["script_file"] = create_script_file( script_type, cls.attrs["script"], entity_context ) if script_type == "sh": schema_file = "task_exec_ssh.py.jinja2" elif script_type == "static": schema_file = "task_exec_escript.py.jinja2" elif script_type == "npsscript": schema_file = "task_exec_powershell.py.jinja2" elif cls.type == "SET_VARIABLE": variables = cls.attrs.get("eval_variables", None) if variables: user_attrs["variables"] = variables script_type = cls.attrs["script_type"] cls.attrs["script_file"] = create_script_file( script_type, cls.attrs["script"], entity_context ) if script_type == "sh": schema_file = "task_setvariable_ssh.py.jinja2" elif script_type == "static": schema_file = "task_setvariable_escript.py.jinja2" elif script_type == "npsscript": schema_file = "task_setvariable_powershell.py.jinja2" elif cls.type == "DELAY": if hasattr(cls, "attrs"): user_attrs["delay_seconds"] = cls.attrs.get("interval_secs", 0) schema_file = "task_delay.py.jinja2" elif cls.type == "SCALING": scaling_count = cls.attrs.get("scaling_count", 1) if scaling_count: user_attrs["scaling_count"] = scaling_count scaling_type = cls.attrs["scaling_type"] if scaling_type == "SCALEOUT": schema_file = "task_scaling_scaleout.py.jinja2" elif scaling_type == "SCALEIN": schema_file = "task_scaling_scalein.py.jinja2" elif cls.type == "HTTP": attrs = cls.attrs # TODO add basic_cred creds support. For now default cred used user_attrs["headers"] = {} user_attrs["secret_headers"] = {} user_attrs["status_mapping"] = {} for var in attrs.get("headers", []): var_type = var["type"] if var_type == "LOCAL": user_attrs["headers"][var["name"]] = var["value"] elif var_type == "SECRET": user_attrs["secret_headers"][var["name"]] = var["value"] for status in attrs.get("expected_response_params", []): user_attrs["status_mapping"][status["code"]] = ( True if status["status"] == "SUCCESS" else False ) user_attrs["response_paths"] = attrs.get("response_paths", {}) method = attrs["method"] if method == "GET": schema_file = "task_http_get.py.jinja2" elif method == "POST": schema_file = "task_http_post.py.jinja2" elif method == "PUT": schema_file = "task_http_put.py.jinja2" elif method == "DELETE": # TODO remove it from here if not cls.attrs["request_body"]: cls.attrs["request_body"] = {} schema_file = "task_http_delete.py.jinja2" elif cls.type == "CALL_RUNBOOK": # TODO shift this working to explicit method for task decompile runbook = RefType.decompile(cls.attrs["runbook_reference"]) render_ref_template(target) user_attrs = { "name": cls.name, "action": RUNBOOK_ACTION_MAP[runbook.__name__], "target": target.name, } schema_file = "task_call_runbook.py.jinja2" else: raise Exception("Invalid task type") text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()
def render_task_template( cls, entity_context="", RUNBOOK_ACTION_MAP={}, CONFIG_SPEC_MAP={} ): LOG.debug("Rendering {} task template".format(cls.name)) if not isinstance(cls, TaskType): raise TypeError("{} is not of type {}".format(cls, TaskType)) # update entity_context entity_context = entity_context + "_Task_" + cls.__name__ user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.name target = getattr(cls, "target_any_local_reference", None) if target: # target will be modified to have correct name(DSL name) user_attrs["target"] = render_ref_template(target) cred = cls.attrs.get("login_credential_local_reference", None) if cred: user_attrs["cred"] = "ref({})".format( get_cred_var_name(getattr(cred, "name", "") or cred.__name__) ) if cls.type == "EXEC": script_type = cls.attrs["script_type"] cls.attrs["script_file"] = create_script_file( script_type, cls.attrs["script"], entity_context ) if script_type == "sh": schema_file = "task_exec_ssh.py.jinja2" elif script_type == "static": schema_file = "task_exec_escript.py.jinja2" elif script_type == "npsscript": schema_file = "task_exec_powershell.py.jinja2" elif cls.type == "SET_VARIABLE": variables = cls.attrs.get("eval_variables", None) if variables: user_attrs["variables"] = variables script_type = cls.attrs["script_type"] cls.attrs["script_file"] = create_script_file( script_type, cls.attrs["script"], entity_context ) if script_type == "sh": schema_file = "task_setvariable_ssh.py.jinja2" elif script_type == "static": schema_file = "task_setvariable_escript.py.jinja2" elif script_type == "npsscript": schema_file = "task_setvariable_powershell.py.jinja2" elif cls.type == "DELAY": if hasattr(cls, "attrs"): user_attrs["delay_seconds"] = cls.attrs.get("interval_secs", 0) schema_file = "task_delay.py.jinja2" elif cls.type == "SCALING": scaling_count = cls.attrs.get("scaling_count", 1) if scaling_count: user_attrs["scaling_count"] = scaling_count scaling_type = cls.attrs["scaling_type"] if scaling_type == "SCALEOUT": schema_file = "task_scaling_scaleout.py.jinja2" elif scaling_type == "SCALEIN": schema_file = "task_scaling_scalein.py.jinja2" elif cls.type == "HTTP": attrs = cls.attrs user_attrs["headers"] = {} user_attrs["secret_headers"] = {} user_attrs["status_mapping"] = {} for var in attrs.get("headers", []): var_type = var["type"] if var_type == "LOCAL": user_attrs["headers"][var["name"]] = var["value"] elif var_type == "SECRET": user_attrs["secret_headers"][var["name"]] = var["value"] for status in attrs.get("expected_response_params", []): user_attrs["status_mapping"][status["code"]] = ( True if status["status"] == "SUCCESS" else False ) # Store auth objects auth_obj = attrs.get("authentication", {}) auth_type = auth_obj.get("type", "") if auth_type == "basic_with_cred": auth_cred = auth_obj.get("credential_local_reference", None) if auth_cred: user_attrs["cred"] = "ref({})".format( get_cred_var_name( getattr(auth_cred, "name", "") or auth_cred.__name__ ) ) user_attrs["response_paths"] = attrs.get("response_paths", {}) method = attrs["method"] if method == "GET": schema_file = "task_http_get.py.jinja2" elif method == "POST": schema_file = "task_http_post.py.jinja2" elif method == "PUT": schema_file = "task_http_put.py.jinja2" elif method == "DELETE": # TODO remove it from here if not cls.attrs["request_body"]: cls.attrs["request_body"] = {} schema_file = "task_http_delete.py.jinja2" elif cls.type == "CALL_RUNBOOK": runbook = cls.attrs["runbook_reference"] runbook_name = getattr(runbook, "name", "") or runbook.__name__ user_attrs = { "name": cls.name, "action": RUNBOOK_ACTION_MAP[runbook_name], "target": target.name, } schema_file = "task_call_runbook.py.jinja2" elif cls.type == "CALL_CONFIG": config_name = cls.attrs["config_spec_reference"] user_attrs = { "name": cls.name, "config": CONFIG_SPEC_MAP[config_name]["global_name"], } schema_file = "task_call_config.py.jinja2" else: LOG.error("Task type does not match any known types") sys.exit("Invalid task task") text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()
def render_bp_file_template(cls, with_secrets=False, metadata_obj=None): if not isinstance(cls, BlueprintType): raise TypeError("{} is not of type {}".format(cls, BlueprintType)) user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.__name__ user_attrs["description"] = cls.__doc__ # Find default cred default_cred = cls.default_cred default_cred_name = getattr(default_cred, "name", "") or getattr( default_cred, "__name__", "") credential_list = [] for index, cred in enumerate(cls.credentials): cred_name = getattr(cred, "name", "") or cred.__name__ if default_cred_name and cred_name == default_cred_name: cred.default = True credential_list.append(render_credential_template(cred)) # Map to store the [Name: Rendered template for entity] entity_name_text_map = {} # Edges map to store the edges (dependencies) between entities entity_edges = {} for service in cls.services: entity_name_text_map[service.get_ref().name] = service # Edge from services to other entities for dep in service.dependencies: add_edges(entity_edges, dep.get_ref().name, service.get_ref().name) downloadable_img_list = [] vm_images = [] for package in cls.packages: if getattr(package, "__kind__") == "app_package": entity_name_text_map[package.get_ref().name] = package # Edge from package to service for dep in package.services: add_edges(entity_edges, dep.get_ref().name, package.get_ref().name) else: downloadable_img_list.append( render_vm_disk_package_template(package)) vm_images.append(package.get_ref().name) # Printing all the downloadable images at the top, so ignore its edges for substrate in cls.substrates: entity_name_text_map[substrate.get_ref().name] = substrate deployments = [] for profile in cls.profiles: entity_name_text_map[profile.get_ref().name] = profile # Deployments deployments.extend(profile.deployments) for dep in deployments: add_edges(entity_edges, dep.get_ref().name, profile.get_ref().name) for deployment in deployments: entity_name_text_map[deployment.get_ref().name] = deployment # Edges from deployment to package for dep in deployment.packages: add_edges(entity_edges, dep.get_ref().name, deployment.get_ref().name) # Edges from deployment to substrate add_edges(entity_edges, deployment.substrate.get_ref().name, deployment.get_ref().name) # Other dependencies for dep in deployment.dependencies: add_edges(entity_edges, dep.get_ref().name, deployment.get_ref().name) # Getting the local files used for secrets secret_files = get_secret_variable_files() secret_files.extend(get_cred_files()) if with_secrets: # Fill the secret if flag is set if secret_files: click.secho("Enter the value to be used in secret files") for file_name in secret_files: secret_val = click.prompt("\nValue for {}".format(file_name), default="", show_default=False) file_loc = os.path.join(get_local_dir(), file_name) with open(file_loc, "w+") as fd: fd.write(secret_val) dependepent_entities = [] dependepent_entities = get_ordered_entities(entity_name_text_map, entity_edges) # Rendering templates for k, v in enumerate(dependepent_entities): if isinstance(v, ServiceType): dependepent_entities[k] = render_service_template(v) elif isinstance(v, PackageType): dependepent_entities[k] = render_package_template(v) elif isinstance(v, ProfileType): dependepent_entities[k] = render_profile_template(v) elif isinstance(v, DeploymentType): dependepent_entities[k] = render_deployment_template(v) elif isinstance(v, SubstrateType): dependepent_entities[k] = render_substrate_template( v, vm_images=vm_images) blueprint = render_blueprint_template(cls) # Rendere blueprint metadata metadata_str = render_metadata_template(metadata_obj) user_attrs.update({ "secret_files": secret_files, "credentials": credential_list, "vm_images": downloadable_img_list, "dependent_entities": dependepent_entities, "blueprint": blueprint, "metadata": metadata_str, }) text = render_template("bp_file_helper.py.jinja2", obj=user_attrs) return text.strip()
def render_ahv_vm_nic(cls): # Note cls.get_dict() may not contain subnet name # So it will fail. So use class attributes instead of getting dict object subnet_ref = cls.subnet_reference if subnet_ref: subnet_ref = subnet_ref.get_dict() nic_type = cls.nic_type network_function_nic_type = cls.network_function_nic_type subnet_uuid = subnet_ref.get("uuid", "") subnet_cache_data = Cache.get_entity_data_using_uuid( entity_type="ahv_subnet", uuid=subnet_uuid ) user_attrs = {} if not subnet_cache_data: LOG.error("Subnet with uuid '{}' not found".format(subnet_uuid)) sys.exit(-1) user_attrs["subnet_name"] = subnet_cache_data["name"] user_attrs["cluster_name"] = subnet_cache_data["cluster"] schema_file = "" if nic_type == "NORMAL_NIC": if network_function_nic_type == "INGRESS": schema_file = "ahv_normal_ingress_nic.py.jinja2" elif network_function_nic_type == "EGRESS": schema_file = "ahv_normal_egress_nic.py.jinja2" elif network_function_nic_type == "TAP": schema_file = "ahv_normal_tap_nic.py.jinja2" else: LOG.error( "Unknown network function nic type '{}'".format( network_function_nic_type ) ) sys.exit(-1) elif nic_type == "DIRECT_NIC": if network_function_nic_type == "INGRESS": schema_file = "ahv_direct_ingress_nic.py.jinja2" elif network_function_nic_type == "EGRESS": schema_file = "ahv_direct_egress_nic.py.jinja2" elif network_function_nic_type == "TAP": schema_file = "ahv_direct_tap_nic.py.jinja2" else: LOG.error( "Unknown network function nic type '{}'".format( network_function_nic_type ) ) sys.exit(-1) else: LOG.error("Unknown nic type '{}'".format(nic_type)) sys.exit(-1) text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()
def render_variable_template(cls, entity_context): LOG.debug("Rendering {} variable template".format(cls.__name__)) if not isinstance(cls, VariableType): raise TypeError("{} is not of type {}".format(cls, VariableType)) # Updating the context of variables entity_context = entity_context + "_variable_" + cls.__name__ user_attrs = cls.get_user_attrs() user_attrs["description"] = cls.__doc__ or "" # Escape new line character. As it is inline parameter for CalmVariable helper user_attrs["description"] = user_attrs["description"].replace("\n", "\\n") var_val_type = getattr(cls, "value_type", "STRING") var_type = "" schema_file = None if not cls.options: var_type = "simple" else: options = cls.options.get_dict() choices = options.get("choices", []) option_type = options.get("type", "") if (not choices) and (option_type == "PREDEFINED"): var_type = "simple" if cls.regex: regex = cls.regex.get_dict() user_attrs["regex"] = regex.get("value", None) user_attrs["validate_regex"] = regex.get("should_validate", False) else: user_attrs["regex"] = None user_attrs["validate_regex"] = False if cls.editables: user_attrs["runtime"] = cls.editables["value"] else: user_attrs["runtime"] = False user_attrs["name"] = cls.__name__ if var_type == "simple": is_secret = True if user_attrs["type"] == "SECRET" else False if is_secret: user_attrs["value"] = get_secret_var_val(entity_context) if var_val_type == "STRING": schema_file = "var_simple_secret_string.py.jinja2" elif var_val_type == "INT": schema_file = "var_simple_secret_int.py.jinja2" elif var_val_type == "TIME": schema_file = "var_simple_secret_time.py.jinja2" elif var_val_type == "DATE": schema_file = "var_simple_secret_date.py.jinja2" elif var_val_type == "DATE_TIME": schema_file = "var_simple_secret_datetime.py.jinja2" elif var_val_type == "MULTILINE_STRING": schema_file = "var_simple_secret_multiline.py.jinja2" else: if var_val_type == "STRING": schema_file = "var_simple_string.py.jinja2" elif var_val_type == "INT": schema_file = "var_simple_int.py.jinja2" elif var_val_type == "TIME": schema_file = "var_simple_time.py.jinja2" elif var_val_type == "DATE": schema_file = "var_simple_date.py.jinja2" elif var_val_type == "DATE_TIME": schema_file = "var_simple_datetime.py.jinja2" elif var_val_type == "MULTILINE_STRING": user_attrs["value"] = repr(user_attrs["value"]) schema_file = "var_simple_multiline.py.jinja2" else: data_type = cls.data_type options = cls.options.get_dict() option_type = options.get("type", "PREDEFINED") if option_type == "PREDEFINED": user_attrs["choices"] = options.get("choices", []) if data_type == "BASE": if var_val_type == "STRING": schema_file = "var_with_options_predefined_string.py.jinja2" elif var_val_type == "INT": schema_file = "var_with_options_predefined_int.py.jinja2" elif var_val_type == "DATE": schema_file = "var_with_options_predefined_date.py.jinja2" elif var_val_type == "TIME": schema_file = "var_with_options_predefined_time.py.jinja2" elif var_val_type == "DATE_TIME": schema_file = "var_with_options_predefined_datetime.py.jinja2" elif var_val_type == "MULTILINE_STRING": user_attrs["value"] = repr(user_attrs["value"]) schema_file = "var_with_options_predefined_multiline.py.jinja2" else: defaults = cls.value user_attrs["value"] = defaults.split(",") if var_val_type == "STRING": schema_file = "var_with_options_predefined_array_string.py.jinja2" elif var_val_type == "INT": schema_file = "var_with_options_predefined_array_int.py.jinja2" elif var_val_type == "DATE": schema_file = "var_with_options_predefined_array_date.py.jinja2" elif var_val_type == "TIME": schema_file = "var_with_options_predefined_array_time.py.jinja2" elif var_val_type == "DATE_TIME": schema_file = "var_with_options_predefined_array_datetime.py.jinja2" elif var_val_type == "MULTILINE_STRING": user_attrs["value"] = repr(user_attrs["value"]) schema_file = ( "var_with_options_predefined_array_multiline.py.jinja2" ) else: options.pop("choices", None) task = TaskType.decompile(options) task.__name__ = "SampleTask" user_attrs["value"] = render_task_template( task, entity_context=entity_context ) if data_type == "BASE": if var_val_type == "STRING": schema_file = "var_with_options_fromTask_string.py.jinja2" elif var_val_type == "INT": schema_file = "var_with_options_fromTask_int.py.jinja2" elif var_val_type == "DATE": schema_file = "var_with_options_fromTask_date.py.jinja2" elif var_val_type == "TIME": schema_file = "var_with_options_fromTask_time.py.jinja2" elif var_val_type == "DATE_TIME": schema_file = "var_with_options_fromTask_datetime.py.jinja2" elif var_val_type == "MULTILINE_STRING": schema_file = "var_with_options_fromTask_multiline.py.jinja2" else: if var_val_type == "STRING": schema_file = "var_with_options_fromTask_array_string.py.jinja2" elif var_val_type == "INT": schema_file = "var_with_options_fromTask_array_int.py.jinja2" elif var_val_type == "DATE": schema_file = "var_with_options_fromTask_array_date.py.jinja2" elif var_val_type == "TIME": schema_file = "var_with_options_fromTask_array_time.py.jinja2" elif var_val_type == "DATE_TIME": schema_file = "var_with_options_fromTask_array_datetime.py.jinja2" elif var_val_type == "MULTILINE_STRING": schema_file = "var_with_options_fromTask_array_multiline.py.jinja2" if not schema_file: raise Exception("Unknown variable type") text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()
def render_substrate_template(cls, vm_images=[]): LOG.debug("Rendering {} substrate template".format(cls.__name__)) if not isinstance(cls, SubstrateType): raise TypeError("{} is not of type {}".format(cls, SubstrateType)) # Entity context entity_context = "Substrate_" + cls.__name__ user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.__name__ user_attrs["description"] = cls.__doc__ or "" # Update substrate name map and gui name gui_display_name = getattr(cls, "name", "") or cls.__name__ if gui_display_name != cls.__name__: user_attrs["gui_display_name"] = gui_display_name # updating ui and dsl name mapping update_substrate_name(gui_display_name, cls.__name__) provider_spec_editables = user_attrs.get("provider_spec_editables", {}) create_spec_editables = provider_spec_editables.get("create_spec", {}) readiness_probe_editables = provider_spec_editables.get( "readiness_probe", {}) # Handle readiness probe for substrate rp_editable_list = [] for k, v in readiness_probe_editables.items(): if v: rp_editable_list.append(k) # Appending readiness_probe editables to readiness_probe object readiness_probe = user_attrs["readiness_probe"] readiness_probe.editables_list = rp_editable_list user_attrs["readiness_probe"] = render_readiness_probe_template( user_attrs["readiness_probe"]) spec_dir = get_specs_dir() # Handle create spec runtime editables if create_spec_editables: create_spec_editable_file_name = cls.__name__ + "_create_spec_editables.yaml" file_location = os.path.join(spec_dir, create_spec_editable_file_name) dsl_file_location_alias = "os.path.join('{}', '{}')".format( get_specs_dir_key(), create_spec_editable_file_name) user_attrs["provider_spec_editables"] = "read_spec({})".format( dsl_file_location_alias) # Write editable spec to separate file with open(file_location, "w+") as fd: fd.write(yaml.dump(create_spec_editables, default_flow_style=False)) # Handle provider_spec for substrate provider_spec = cls.provider_spec if cls.provider_type == "AHV_VM": boot_config = provider_spec["resources"].get("boot_config", {}) if not boot_config: LOG.error("Boot config not present in {} substrate spec".format( cls.__name__)) sys.exit(-1) vm_cls = AhvVmType.decompile( provider_spec, context=[cls.__schema_name__, gui_display_name]) user_attrs["provider_spec"] = vm_cls.__name__ ahv_vm_str = render_ahv_vm(vm_cls, boot_config) else: # creating a file for storing provider_spec provider_spec_file_name = cls.__name__ + "_provider_spec.yaml" user_attrs["provider_spec"] = get_provider_spec_string( spec=provider_spec, filename=provider_spec_file_name, provider_type=cls.provider_type, vm_images=vm_images, ) # Write provider spec to separate file file_location = os.path.join(spec_dir, provider_spec_file_name) with open(file_location, "w+") as fd: fd.write(yaml.dump(provider_spec, default_flow_style=False)) # Actions action_list = [] system_actions = { v: k for k, v in SubstrateType.ALLOWED_FRAGMENT_ACTIONS.items() } for action in user_attrs.get("actions", []): if action.__name__ in list(system_actions.keys()): action.name = system_actions[action.__name__] action.__name__ = system_actions[action.__name__] action_list.append(render_action_template(action, entity_context)) user_attrs["actions"] = action_list substrate_text = render_template(schema_file="substrate.py.jinja2", obj=user_attrs) if cls.provider_type == "AHV_VM": # Append definition for ahv vm class on top of substrate class substrate_text = "{}\n{}".format(ahv_vm_str, substrate_text) return substrate_text.strip()
def render_profile_template(cls): LOG.debug("Rendering {} profile template".format(cls.__name__)) if not isinstance(cls, ProfileType): raise TypeError("{} is not of type {}".format(cls, ProfileType)) # Entity context entity_context = "Profile_" + cls.__name__ user_attrs = cls.get_user_attrs() user_attrs["name"] = cls.__name__ user_attrs["description"] = cls.__doc__ or "" # Update profile name map and gui name gui_display_name = getattr(cls, "name", "") or cls.__name__ if gui_display_name != cls.__name__: user_attrs["gui_display_name"] = gui_display_name # updating ui and dsl name mapping update_profile_name(gui_display_name, cls.__name__) restore_config_list = [] for idx, entity in enumerate(user_attrs.get("restore_configs", [])): CONFIG_SPEC_MAP[entity.name] = { "global_name": "{}.restore_configs[{}]".format(cls.__name__, idx), "local_name": "restore_configs[{}]".format(idx), } restore_config_list.append( render_restore_config_template(entity, entity_context)) snapshot_config_list = [] for idx, entity in enumerate(user_attrs.get("snapshot_configs", [])): CONFIG_SPEC_MAP[entity.name] = { "global_name": "{}.snapshot_configs[{}]".format(cls.__name__, idx), "local_name": "snapshot_configs[{}]".format(idx), } snapshot_config_list.append( render_snapshot_config_template(entity, entity_context, CONFIG_SPEC_MAP)) update_config_list = [] for idx, entity in enumerate(user_attrs.get("update_configs", [])): CONFIG_SPEC_MAP[entity.name] = { "global_name": "{}.update_configs[{}]".format(cls.__name__, idx), "local_name": "update_configs[{}]".format(idx), } update_config_list.append( render_update_config_template(entity, entity_context)) action_list = [] for action in user_attrs.get("actions", []): action_list.append( render_action_template(action, entity_context, CONFIG_SPEC_MAP)) deployment_list = [] for deployment in user_attrs.get("deployments", []): deployment_list.append(deployment.__name__) variable_list = [] for entity in user_attrs.get("variables", []): variable_list.append(render_variable_template(entity, entity_context)) user_attrs["variables"] = variable_list user_attrs["deployments"] = ", ".join(deployment_list) user_attrs["actions"] = action_list user_attrs["restore_configs"] = ", ".join(restore_config_list) user_attrs["snapshot_configs"] = ", ".join(snapshot_config_list) text = render_template("profile.py.jinja2", obj=user_attrs) return text.strip()
def render_ahv_vm_disk(cls, boot_config): data_source_ref = cls.data_source_reference or {} if data_source_ref: data_source_ref = data_source_ref.get_dict() device_properties = cls.device_properties.get_dict() disk_size_mib = cls.disk_size_mib # find device type device_type = device_properties["device_type"] adapter_type = device_properties["disk_address"]["adapter_type"] adapter_index = device_properties["disk_address"]["device_index"] schema_file = "" user_attrs = {} # Atleast one disk should be bootable if boot_config: if ( adapter_type == boot_config["boot_device"]["disk_address"]["adapter_type"] and adapter_index == boot_config["boot_device"]["disk_address"]["device_index"] ): user_attrs["bootable"] = True # find operation_type if data_source_ref: if data_source_ref["kind"] == "app_package": user_attrs["name"] = data_source_ref.get("name") user_attrs["name"] = ( get_package_name(user_attrs["name"]) or user_attrs["name"] ) operation_type = "cloneFromVMDiskPackage" elif data_source_ref["kind"] == "image": operation_type = "cloneFromImageService" img_uuid = data_source_ref.get("uuid") disk_cache_data = ( Cache.get_entity_data_using_uuid( entity_type=CACHE.ENTITY.AHV_DISK_IMAGE, uuid=img_uuid ) or {} ) if not disk_cache_data: # Windows images may not be present LOG.warning("Image with uuid '{}' not found".format(img_uuid)) user_attrs["name"] = disk_cache_data.get("name", "") else: LOG.error( "Unknown kind `{}` for data source reference in image".format( data_source_ref["kind"] ) ) else: if device_type == "DISK": user_attrs["size"] = disk_size_mib // 1024 operation_type = "allocateOnStorageContainer" elif device_type == "CDROM": operation_type = "emptyCdRom" else: LOG.error("Unknown device type") sys.exit(-1) # TODO add whitelisting from project via attached accounts if device_type == "DISK": if adapter_type == "SCSI": if operation_type == "cloneFromImageService": schema_file = "ahv_vm_disk_scsi_clone_from_image.py.jinja2" elif operation_type == "cloneFromVMDiskPackage": schema_file = "ahv_vm_disk_scsi_clone_from_pkg.py.jinja2" elif operation_type == "allocateOnStorageContainer": schema_file = "ahv_vm_disk_scsi_allocate_container.py.jinja2" else: LOG.error("Unknown operation type {}".format(operation_type)) sys.exit(-1) elif adapter_type == "PCI": if operation_type == "cloneFromImageService": schema_file = "ahv_vm_disk_pci_clone_from_image.py.jinja2" elif operation_type == "cloneFromVMDiskPackage": schema_file = "ahv_vm_disk_pci_clone_from_pkg.py.jinja2" elif operation_type == "allocateOnStorageContainer": schema_file = "ahv_vm_disk_pci_allocate_container.py.jinja2" else: LOG.error("Unknown operation type {}".format(operation_type)) sys.exit(-1) else: LOG.error("Unknown adapter type {}".format(adapter_type)) sys.exit(-1) else: # CD-ROM if adapter_type == "SATA": if operation_type == "cloneFromImageService": schema_file = "ahv_vm_cdrom_sata_clone_from_image.py.jinja2" elif operation_type == "cloneFromVMDiskPackage": schema_file = "ahv_vm_cdrom_sata_clone_from_pkg.py.jinja2" elif operation_type == "emptyCdRom": schema_file = "ahv_vm_cdrom_sata_empty_cdrom.py.jinja2" else: LOG.error("Unknown operation type {}".format(operation_type)) sys.exit(-1) elif adapter_type == "IDE": if operation_type == "cloneFromImageService": schema_file = "ahv_vm_cdrom_ide_clone_from_image.py.jinja2" elif operation_type == "cloneFromVMDiskPackage": schema_file = "ahv_vm_cdrom_ide_clone_from_pkg.py.jinja2" elif operation_type == "emptyCdRom": schema_file = "ahv_vm_cdrom_ide_empty_cdrom.py.jinja2" else: LOG.error("Unknown operation type {}".format(operation_type)) sys.exit(-1) else: LOG.error("Unknown adapter type {}".format(adapter_type)) sys.exit(-1) text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()
def render_ahv_vm_gc(cls, vm_name_prefix=""): schema_file = "" user_attrs = {} user_attrs = cls.get_dict() cloud_init = user_attrs.get("cloud_init", {}) sys_prep = user_attrs.get("sysprep", {}) file_name = "" spec_dir = get_specs_dir() if cloud_init: schema_file = "ahv_vm_cloud_init.py.jinja2" file_name = "{}_cloud_init_data.yaml".format(vm_name_prefix) user_attrs["filename"] = "os.path.join('{}', '{}')".format( get_specs_dir_key(), file_name) cloud_init_user_data = cloud_init.get("user_data", "") if not cloud_init_user_data: return with open(os.path.join(spec_dir, file_name), "w+") as fd: # TODO take care of macro case fd.write(yaml.dump(cloud_init_user_data, default_flow_style=False)) elif sys_prep: file_name = "{}_sysprep_unattend_xml.xml".format(vm_name_prefix) user_attrs["filename"] = "os.path.join('{}', '{}')".format( get_specs_dir_key(), file_name) sysprep_unattend_xml = sys_prep.get("unattend_xml", "") with open(os.path.join(spec_dir, file_name), "w+") as fd: fd.write(sysprep_unattend_xml) install_type = sys_prep.get("install_type", "PREPARED") is_domain = sys_prep.get("is_domain", False) if is_domain and sys_prep.get("domain_credential_reference"): cred = RefType.decompile(sys_prep["domain_credential_reference"]) user_attrs["credential"] = "ref({})".format( get_cred_var_name(cred.__name__)) if install_type == "FRESH": if is_domain: schema_file = "ahv_vm_fresh_sysprep_with_domain.py.jinja2" else: schema_file = "ahv_vm_fresh_sysprep_without_domain.py.jinja2" elif install_type == "PREPARED": if is_domain: schema_file = "ahv_vm_prepared_sysprep_with_domain.py.jinja2" else: schema_file = "ahv_vm_prepared_sysprep_without_domain.py.jinja2" else: LOG.error( "Unknown install type '{}' for sysprep guest customization". format(install_type)) sys.exit(-1) else: return None text = render_template(schema_file=schema_file, obj=user_attrs) return text.strip()