Пример #1
0
 def open_file(self, extension, normalize=False):
     # Create the target directory if not already exists.
     target_directory = self.create_target_directory()
     # Compute the file path.
     # TODO: call sefl.compute_filename()
     template_yaml = self.tosca_service_template.get_yaml()
     metadata = template_yaml.get("metadata")
     if metadata is None:
         metadata = template_yaml
     template_name = metadata.get("template_name")
     if template_name is not None:
         filename = template_name
         template_version = metadata.get("template_version")
         if template_version is not None:
             filename = filename + "-" + str(template_version)
         if normalize:
             filename = normalize_name(filename)
         if extension is not None:
             filename = filename + ".ext"
     else:
         filename = self.tosca_service_template.get_filename()
     if extension is not None:
         filename = filename[: filename.rfind(".")]
         if normalize:
             filename = normalize_name(filename)
         filepath = target_directory + "/" + filename + extension
     else:
         filepath = target_directory + "/" + filename
     # Open the file.
     self.file = open(filepath, "w")
     self.logger.info(filepath + " opened.")
 def generate_container(self, container_name, containeds):
     node_template = node_templates.get(container_name)
     node_template_type = node_template.get(TYPE)
     uml2_kind = get_uml2_kind(node_template_type)
     node_template_artifacts = get_dict(node_template, ARTIFACTS)
     if len(containeds) == 0 and len(node_template_artifacts) == 0:
         self.generate(
             uml2_kind,
             ' "',
             container_name,
             ": ",
             short_type_name(node_template_type),
             '" as node_',
             normalize_name(container_name),
             sep="",
         )
     else:
         self.generate(
             uml2_kind,
             ' "',
             container_name,
             ": ",
             short_type_name(node_template_type),
             '" as node_',
             normalize_name(container_name),
             " {",
             sep="",
         )
         for contained_name, contained_dict in containeds.items():
             generate_container(self, contained_name, contained_dict)
         for artifact_name, artifact_yaml in node_template_artifacts.items(
         ):
             artifact_type = syntax.get_artifact_type(artifact_yaml)
             if artifact_type is None:
                 artifact_type = "Artifact"
             self.generate(
                 'artifact "',
                 syntax.get_artifact_file(artifact_yaml),
                 '" <<',
                 artifact_type,
                 ">> as node_",
                 normalize_name(container_name),
                 "_artifact_",
                 normalize_name(artifact_name),
                 sep="",
             )
         self.generate("}")
