2 releases

0.1.1 Nov 23, 2024
0.1.0 Nov 22, 2024

#107 in Template engine

Download history 234/week @ 2024-11-18 38/week @ 2024-11-25

272 downloads per month

MIT license

50KB
951 lines

TOSCA-Solver

This crate infers the relationships between TOSCA node templates when given a set of node templates and their requirements.

Each TOSCA requirement is encoded as a set of constraints including:

  • node and capability types
  • the relationship's valid_target_types
  • node_filter constraints
  • node_filter match expressions

solve() will return the nodes that match the requirements associated with a given set of nodes.

By default this crate is exposed as a Python extension module and is used by Unfurl, but it could be used by any TOSCA 1.3 processor.

Usage

By default, this crate is built as a Python extension, to disable this feature, set default-features = false. The solve function is its main entry point and can invoked from the Rust or Python. Your TOSCA topology will have to be encoded as a HashMap of Nodes -- see https://github.com/onecommons/unfurl/blob/main/unfurl/solver.py for an example.

Design notes

Finding the match for a TOSCA requirement with a node_filter can't be determined with a simple algorithm. For example, a requirement node_filter's match can depend on a property value that is itself computed from a requirement (e.g. via TOSCA's get_property function). So finding a node filter match might change a property's value, which in turn could affect the node_filter match.

In addition to this basic functionality, this solver will use type inference to resolve requirements that haven't defined explicit node targets and supports Unfurl's node_filter extensions for applying constraints and graph querying.

Luckily, by eschewing negation and quantification we can avoid the need for a full SAT solver and instead encode the inference rules as Datalog-like query rules using Ascent -- a simpler and more scalable approach.

Why?

One of Unfurl's goal is to enable adaptable blueprints that can easily compose independent, open-source components -- imagine something like a package manager for the cloud. This crate allows blueprints to express their requirements in a loosely-coupled, generic manner.

Development

You can use the standard cargo commands for development if you use its --no-default-features flag to skip compiling with the "pyo3/extension-module" feature.

To compile the Python extension, in the parent of this directory, run:

python setup.py build_rust --debug --inplace

Run pip install setuptools-rust>=1.7.0 pbr to install setup.py's requirements.

Tests

Cargo tests should be invoked with cargo test --no-default-features because the "pyo3/extension-module" feature doesn't work with cargo test.

Unfurl's Python unit tests have more extensive tests in https://github.com/onecommons/unfurl/blob/main/tests/test_solver.py. See Unfurl's main README for instructions on running its unit tests.

Dependencies

~7MB
~125K SLoC