def deploy(service_template: str, inputs: typing.Optional[dict], storage: Storage, verbose_mode: bool, num_workers: int, delete_existing_state: bool): """ :raises ParseError: :raises DataError: """ if delete_existing_state: storage.remove("instances") if inputs is None: if storage.exists("inputs"): inputs = yaml.safe_load(storage.read("inputs")) else: inputs = {} storage.write_json(inputs, "inputs") storage.write(service_template, "root_file") workdir = str(Path.cwd()) if storage.exists("csars"): csar_dir = Path(storage.path) / "csars" / "csar" workdir = str(csar_dir) ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir)) else: ast = tosca.load(Path.cwd(), PurePath(service_template)) template = ast.get_template(inputs) topology = template.instantiate(storage) topology.deploy(verbose_mode, workdir, num_workers)
def validate_csar(csar_path: PurePath, inputs: typing.Optional[dict], storage: Storage, verbose: bool, executors: bool): if inputs is None: inputs = {} csar = CloudServiceArchive.create(csar_path) csar.validate_csar() entrypoint = csar.get_entrypoint() if entrypoint is not None: if isinstance(csar, DirCloudServiceArchive): workdir = Path(csar_path) ast = tosca.load(workdir, entrypoint) template = ast.get_template(inputs) if executors: topology = template.instantiate(storage) topology.validate(verbose, workdir, 1) else: with TemporaryDirectory() as csar_validation_dir: csar.unpackage_csar(csar_validation_dir) workdir = Path(csar_validation_dir) ast = tosca.load(workdir, entrypoint) template = ast.get_template(inputs) if executors: topology = template.instantiate(storage) topology.validate(verbose, csar_validation_dir, 1)
def test_imports_from_multiple_levels(self, tmp_path, yaml_text): name = pathlib.PurePath("template.yaml") (tmp_path / name).write_text( yaml_text( # language=yaml """ tosca_definitions_version: tosca_simple_yaml_1_3 imports: - subfolder/a.yaml - subfolder/b.yaml """)) (tmp_path / "subfolder").mkdir() (tmp_path / "subfolder/a.yaml").write_text( yaml_text( # language=yaml """ tosca_definitions_version: tosca_simple_yaml_1_3 imports: - b.yaml """)) (tmp_path / "subfolder/b.yaml").write_text( yaml_text( # language=yaml """ tosca_definitions_version: tosca_simple_yaml_1_3 data_types: my_type: derived_from: tosca.datatypes.xml """)) tosca.load(tmp_path, name)
def test_merge_topology_template(self, tmp_path, yaml_text): name = pathlib.PurePath("template.yaml") (tmp_path / name).write_text( yaml_text( # language=yaml """ tosca_definitions_version: tosca_simple_yaml_1_3 imports: - merge.yaml topology_template: inputs: some-input: type: string node_templates: my_node: type: tosca.nodes.SoftwareComponent """)) (tmp_path / "merge.yaml").write_text( yaml_text( # language=yaml """ tosca_definitions_version: tosca_simple_yaml_1_3 topology_template: inputs: other-input: type: string node_templates: other_node: type: tosca.nodes.SoftwareComponent """)) tosca.load(tmp_path, name)
def test_merge_duplicate_node_templates_invalid(self, tmp_path, yaml_text): name = pathlib.PurePath("template.yaml") (tmp_path / name).write_text( yaml_text(""" tosca_definitions_version: tosca_simple_yaml_1_3 imports: - merge1.yaml - merge2.yaml topology_template: node_templates: my_node: type: tosca.nodes.SoftwareComponent """)) (tmp_path / "merge1.yaml").write_text( yaml_text(""" tosca_definitions_version: tosca_simple_yaml_1_3 topology_template: node_templates: other_node: type: tosca.nodes.SoftwareComponent """)) (tmp_path / "merge2.yaml").write_text( yaml_text(""" tosca_definitions_version: tosca_simple_yaml_1_3 topology_template: node_templates: other_node: type: tosca.nodes.SoftwareComponent """)) with pytest.raises(ParseError): tosca.load(tmp_path, name)
def diff_templates( service_template_old: str, workdir_old: str, inputs_old: typing.Optional[dict], service_template_new: str, workdir_new: str, inputs_new: typing.Optional[dict], template_comparer: TemplateComparer, verbose_mode: bool ): if inputs_new is None: inputs_new = {} if inputs_old is None: inputs_old = {} ast_old = tosca.load(Path(workdir_old), PurePath(service_template_old)) ast_new = tosca.load(Path(workdir_new), PurePath(service_template_new)) template_old = ast_old.get_template(inputs_old) template_new = ast_new.get_template(inputs_new) context = TemplateContext(template_old, template_new, workdir_old, workdir_new) _, diff = template_comparer.compare_service_template(template_old, template_new, context) return diff
def deploy_service_template(service_template_path: PurePath, inputs: typing.Optional[dict], storage: Storage, verbose_mode: bool, num_workers: int, delete_existing_state: bool): if delete_existing_state: storage.remove("instances") if inputs is None: if storage.exists("inputs"): inputs = yaml.safe_load(storage.read("inputs")) else: inputs = {} storage.write_json(inputs, "inputs") storage.write(str(service_template_path), "root_file") # set workdir and check if service template/CSAR has been initialized workdir = Path(service_template_path.parent) if storage.exists("csars"): csar_dir = Path(storage.path) / "csars" / "csar" workdir = csar_dir ast = tosca.load(workdir, service_template_path.relative_to(csar_dir)) else: ast = tosca.load(workdir, PurePath(service_template_path.name)) # initialize service template and deploy template = ast.get_template(inputs) topology = template.instantiate(storage) topology.deploy(verbose_mode, workdir, num_workers)
def outputs(storage: Storage) -> dict: """ Get deployment outputs. :raises ParseError: :raises DataError: """ if storage.exists("inputs"): inputs = storage.read_json("inputs") else: inputs = {} if storage.exists("root_file"): service_template_path = PurePath(storage.read("root_file")) if storage.exists("csars"): csar_dir = Path(storage.path) / "csars" / "csar" ast = tosca.load(Path(csar_dir), service_template_path.relative_to(csar_dir)) else: ast = tosca.load(Path(service_template_path.parent), PurePath(service_template_path.name)) template = ast.get_template(inputs) # We need to instantiate the template in order # to get access to the instance state. template.instantiate(storage) result: Dict = template.get_outputs() return result else: print("There is no root_file in storage.") return {}
def undeploy(storage: Storage, verbose_mode: bool, num_workers: int): """ Undeploy a deployment. :raises ParseError: :raises DataError: """ if storage.exists("inputs"): inputs = storage.read_json("inputs") else: inputs = {} if storage.exists("root_file"): service_template = storage.read("root_file") workdir = str(Path.cwd()) if storage.exists("csars"): csar_dir = Path(storage.path) / "csars" / "csar" workdir = str(csar_dir) ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir)) else: ast = tosca.load(Path.cwd(), PurePath(service_template)) template = ast.get_template(inputs) topology = template.instantiate(storage) topology.undeploy(verbose_mode, workdir, num_workers) else: print("There is no root_file in storage.")
def test_duplicate_import(self, tmp_path, yaml_text): name = pathlib.PurePath("template.yaml") (tmp_path / name).write_text( yaml_text(""" tosca_definitions_version: tosca_simple_yaml_1_3 imports: [ template.yaml ] """)) tosca.load(tmp_path, name)
def validate(args): print("Validating service template ...") try: tosca.load(Path.cwd(), PurePath(args.template.name)) print("Done.") return 0 except ParseError as e: print("{}: {}".format(e.loc, e)) return 1
def info(csar_or_rootdir: Optional[PurePath], storage: Storage) -> dict: info_dict: Dict[str, Optional[str]] = dict(service_template=None, content_root=None, inputs=None, status=None) # stateless autodetect first if possible, # which can then be overwritten via state if csar_or_rootdir is not None: csar = CloudServiceArchive.create(csar_or_rootdir) try: csar.validate_csar() info_dict["content_root"] = str(csar_or_rootdir) meta = csar.parse_csar_meta() if meta is not None: info_dict["service_template"] = meta.entry_definitions except OperaError: pass if storage.exists("root_file"): service_template = storage.read("root_file") info_dict["service_template"] = service_template if storage.exists("inputs"): info_dict["inputs"] = str(storage.path / "inputs") inputs = yaml.safe_load(storage.read("inputs")) else: inputs = {} if storage.exists("csars/csar"): csar_dir = Path(storage.path) / "csars" / "csar" info_dict["content_root"] = str(csar_dir) ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir)) else: ast = tosca.load(Path.cwd(), PurePath(service_template)) if storage.exists("instances"): template = ast.get_template(inputs) # We need to instantiate the template in order # to get access to the instance state. topology = template.instantiate(storage) info_dict["status"] = topology.get_info() else: info_dict["status"] = "initialized" return info_dict
def test_undefined_required_properties3(self, tmp_path, yaml_text): name = pathlib.PurePath("template.yaml") (tmp_path / name).write_text( yaml_text( # language=yaml """ tosca_definitions_version: tosca_simple_yaml_1_3 node_types: my_node_type: derived_from: tosca.nodes.Root properties: property1: type: integer property2: type: float property3: type: string topology_template: node_templates: my_node_template: type: my_node_type properties: property1: 42 property2: 42.0 """)) storage = Storage(tmp_path / pathlib.Path(".opera")) storage.write("template.yaml", "root_file") ast = tosca.load(tmp_path, name) with pytest.raises(ParseError, match="Missing a required property: property3"): ast.get_template({})
def test_undeclared_requirements(self, tmp_path, yaml_text): name = pathlib.PurePath("template.yaml") (tmp_path / name).write_text( yaml_text( # language=yaml """ tosca_definitions_version: tosca_simple_yaml_1_3 topology_template: node_templates: node_1: type: tosca.nodes.SoftwareComponent node_2: type: tosca.nodes.SoftwareComponent requirements: - dependency: node_1 node_3: type: tosca.nodes.SoftwareComponent requirements: - dependency_not_defined1: node_1 """)) storage = Storage(tmp_path / pathlib.Path(".opera")) storage.write("template.yaml", "root_file") ast = tosca.load(tmp_path, name) with pytest.raises( ParseError, match="Undeclared requirements: dependency_not_defined1"): ast.get_template({})
def get_nodes(self, file, temp_Dir): try: entry_file = file storage = Storage(Path(temp_Dir)) storage.write(entry_file, "root_file") ast = tosca.load(Path(temp_Dir), PurePath(entry_file)) template = ast.get_template({}) topology = template.instantiate(storage) nodes = topology.nodes node_keys = list(nodes.keys()) node_values = list(nodes.values()) node_list = [] node_keys_updates = [] for val in range(len(node_values)): if len(node_values[val].template.requirements) > 0: temp_node = node_keys[val][:-2] node_list.append(temp_node) for node in node_keys: node_keys_updates.append(node[:-2]) return node_list, node_keys_updates except ParseError as e: print("{}: {}".format(e.loc, e)) return 1, 1 except DataError as e: print(str(e)) return 1, 1
def test_stdlib_is_present(self, tmp_path, typ): name = pathlib.PurePath("stdlib.yaml") (tmp_path / name).write_text( "tosca_definitions_version: tosca_simple_yaml_1_3", ) doc = tosca.load(tmp_path, name) assert doc.dig(*typ) is not None
def outputs(args): if args.instance_path and not path.isdir(args.instance_path): raise argparse.ArgumentTypeError( "Directory {0} is not a valid path!".format(args.instance_path)) storage = Storage(Path(args.instance_path).joinpath( ".opera")) if args.instance_path else Storage(Path(".opera")) root = storage.read("root_file") inputs = storage.read_json("inputs") try: ast = tosca.load(Path.cwd(), PurePath(root)) template = ast.get_template(inputs) topology = template.instantiate(storage) # We need to instantiate the template in order to get access to the # instance state. print(format_outputs(template.get_outputs(), args.format)) except ParseError as e: print("{}: {}".format(e.loc, e)) return 1 except DataError as e: print(str(e)) return 1 return 0
def init_compressed_csar(csar_name: str, inputs: typing.Optional[dict], storage: Storage, clean_storage: bool): if storage.exists("root_file"): if clean_storage: storage.remove_all() else: print("Looks like service template or CSAR has already been initialized. " "Use the --clean/-c flag to clear the storage.") return if inputs is None: inputs = {} storage.write_json(inputs, "inputs") csars_dir = Path(storage.path) / "csars" csars_dir.mkdir(exist_ok=True) csar = CloudServiceArchive.create(PurePath(csar_name)) csar.validate_csar() tosca_service_template = csar.get_entrypoint() # unzip csar and save the path to storage csar_dir = csars_dir / Path("csar") ZipFile(csar_name, "r").extractall(csar_dir) csar_tosca_service_template_path = csar_dir / tosca_service_template storage.write(str(csar_tosca_service_template_path), "root_file") # try to initiate service template from csar ast = tosca.load(Path(csar_dir), Path(tosca_service_template)) template = ast.get_template(inputs) template.instantiate(storage)
def test_load_minimal_document(self, tmp_path): name = pathlib.PurePath("root.yaml") (tmp_path / name).write_text("tosca_definitions_version: tosca_simple_yaml_1_3") doc = tosca.load(tmp_path, name) assert doc.tosca_definitions_version.data == "tosca_simple_yaml_1_3"
def deploy(args): if args.instance_path and not path.isdir(args.instance_path): raise argparse.ArgumentTypeError( "Directory {0} is not a valid path!".format(args.instance_path)) storage = Storage(Path(args.instance_path).joinpath( ".opera")) if args.instance_path else Storage(Path(".opera")) storage.write(args.csar.name, "root_file") # TODO(@tadeboro): This should be part of the init command that we do not # have yet. try: inputs = yaml.safe_load(args.inputs) if args.inputs else {} storage.write_json(inputs, "inputs") except Exception as e: print("Invalid inputs: {}".format(e)) return 1 try: ast = tosca.load(Path.cwd(), PurePath(args.csar.name)) template = ast.get_template(inputs) topology = template.instantiate(storage) topology.deploy() except ParseError as e: print("{}: {}".format(e.loc, e)) return 1 except DataError as e: print(str(e)) return 1 return 0
def deploy_compressed_csar(csar_path: PurePath, inputs: typing.Optional[dict], storage: Storage, verbose_mode: bool, num_workers: int, delete_existing_state: bool): if delete_existing_state: storage.remove("instances") if inputs is None: inputs = {} storage.write_json(inputs, "inputs") csars_dir = Path(storage.path) / "csars" csars_dir.mkdir(exist_ok=True) csar = CloudServiceArchive.create(csar_path) csar.validate_csar() tosca_service_template = csar.get_entrypoint() # unzip csar, save the path to storage and set workdir csar_dir = csars_dir / Path("csar") ZipFile(csar_path, "r").extractall(csar_dir) # pylint: disable=consider-using-with csar_tosca_service_template_path = csar_dir / tosca_service_template storage.write(str(csar_tosca_service_template_path), "root_file") workdir = str(csar_dir) # initialize service template from CSAR and deploy ast = tosca.load(Path(csar_dir), Path(tosca_service_template)) template = ast.get_template(inputs) topology = template.instantiate(storage) topology.deploy(verbose_mode, workdir, num_workers)
def prepare_template(path, yaml_text, template): name = pathlib.PurePath("template.yaml") (path / name).write_text(yaml_text(template)) storage = Storage(path / pathlib.Path(".opera")) storage.write("template.yaml", "root_file") ast = tosca.load(path, name) template = ast.get_template({}) topology = template.instantiate(storage) return template, topology, path, storage
def get_template(storage): if storage.exists("inputs"): inputs = storage.read_json("inputs") else: inputs = {} if storage.exists("root_file"): service_template = storage.read("root_file") if storage.exists("csars"): csar_dir = Path(storage.path) / "csars" / "csar" ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir)) else: ast = tosca.load(Path.cwd(), PurePath(service_template)) template = ast.get_template(inputs) return template else: return None
def initialize_service_template(service_template: str, inputs: typing.Optional[dict], storage: Storage): if inputs is None: inputs = {} storage.write_json(inputs, "inputs") storage.write(service_template, "root_file") ast = tosca.load(Path.cwd(), PurePath(service_template)) template = ast.get_template(inputs) template.instantiate(storage)
def validate_service_template(service_template_path: PurePath, inputs: typing.Optional[dict], storage: Storage, verbose: bool, executors: bool): if inputs is None: inputs = {} workdir = Path(service_template_path.parent) ast = tosca.load(workdir, PurePath(service_template_path.name)) template = ast.get_template(inputs) if executors: topology = template.instantiate(storage) topology.validate(verbose, workdir, 1)
def outputs(storage: Storage) -> dict: """ :raises ParseError: :raises DataError: """ service_template = storage.read("root_file") inputs = storage.read_json("inputs") if storage.exists("csars"): csar_dir = Path(storage.path) / "csars" / "csar" ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir)) else: ast = tosca.load(Path.cwd(), PurePath(service_template)) template = ast.get_template(inputs) # We need to instantiate the template in order # to get access to the instance state. template.instantiate(storage) return template.get_outputs()
def notify(storage: Storage, verbose_mode: bool, trigger_name_or_event: str, notification_file_contents: typing.Optional[str]): if storage.exists("inputs"): inputs = yaml.safe_load(storage.read("inputs")) else: inputs = {} if storage.exists("root_file"): service_template = storage.read("root_file") workdir = str(Path.cwd()) if storage.exists("csars"): csar_dir = Path(storage.path) / "csars" / "csar" workdir = str(csar_dir) ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir)) else: ast = tosca.load(Path.cwd(), PurePath(service_template)) template = ast.get_template(inputs) # check if specified trigger or event name exists in template if trigger_name_or_event: trigger_name_or_event_exists = False for policy in template.policies: for trigger in policy.triggers.values(): if trigger_name_or_event in (trigger.name, trigger.event.data): trigger_name_or_event_exists = True break if not trigger_name_or_event_exists: raise DataError( "The provided trigger or event name does not exist: {}.". format(trigger_name_or_event)) topology = template.instantiate(storage) topology.notify(verbose_mode, workdir, trigger_name_or_event, notification_file_contents) else: print("There is no root_file in storage.")
def test_custom_type_is_present(self, tmp_path, yaml_text, typ): root = tmp_path / "root.yaml" root.write_text( yaml_text(""" tosca_definitions_version: tosca_simple_yaml_1_3 {}: my.custom.Type: derived_from: {} """.format(*typ))) doc = tosca.load(root.parent, root.name) assert doc.dig(typ[0], "my.custom.Type") is not None
def test_custom_type_is_present(self, tmp_path, yaml_text, typ): name = pathlib.PurePath("custom.yaml") (tmp_path / name).write_text( yaml_text(""" tosca_definitions_version: tosca_simple_yaml_1_3 {}: my.custom.Type: derived_from: {} """.format(*typ))) doc = tosca.load(tmp_path, name) assert doc.dig(typ[0], "my.custom.Type") is not None
def test_loads_template_part(self, tmp_path, yaml_text): name = pathlib.PurePath("template.yaml") (tmp_path / name).write_text( yaml_text(""" tosca_definitions_version: tosca_simple_yaml_1_3 topology_template: node_templates: my_node: type: tosca.nodes.SoftwareComponent """)) doc = tosca.load(tmp_path, name) assert doc.topology_template.node_templates["my_node"] is not None