Пример #3
0
 def open_file(self, extension, normalize=False):
     # Create the target directory if not already exists.
     target_directory = self.create_target_directory()
     # Compute the file path.
     # TODO: call self.compute_filename()
     format = self.configuration.get("Generator", "filename-format")
     if format == "fullname":
         filename = self.get_filename(self.tosca_service_template)
         filename = filename[:filename.rfind(".")]
         if normalize:
             filename = normalize_name(filename)
         filepath = target_directory + "/" + filename
         if extension != None:
             filepath += extension
     else:  # else format is shortname
         template_yaml = self.tosca_service_template.get_yaml()
         metadata = template_yaml.get("metadata")
         if metadata == None:
             metadata = template_yaml
         template_name = metadata.get("template_name")
         if template_name != None:
             filename = template_name
             template_version = metadata.get("template_version")
             if template_version != None:
                 filename = filename + "-" + str(template_version)
             if normalize:
                 filename = normalize_name(filename)
             if extension != None:
                 filename = filename + ".ext"
         else:
             filename = self.get_filename(self.tosca_service_template)
         if extension != None:
             filename = filename[:filename.rfind(".")]
             if normalize:
                 filename = normalize_name(filename)
             filepath = target_directory + "/" + filename + extension
         else:
             filepath = target_directory + "/" + filename
     # Open the file.
     self.file = open(filepath, "w")
     self.info(filepath + " opened.")
    def generate_node_template(self, steps, node_name, node_template):
        templated_steps = \
            self.get_config_for_a_type("node_types", node_template.get('type'))
        if templated_steps is None:
            return

        # duplicate templated_steps
        templated_steps = copy.deepcopy(templated_steps.get('steps', {}))

        if isinstance(templated_steps, dict):
            for step_name, step_def in templated_steps.items():
                # the target of steps is the node name
                step_def["target"] = node_name
                # rename on_success steps
                on_success_steps = step_def.get("on_success")
                if on_success_steps != None:
                    for idx in range(0, len(on_success_steps)):
                        on_success_step_name = on_success_steps[idx]
                        if on_success_step_name in templated_steps:
                            on_success_steps[
                                idx] = on_success_step_name + '_' + utils.normalize_name(
                                    node_name)

                # add the step to the workflow steps
                steps[step_name + '_' +
                      utils.normalize_name(node_name)] = step_def

        elif isinstance(templated_steps, list):
            previous_step = {}
            for templated_step in templated_steps:
                for step_name, step_def in templated_step.items():
                    # the target of steps is the node name
                    step_def["target"] = node_name
                    # link previous step with this step
                    previous_step["on_success"] = [
                        step_name + '_' + utils.normalize_name(node_name)
                    ]
                    previous_step = step_def
                    # add the step to the workflow steps
                    steps[step_name + '_' +
                          utils.normalize_name(node_name)] = step_def
    def generate_relationship_weave_steps(self, steps, relationship):
        weave_steps = \
            self.get_config_for_a_type( \
                    "relationship_types", \
                    relationship.relationship_type_name)
        if weave_steps is None:
            return

        format_args = {
            'SOURCE':
            utils.normalize_name(relationship.source_node_template_name),
            'TARGET':
            utils.normalize_name(relationship.target_node_template_name),
        }
        for weave_step in weave_steps.get("weave_steps", []):
            weave_step = weave_step.format_map(format_args)
            self.processor.debug("  weave " + weave_step)
            tmp = weave_step.split(' ')
            if steps.get(tmp[0]) is None:
                self.processor.debug("- no %r step" % tmp[0])
                continue  # next weave_step
            if steps.get(tmp[2]) is None:
                self.processor.debug("- no %r step" % tmp[2])
                continue  # next weave_step
            on_success = steps[tmp[0]].get("on_success")
            if on_success is None:
                on_success = []
                steps[tmp[0]]["on_success"] = on_success
            if tmp[1] == "before":
                if tmp[2] not in on_success:
                    on_success.append(tmp[2])
            elif tmp[1] == "follow":
                if steps[tmp[2]].get("on_success") != None:
                    for s in steps[tmp[2]]["on_success"]:
                        if s not in on_success:
                            on_success.append(s)
                steps[tmp[2]]["on_success"] = []  # TODO or [ tmp[0] ] ???
            else:
                raise Exception(weave_step)
Пример #6
0
 def compute_filename(self, tosca_service_template, normalize=True):
     # Compute the file path.
     template_yaml = tosca_service_template.get_yaml()
     metadata = template_yaml.get("metadata")
     if metadata is None:
         metadata = template_yaml
     template_name = metadata.get("template_name")
     if template_name is not None:
         filename = template_name
         template_version = metadata.get("template_version")
         if template_version is not None:
             filename = filename + "-" + str(template_version)
     else:
         tmp = tosca_service_template.get_filename()
         filename = tmp[: tmp.rfind(".")]
     if normalize:
         filename = normalize_name(filename)
     return filename
Пример #7
0
 def compute_filename(self, tosca_service_template, normalize=True):
     # Compute the file path.
     format = self.configuration.get("Generator", "filename-format")
     if format == "fullname":
         filename = self.get_filename(tosca_service_template)
         return filename[:filename.rfind('.')]
     # else format is shortname
     template_yaml = tosca_service_template.get_yaml()
     metadata = template_yaml.get("metadata")
     if metadata is None:
         metadata = template_yaml
     template_name = metadata.get("template_name")
     if template_name is not None:
         filename = template_name
         template_version = metadata.get("template_version")
         if template_version is not None:
             filename = filename + "-" + str(template_version)
     else:
         tmp = self.get_filename(tosca_service_template)
         filename = tmp[:tmp.rfind(".")]
     if normalize:
         filename = normalize_name(filename)
     return filename
    def generation(self):
        self.info("TOSCA diagram generation")

        topology_template = syntax.get_topology_template(
            self.tosca_service_template.get_yaml())
        # Generate only for TOSCA topology template.
        if topology_template is None:
            return

        # Generate the TOSCA diagram.
        self.open_file(".dot")

        self.generate("graph ToscaDiagram {")
        self.generate('  rankdir="LR"')

        target_capability_ids = {
        }  # map<requirement_assignment_id,capability_id>
        connected_capabilities = set()  # set<node_name.capability_name>
        connected_requirements = set()  # set<node_name.requirement_name>

        substitution_mappings = syntax.get_substitution_mappings(
            topology_template)
        if substitution_mappings is not None:
            for capability_name, capability_yaml in syntax.get_capabilities(
                    substitution_mappings).items():
                if capability_yaml:
                    if not isinstance(capability_yaml, list):
                        continue  # TODO something when capability_yaml is not a list
                    capability_name_id = "topology_template_substitution_mappings_capability_" + normalize_name(
                        capability_name)
                    self.generate(
                        "  ",
                        capability_name_id,
                        '[label="',
                        capability_name,
                        '" shape=cds style=filled fillcolor=orange]',
                        sep="",
                    )
                    self.generate(
                        "  ",
                        capability_name_id,
                        " -- ",
                        normalize_name(capability_yaml[0]),
                        "_capability_",
                        normalize_name(capability_yaml[1]),
                        "[style=dotted]",
                        sep="",
                    )
                    connected_capabilities.add(capability_yaml[0] + "." +
                                               capability_yaml[1])

            for (
                    requirement_name,
                    requirement_yaml,
            ) in syntax.get_substitution_mappings_requirements(
                    substitution_mappings).items():
                if requirement_yaml:
                    connected_requirements.add(requirement_yaml[0] + "." +
                                               requirement_yaml[1])

            substitution_mappings_node_type = syntax.get_node_type(
                substitution_mappings)
            self.generate("  subgraph clusterSubstitutionMappings {")
            self.generate('    label="',
                          substitution_mappings_node_type,
                          '"',
                          sep="")

        node_templates = syntax.get_node_templates(topology_template)

        for node_name, node_yaml in node_templates.items():
            node_type_requirements = syntax.get_requirements_dict(
                self.type_system.merge_type(syntax.get_type(node_yaml)))
            for requirement in syntax.get_requirements_list(node_yaml):
                for requirement_name, requirement_yaml in requirement.items():
                    # ACK for Alien4Cloud
                    requirement_name = syntax.get_type_requirement(
                        requirement_yaml, requirement_name)
                    if requirement_yaml:
                        requirement_capability = syntax.get_requirement_capability(
                            node_type_requirements.get(requirement_name))
                        if requirement_capability is None:
                            self.error(
                                requirement_name + ": capability undefined",
                                requirement_name,
                            )
                            continue
                        requirement_node = syntax.get_requirement_node_template(
                            requirement_yaml)
                        if requirement_node is None:
                            continue
                        capability_found = False
                        requirement_node_template = node_templates.get(
                            requirement_node)
                        if requirement_node_template is None:
                            self.error(
                                requirement_node + " node template undefined",
                                requirement_node,
                            )
                            continue
                        for capability_name, capability_yaml in syntax.get_capabilities(
                                self.type_system.merge_node_type(
                                    syntax.get_type(
                                        requirement_node_template))).items():
                            if self.type_system.is_derived_from(
                                    syntax.get_capability_type(
                                        capability_yaml),
                                    requirement_capability,
                            ):
                                capability_found = True
                                break
                        if capability_found:
                            target_capability_ids[id(requirement)] = (
                                self.get_node_name_id(requirement_node) +
                                "_capability_" +
                                normalize_name(capability_name))
                            connected_capabilities.add(requirement_node + "." +
                                                       capability_name)
                            connected_requirements.add(node_name + "." +
                                                       requirement_name)
                        else:
                            self.error(
                                ' capability of type "' +
                                requirement_capability + '" not found',
                                requirement_node_template,
                            )

        for node_name, node_yaml in node_templates.items():
            node_name_id = self.get_node_name_id(node_name)
            node_type = syntax.get_type(node_yaml)
            merged_node_type = self.type_system.merge_type(node_type)
            self.generate("    subgraph cluster", node_name_id, " {", sep="")
            self.generate("      color=white")
            self.generate('      label=""')
            self.generate(
                "      ",
                node_name_id,
                '[label="',
                node_name,
                ": ",
                short_type_name(node_type),
                '|\l\l\l\l" shape=record style=rounded]',
                sep="",
            )
            for capability_name, capability_yaml in syntax.get_capabilities(
                    merged_node_type).items():
                if (node_name + "." + capability_name in connected_capabilities
                        or node_yaml.get("capabilities",
                                         {}).get(capability_name) is not None):
                    self.generate(
                        "      ",
                        node_name_id,
                        "_capability_",
                        normalize_name(capability_name),
                        '[label="',
                        capability_name,
                        '" shape=cds style=filled fillcolor=orange]',
                        sep="",
                    )
                    self.generate(
                        "      ",
                        node_name_id,
                        "_capability_",
                        normalize_name(capability_name),
                        " -- ",
                        node_name_id,
                        sep="",
                    )
            for requirement_name, requirement_yaml in syntax.get_requirements_dict(
                    merged_node_type).items():
                if (node_name + "." + requirement_name
                        in connected_requirements
                        or requirement_yaml.get("occurrences", [1, 1])[0] > 0):
                    self.generate(
                        "      ",
                        node_name_id,
                        "_requirement_",
                        normalize_name(requirement_name),
                        '[label="',
                        requirement_name,
                        '" shape=cds style=filled fillcolor=turquoise]',
                        sep="",
                    )
                    self.generate(
                        "      ",
                        node_name_id,
                        " -- ",
                        node_name_id,
                        "_requirement_",
                        normalize_name(requirement_name),
                        sep="",
                    )
            self.generate("    }")

        for node_name, node_yaml in node_templates.items():
            node_name_id = self.get_node_name_id(node_name)
            for requirement in syntax.get_requirements_list(node_yaml):
                for requirement_name, requirement_yaml in requirement.items():
                    # ACK for Alien4Cloud
                    requirement_name = syntax.get_type_requirement(
                        requirement_yaml, requirement_name)
                    capability_id = target_capability_ids.get(id(requirement))
                    if capability_id is not None:
                        self.generate(
                            "    ",
                            node_name_id,
                            "_requirement_",
                            normalize_name(requirement_name),
                            " -- ",
                            capability_id,
                            "[style=dotted]",
                            sep="",
                        )

        if substitution_mappings is not None:
            self.generate("  }")
            for (
                    requirement_name,
                    requirement_yaml,
            ) in syntax.get_substitution_mappings_requirements(
                    substitution_mappings).items():
                if requirement_yaml:
                    requirement_name_id = "topology_template_substitution_mappings_requirement_" + normalize_name(
                        requirement_name)
                    self.generate(
                        "  ",
                        requirement_name_id,
                        '[label="',
                        requirement_name,
                        '" shape=cds style=filled fillcolor=turquoise]',
                        sep="",
                    )
                    self.generate(
                        "  ",
                        normalize_name(requirement_yaml[0]),
                        "_requirement_",
                        normalize_name(requirement_yaml[1]),
                        " -- ",
                        requirement_name_id,
                        "[style=dotted]",
                        sep="",
                    )

        self.generate("}")
        self.close_file()
 def get_node_name_id(self, node_name):
     node_name_id = normalize_name(node_name)
     if node_name_id == "node":  # 'node' is a dot keyword
         node_name_id = "node_node"  # rename to 'node_node' to avoid dot error.
     return node_name_id
    def generate_UML2_deployment_diagram(self, topology_template):
        self.generate("@startuml")
        self.generate("skinparam componentStyle uml2")
        self.generate()

        node_templates = get_dict(topology_template, NODE_TEMPLATES)

        non_containeds = list(node_templates.keys())
        containers = {}
        contained_containers = []

        # Iterate over all node templates to find containers.
        for node_template_name, node_template_yaml in node_templates.items():
            merged_node_template_type = self.type_system.merge_node_type(
                node_template_yaml.get(TYPE))
            # Iterate over all capabilities of the node template type.
            for capability_name, capability_yaml in get_dict(
                    merged_node_template_type, CAPABILITIES).items():
                capability_type = get_capability_type(capability_yaml)
                if self.type_system.is_derived_from(
                        capability_type, "tosca.capabilities.Container"):
                    containers[node_template_name] = containers.get(
                        node_template_name, dict())
                    try:
                        non_containeds.remove(node_template_name)
                    except ValueError:
                        pass

        # Iterate over all node templates to find containeds.
        for node_template_name, node_template_yaml in node_templates.items():
            merged_node_template_type = self.type_system.merge_node_type(
                node_template_yaml.get(TYPE))
            # Iterate over all requirements of the node template.
            for requirement in get_list(node_template_yaml, REQUIREMENTS):
                for requirement_name, requirement_yaml in requirement.items():
                    requirement_definition = get_dict(
                        merged_node_template_type,
                        REQUIREMENTS).get(requirement_name)
                    requirement_relationship = syntax.get_requirement_relationship(
                        requirement_definition)
                    requirement_relationship_type = syntax.get_relationship_type(
                        requirement_relationship)
                    if self.type_system.is_derived_from(
                            requirement_relationship_type,
                            "tosca.relationships.HostedOn"):
                        requirement_node = get_requirement_node_template(
                            requirement_yaml)
                        if requirement_node is not None:
                            try:
                                containers[requirement_node][
                                    node_template_name] = containers.get(
                                        node_template_name, dict())
                            except KeyError as e:
                                self.error(e)
                            contained_containers.append(node_template_name)
                            try:
                                non_containeds.remove(node_template_name)
                            except ValueError:
                                pass

        # TODO: Remove containers contained by other containers.
        for contained_container_name in contained_containers:
            if containers.get(contained_container_name) is not None:
                del containers[contained_container_name]

        # Iterate over all containers.

        def get_uml2_kind(tosca_type):
            uml2_kind = "component"
            for tt, kind in self.configuration.get(UML2, "kinds").items():
                if self.type_system.is_derived_from(tosca_type, tt):
                    uml2_kind = kind
                    break
            return uml2_kind

        def generate_container(self, container_name, containeds):
            node_template = node_templates.get(container_name)
            node_template_type = node_template.get(TYPE)
            uml2_kind = get_uml2_kind(node_template_type)
            node_template_artifacts = get_dict(node_template, ARTIFACTS)
            if len(containeds) == 0 and len(node_template_artifacts) == 0:
                self.generate(
                    uml2_kind,
                    ' "',
                    container_name,
                    ": ",
                    short_type_name(node_template_type),
                    '" as node_',
                    normalize_name(container_name),
                    sep="",
                )
            else:
                self.generate(
                    uml2_kind,
                    ' "',
                    container_name,
                    ": ",
                    short_type_name(node_template_type),
                    '" as node_',
                    normalize_name(container_name),
                    " {",
                    sep="",
                )
                for contained_name, contained_dict in containeds.items():
                    generate_container(self, contained_name, contained_dict)
                for artifact_name, artifact_yaml in node_template_artifacts.items(
                ):
                    artifact_type = syntax.get_artifact_type(artifact_yaml)
                    if artifact_type is None:
                        artifact_type = "Artifact"
                    self.generate(
                        'artifact "',
                        syntax.get_artifact_file(artifact_yaml),
                        '" <<',
                        artifact_type,
                        ">> as node_",
                        normalize_name(container_name),
                        "_artifact_",
                        normalize_name(artifact_name),
                        sep="",
                    )
                self.generate("}")

        substitution_mappings = topology_template.get(SUBSTITUTION_MAPPINGS)
        if substitution_mappings:
            # Create components connected to the capabilities of the substitition mapping.
            for capability_name, capability_yaml in get_dict(
                    substitution_mappings, CAPABILITIES).items():
                self.generate(
                    'component "a node" as substitution_mappings_capability_',
                    normalize_name(capability_name),
                    sep="",
                )

            substitution_mappings_node_type = substitution_mappings.get(
                NODE_TYPE)
            self.generate(
                get_uml2_kind(substitution_mappings_node_type),
                ' ": ',
                substitution_mappings_node_type,
                '" as substitution_mappings {',
                sep="",
            )

        for container_name, containeds in containers.items():
            generate_container(self, container_name, containeds)

        for node_template_name in non_containeds:
            generate_container(self, node_template_name, {})

        relationship_templates = get_dict(topology_template,
                                          RELATIONSHIP_TEMPLATES)

        # Iterate over all node templates to draw relationships.
        for node_template_name, node_template_yaml in node_templates.items():
            merged_node_template_type = self.type_system.merge_node_type(
                node_template_yaml.get(TYPE))
            # Iterate over all requirements of the node template.
            for requirement in get_list(node_template_yaml, REQUIREMENTS):
                for requirement_name, requirement_yaml in requirement.items():
                    requirement_relationship_type = None
                    if type(requirement_yaml) == dict:
                        requirement_relationship = syntax.get_requirement_relationship(
                            requirement_yaml)
                        if type(requirement_relationship) == dict:
                            requirement_relationship_type = syntax.get_relationship_type(
                                requirement_relationship)
                        else:
                            relationship_template = relationship_templates.get(
                                requirement_relationship)
                            if relationship_template:
                                requirement_relationship_type = relationship_template.get(
                                    TYPE)
                            else:
                                requirement_relationship_type = requirement_relationship
                    if requirement_relationship_type is None:
                        requirement = get_dict(merged_node_template_type,
                                               REQUIREMENTS).get(
                                                   requirement_name, {})
                        tmp = syntax.get_requirement_relationship(requirement)
                        requirement_relationship_type = syntax.get_relationship_type(
                            tmp)
                    if requirement_relationship_type is None:
                        continue

                    if not self.type_system.is_derived_from(
                            requirement_relationship_type,
                            "tosca.relationships.HostedOn"):
                        requirement_node = get_requirement_node_template(
                            requirement_yaml)
                        if requirement_node:
                            self.generate(
                                "node_",
                                normalize_name(node_template_name),
                                ' "',
                                requirement_name,
                                '" ..> node_',
                                normalize_name(requirement_node),
                                " : <<",
                                short_type_name(requirement_relationship_type),
                                ">>",
                                sep="",
                            )

        if substitution_mappings:
            self.generate("}")
            # Connect created components to the nodes exported by the capabilities of the substitition mapping.
            for capability_name, capability_yaml in get_dict(
                    substitution_mappings, CAPABILITIES).items():
                if type(capability_yaml) != list:
                    continue  # TODO
                target_node_name = capability_yaml[0]
                target_capability_name = capability_yaml[1]
                self.generate(
                    "substitution_mappings_capability_",
                    normalize_name(capability_name),
                    ' "',
                    capability_name,
                    '" ..> node_',
                    normalize_name(target_node_name),
                    sep="",
                )

            merged_substitution_mappings_node_type = self.type_system.merge_node_type(
                substitution_mappings_node_type)
            # Get all requirements of the node type of the substitution mapping.
            all_requirement_declarations = get_dict(
                merged_substitution_mappings_node_type, REQUIREMENTS)
            req_idx = 0
            # Iterate over all requirements of the substitution mapping.
            for (
                    requirement_name,
                    requirement_yaml,
            ) in syntax.get_substitution_mappings_requirements(
                    substitution_mappings).items():
                requirement_capability = syntax.get_requirement_capability(
                    all_requirement_declarations.get(requirement_name))
                if requirement_capability is None:
                    continue
                self.generate(
                    get_uml2_kind(requirement_capability),
                    ' ": ',
                    short_type_name(requirement_capability),
                    '" as substitution_mappings_requirement_',
                    req_idx,
                    sep="",
                )
                requirement_node = requirement_yaml[0]
                requirement_node_capability = requirement_yaml[1]
                self.generate(
                    "node_",
                    normalize_name(requirement_node),
                    ' "',
                    normalize_name(requirement_node_capability),
                    '" ..> "',
                    requirement_name,
                    '" substitution_mappings_requirement_',
                    req_idx,
                    sep="",
                )
                req_idx = req_idx + 1

        self.generate("@enduml")
    def generate_UML2_component_diagram(self, topology_template,
                                        with_relationships):
        self.generate("@startuml")
        self.generate("skinparam componentStyle uml2")
        if with_relationships:
            self.generate("skinparam component {")
            self.generate("  backgroundColor<<relationship>> White")
            self.generate("}")
        self.generate()

        substitution_mappings = topology_template.get(SUBSTITUTION_MAPPINGS)
        if substitution_mappings:
            substitution_mappings_uml_id = SUBSTITUTION_MAPPINGS
            substitution_mappings_node_type = substitution_mappings.get(
                NODE_TYPE)
            merged_substitution_mappings_type = self.type_system.merge_node_type(
                substitution_mappings_node_type)
            for capability_name, capability_yaml in get_dict(
                    merged_substitution_mappings_type, CAPABILITIES).items():
                capability_uml_id = (substitution_mappings_uml_id + "_" +
                                     normalize_name(capability_name))
                # Declare an UML interface for the substitution_mappings capability.
                self.generate('interface "',
                              capability_name,
                              '" as ',
                              capability_uml_id,
                              sep="")
            self.generate(
                'component ": ',
                substitution_mappings_node_type,
                '" <<node>> as ',
                substitution_mappings_uml_id,
                " {",
                sep="",
            )

        relationship_templates = get_dict(topology_template,
                                          RELATIONSHIP_TEMPLATES)

        already_generated_interfaces = {}

        # Iterate over all node templates.
        node_templates = get_dict(topology_template, NODE_TEMPLATES)
        for node_template_name, node_template_yaml in node_templates.items():
            node_template_type = node_template_yaml.get(TYPE)
            merged_node_template_type = self.type_system.merge_node_type(
                node_template_type)
            node_template_uml_id = "node_" + normalize_name(node_template_name)
            # Declare an UML component for the node template.
            self.generate(
                'component "',
                node_template_name,
                ": ",
                short_type_name(node_template_type),
                '" <<node>> as ',
                node_template_uml_id,
                sep="",
            )
            # Iterate over all capabilities of the node template.
            for capability_name, capability_yaml in get_dict(
                    merged_node_template_type, CAPABILITIES).items():
                if type(capability_yaml) == dict:
                    capability_occurrences = capability_yaml.get(OCCURRENCES)
                else:
                    capability_occurrences = None
                if with_relationships or (capability_occurrences
                                          and capability_occurrences[0] > 0):
                    capability_uml_id = (node_template_uml_id + "_" +
                                         normalize_name(capability_name))
                    # Declare an UML interface for the node template capability.
                    self.generate(
                        'interface "',
                        capability_name,
                        '" as ',
                        capability_uml_id,
                        sep="",
                    )
                    # Connect the capability UML interface to the node template UML component.
                    self.generate(capability_uml_id, "--",
                                  node_template_uml_id)
                    already_generated_interfaces[
                        capability_uml_id] = capability_uml_id
            if with_relationships:
                # Iterate over all requirements of the node template.
                index = 0
                for requirement in get_list(node_template_yaml, REQUIREMENTS):
                    for requirement_name, requirement_yaml in requirement.items(
                    ):
                        requirement_uml_id = (
                            node_template_uml_id + "_" +
                            normalize_name(requirement_name) +
                            "_relationship" + str(index))
                        index = index + 1

                        requirement_node = get_requirement_node_template(
                            requirement_yaml)
                        if requirement_node is None:
                            continue

                        relationship_component_name = ""  # No name.
                        relationship_component_type = None

                        if type(requirement_yaml) == dict:
                            requirement_relationship = syntax.get_requirement_relationship(
                                requirement_yaml)
                            if type(requirement_relationship) == dict:
                                relationship_component_type = syntax.get_relationship_type(
                                    requirement_relationship)
                            else:
                                relationship_template = relationship_templates.get(
                                    requirement_relationship)
                                if relationship_template:
                                    relationship_component_name = (
                                        requirement_relationship)
                                    relationship_component_type = relationship_template.get(
                                        TYPE)
                                else:
                                    relationship_component_type = (
                                        requirement_relationship)
                        if relationship_component_type is None:
                            requirement = get_dict(merged_node_template_type,
                                                   REQUIREMENTS).get(
                                                       requirement_name, {})
                            tmp = syntax.get_requirement_relationship(
                                requirement)
                            relationship_component_type = syntax.get_relationship_type(
                                tmp)
                        if relationship_component_type is None:
                            continue
                        # Declare an UML component for the node template requirement relationship.
                        self.generate(
                            'component "',
                            relationship_component_name,
                            ": ",
                            short_type_name(relationship_component_type),
                            '" <<relationship>> as ',
                            requirement_uml_id,
                            sep="",
                        )
                        # Declare an UML interface for the node template requirement relationship.
                        self.generate('interface " " as ',
                                      requirement_uml_id,
                                      "_source",
                                      sep="")
                        # Connect the UML interface to the relationship UML component.
                        self.generate(
                            requirement_uml_id,
                            "_source",
                            " -- ",
                            requirement_uml_id,
                            sep="",
                        )
                        # Connect the node template UML component to the relationship UML component.
                        self.generate(
                            node_template_uml_id,
                            " --( ",
                            requirement_uml_id,
                            "_source",
                            " : ",
                            requirement_name,
                            sep="",
                        )
            self.generate()

        # Iterate over all node templates.
        for node_template_name, node_template_yaml in node_templates.items():
            node_template_uml_id = "node_" + normalize_name(node_template_name)
            node_template_type = node_template_yaml.get(TYPE)
            merged_node_template_type = self.type_system.merge_node_type(
                node_template_type)
            # Iterate over all requirements of the node template.
            index = 0
            for requirement in get_list(node_template_yaml, REQUIREMENTS):
                for requirement_name, requirement_yaml in requirement.items():
                    source_uml_id = node_template_uml_id
                    if with_relationships:
                        source_uml_id = (source_uml_id + "_" +
                                         normalize_name(requirement_name) +
                                         "_relationship" + str(index))
                    index = index + 1
                    requirement_node = get_requirement_node_template(
                        requirement_yaml)
                    if requirement_node is None:
                        continue
                    requirement_node_template = node_templates.get(
                        requirement_node)
                    if requirement_node_template is None:
                        continue
                    requirement_node_type_name = requirement_node_template.get(
                        TYPE)
                    if requirement_node_type_name is None:
                        continue

                    requirement_capability = syntax.get_requirement_capability(
                        get_dict(merged_node_template_type,
                                 REQUIREMENTS).get(requirement_name))
                    capability_found = False
                    for (capability_name, capability_yaml) in get_dict(
                            self.type_system.merge_node_type(
                                requirement_node_type_name),
                            CAPABILITIES,
                    ).items():
                        if self.type_system.is_derived_from(
                                syntax.get_capability_type(capability_yaml),
                                requirement_capability,
                        ):
                            capability_found = True
                            break
                    if capability_found:
                        target_node_uml_id = "node_" + normalize_name(
                            requirement_node)
                        target_capability_uml_id = (
                            target_node_uml_id + "_" +
                            normalize_name(capability_name))
                        if with_relationships:
                            self.generate(source_uml_id,
                                          " --( ",
                                          target_capability_uml_id,
                                          sep="")
                        else:
                            if (already_generated_interfaces.get(
                                    target_capability_uml_id) is None):
                                self.generate(
                                    'interface "',
                                    capability_name,
                                    '" as ',
                                    target_capability_uml_id,
                                    sep="",
                                )
                                # Connect the capability UML interface to the node template UML component.
                                self.generate(target_capability_uml_id, "--",
                                              target_node_uml_id)
                                already_generated_interfaces[
                                    target_capability_uml_id] = target_capability_uml_id
                            self.generate(
                                source_uml_id,
                                " --( ",
                                target_capability_uml_id,
                                " : ",
                                requirement_name,
                                sep="",
                            )

        if substitution_mappings:
            capabilities = get_dict(substitution_mappings, CAPABILITIES)

            for capability_name, capability_yaml in get_dict(
                    merged_substitution_mappings_type, CAPABILITIES).items():
                capability = capabilities.get(capability_name)
                if capability is not None:
                    if type(capability) != list:
                        continue  # TODO when capability is not a list
                    target_node_uml_id = "node_" + capability[0]
                    target_uml_id = (target_node_uml_id + "_" +
                                     normalize_name(capability[1]))

                    if already_generated_interfaces.get(target_uml_id) is None:
                        self.generate(
                            'interface "',
                            capability_name,
                            '" as ',
                            target_uml_id,
                            sep="",
                        )
                        # Connect the capability UML interface to the node template UML component.
                        self.generate(target_uml_id, "--", target_node_uml_id)
                        already_generated_interfaces[
                            target_uml_id] = target_uml_id

            self.generate("}")

            for capability_name, capability_yaml in get_dict(
                    merged_substitution_mappings_type, CAPABILITIES).items():
                capability_uml_id = (substitution_mappings_uml_id + "_" +
                                     normalize_name(capability_name))
                # Connect the capability UML interface to the node template UML component.
                capability = capabilities.get(capability_name)
                if capability is not None:
                    if type(capability) != list:
                        continue  # TODO when capability is not a list
                    target_node_uml_id = "node_" + capability[0]
                    target_uml_id = (target_node_uml_id + "_" +
                                     normalize_name(capability[1]))
                    self.generate(capability_uml_id, "--(", target_uml_id)
                else:
                    self.generate(capability_uml_id, "--",
                                  substitution_mappings_uml_id)

            index = 0
            for (
                    requirement_name,
                    requirement_yaml,
            ) in syntax.get_substitution_mappings_requirements(
                    substitution_mappings).items():
                interface_uml_id = (substitution_mappings_uml_id + "_" +
                                    normalize_name(requirement_name) +
                                    str(index))
                index = index + 1
                self.generate('interface "', requirement_name, '" as ',
                              interface_uml_id)
                if requirement_yaml:
                    source_uml_id = "node_" + normalize_name(
                        requirement_yaml[0])
                    self.generate(
                        source_uml_id,
                        " --( ",
                        interface_uml_id,
                        " : ",
                        requirement_yaml[1],
                        sep="",
                    )
                else:
                    self.generate(
                        substitution_mappings_uml_id,
                        " -- ",
                        interface_uml_id,
                        " : ",
                        requirement_name,
                    )

        self.generate("@enduml")